diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..017f612 Binary files /dev/null and b/.DS_Store differ diff --git a/.env b/.env deleted file mode 100644 index e223a35..0000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -SERVER_ROOT='https://mobile-stage.eatvio.ru/api' -STORAGE_URL='https://mobile-stage.eatvio.ru/storage/' \ No newline at end of file diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 955d74d..e8e1609 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -78,7 +78,6 @@ jobs: - name: Test run: | - touch .env flutter test - name: Build apk diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a8fbb7d..54d180c 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -84,12 +84,11 @@ jobs: - name: Native Analyze run: flutter analyze - - name: Run Code Metrics - run: flutter pub run dart_code_metrics:metrics lib --disable-sunset-warning --fatal-warnings --fatal-performance + #- name: Run Code Metrics + # run: flutter pub run dart_code_metrics:metrics lib --disable-sunset-warning --fatal-warnings --fatal-performance - name: Test run: | - touch .env flutter test - name: Build apk @@ -107,5 +106,5 @@ jobs: - name: Upload APK artifact uses: actions/upload-artifact@v3 with: - name: EatvioApp-APK + name: ${{ env.APK_NAME }} path: ${{ env.APK_NAME }} diff --git a/.gitignore b/.gitignore index e167a73..4a5c4e7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ /.flutter-plugins /.flutter-plugins-dependencies /.packages -/.env \ No newline at end of file +/node_modules/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cd6bc42 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +run-tests: + flutter test + +run-analyse: + flutter analyze + +run-checks: run-analyse run-tests \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index 22f0401..3d36fce 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -27,10 +27,8 @@ dart_code_metrics: # maximum-nesting-level: 5 # metrics-exclude: # - test/** -# rules: # - newline-before-return # - no-boolean-literal-compare # - no-empty-block -# - prefer-trailing-comma # - prefer-conditional-expressions -# - no-equal-then-else +# - no-equal-then-else \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 435e017..516dace 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,13 +1,9 @@ - - + + - + \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 536165d..83b4cf1 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false + id "com.android.application" version "7.3.1" apply false + id "org.jetbrains.kotlin.android" version "1.9.10" apply false } include ":app" diff --git a/flutter_01.log b/flutter_01.log new file mode 100644 index 0000000..f7f3c20 --- /dev/null +++ b/flutter_01.log @@ -0,0 +1,97 @@ +Flutter crash report. +Please report a bug at https://github.com/flutter/flutter/issues. + +## command + +flutter analyze + +## exception + +PathNotFoundException: PathNotFoundException: Cannot open file, path = '/home/alex/snap/flutter/common/flutter/version' (OS Error: No such file or directory, errno = 2) + +``` +#0 _File.throwIfError (dart:io/file_impl.dart:675:7) +#1 _File.openSync (dart:io/file_impl.dart:490:5) +#2 _File.readAsBytesSync (dart:io/file_impl.dart:574:18) +#3 _File.readAsStringSync (dart:io/file_impl.dart:624:18) +#4 ForwardingFile.readAsStringSync (package:file/src/forwarding/forwarding_file.dart:99:16) +#5 ErrorHandlingFile.readAsStringSync. (package:flutter_tools/src/base/error_handling_io.dart:217:22) +#6 _runSync (package:flutter_tools/src/base/error_handling_io.dart:587:14) +#7 ErrorHandlingFile.readAsStringSync (package:flutter_tools/src/base/error_handling_io.dart:216:12) +#8 _DefaultPub.get (package:flutter_tools/src/dart/pub.dart:302:58) +#9 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:1724:17) + +#10 FlutterCommand.run. (package:flutter_tools/src/runner/flutter_command.dart:1394:27) + +#11 AppContext.run. (package:flutter_tools/src/base/context.dart:153:19) + +#12 CommandRunner.runCommand (package:args/command_runner.dart:212:13) + +#13 FlutterCommandRunner.runCommand. (package:flutter_tools/src/runner/flutter_command_runner.dart:372:9) + +#14 AppContext.run. (package:flutter_tools/src/base/context.dart:153:19) + +#15 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:308:5) + +#16 run.. (package:flutter_tools/runner.dart:130:9) + +#17 AppContext.run. (package:flutter_tools/src/base/context.dart:153:19) + +#18 main (package:flutter_tools/executable.dart:93:3) + +``` + +## flutter doctor + +``` +[!] Flutter (Channel [user-branch], 0.0.0-unknown, on Ubuntu 24.04 LTS 6.8.0-38-generic, locale ru_RU.UTF-8) + ! Flutter version 0.0.0-unknown on channel [user-branch] at /home/alex/snap/flutter/common/flutter + Currently on an unknown channel. Run `flutter channel` to switch to an official channel. + If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install. + Cannot resolve current version, possibly due to local changes. + Reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install. + ! Upstream repository unknown source is not a standard remote. + Set environment variable "FLUTTER_GIT_URL" to unknown source to dismiss this error. + • Framework revision (), 1970-01-01 03:00:00.000 + • Engine revision edd8546116 + • Dart version 3.4.3 + • DevTools version 2.34.3 + • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades. + +[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) + • Android SDK at /home/alex/Android/Sdk + • Platform android-35, build-tools 35.0.0 + • Java binary at: /snap/android-studio/161/jbr/bin/java + • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105) + • All Android licenses accepted. + +[✓] Chrome - develop for the web + • Chrome at google-chrome + +[✓] Linux toolchain - develop for Linux desktop + • clang version 10.0.0-4ubuntu1 + • cmake version 3.16.3 + • ninja version 1.10.0 + • pkg-config version 0.29.1 + +[✓] Android Studio (version 2024.1) + • Android Studio at /snap/android-studio/161 + • Flutter plugin version 80.0.2 + • Dart plugin can be installed from: + 🔨 https://plugins.jetbrains.com/plugin/6351-dart + • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105) + +[✓] VS Code (version 1.91.1) + • VS Code at /usr/share/code + • Flutter extension version 3.92.0 + +[✓] Connected device (3 available) + • sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 15 (API 35) (emulator) + • Linux (desktop) • linux • linux-x64 • Ubuntu 24.04 LTS 6.8.0-38-generic + • Chrome (web) • chrome • web-javascript • Google Chrome 126.0.6478.126 + +[✓] Network resources + • All expected network resources are available. + +! Doctor found issues in 1 category. +``` diff --git a/ios/Podfile b/ios/Podfile index 279576f..27c089c 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '12.0' +platform :ios, '14.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -37,5 +37,9 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) + target.build_configurations.each do |config| + config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' + end end end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 68ec53f..7454c98 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 68F4DD6659288F4CFDC41C5C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7024DE075B2C1E5A149230E4 /* Pods_Runner.framework */; }; + 46B43B96F809CEC6058EFDD3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15ADDB2A35F334AF0AE50011 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -32,13 +32,12 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1DC098B20AE17A152A9E7BC6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 15ADDB2A35F334AF0AE50011 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 4B6A3CFB60775CA626789750 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 7024DE075B2C1E5A149230E4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 938EE8FB5BAA359AAEDEFFF8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -46,7 +45,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - EC46FEE88A2E87A3510B5EC3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 9D8D6181877DE17809AFF936 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + DF0C4038A57E19D3ABA03C15 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,27 +54,19 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 68F4DD6659288F4CFDC41C5C /* Pods_Runner.framework in Frameworks */, + 46B43B96F809CEC6058EFDD3 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 28430AE518366E9EB19A31C9 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7024DE075B2C1E5A149230E4 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 6F201E010624CF963CC3A17B /* Pods */ = { isa = PBXGroup; children = ( - 1DC098B20AE17A152A9E7BC6 /* Pods-Runner.debug.xcconfig */, - 4B6A3CFB60775CA626789750 /* Pods-Runner.release.xcconfig */, - EC46FEE88A2E87A3510B5EC3 /* Pods-Runner.profile.xcconfig */, + 938EE8FB5BAA359AAEDEFFF8 /* Pods-Runner.debug.xcconfig */, + 9D8D6181877DE17809AFF936 /* Pods-Runner.release.xcconfig */, + DF0C4038A57E19D3ABA03C15 /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -97,7 +89,7 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 6F201E010624CF963CC3A17B /* Pods */, - 28430AE518366E9EB19A31C9 /* Frameworks */, + AEE6B7943D197783DD1CB2EE /* Frameworks */, ); sourceTree = ""; }; @@ -124,6 +116,14 @@ path = Runner; sourceTree = ""; }; + AEE6B7943D197783DD1CB2EE /* Frameworks */ = { + isa = PBXGroup; + children = ( + 15ADDB2A35F334AF0AE50011 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -131,14 +131,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - C9531164650CD277994F87F5 /* [CP] Check Pods Manifest.lock */, + 9A49250058577CAA8C897A03 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 8944C2327F94FA34E28A19A3 /* [CP] Embed Pods Frameworks */, + 1D324C14EB43C988423BC1AD /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -198,23 +198,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 8944C2327F94FA34E28A19A3 /* [CP] Embed Pods Frameworks */ = { + 1D324C14EB43C988423BC1AD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -231,6 +215,22 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -246,7 +246,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - C9531164650CD277994F87F5 /* [CP] Check Pods Manifest.lock */ = { + 9A49250058577CAA8C897A03 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index fb18841..8795a89 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -52,5 +52,12 @@ UIApplicationSupportsIndirectInputEvents + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSLocationWhenInUseUsageDescription + diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/FMDB.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/FMDB.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/FMDB.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/Flutter.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/Flutter.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/Flutter.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/flutter_keyboard_visibility.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/flutter_keyboard_visibility.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/flutter_keyboard_visibility.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios-image_picker_ios_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios-image_picker_ios_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios-image_picker_ios_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/image_picker_ios.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/isar_flutter_libs.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/isar_flutter_libs.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/isar_flutter_libs.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/location.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/location.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/location.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation-path_provider_foundation_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation-path_provider_foundation_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation-path_provider_foundation_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/path_provider_foundation.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios-pointer_interceptor_ios_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios-pointer_interceptor_ios_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios-pointer_interceptor_ios_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/pointer_interceptor_ios.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation-shared_preferences_foundation_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation-shared_preferences_foundation_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation-shared_preferences_foundation_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/shared_preferences_foundation.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite-sqflite_ios_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite-sqflite_ios_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite-sqflite_ios_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/sqflite.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios-url_launcher_ios_privacy.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios-url_launcher_ios_privacy.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios-url_launcher_ios_privacy.build/dgph differ diff --git a/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios.build/dgph b/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios.build/dgph new file mode 100644 index 0000000..01c5654 Binary files /dev/null and b/ios/build/ios/Pods.build/Release-iphonesimulator/url_launcher_ios.build/dgph differ diff --git a/lib/app_router.dart b/lib/app_router.dart index 3c60e6e..9685111 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -1,37 +1,28 @@ +import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/blog_post/presentation/pages/blog_post_screen.dart'; +import 'package:eatvio_app/features/blog_post_create/presentation/pages/blog_post_create_screen.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart'; +import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; +import 'package:eatvio_app/features/recipes/presentation/pages/about_recipes_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart'; import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/diary_edit_screen.dart'; import 'package:eatvio_app/presentation/diets/diet_create_screen/diet_create_screen.dart'; import 'package:eatvio_app/presentation/diets/diet_select_screen/diet_select_screen.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_create_screen/blog_post_create_screen.dart'; import 'package:eatvio_app/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_screen/blog_post_screen.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/feed_screen.dart'; import 'package:eatvio_app/presentation/glossary/glossary_screen/glossary_screen.dart'; import 'package:eatvio_app/presentation/plans/plan_select_screen/plan_select_screen.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/my_profile_screen.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/my_settings_screen.dart'; import 'package:eatvio_app/presentation/recipe/recipe_select_screen/recipe_select_screen.dart'; -import 'package:eatvio_app/presentation/registration/additional_information_screen/additional_information_screen.dart'; -import 'package:eatvio_app/presentation/registration/allergies_screen/allergies_screen.dart'; -import 'package:eatvio_app/presentation/registration/blood_pressure_screen/blood_pressure_screen.dart'; -import 'package:eatvio_app/presentation/registration/body_circumferences_screen/body_circumferences_screen.dart'; -import 'package:eatvio_app/presentation/registration/city_of_living_screen/city_of_living_screen.dart'; -import 'package:eatvio_app/presentation/registration/credentials_screen/credentials_screen.dart'; -import 'package:eatvio_app/presentation/registration/date_of_birth_screen/date_of_birth_screen.dart'; -import 'package:eatvio_app/presentation/registration/favorite_foods_screen/favorite_foods_screen.dart'; -import 'package:eatvio_app/presentation/registration/favorite_sports_screen/favorite_sports_screen.dart'; -import 'package:eatvio_app/presentation/registration/gender_screen/gender_screen.dart'; -import 'package:eatvio_app/presentation/registration/height_screen/height_screen.dart'; -import 'package:eatvio_app/presentation/registration/language_select_screen/language_select_screen.dart'; -import 'package:eatvio_app/presentation/registration/medicine_intake_screen/medicine_intake_screen.dart'; -import 'package:eatvio_app/presentation/registration/name_screen/name_screen.dart'; -import 'package:eatvio_app/presentation/registration/weight_screen/weight_screen.dart'; -import 'package:eatvio_app/widgets/bottom_navigation_bar_widget.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; class AppRouter { @@ -45,111 +36,17 @@ class AppRouter { path: '/auth-screen', name: 'authScreen', redirect: (context, state) async { - if (await TokenStorage.haveTokenInStorage()) return '/my-profile-screen'; + if (await TokenStorage.haveTokenInStorage()) { + return '/my-profile-screen'; + } return null; }, builder: (context, state) => AuthScreen.builder(context), routes: [ GoRoute( - path: 'language-select-screen', - name: 'languageSelectScreen', - builder: (context, state) => LanguageSelectScreen.builder(context), - routes: [ - GoRoute( - path: 'credentials-screen', - name: 'credentialsScreen', - builder: (context, state) => CredentialsScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'name-screen', - name: 'nameScreen', - builder: (context, state) => NameScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'gender-screen', - name: 'genderScreen', - builder: (context, state) => GenderScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'date-of-birth-screen', - name: 'dateOfBirthScreen', - builder: (context, state) => DateOfBirthScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'city-of-living-screen', - name: 'cityOfLivingScreen', - builder: (context, state) => CityOfLivingScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'body-circumferences-screen', - name: 'bodyCircumferencesScreen', - builder: (context, state) => BodyCircumferencesScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'weight-screen', - name: 'weightScreen', - builder: (context, state) => WeightScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'height-screen', - name: 'heightScreen', - builder: (context, state) => HeightScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'blood-pressure-screen', - name: 'bloodPressureScreen', - builder: (context, state) => BloodPressureScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'favorite-sports-screen', - name: 'favoriteSportsScreen', - builder: (context, state) => FavoriteSportsScreen.builder(context, state.extra), - routes: [ - GoRoute( - name: 'allergiesScreen', - path: 'allergiesScreen', - builder: (context, state) => AllergiesScreen.builder(context, state.extra), - routes: [ - GoRoute( - name: 'medicineIntakeScreen', - path: 'medicine-intake-screen', - builder: (context, state) => MedicineIntakeScreen.builder(context, state.extra), - ), - GoRoute( - name: 'favoriteFoodsScreen', - path: 'favorite-foods-screen', - builder: (context, state) => FavoriteFoodsScreen.builder(context, state.extra), - routes: [ - GoRoute( - path: 'additional-information-screen', - name: 'additionalInformationScreen', - builder: (context, state) => AdditionalInformationScreen.builder(context, state.extra), - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], - ), - ], + path: 'registration-screen', + name: 'registrationScreen', + builder: (context, state) => const RegistrationScreen(), ), ], ), @@ -161,57 +58,64 @@ class AppRouter { GoRoute( path: '/my-profile-screen', name: 'myProfileScreen', + redirect: (context, state) async { + await context.read().runInitialization(); + return null; + }, builder: (context, state) => MyProfileScreen(), ), GoRoute( path: '/feed-screen', name: 'feedScreen', builder: (context, state) => FeedScreen(), - routes: [ - GoRoute( - path: 'blog-post-create-screen', - name: 'blogPostCreateScreen', - builder: (context, state) => BlogPostCreateScreen.builder(context), - ), - GoRoute( - path: 'blog-post-screen', - name: 'blogPostScreen', - builder: (context, state) => BlogPostScreen.builder( - context, - state.extra.toString(), - ), - routes: [ - GoRoute( - path: 'blog-post-edit-screen', - name: 'blogPostEditScreen', - builder: (context, state) => BlogPostEditScreen.builder( - context, - state.extra, - ), - ), - ], - ), - ], ), GoRoute( - path: '/diary-screen', - name: 'diaryScreen', - builder: (context, state) => DiaryEditScreen(), - ), + path: '/diary-screen', + name: 'diaryScreen', + builder: (context, state) { + if (state.extra != null) + return DiaryScreen(diaryID: state.extra as String); + else + return DiaryScreen(diaryID: '0'); + }), GoRoute( path: '/chat-select-screen', name: 'chatSelectScreen', builder: (context, state) => ChatSelectScreen(), - routes: [ - GoRoute( - path: 'chat-screen', - name: 'chatScreen', - builder: (context, state) => ChatScreen(chatId: state.extra as String), - ), - ], ), ], ), + GoRoute( + path: '/about-recipes-screen', + name: 'aboutRecipesScreen', + builder: (context, state) => AboutRecipesScreen( + recipes: state.extra as Recipes, + ), + ), + GoRoute( + path: '/blog-post-create-screen', + name: 'blogPostCreateScreen', + builder: (context, state) => BlogPostCreateScreen.builder(context), + ), + GoRoute( + path: '/blog-post-screen', + name: 'blogPostScreen', + builder: (context, state) => + BlogPostScreen(blogPostID: state.extra as String), + ), + GoRoute( + path: '/blog-post-edit-screen', + name: 'blogPostEditScreen', + builder: (context, state) => BlogPostEditScreen.builder( + context, + state.extra, + ), + ), + GoRoute( + path: '/chat-screen', + name: 'chatScreen', + builder: (context, state) => ChatScreen(chatId: state.extra as String), + ), GoRoute( path: '/my-settings-screen', name: 'mySettingsScreen', @@ -237,6 +141,11 @@ class AppRouter { name: 'planSelectScreen', builder: (context, state) => PlanSelectScreen.builder(context), ), + GoRoute( + path: '/calendar-screen', + name: 'calendarScreen', + builder: (context, state) => CalendarScreen(), + ), GoRoute( path: '/glossary-screen', name: 'glossaryScreen', diff --git a/lib/core/app_export.dart b/lib/core/app_export.dart index 233b58c..76a7955 100644 --- a/lib/core/app_export.dart +++ b/lib/core/app_export.dart @@ -1,7 +1,6 @@ -export 'package:flutter_bloc/flutter_bloc.dart'; export 'package:eatvio_app/core/constants/constants.dart'; export 'package:eatvio_app/core/errors/exceptions.dart'; -export 'package:eatvio_app/core/network/network_info.dart'; +export 'package:eatvio_app/core/utils/date_time_utils.dart'; export 'package:eatvio_app/core/utils/image_constant.dart'; export 'package:eatvio_app/core/utils/logger.dart'; export 'package:eatvio_app/core/utils/pref_utils.dart'; @@ -12,6 +11,7 @@ export 'package:eatvio_app/theme/app_decoration.dart'; export 'package:eatvio_app/theme/custom_text_style.dart'; export 'package:eatvio_app/theme/theme_helper.dart'; export 'package:eatvio_app/widgets/custom_image_view.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + export '../theme/bloc/theme_bloc.dart'; export '../theme/custom_button_style.dart'; -export 'package:eatvio_app/core/utils/date_time_utils.dart'; diff --git a/lib/core/constants/constants.dart b/lib/core/constants/constants.dart index 8b13789..396c2dc 100644 --- a/lib/core/constants/constants.dart +++ b/lib/core/constants/constants.dart @@ -1 +1 @@ - +const String baseUrl = 'https://dev2.eatvio.com'; diff --git a/lib/core/errors/exceptions.dart b/lib/core/errors/exceptions.dart index d7d4de8..7cbb3f1 100644 --- a/lib/core/errors/exceptions.dart +++ b/lib/core/errors/exceptions.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/main.dart'; +import 'package:flutter/material.dart'; class ServerException implements Exception {} @@ -13,8 +13,7 @@ class NoInternetException implements Exception { NoInternetException([String message = 'NoInternetException Occurred']) { if (globalMessengerKey.currentState != null) { - globalMessengerKey.currentState! - .showSnackBar(SnackBar(content: Text(message))); + globalMessengerKey.currentState!.showSnackBar(SnackBar(content: Text(message))); } this._message = message; } diff --git a/lib/core/initialization_cubit/initialization_cubit.dart b/lib/core/initialization_cubit/initialization_cubit.dart new file mode 100644 index 0000000..29a42f6 --- /dev/null +++ b/lib/core/initialization_cubit/initialization_cubit.dart @@ -0,0 +1,100 @@ +import 'package:dart_pusher_channels/dart_pusher_channels.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; +import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; +import 'package:eatvio_app/locator_service.dart'; + +class InitializationCubit extends Cubit { + final ChatRepository chatRepository; + bool wasInitialized = false; + + InitializationCubit({required this.chatRepository}) : super(const InitializationState.loading()); + + Future subscribeNotifications(int userId, PusherChannelsClient client) async { + final privateNotificationChannel = await client.privateChannel( + 'private-message-events.$userId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', + }, + ), + ); + + privateNotificationChannel.subscribe(); + + privateNotificationChannel.bindToAll().listen((event) { + sl().incrementCounter(); + }); + } + + Future subscribeChatMessages(int userId, PusherChannelsClient client) async { + final privateMessagesChannel = await client.privateChannel( + 'private-new-chat-messages.$userId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', + }, + ), + ); + + privateMessagesChannel.subscribe(); + + privateMessagesChannel.bindToAll().listen((event) { + sl().incrementCounter(); + }); + } + + Future runInitialization() async { + if (!wasInitialized) { + wasInitialized = true; + try { + await TokenStorage.haveTokenInStorage(); + final wsUrl = await chatRepository.getWebsocket(); + final options = PusherChannelsOptions.fromHost( + scheme: 'wss', + key: wsUrl.key, + host: wsUrl.host, + shouldSupplyMetadataQueries: true, + metadata: PusherChannelsOptionsMetadata.byDefault(), + port: 443, + ); + final client = PusherChannelsClient.websocket( + options: options, + connectionErrorHandler: (exception, trace, refresh) { + refresh(); + }, + minimumReconnectDelayDuration: const Duration( + seconds: 1, + ), + defaultActivityDuration: const Duration( + seconds: 120, + ), + activityDurationOverride: const Duration( + seconds: 120, + ), + waitForPongDuration: const Duration( + seconds: 30, + ), + ); + await client.connect(); + + await subscribeNotifications(wsUrl.userId, client); + await subscribeChatMessages(wsUrl.userId, client); + + emit(InitializationState.success( + client: client, + )); + } catch (e) { + emit(InitializationState.error( + errorMessage: e.toString(), + )); + rethrow; + } + } + } +} diff --git a/lib/core/initialization_cubit/initialization_state.dart b/lib/core/initialization_cubit/initialization_state.dart new file mode 100644 index 0000000..43318d0 --- /dev/null +++ b/lib/core/initialization_cubit/initialization_state.dart @@ -0,0 +1,19 @@ +import 'package:dart_pusher_channels/dart_pusher_channels.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'initialization_state.freezed.dart'; + +@freezed +abstract class InitializationState with _$InitializationState { + const factory InitializationState() = _InitializationState; + + const factory InitializationState.loading() = InitializationStateLoading; + + const factory InitializationState.success({ + required PusherChannelsClient client, + }) = InitializationStateSuccess; + + const factory InitializationState.error({ + required String errorMessage, + }) = InitializationStateError; +} diff --git a/lib/core/initialization_cubit/initialization_state.freezed.dart b/lib/core/initialization_cubit/initialization_state.freezed.dart new file mode 100644 index 0000000..3364e44 --- /dev/null +++ b/lib/core/initialization_cubit/initialization_state.freezed.dart @@ -0,0 +1,622 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'initialization_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$InitializationState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(PusherChannelsClient client) success, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(PusherChannelsClient client)? success, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(PusherChannelsClient client)? success, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_InitializationState value) $default, { + required TResult Function(InitializationStateLoading value) loading, + required TResult Function(InitializationStateSuccess value) success, + required TResult Function(InitializationStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_InitializationState value)? $default, { + TResult? Function(InitializationStateLoading value)? loading, + TResult? Function(InitializationStateSuccess value)? success, + TResult? Function(InitializationStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_InitializationState value)? $default, { + TResult Function(InitializationStateLoading value)? loading, + TResult Function(InitializationStateSuccess value)? success, + TResult Function(InitializationStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $InitializationStateCopyWith<$Res> { + factory $InitializationStateCopyWith( + InitializationState value, $Res Function(InitializationState) then) = + _$InitializationStateCopyWithImpl<$Res, InitializationState>; +} + +/// @nodoc +class _$InitializationStateCopyWithImpl<$Res, $Val extends InitializationState> + implements $InitializationStateCopyWith<$Res> { + _$InitializationStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitializationStateImplCopyWith<$Res> { + factory _$$InitializationStateImplCopyWith(_$InitializationStateImpl value, + $Res Function(_$InitializationStateImpl) then) = + __$$InitializationStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitializationStateImplCopyWithImpl<$Res> + extends _$InitializationStateCopyWithImpl<$Res, _$InitializationStateImpl> + implements _$$InitializationStateImplCopyWith<$Res> { + __$$InitializationStateImplCopyWithImpl(_$InitializationStateImpl _value, + $Res Function(_$InitializationStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitializationStateImpl implements _InitializationState { + const _$InitializationStateImpl(); + + @override + String toString() { + return 'InitializationState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$InitializationStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(PusherChannelsClient client) success, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(PusherChannelsClient client)? success, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(PusherChannelsClient client)? success, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_InitializationState value) $default, { + required TResult Function(InitializationStateLoading value) loading, + required TResult Function(InitializationStateSuccess value) success, + required TResult Function(InitializationStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_InitializationState value)? $default, { + TResult? Function(InitializationStateLoading value)? loading, + TResult? Function(InitializationStateSuccess value)? success, + TResult? Function(InitializationStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_InitializationState value)? $default, { + TResult Function(InitializationStateLoading value)? loading, + TResult Function(InitializationStateSuccess value)? success, + TResult Function(InitializationStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _InitializationState implements InitializationState { + const factory _InitializationState() = _$InitializationStateImpl; +} + +/// @nodoc +abstract class _$$InitializationStateLoadingImplCopyWith<$Res> { + factory _$$InitializationStateLoadingImplCopyWith( + _$InitializationStateLoadingImpl value, + $Res Function(_$InitializationStateLoadingImpl) then) = + __$$InitializationStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitializationStateLoadingImplCopyWithImpl<$Res> + extends _$InitializationStateCopyWithImpl<$Res, + _$InitializationStateLoadingImpl> + implements _$$InitializationStateLoadingImplCopyWith<$Res> { + __$$InitializationStateLoadingImplCopyWithImpl( + _$InitializationStateLoadingImpl _value, + $Res Function(_$InitializationStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitializationStateLoadingImpl implements InitializationStateLoading { + const _$InitializationStateLoadingImpl(); + + @override + String toString() { + return 'InitializationState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$InitializationStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(PusherChannelsClient client) success, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(PusherChannelsClient client)? success, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(PusherChannelsClient client)? success, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_InitializationState value) $default, { + required TResult Function(InitializationStateLoading value) loading, + required TResult Function(InitializationStateSuccess value) success, + required TResult Function(InitializationStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_InitializationState value)? $default, { + TResult? Function(InitializationStateLoading value)? loading, + TResult? Function(InitializationStateSuccess value)? success, + TResult? Function(InitializationStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_InitializationState value)? $default, { + TResult Function(InitializationStateLoading value)? loading, + TResult Function(InitializationStateSuccess value)? success, + TResult Function(InitializationStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class InitializationStateLoading implements InitializationState { + const factory InitializationStateLoading() = _$InitializationStateLoadingImpl; +} + +/// @nodoc +abstract class _$$InitializationStateSuccessImplCopyWith<$Res> { + factory _$$InitializationStateSuccessImplCopyWith( + _$InitializationStateSuccessImpl value, + $Res Function(_$InitializationStateSuccessImpl) then) = + __$$InitializationStateSuccessImplCopyWithImpl<$Res>; + @useResult + $Res call({PusherChannelsClient client}); +} + +/// @nodoc +class __$$InitializationStateSuccessImplCopyWithImpl<$Res> + extends _$InitializationStateCopyWithImpl<$Res, + _$InitializationStateSuccessImpl> + implements _$$InitializationStateSuccessImplCopyWith<$Res> { + __$$InitializationStateSuccessImplCopyWithImpl( + _$InitializationStateSuccessImpl _value, + $Res Function(_$InitializationStateSuccessImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? client = null, + }) { + return _then(_$InitializationStateSuccessImpl( + client: null == client + ? _value.client + : client // ignore: cast_nullable_to_non_nullable + as PusherChannelsClient, + )); + } +} + +/// @nodoc + +class _$InitializationStateSuccessImpl implements InitializationStateSuccess { + const _$InitializationStateSuccessImpl({required this.client}); + + @override + final PusherChannelsClient client; + + @override + String toString() { + return 'InitializationState.success(client: $client)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$InitializationStateSuccessImpl && + (identical(other.client, client) || other.client == client)); + } + + @override + int get hashCode => Object.hash(runtimeType, client); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$InitializationStateSuccessImplCopyWith<_$InitializationStateSuccessImpl> + get copyWith => __$$InitializationStateSuccessImplCopyWithImpl< + _$InitializationStateSuccessImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(PusherChannelsClient client) success, + required TResult Function(String errorMessage) error, + }) { + return success(client); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(PusherChannelsClient client)? success, + TResult? Function(String errorMessage)? error, + }) { + return success?.call(client); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(PusherChannelsClient client)? success, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (success != null) { + return success(client); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_InitializationState value) $default, { + required TResult Function(InitializationStateLoading value) loading, + required TResult Function(InitializationStateSuccess value) success, + required TResult Function(InitializationStateError value) error, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_InitializationState value)? $default, { + TResult? Function(InitializationStateLoading value)? loading, + TResult? Function(InitializationStateSuccess value)? success, + TResult? Function(InitializationStateError value)? error, + }) { + return success?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_InitializationState value)? $default, { + TResult Function(InitializationStateLoading value)? loading, + TResult Function(InitializationStateSuccess value)? success, + TResult Function(InitializationStateError value)? error, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class InitializationStateSuccess implements InitializationState { + const factory InitializationStateSuccess( + {required final PusherChannelsClient client}) = + _$InitializationStateSuccessImpl; + + PusherChannelsClient get client; + @JsonKey(ignore: true) + _$$InitializationStateSuccessImplCopyWith<_$InitializationStateSuccessImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$InitializationStateErrorImplCopyWith<$Res> { + factory _$$InitializationStateErrorImplCopyWith( + _$InitializationStateErrorImpl value, + $Res Function(_$InitializationStateErrorImpl) then) = + __$$InitializationStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$InitializationStateErrorImplCopyWithImpl<$Res> + extends _$InitializationStateCopyWithImpl<$Res, + _$InitializationStateErrorImpl> + implements _$$InitializationStateErrorImplCopyWith<$Res> { + __$$InitializationStateErrorImplCopyWithImpl( + _$InitializationStateErrorImpl _value, + $Res Function(_$InitializationStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$InitializationStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$InitializationStateErrorImpl implements InitializationStateError { + const _$InitializationStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'InitializationState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$InitializationStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$InitializationStateErrorImplCopyWith<_$InitializationStateErrorImpl> + get copyWith => __$$InitializationStateErrorImplCopyWithImpl< + _$InitializationStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(PusherChannelsClient client) success, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(PusherChannelsClient client)? success, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(PusherChannelsClient client)? success, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_InitializationState value) $default, { + required TResult Function(InitializationStateLoading value) loading, + required TResult Function(InitializationStateSuccess value) success, + required TResult Function(InitializationStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_InitializationState value)? $default, { + TResult? Function(InitializationStateLoading value)? loading, + TResult? Function(InitializationStateSuccess value)? success, + TResult? Function(InitializationStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_InitializationState value)? $default, { + TResult Function(InitializationStateLoading value)? loading, + TResult Function(InitializationStateSuccess value)? success, + TResult Function(InitializationStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class InitializationStateError implements InitializationState { + const factory InitializationStateError({required final String errorMessage}) = + _$InitializationStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$InitializationStateErrorImplCopyWith<_$InitializationStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/core/network/network_info.dart b/lib/core/network/network_info.dart deleted file mode 100644 index c92c521..0000000 --- a/lib/core/network/network_info.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:connectivity_plus/connectivity_plus.dart'; - -// For checking internet connectivity -abstract class NetworkInfoI { - Future isConnected(); - - Future get connectivityResult; - - Stream get onConnectivityChanged; -} - -class NetworkInfo implements NetworkInfoI { - Connectivity connectivity; - - static final NetworkInfo _networkInfo = NetworkInfo._internal(Connectivity()); - - factory NetworkInfo() { - return _networkInfo; - } - - NetworkInfo._internal(this.connectivity) { - connectivity = this.connectivity; - } - - ///checks internet is connected or not - ///returns [true] if internet is connected - ///else it will return [false] - @override - Future isConnected() async { - final result = await connectivity.checkConnectivity(); - if (result != ConnectivityResult.none) { - return true; - } - return false; - } - - // to check type of internet connectivity - @override - Future get connectivityResult async { - return connectivity.checkConnectivity(); - } - - //check the type on internet connection on changed of internet connection - @override - Stream get onConnectivityChanged => - connectivity.onConnectivityChanged; -} diff --git a/lib/core/token_storage.dart b/lib/core/token_storage.dart index 82d2935..1179241 100644 --- a/lib/core/token_storage.dart +++ b/lib/core/token_storage.dart @@ -3,7 +3,7 @@ import 'package:eatvio_app/locator_service.dart'; import 'package:hive_flutter/hive_flutter.dart'; abstract class TokenStorage { - static addTokenToDioHeader(String token) { + static _addTokenToDioHeader(String token) { sl().options.headers['Authorization'] = 'Bearer $token'; } @@ -13,20 +13,17 @@ abstract class TokenStorage { if (token == null) { return false; } else { - addTokenToDioHeader(token); + _addTokenToDioHeader(token); return true; } } - static getTokenFromStorage() async => await Hive.openBox('token') - ..get('token'); + static Future getTokenFromStorage() async => (await Hive.openBox('token')).get('token'); static saveTokenInStorage(String token) async { - await Hive.openBox('token') - ..put('token', token); - addTokenToDioHeader(token); + (await Hive.openBox('token')).put('token', token); + _addTokenToDioHeader(token); } - static removeTokenInStorage(String token) async => await Hive.openBox('token') - ..delete('token'); + static removeTokenInStorage() async => (await Hive.openBox('token')).delete('token'); } diff --git a/lib/core/utils/image_constant.dart b/lib/core/utils/image_constant.dart index 07aa9ab..791dacc 100644 --- a/lib/core/utils/image_constant.dart +++ b/lib/core/utils/image_constant.dart @@ -15,6 +15,7 @@ class ImageConstant { static String imageNotFound = 'assets/images/image_not_found.png'; static String imaGlass = 'assets/images/image_glass.svg'; + // Настройки images static String imgClose = '$imagePath/img_close.svg'; @@ -24,15 +25,13 @@ class ImageConstant { // Блог images static String imgRectangle14 = '$imagePath/img_rectangle_14.png'; - static String imgRectangle14220x341 = - '$imagePath/img_rectangle_14_220x341.png'; + static String imgRectangle14220x341 = '$imagePath/img_rectangle_14_220x341.png'; // Блог - Tab Container images static String imgCrop = '$imagePath/img_crop.svg'; // Статья images - static String imgRectangle14220x375 = - '$imagePath/img_rectangle_14_220x375.png'; + static String imgRectangle14220x375 = '$imagePath/img_rectangle_14_220x375.png'; static String imgVector = '$imagePath/img_vector.svg'; @@ -116,13 +115,11 @@ class ImageConstant { static String imgNavBlueGray400 = '$imagePath/img_nav_blue_gray_400.svg'; - static String imgNavBlueGray40024x23 = - '$imagePath/img_nav_blue_gray_400_24x23.svg'; + static String imgNavBlueGray40024x23 = '$imagePath/img_nav_blue_gray_400_24x23.svg'; static String imgNavPrimary = '$imagePath/img_nav_primary.svg'; - static String imgNavBlueGray40024x25 = - '$imagePath/img_nav_blue_gray_400_24x25.svg'; + static String imgNavBlueGray40024x25 = '$imagePath/img_nav_blue_gray_400_24x25.svg'; static String imgEye = '$imagePath/img_eye.svg'; @@ -134,11 +131,9 @@ class ImageConstant { static String imgEllipse142x42 = '$imagePath/img_ellipse_1_42x42.png'; - static String imgIconMoreHorizontal = - '$imagePath/img_icon_more_horizontal.svg'; + static String imgIconMoreHorizontal = '$imagePath/img_icon_more_horizontal.svg'; - static String imgRectangle14250x311 = - '$imagePath/img_rectangle_14_250x311.png'; + static String imgRectangle14250x311 = '$imagePath/img_rectangle_14_250x311.png'; static String imgIconMessageSquare = '$imagePath/img_icon_message_square.svg'; diff --git a/lib/core/utils/progress_dialog_utils.dart b/lib/core/utils/progress_dialog_utils.dart index ce4da75..ced3347 100644 --- a/lib/core/utils/progress_dialog_utils.dart +++ b/lib/core/utils/progress_dialog_utils.dart @@ -8,18 +8,19 @@ class ProgressDialogUtils { static void showProgressDialog({BuildContext? context, isCancellable = false}) async { if (!isProgressVisible && AppRouter.navigatorKey.currentState?.overlay?.context != null) { showDialog( - barrierDismissible: isCancellable, - context: AppRouter.navigatorKey.currentState!.overlay!.context, - builder: (BuildContext context) { - return Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 4, - valueColor: AlwaysStoppedAnimation( - Colors.white, - ), + barrierDismissible: isCancellable, + context: AppRouter.navigatorKey.currentState!.overlay!.context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator.adaptive( + strokeWidth: 4, + valueColor: AlwaysStoppedAnimation( + Colors.white, ), - ); - }); + ), + ); + }, + ); isProgressVisible = true; } } diff --git a/lib/core/utils/size_utils.dart b/lib/core/utils/size_utils.dart index a6de3e6..04f09c8 100644 --- a/lib/core/utils/size_utils.dart +++ b/lib/core/utils/size_utils.dart @@ -3,7 +3,8 @@ import 'package:flutter/material.dart'; // This functions are responsible to make UI responsive across all the mobile devices. MediaQueryData mediaQueryData = MediaQueryData.fromView( - WidgetsBinding.instance.platformDispatcher.views.single); + WidgetsBinding.instance.platformDispatcher.views.single, +); // These are the Viewport values of your Figma Design. // These are used in the code as a reference to create your UI Responsively. @@ -30,8 +31,7 @@ extension ResponsiveExtension on num { double get h => ((this * _width) / FIGMA_DESIGN_WIDTH); ///This method is used to set padding/margin (for the top and bottom side) & height of the screen or widget according to the Viewport height. - double get v => - (this * _height) / (FIGMA_DESIGN_HEIGHT - FIGMA_DESIGN_STATUS_BAR); + double get v => (this * _height) / (FIGMA_DESIGN_HEIGHT - FIGMA_DESIGN_STATUS_BAR); ///This method is used to set smallest px in image height and width double get adaptSize { diff --git a/lib/data/models/selectionPopupModel/selection_popup_model.dart b/lib/data/models/selectionPopupModel/selection_popup_model.dart index e9aa2c8..f304e8d 100644 --- a/lib/data/models/selectionPopupModel/selection_popup_model.dart +++ b/lib/data/models/selectionPopupModel/selection_popup_model.dart @@ -1,15 +1,13 @@ -///SelectionPopupModel is common model -///used for setting data into dropdowns -class SelectionPopupModel { - int? id; - String title; - dynamic value; - bool isSelected; +import 'package:freezed_annotation/freezed_annotation.dart'; - SelectionPopupModel({ - this.id, - required this.title, - this.value, - this.isSelected = false, - }); +part 'selection_popup_model.freezed.dart'; + +@freezed +class SelectionPopupModel with _$SelectionPopupModel { + const factory SelectionPopupModel({ + int? id, + required String title, + dynamic value, + @Default(false) bool isSelected, + }) = _SelectionPopupModel; } diff --git a/lib/data/models/selectionPopupModel/selection_popup_model.freezed.dart b/lib/data/models/selectionPopupModel/selection_popup_model.freezed.dart new file mode 100644 index 0000000..917785c --- /dev/null +++ b/lib/data/models/selectionPopupModel/selection_popup_model.freezed.dart @@ -0,0 +1,189 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'selection_popup_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$SelectionPopupModel { + int? get id => throw _privateConstructorUsedError; + String get title => throw _privateConstructorUsedError; + dynamic get value => throw _privateConstructorUsedError; + bool get isSelected => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SelectionPopupModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SelectionPopupModelCopyWith<$Res> { + factory $SelectionPopupModelCopyWith( + SelectionPopupModel value, $Res Function(SelectionPopupModel) then) = + _$SelectionPopupModelCopyWithImpl<$Res, SelectionPopupModel>; + @useResult + $Res call({int? id, String title, dynamic value, bool isSelected}); +} + +/// @nodoc +class _$SelectionPopupModelCopyWithImpl<$Res, $Val extends SelectionPopupModel> + implements $SelectionPopupModelCopyWith<$Res> { + _$SelectionPopupModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? title = null, + Object? value = freezed, + Object? isSelected = null, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int?, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + value: freezed == value + ? _value.value + : value // ignore: cast_nullable_to_non_nullable + as dynamic, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SelectionPopupModelImplCopyWith<$Res> + implements $SelectionPopupModelCopyWith<$Res> { + factory _$$SelectionPopupModelImplCopyWith(_$SelectionPopupModelImpl value, + $Res Function(_$SelectionPopupModelImpl) then) = + __$$SelectionPopupModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int? id, String title, dynamic value, bool isSelected}); +} + +/// @nodoc +class __$$SelectionPopupModelImplCopyWithImpl<$Res> + extends _$SelectionPopupModelCopyWithImpl<$Res, _$SelectionPopupModelImpl> + implements _$$SelectionPopupModelImplCopyWith<$Res> { + __$$SelectionPopupModelImplCopyWithImpl(_$SelectionPopupModelImpl _value, + $Res Function(_$SelectionPopupModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? title = null, + Object? value = freezed, + Object? isSelected = null, + }) { + return _then(_$SelectionPopupModelImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int?, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + value: freezed == value + ? _value.value + : value // ignore: cast_nullable_to_non_nullable + as dynamic, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$SelectionPopupModelImpl implements _SelectionPopupModel { + const _$SelectionPopupModelImpl( + {this.id, required this.title, this.value, this.isSelected = false}); + + @override + final int? id; + @override + final String title; + @override + final dynamic value; + @override + @JsonKey() + final bool isSelected; + + @override + String toString() { + return 'SelectionPopupModel(id: $id, title: $title, value: $value, isSelected: $isSelected)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SelectionPopupModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.title, title) || other.title == title) && + const DeepCollectionEquality().equals(other.value, value) && + (identical(other.isSelected, isSelected) || + other.isSelected == isSelected)); + } + + @override + int get hashCode => Object.hash(runtimeType, id, title, + const DeepCollectionEquality().hash(value), isSelected); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SelectionPopupModelImplCopyWith<_$SelectionPopupModelImpl> get copyWith => + __$$SelectionPopupModelImplCopyWithImpl<_$SelectionPopupModelImpl>( + this, _$identity); +} + +abstract class _SelectionPopupModel implements SelectionPopupModel { + const factory _SelectionPopupModel( + {final int? id, + required final String title, + final dynamic value, + final bool isSelected}) = _$SelectionPopupModelImpl; + + @override + int? get id; + @override + String get title; + @override + dynamic get value; + @override + bool get isSelected; + @override + @JsonKey(ignore: true) + _$$SelectionPopupModelImplCopyWith<_$SelectionPopupModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/data/models/tokenModel/token_model.dart b/lib/data/models/tokenModel/token_model.dart index 3aa1d3f..ce310e2 100644 --- a/lib/data/models/tokenModel/token_model.dart +++ b/lib/data/models/tokenModel/token_model.dart @@ -1,4 +1,5 @@ import 'package:hive/hive.dart'; + /// https://pub.dev/packages/flutter_secure_storage TODO replace hive to secure_storage for token storage @HiveType(typeId: 0) class TokenModel { diff --git a/lib/data/models/userRegistrationModel/user_registration_model.dart b/lib/data/models/userRegistrationModel/user_registration_model.dart index baeb3a1..419ee5c 100644 --- a/lib/data/models/userRegistrationModel/user_registration_model.dart +++ b/lib/data/models/userRegistrationModel/user_registration_model.dart @@ -1,92 +1,39 @@ -class UserRegistrationSheet { - String name; - String firstName; - String lastName; - String email; - String password; - String passwordConfirmation; - String termsAccepted; - String birthdate; - String gender; - String country; - String city; - String lang; - String weight; - String height; - String chestCircumference; - String waistCircumference; - String hipCircumference; - String bloodPressureUp; - String bloodPressureDown; - String hasHypo = ''; - String hasHyper = ''; - String aboutAllergy = ''; - String aboutTakingPils = ''; - String aboutSportHobbies = ''; - String favoriteFoods = ''; - String unfavoriteFoods = ''; - String additionalInfo = ''; +import 'package:freezed_annotation/freezed_annotation.dart'; - UserRegistrationSheet({ - required this.name, - required this.firstName, - required this.lastName, - required this.email, - required this.password, - required this.passwordConfirmation, - required this.termsAccepted, - required this.birthdate, - required this.gender, - required this.country, - required this.city, - required this.lang, - required this.weight, - required this.height, - required this.chestCircumference, - required this.waistCircumference, - required this.hipCircumference, - required this.bloodPressureUp, - required this.bloodPressureDown, - required this.hasHypo, - required this.hasHyper, - required this.aboutAllergy, - required this.aboutTakingPils, - required this.aboutSportHobbies, - required this.favoriteFoods, - required this.unfavoriteFoods, - required this.additionalInfo, - }); +part 'user_registration_model.freezed.dart'; +part 'user_registration_model.g.dart'; - Map toJson() { - return { - 'name': name, - 'first_name': firstName, - 'last_name': lastName, - 'email': email, - 'password': password, - 'password_confirmation': passwordConfirmation, - 'terms': termsAccepted, - 'birthdate': birthdate.toString(), - 'gender': gender, - 'country': country, - 'city': city, - 'lang': lang, - 'weight': weight, - 'height': height, - 'chest_circumference': chestCircumference, - 'waist_circumference': waistCircumference, - 'hip_circumference': hipCircumference, - 'blood_pressure_up': bloodPressureUp, - 'blood_pressure_down': bloodPressureDown, - 'has_hypo': hasHypo, - 'has_hyper': hasHyper, - 'about_alergy': aboutAllergy, - 'about_taking_pils': aboutTakingPils, - 'about_sport_hobbies': aboutSportHobbies, - 'favorite_foods': favoriteFoods, - 'unfavorite_foods': unfavoriteFoods, - 'additional_info': additionalInfo, - 'activity_coefficient': '1.2', - }; - } +@freezed +class UserRegistrationSheet with _$UserRegistrationSheet { + const factory UserRegistrationSheet({ + @JsonKey(name: 'first_name') required String firstName, + @JsonKey(name: 'last_name') required String lastName, + required String email, + required String password, + @JsonKey(name: 'password_confirmation') required String passwordConfirmation, + @Default('accepted') @JsonKey(name: 'terms') String termsAccepted, + required String birthdate, + required String gender, + required String location, + @JsonKey(name: 'response_body') required String responseBody, + required String lang, + required int weight, + required int height, + @JsonKey(name: 'chest_circumference') required int chestCircumference, + @JsonKey(name: 'waist_circumference') required int waistCircumference, + @JsonKey(name: 'hip_circumference') required int hipCircumference, + @JsonKey(name: 'blood_pressure_up') required int bloodPressureUp, + @JsonKey(name: 'blood_pressure_down') required int bloodPressureDown, + @JsonKey(name: 'has_hypo') required int hasHypo, + @JsonKey(name: 'has_hyper') required int hasHyper, + @JsonKey(name: 'about_alergy') required String aboutAllergy, + @JsonKey(name: 'about_taking_pils') required String aboutTakingPils, + @JsonKey(name: 'about_sport_hobbies') required String aboutSportHobbies, + @JsonKey(name: 'favorite_foods') required String favoriteFoods, + @JsonKey(name: 'unfavorite_foods') required String unfavoriteFoods, + @JsonKey(name: 'additional_info') required String additionalInfo, + @Default(1.2) @JsonKey(name: 'activity_coefficient') double activityCoefficient, + }) = _UserRegistrationSheet; + + factory UserRegistrationSheet.fromJson(Map json) => _$UserRegistrationSheetFromJson(json); } diff --git a/lib/data/models/userRegistrationModel/user_registration_model.freezed.dart b/lib/data/models/userRegistrationModel/user_registration_model.freezed.dart new file mode 100644 index 0000000..4a15327 --- /dev/null +++ b/lib/data/models/userRegistrationModel/user_registration_model.freezed.dart @@ -0,0 +1,794 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'user_registration_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +UserRegistrationSheet _$UserRegistrationSheetFromJson( + Map json) { + return _UserRegistrationSheet.fromJson(json); +} + +/// @nodoc +mixin _$UserRegistrationSheet { + @JsonKey(name: 'first_name') + String get firstName => throw _privateConstructorUsedError; + @JsonKey(name: 'last_name') + String get lastName => throw _privateConstructorUsedError; + String get email => throw _privateConstructorUsedError; + String get password => throw _privateConstructorUsedError; + @JsonKey(name: 'password_confirmation') + String get passwordConfirmation => throw _privateConstructorUsedError; + @JsonKey(name: 'terms') + String get termsAccepted => throw _privateConstructorUsedError; + String get birthdate => throw _privateConstructorUsedError; + String get gender => throw _privateConstructorUsedError; + String get location => throw _privateConstructorUsedError; + @JsonKey(name: 'response_body') + String get responseBody => throw _privateConstructorUsedError; + String get lang => throw _privateConstructorUsedError; + int get weight => throw _privateConstructorUsedError; + int get height => throw _privateConstructorUsedError; + @JsonKey(name: 'chest_circumference') + int get chestCircumference => throw _privateConstructorUsedError; + @JsonKey(name: 'waist_circumference') + int get waistCircumference => throw _privateConstructorUsedError; + @JsonKey(name: 'hip_circumference') + int get hipCircumference => throw _privateConstructorUsedError; + @JsonKey(name: 'blood_pressure_up') + int get bloodPressureUp => throw _privateConstructorUsedError; + @JsonKey(name: 'blood_pressure_down') + int get bloodPressureDown => throw _privateConstructorUsedError; + @JsonKey(name: 'has_hypo') + int get hasHypo => throw _privateConstructorUsedError; + @JsonKey(name: 'has_hyper') + int get hasHyper => throw _privateConstructorUsedError; + @JsonKey(name: 'about_alergy') + String get aboutAllergy => throw _privateConstructorUsedError; + @JsonKey(name: 'about_taking_pils') + String get aboutTakingPils => throw _privateConstructorUsedError; + @JsonKey(name: 'about_sport_hobbies') + String get aboutSportHobbies => throw _privateConstructorUsedError; + @JsonKey(name: 'favorite_foods') + String get favoriteFoods => throw _privateConstructorUsedError; + @JsonKey(name: 'unfavorite_foods') + String get unfavoriteFoods => throw _privateConstructorUsedError; + @JsonKey(name: 'additional_info') + String get additionalInfo => throw _privateConstructorUsedError; + @JsonKey(name: 'activity_coefficient') + double get activityCoefficient => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $UserRegistrationSheetCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserRegistrationSheetCopyWith<$Res> { + factory $UserRegistrationSheetCopyWith(UserRegistrationSheet value, + $Res Function(UserRegistrationSheet) then) = + _$UserRegistrationSheetCopyWithImpl<$Res, UserRegistrationSheet>; + @useResult + $Res call( + {@JsonKey(name: 'first_name') String firstName, + @JsonKey(name: 'last_name') String lastName, + String email, + String password, + @JsonKey(name: 'password_confirmation') String passwordConfirmation, + @JsonKey(name: 'terms') String termsAccepted, + String birthdate, + String gender, + String location, + @JsonKey(name: 'response_body') String responseBody, + String lang, + int weight, + int height, + @JsonKey(name: 'chest_circumference') int chestCircumference, + @JsonKey(name: 'waist_circumference') int waistCircumference, + @JsonKey(name: 'hip_circumference') int hipCircumference, + @JsonKey(name: 'blood_pressure_up') int bloodPressureUp, + @JsonKey(name: 'blood_pressure_down') int bloodPressureDown, + @JsonKey(name: 'has_hypo') int hasHypo, + @JsonKey(name: 'has_hyper') int hasHyper, + @JsonKey(name: 'about_alergy') String aboutAllergy, + @JsonKey(name: 'about_taking_pils') String aboutTakingPils, + @JsonKey(name: 'about_sport_hobbies') String aboutSportHobbies, + @JsonKey(name: 'favorite_foods') String favoriteFoods, + @JsonKey(name: 'unfavorite_foods') String unfavoriteFoods, + @JsonKey(name: 'additional_info') String additionalInfo, + @JsonKey(name: 'activity_coefficient') double activityCoefficient}); +} + +/// @nodoc +class _$UserRegistrationSheetCopyWithImpl<$Res, + $Val extends UserRegistrationSheet> + implements $UserRegistrationSheetCopyWith<$Res> { + _$UserRegistrationSheetCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? firstName = null, + Object? lastName = null, + Object? email = null, + Object? password = null, + Object? passwordConfirmation = null, + Object? termsAccepted = null, + Object? birthdate = null, + Object? gender = null, + Object? location = null, + Object? responseBody = null, + Object? lang = null, + Object? weight = null, + Object? height = null, + Object? chestCircumference = null, + Object? waistCircumference = null, + Object? hipCircumference = null, + Object? bloodPressureUp = null, + Object? bloodPressureDown = null, + Object? hasHypo = null, + Object? hasHyper = null, + Object? aboutAllergy = null, + Object? aboutTakingPils = null, + Object? aboutSportHobbies = null, + Object? favoriteFoods = null, + Object? unfavoriteFoods = null, + Object? additionalInfo = null, + Object? activityCoefficient = null, + }) { + return _then(_value.copyWith( + firstName: null == firstName + ? _value.firstName + : firstName // ignore: cast_nullable_to_non_nullable + as String, + lastName: null == lastName + ? _value.lastName + : lastName // ignore: cast_nullable_to_non_nullable + as String, + email: null == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + passwordConfirmation: null == passwordConfirmation + ? _value.passwordConfirmation + : passwordConfirmation // ignore: cast_nullable_to_non_nullable + as String, + termsAccepted: null == termsAccepted + ? _value.termsAccepted + : termsAccepted // ignore: cast_nullable_to_non_nullable + as String, + birthdate: null == birthdate + ? _value.birthdate + : birthdate // ignore: cast_nullable_to_non_nullable + as String, + gender: null == gender + ? _value.gender + : gender // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + responseBody: null == responseBody + ? _value.responseBody + : responseBody // ignore: cast_nullable_to_non_nullable + as String, + lang: null == lang + ? _value.lang + : lang // ignore: cast_nullable_to_non_nullable + as String, + weight: null == weight + ? _value.weight + : weight // ignore: cast_nullable_to_non_nullable + as int, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as int, + chestCircumference: null == chestCircumference + ? _value.chestCircumference + : chestCircumference // ignore: cast_nullable_to_non_nullable + as int, + waistCircumference: null == waistCircumference + ? _value.waistCircumference + : waistCircumference // ignore: cast_nullable_to_non_nullable + as int, + hipCircumference: null == hipCircumference + ? _value.hipCircumference + : hipCircumference // ignore: cast_nullable_to_non_nullable + as int, + bloodPressureUp: null == bloodPressureUp + ? _value.bloodPressureUp + : bloodPressureUp // ignore: cast_nullable_to_non_nullable + as int, + bloodPressureDown: null == bloodPressureDown + ? _value.bloodPressureDown + : bloodPressureDown // ignore: cast_nullable_to_non_nullable + as int, + hasHypo: null == hasHypo + ? _value.hasHypo + : hasHypo // ignore: cast_nullable_to_non_nullable + as int, + hasHyper: null == hasHyper + ? _value.hasHyper + : hasHyper // ignore: cast_nullable_to_non_nullable + as int, + aboutAllergy: null == aboutAllergy + ? _value.aboutAllergy + : aboutAllergy // ignore: cast_nullable_to_non_nullable + as String, + aboutTakingPils: null == aboutTakingPils + ? _value.aboutTakingPils + : aboutTakingPils // ignore: cast_nullable_to_non_nullable + as String, + aboutSportHobbies: null == aboutSportHobbies + ? _value.aboutSportHobbies + : aboutSportHobbies // ignore: cast_nullable_to_non_nullable + as String, + favoriteFoods: null == favoriteFoods + ? _value.favoriteFoods + : favoriteFoods // ignore: cast_nullable_to_non_nullable + as String, + unfavoriteFoods: null == unfavoriteFoods + ? _value.unfavoriteFoods + : unfavoriteFoods // ignore: cast_nullable_to_non_nullable + as String, + additionalInfo: null == additionalInfo + ? _value.additionalInfo + : additionalInfo // ignore: cast_nullable_to_non_nullable + as String, + activityCoefficient: null == activityCoefficient + ? _value.activityCoefficient + : activityCoefficient // ignore: cast_nullable_to_non_nullable + as double, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$UserRegistrationSheetImplCopyWith<$Res> + implements $UserRegistrationSheetCopyWith<$Res> { + factory _$$UserRegistrationSheetImplCopyWith( + _$UserRegistrationSheetImpl value, + $Res Function(_$UserRegistrationSheetImpl) then) = + __$$UserRegistrationSheetImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: 'first_name') String firstName, + @JsonKey(name: 'last_name') String lastName, + String email, + String password, + @JsonKey(name: 'password_confirmation') String passwordConfirmation, + @JsonKey(name: 'terms') String termsAccepted, + String birthdate, + String gender, + String location, + @JsonKey(name: 'response_body') String responseBody, + String lang, + int weight, + int height, + @JsonKey(name: 'chest_circumference') int chestCircumference, + @JsonKey(name: 'waist_circumference') int waistCircumference, + @JsonKey(name: 'hip_circumference') int hipCircumference, + @JsonKey(name: 'blood_pressure_up') int bloodPressureUp, + @JsonKey(name: 'blood_pressure_down') int bloodPressureDown, + @JsonKey(name: 'has_hypo') int hasHypo, + @JsonKey(name: 'has_hyper') int hasHyper, + @JsonKey(name: 'about_alergy') String aboutAllergy, + @JsonKey(name: 'about_taking_pils') String aboutTakingPils, + @JsonKey(name: 'about_sport_hobbies') String aboutSportHobbies, + @JsonKey(name: 'favorite_foods') String favoriteFoods, + @JsonKey(name: 'unfavorite_foods') String unfavoriteFoods, + @JsonKey(name: 'additional_info') String additionalInfo, + @JsonKey(name: 'activity_coefficient') double activityCoefficient}); +} + +/// @nodoc +class __$$UserRegistrationSheetImplCopyWithImpl<$Res> + extends _$UserRegistrationSheetCopyWithImpl<$Res, + _$UserRegistrationSheetImpl> + implements _$$UserRegistrationSheetImplCopyWith<$Res> { + __$$UserRegistrationSheetImplCopyWithImpl(_$UserRegistrationSheetImpl _value, + $Res Function(_$UserRegistrationSheetImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? firstName = null, + Object? lastName = null, + Object? email = null, + Object? password = null, + Object? passwordConfirmation = null, + Object? termsAccepted = null, + Object? birthdate = null, + Object? gender = null, + Object? location = null, + Object? responseBody = null, + Object? lang = null, + Object? weight = null, + Object? height = null, + Object? chestCircumference = null, + Object? waistCircumference = null, + Object? hipCircumference = null, + Object? bloodPressureUp = null, + Object? bloodPressureDown = null, + Object? hasHypo = null, + Object? hasHyper = null, + Object? aboutAllergy = null, + Object? aboutTakingPils = null, + Object? aboutSportHobbies = null, + Object? favoriteFoods = null, + Object? unfavoriteFoods = null, + Object? additionalInfo = null, + Object? activityCoefficient = null, + }) { + return _then(_$UserRegistrationSheetImpl( + firstName: null == firstName + ? _value.firstName + : firstName // ignore: cast_nullable_to_non_nullable + as String, + lastName: null == lastName + ? _value.lastName + : lastName // ignore: cast_nullable_to_non_nullable + as String, + email: null == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + passwordConfirmation: null == passwordConfirmation + ? _value.passwordConfirmation + : passwordConfirmation // ignore: cast_nullable_to_non_nullable + as String, + termsAccepted: null == termsAccepted + ? _value.termsAccepted + : termsAccepted // ignore: cast_nullable_to_non_nullable + as String, + birthdate: null == birthdate + ? _value.birthdate + : birthdate // ignore: cast_nullable_to_non_nullable + as String, + gender: null == gender + ? _value.gender + : gender // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + responseBody: null == responseBody + ? _value.responseBody + : responseBody // ignore: cast_nullable_to_non_nullable + as String, + lang: null == lang + ? _value.lang + : lang // ignore: cast_nullable_to_non_nullable + as String, + weight: null == weight + ? _value.weight + : weight // ignore: cast_nullable_to_non_nullable + as int, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as int, + chestCircumference: null == chestCircumference + ? _value.chestCircumference + : chestCircumference // ignore: cast_nullable_to_non_nullable + as int, + waistCircumference: null == waistCircumference + ? _value.waistCircumference + : waistCircumference // ignore: cast_nullable_to_non_nullable + as int, + hipCircumference: null == hipCircumference + ? _value.hipCircumference + : hipCircumference // ignore: cast_nullable_to_non_nullable + as int, + bloodPressureUp: null == bloodPressureUp + ? _value.bloodPressureUp + : bloodPressureUp // ignore: cast_nullable_to_non_nullable + as int, + bloodPressureDown: null == bloodPressureDown + ? _value.bloodPressureDown + : bloodPressureDown // ignore: cast_nullable_to_non_nullable + as int, + hasHypo: null == hasHypo + ? _value.hasHypo + : hasHypo // ignore: cast_nullable_to_non_nullable + as int, + hasHyper: null == hasHyper + ? _value.hasHyper + : hasHyper // ignore: cast_nullable_to_non_nullable + as int, + aboutAllergy: null == aboutAllergy + ? _value.aboutAllergy + : aboutAllergy // ignore: cast_nullable_to_non_nullable + as String, + aboutTakingPils: null == aboutTakingPils + ? _value.aboutTakingPils + : aboutTakingPils // ignore: cast_nullable_to_non_nullable + as String, + aboutSportHobbies: null == aboutSportHobbies + ? _value.aboutSportHobbies + : aboutSportHobbies // ignore: cast_nullable_to_non_nullable + as String, + favoriteFoods: null == favoriteFoods + ? _value.favoriteFoods + : favoriteFoods // ignore: cast_nullable_to_non_nullable + as String, + unfavoriteFoods: null == unfavoriteFoods + ? _value.unfavoriteFoods + : unfavoriteFoods // ignore: cast_nullable_to_non_nullable + as String, + additionalInfo: null == additionalInfo + ? _value.additionalInfo + : additionalInfo // ignore: cast_nullable_to_non_nullable + as String, + activityCoefficient: null == activityCoefficient + ? _value.activityCoefficient + : activityCoefficient // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$UserRegistrationSheetImpl implements _UserRegistrationSheet { + const _$UserRegistrationSheetImpl( + {@JsonKey(name: 'first_name') required this.firstName, + @JsonKey(name: 'last_name') required this.lastName, + required this.email, + required this.password, + @JsonKey(name: 'password_confirmation') + required this.passwordConfirmation, + @JsonKey(name: 'terms') this.termsAccepted = 'accepted', + required this.birthdate, + required this.gender, + required this.location, + @JsonKey(name: 'response_body') required this.responseBody, + required this.lang, + required this.weight, + required this.height, + @JsonKey(name: 'chest_circumference') required this.chestCircumference, + @JsonKey(name: 'waist_circumference') required this.waistCircumference, + @JsonKey(name: 'hip_circumference') required this.hipCircumference, + @JsonKey(name: 'blood_pressure_up') required this.bloodPressureUp, + @JsonKey(name: 'blood_pressure_down') required this.bloodPressureDown, + @JsonKey(name: 'has_hypo') required this.hasHypo, + @JsonKey(name: 'has_hyper') required this.hasHyper, + @JsonKey(name: 'about_alergy') required this.aboutAllergy, + @JsonKey(name: 'about_taking_pils') required this.aboutTakingPils, + @JsonKey(name: 'about_sport_hobbies') required this.aboutSportHobbies, + @JsonKey(name: 'favorite_foods') required this.favoriteFoods, + @JsonKey(name: 'unfavorite_foods') required this.unfavoriteFoods, + @JsonKey(name: 'additional_info') required this.additionalInfo, + @JsonKey(name: 'activity_coefficient') this.activityCoefficient = 1.2}); + + factory _$UserRegistrationSheetImpl.fromJson(Map json) => + _$$UserRegistrationSheetImplFromJson(json); + + @override + @JsonKey(name: 'first_name') + final String firstName; + @override + @JsonKey(name: 'last_name') + final String lastName; + @override + final String email; + @override + final String password; + @override + @JsonKey(name: 'password_confirmation') + final String passwordConfirmation; + @override + @JsonKey(name: 'terms') + final String termsAccepted; + @override + final String birthdate; + @override + final String gender; + @override + final String location; + @override + @JsonKey(name: 'response_body') + final String responseBody; + @override + final String lang; + @override + final int weight; + @override + final int height; + @override + @JsonKey(name: 'chest_circumference') + final int chestCircumference; + @override + @JsonKey(name: 'waist_circumference') + final int waistCircumference; + @override + @JsonKey(name: 'hip_circumference') + final int hipCircumference; + @override + @JsonKey(name: 'blood_pressure_up') + final int bloodPressureUp; + @override + @JsonKey(name: 'blood_pressure_down') + final int bloodPressureDown; + @override + @JsonKey(name: 'has_hypo') + final int hasHypo; + @override + @JsonKey(name: 'has_hyper') + final int hasHyper; + @override + @JsonKey(name: 'about_alergy') + final String aboutAllergy; + @override + @JsonKey(name: 'about_taking_pils') + final String aboutTakingPils; + @override + @JsonKey(name: 'about_sport_hobbies') + final String aboutSportHobbies; + @override + @JsonKey(name: 'favorite_foods') + final String favoriteFoods; + @override + @JsonKey(name: 'unfavorite_foods') + final String unfavoriteFoods; + @override + @JsonKey(name: 'additional_info') + final String additionalInfo; + @override + @JsonKey(name: 'activity_coefficient') + final double activityCoefficient; + + @override + String toString() { + return 'UserRegistrationSheet(firstName: $firstName, lastName: $lastName, email: $email, password: $password, passwordConfirmation: $passwordConfirmation, termsAccepted: $termsAccepted, birthdate: $birthdate, gender: $gender, location: $location, responseBody: $responseBody, lang: $lang, weight: $weight, height: $height, chestCircumference: $chestCircumference, waistCircumference: $waistCircumference, hipCircumference: $hipCircumference, bloodPressureUp: $bloodPressureUp, bloodPressureDown: $bloodPressureDown, hasHypo: $hasHypo, hasHyper: $hasHyper, aboutAllergy: $aboutAllergy, aboutTakingPils: $aboutTakingPils, aboutSportHobbies: $aboutSportHobbies, favoriteFoods: $favoriteFoods, unfavoriteFoods: $unfavoriteFoods, additionalInfo: $additionalInfo, activityCoefficient: $activityCoefficient)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserRegistrationSheetImpl && + (identical(other.firstName, firstName) || + other.firstName == firstName) && + (identical(other.lastName, lastName) || + other.lastName == lastName) && + (identical(other.email, email) || other.email == email) && + (identical(other.password, password) || + other.password == password) && + (identical(other.passwordConfirmation, passwordConfirmation) || + other.passwordConfirmation == passwordConfirmation) && + (identical(other.termsAccepted, termsAccepted) || + other.termsAccepted == termsAccepted) && + (identical(other.birthdate, birthdate) || + other.birthdate == birthdate) && + (identical(other.gender, gender) || other.gender == gender) && + (identical(other.location, location) || + other.location == location) && + (identical(other.responseBody, responseBody) || + other.responseBody == responseBody) && + (identical(other.lang, lang) || other.lang == lang) && + (identical(other.weight, weight) || other.weight == weight) && + (identical(other.height, height) || other.height == height) && + (identical(other.chestCircumference, chestCircumference) || + other.chestCircumference == chestCircumference) && + (identical(other.waistCircumference, waistCircumference) || + other.waistCircumference == waistCircumference) && + (identical(other.hipCircumference, hipCircumference) || + other.hipCircumference == hipCircumference) && + (identical(other.bloodPressureUp, bloodPressureUp) || + other.bloodPressureUp == bloodPressureUp) && + (identical(other.bloodPressureDown, bloodPressureDown) || + other.bloodPressureDown == bloodPressureDown) && + (identical(other.hasHypo, hasHypo) || other.hasHypo == hasHypo) && + (identical(other.hasHyper, hasHyper) || + other.hasHyper == hasHyper) && + (identical(other.aboutAllergy, aboutAllergy) || + other.aboutAllergy == aboutAllergy) && + (identical(other.aboutTakingPils, aboutTakingPils) || + other.aboutTakingPils == aboutTakingPils) && + (identical(other.aboutSportHobbies, aboutSportHobbies) || + other.aboutSportHobbies == aboutSportHobbies) && + (identical(other.favoriteFoods, favoriteFoods) || + other.favoriteFoods == favoriteFoods) && + (identical(other.unfavoriteFoods, unfavoriteFoods) || + other.unfavoriteFoods == unfavoriteFoods) && + (identical(other.additionalInfo, additionalInfo) || + other.additionalInfo == additionalInfo) && + (identical(other.activityCoefficient, activityCoefficient) || + other.activityCoefficient == activityCoefficient)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hashAll([ + runtimeType, + firstName, + lastName, + email, + password, + passwordConfirmation, + termsAccepted, + birthdate, + gender, + location, + responseBody, + lang, + weight, + height, + chestCircumference, + waistCircumference, + hipCircumference, + bloodPressureUp, + bloodPressureDown, + hasHypo, + hasHyper, + aboutAllergy, + aboutTakingPils, + aboutSportHobbies, + favoriteFoods, + unfavoriteFoods, + additionalInfo, + activityCoefficient + ]); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserRegistrationSheetImplCopyWith<_$UserRegistrationSheetImpl> + get copyWith => __$$UserRegistrationSheetImplCopyWithImpl< + _$UserRegistrationSheetImpl>(this, _$identity); + + @override + Map toJson() { + return _$$UserRegistrationSheetImplToJson( + this, + ); + } +} + +abstract class _UserRegistrationSheet implements UserRegistrationSheet { + const factory _UserRegistrationSheet( + {@JsonKey(name: 'first_name') required final String firstName, + @JsonKey(name: 'last_name') required final String lastName, + required final String email, + required final String password, + @JsonKey(name: 'password_confirmation') + required final String passwordConfirmation, + @JsonKey(name: 'terms') final String termsAccepted, + required final String birthdate, + required final String gender, + required final String location, + @JsonKey(name: 'response_body') required final String responseBody, + required final String lang, + required final int weight, + required final int height, + @JsonKey(name: 'chest_circumference') + required final int chestCircumference, + @JsonKey(name: 'waist_circumference') + required final int waistCircumference, + @JsonKey(name: 'hip_circumference') required final int hipCircumference, + @JsonKey(name: 'blood_pressure_up') required final int bloodPressureUp, + @JsonKey(name: 'blood_pressure_down') + required final int bloodPressureDown, + @JsonKey(name: 'has_hypo') required final int hasHypo, + @JsonKey(name: 'has_hyper') required final int hasHyper, + @JsonKey(name: 'about_alergy') required final String aboutAllergy, + @JsonKey(name: 'about_taking_pils') required final String aboutTakingPils, + @JsonKey(name: 'about_sport_hobbies') + required final String aboutSportHobbies, + @JsonKey(name: 'favorite_foods') required final String favoriteFoods, + @JsonKey(name: 'unfavorite_foods') required final String unfavoriteFoods, + @JsonKey(name: 'additional_info') required final String additionalInfo, + @JsonKey(name: 'activity_coefficient') + final double activityCoefficient}) = _$UserRegistrationSheetImpl; + + factory _UserRegistrationSheet.fromJson(Map json) = + _$UserRegistrationSheetImpl.fromJson; + + @override + @JsonKey(name: 'first_name') + String get firstName; + @override + @JsonKey(name: 'last_name') + String get lastName; + @override + String get email; + @override + String get password; + @override + @JsonKey(name: 'password_confirmation') + String get passwordConfirmation; + @override + @JsonKey(name: 'terms') + String get termsAccepted; + @override + String get birthdate; + @override + String get gender; + @override + String get location; + @override + @JsonKey(name: 'response_body') + String get responseBody; + @override + String get lang; + @override + int get weight; + @override + int get height; + @override + @JsonKey(name: 'chest_circumference') + int get chestCircumference; + @override + @JsonKey(name: 'waist_circumference') + int get waistCircumference; + @override + @JsonKey(name: 'hip_circumference') + int get hipCircumference; + @override + @JsonKey(name: 'blood_pressure_up') + int get bloodPressureUp; + @override + @JsonKey(name: 'blood_pressure_down') + int get bloodPressureDown; + @override + @JsonKey(name: 'has_hypo') + int get hasHypo; + @override + @JsonKey(name: 'has_hyper') + int get hasHyper; + @override + @JsonKey(name: 'about_alergy') + String get aboutAllergy; + @override + @JsonKey(name: 'about_taking_pils') + String get aboutTakingPils; + @override + @JsonKey(name: 'about_sport_hobbies') + String get aboutSportHobbies; + @override + @JsonKey(name: 'favorite_foods') + String get favoriteFoods; + @override + @JsonKey(name: 'unfavorite_foods') + String get unfavoriteFoods; + @override + @JsonKey(name: 'additional_info') + String get additionalInfo; + @override + @JsonKey(name: 'activity_coefficient') + double get activityCoefficient; + @override + @JsonKey(ignore: true) + _$$UserRegistrationSheetImplCopyWith<_$UserRegistrationSheetImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/data/models/userRegistrationModel/user_registration_model.g.dart b/lib/data/models/userRegistrationModel/user_registration_model.g.dart new file mode 100644 index 0000000..9500e91 --- /dev/null +++ b/lib/data/models/userRegistrationModel/user_registration_model.g.dart @@ -0,0 +1,72 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_registration_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$UserRegistrationSheetImpl _$$UserRegistrationSheetImplFromJson( + Map json) => + _$UserRegistrationSheetImpl( + firstName: json['first_name'] as String, + lastName: json['last_name'] as String, + email: json['email'] as String, + password: json['password'] as String, + passwordConfirmation: json['password_confirmation'] as String, + termsAccepted: json['terms'] as String? ?? 'accepted', + birthdate: json['birthdate'] as String, + gender: json['gender'] as String, + location: json['location'] as String, + responseBody: json['response_body'] as String, + lang: json['lang'] as String, + weight: (json['weight'] as num).toInt(), + height: (json['height'] as num).toInt(), + chestCircumference: (json['chest_circumference'] as num).toInt(), + waistCircumference: (json['waist_circumference'] as num).toInt(), + hipCircumference: (json['hip_circumference'] as num).toInt(), + bloodPressureUp: (json['blood_pressure_up'] as num).toInt(), + bloodPressureDown: (json['blood_pressure_down'] as num).toInt(), + hasHypo: (json['has_hypo'] as num).toInt(), + hasHyper: (json['has_hyper'] as num).toInt(), + aboutAllergy: json['about_alergy'] as String, + aboutTakingPils: json['about_taking_pils'] as String, + aboutSportHobbies: json['about_sport_hobbies'] as String, + favoriteFoods: json['favorite_foods'] as String, + unfavoriteFoods: json['unfavorite_foods'] as String, + additionalInfo: json['additional_info'] as String, + activityCoefficient: + (json['activity_coefficient'] as num?)?.toDouble() ?? 1.2, + ); + +Map _$$UserRegistrationSheetImplToJson( + _$UserRegistrationSheetImpl instance) => + { + 'first_name': instance.firstName, + 'last_name': instance.lastName, + 'email': instance.email, + 'password': instance.password, + 'password_confirmation': instance.passwordConfirmation, + 'terms': instance.termsAccepted, + 'birthdate': instance.birthdate, + 'gender': instance.gender, + 'location': instance.location, + 'response_body': instance.responseBody, + 'lang': instance.lang, + 'weight': instance.weight, + 'height': instance.height, + 'chest_circumference': instance.chestCircumference, + 'waist_circumference': instance.waistCircumference, + 'hip_circumference': instance.hipCircumference, + 'blood_pressure_up': instance.bloodPressureUp, + 'blood_pressure_down': instance.bloodPressureDown, + 'has_hypo': instance.hasHypo, + 'has_hyper': instance.hasHyper, + 'about_alergy': instance.aboutAllergy, + 'about_taking_pils': instance.aboutTakingPils, + 'about_sport_hobbies': instance.aboutSportHobbies, + 'favorite_foods': instance.favoriteFoods, + 'unfavorite_foods': instance.unfavoriteFoods, + 'additional_info': instance.additionalInfo, + 'activity_coefficient': instance.activityCoefficient, + }; diff --git a/lib/features/blog_post/models/blog_post_model.dart b/lib/features/blog_post/models/blog_post_model.dart new file mode 100644 index 0000000..1a428e0 --- /dev/null +++ b/lib/features/blog_post/models/blog_post_model.dart @@ -0,0 +1,22 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'blog_post_model.freezed.dart'; +part 'blog_post_model.g.dart'; + +@freezed +class BlogPostModel with _$BlogPostModel { + const factory BlogPostModel({ + required int id, + required String state, + String? image, + required String description, + String? author_name, + String? author_avatar_path, + @JsonKey(name: "youtube_url") required String youtubeUrl, + @JsonKey(name: "created_at") required DateTime createdAt, + @JsonKey(name: "updated_at") required DateTime updatedAt, + required String title, + }) = _BlogPostModel; + + factory BlogPostModel.fromJson(Map json) => _$BlogPostModelFromJson(json); +} diff --git a/lib/features/blog_post/models/blog_post_model.freezed.dart b/lib/features/blog_post/models/blog_post_model.freezed.dart new file mode 100644 index 0000000..7c0a750 --- /dev/null +++ b/lib/features/blog_post/models/blog_post_model.freezed.dart @@ -0,0 +1,351 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'blog_post_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +BlogPostModel _$BlogPostModelFromJson(Map json) { + return _BlogPostModel.fromJson(json); +} + +/// @nodoc +mixin _$BlogPostModel { + int get id => throw _privateConstructorUsedError; + String get state => throw _privateConstructorUsedError; + String? get image => throw _privateConstructorUsedError; + String get description => throw _privateConstructorUsedError; + String? get author_name => throw _privateConstructorUsedError; + String? get author_avatar_path => throw _privateConstructorUsedError; + @JsonKey(name: "youtube_url") + String get youtubeUrl => throw _privateConstructorUsedError; + @JsonKey(name: "created_at") + DateTime get createdAt => throw _privateConstructorUsedError; + @JsonKey(name: "updated_at") + DateTime get updatedAt => throw _privateConstructorUsedError; + String get title => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $BlogPostModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BlogPostModelCopyWith<$Res> { + factory $BlogPostModelCopyWith( + BlogPostModel value, $Res Function(BlogPostModel) then) = + _$BlogPostModelCopyWithImpl<$Res, BlogPostModel>; + @useResult + $Res call( + {int id, + String state, + String? image, + String description, + String? author_name, + String? author_avatar_path, + @JsonKey(name: "youtube_url") String youtubeUrl, + @JsonKey(name: "created_at") DateTime createdAt, + @JsonKey(name: "updated_at") DateTime updatedAt, + String title}); +} + +/// @nodoc +class _$BlogPostModelCopyWithImpl<$Res, $Val extends BlogPostModel> + implements $BlogPostModelCopyWith<$Res> { + _$BlogPostModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? state = null, + Object? image = freezed, + Object? description = null, + Object? author_name = freezed, + Object? author_avatar_path = freezed, + Object? youtubeUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + image: freezed == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String?, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + author_name: freezed == author_name + ? _value.author_name + : author_name // ignore: cast_nullable_to_non_nullable + as String?, + author_avatar_path: freezed == author_avatar_path + ? _value.author_avatar_path + : author_avatar_path // ignore: cast_nullable_to_non_nullable + as String?, + youtubeUrl: null == youtubeUrl + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$BlogPostModelImplCopyWith<$Res> + implements $BlogPostModelCopyWith<$Res> { + factory _$$BlogPostModelImplCopyWith( + _$BlogPostModelImpl value, $Res Function(_$BlogPostModelImpl) then) = + __$$BlogPostModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String state, + String? image, + String description, + String? author_name, + String? author_avatar_path, + @JsonKey(name: "youtube_url") String youtubeUrl, + @JsonKey(name: "created_at") DateTime createdAt, + @JsonKey(name: "updated_at") DateTime updatedAt, + String title}); +} + +/// @nodoc +class __$$BlogPostModelImplCopyWithImpl<$Res> + extends _$BlogPostModelCopyWithImpl<$Res, _$BlogPostModelImpl> + implements _$$BlogPostModelImplCopyWith<$Res> { + __$$BlogPostModelImplCopyWithImpl( + _$BlogPostModelImpl _value, $Res Function(_$BlogPostModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? state = null, + Object? image = freezed, + Object? description = null, + Object? author_name = freezed, + Object? author_avatar_path = freezed, + Object? youtubeUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + }) { + return _then(_$BlogPostModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + image: freezed == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String?, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + author_name: freezed == author_name + ? _value.author_name + : author_name // ignore: cast_nullable_to_non_nullable + as String?, + author_avatar_path: freezed == author_avatar_path + ? _value.author_avatar_path + : author_avatar_path // ignore: cast_nullable_to_non_nullable + as String?, + youtubeUrl: null == youtubeUrl + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$BlogPostModelImpl implements _BlogPostModel { + const _$BlogPostModelImpl( + {required this.id, + required this.state, + this.image, + required this.description, + this.author_name, + this.author_avatar_path, + @JsonKey(name: "youtube_url") required this.youtubeUrl, + @JsonKey(name: "created_at") required this.createdAt, + @JsonKey(name: "updated_at") required this.updatedAt, + required this.title}); + + factory _$BlogPostModelImpl.fromJson(Map json) => + _$$BlogPostModelImplFromJson(json); + + @override + final int id; + @override + final String state; + @override + final String? image; + @override + final String description; + @override + final String? author_name; + @override + final String? author_avatar_path; + @override + @JsonKey(name: "youtube_url") + final String youtubeUrl; + @override + @JsonKey(name: "created_at") + final DateTime createdAt; + @override + @JsonKey(name: "updated_at") + final DateTime updatedAt; + @override + final String title; + + @override + String toString() { + return 'BlogPostModel(id: $id, state: $state, image: $image, description: $description, author_name: $author_name, author_avatar_path: $author_avatar_path, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.state, state) || other.state == state) && + (identical(other.image, image) || other.image == image) && + (identical(other.description, description) || + other.description == description) && + (identical(other.author_name, author_name) || + other.author_name == author_name) && + (identical(other.author_avatar_path, author_avatar_path) || + other.author_avatar_path == author_avatar_path) && + (identical(other.youtubeUrl, youtubeUrl) || + other.youtubeUrl == youtubeUrl) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && + (identical(other.title, title) || other.title == title)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, state, image, description, + author_name, author_avatar_path, youtubeUrl, createdAt, updatedAt, title); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BlogPostModelImplCopyWith<_$BlogPostModelImpl> get copyWith => + __$$BlogPostModelImplCopyWithImpl<_$BlogPostModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$BlogPostModelImplToJson( + this, + ); + } +} + +abstract class _BlogPostModel implements BlogPostModel { + const factory _BlogPostModel( + {required final int id, + required final String state, + final String? image, + required final String description, + final String? author_name, + final String? author_avatar_path, + @JsonKey(name: "youtube_url") required final String youtubeUrl, + @JsonKey(name: "created_at") required final DateTime createdAt, + @JsonKey(name: "updated_at") required final DateTime updatedAt, + required final String title}) = _$BlogPostModelImpl; + + factory _BlogPostModel.fromJson(Map json) = + _$BlogPostModelImpl.fromJson; + + @override + int get id; + @override + String get state; + @override + String? get image; + @override + String get description; + @override + String? get author_name; + @override + String? get author_avatar_path; + @override + @JsonKey(name: "youtube_url") + String get youtubeUrl; + @override + @JsonKey(name: "created_at") + DateTime get createdAt; + @override + @JsonKey(name: "updated_at") + DateTime get updatedAt; + @override + String get title; + @override + @JsonKey(ignore: true) + _$$BlogPostModelImplCopyWith<_$BlogPostModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/blog_post/models/blog_post_model.g.dart b/lib/features/blog_post/models/blog_post_model.g.dart new file mode 100644 index 0000000..2e3233c --- /dev/null +++ b/lib/features/blog_post/models/blog_post_model.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'blog_post_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$BlogPostModelImpl _$$BlogPostModelImplFromJson(Map json) => + _$BlogPostModelImpl( + id: (json['id'] as num).toInt(), + state: json['state'] as String, + image: json['image'] as String?, + description: json['description'] as String, + author_name: json['author_name'] as String?, + author_avatar_path: json['author_avatar_path'] as String?, + youtubeUrl: json['youtube_url'] as String, + createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), + title: json['title'] as String, + ); + +Map _$$BlogPostModelImplToJson(_$BlogPostModelImpl instance) => + { + 'id': instance.id, + 'state': instance.state, + 'image': instance.image, + 'description': instance.description, + 'author_name': instance.author_name, + 'author_avatar_path': instance.author_avatar_path, + 'youtube_url': instance.youtubeUrl, + 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), + 'title': instance.title, + }; diff --git a/lib/features/blog_post/presentation/bloc/blog_post_cubit.dart b/lib/features/blog_post/presentation/bloc/blog_post_cubit.dart new file mode 100644 index 0000000..301e0ef --- /dev/null +++ b/lib/features/blog_post/presentation/bloc/blog_post_cubit.dart @@ -0,0 +1,20 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_state.dart'; +import 'package:eatvio_app/features/blog_post/repositories/blog_post_repository.dart'; + +class BlogPostCubit extends Cubit { + final BlogPostRepository blogPostRepository; + + BlogPostCubit({required this.blogPostRepository}) : super(const BlogPostState.loading()); + + loadBlogPost(String blogPostID) async { + emit(const BlogPostState.loading()); + try { + final blogPost = await blogPostRepository.getBlogPost(blogPostID); + emit(BlogPostState.loaded(blogPost: blogPost)); + } catch (e) { + emit(BlogPostState.error(errorMessage: e.toString())); + print(e); + } + } +} diff --git a/lib/features/blog_post/presentation/bloc/blog_post_state.dart b/lib/features/blog_post/presentation/bloc/blog_post_state.dart new file mode 100644 index 0000000..c8a4d0e --- /dev/null +++ b/lib/features/blog_post/presentation/bloc/blog_post_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/blog_post/models/blog_post_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'blog_post_state.freezed.dart'; + +@freezed +abstract class BlogPostState with _$BlogPostState { + const factory BlogPostState() = _BlogPostState; + + const factory BlogPostState.loading() = BlogPostStateLoading; + + const factory BlogPostState.loaded({ + required BlogPostModel blogPost, + }) = BlogPostStateLoaded; + + const factory BlogPostState.error({ + required String errorMessage, + }) = BlogPostStateError; +} diff --git a/lib/features/blog_post/presentation/bloc/blog_post_state.freezed.dart b/lib/features/blog_post/presentation/bloc/blog_post_state.freezed.dart new file mode 100644 index 0000000..4f99a3c --- /dev/null +++ b/lib/features/blog_post/presentation/bloc/blog_post_state.freezed.dart @@ -0,0 +1,622 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'blog_post_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$BlogPostState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(BlogPostModel blogPost) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(BlogPostModel blogPost)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(BlogPostModel blogPost)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostState value) $default, { + required TResult Function(BlogPostStateLoading value) loading, + required TResult Function(BlogPostStateLoaded value) loaded, + required TResult Function(BlogPostStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostState value)? $default, { + TResult? Function(BlogPostStateLoading value)? loading, + TResult? Function(BlogPostStateLoaded value)? loaded, + TResult? Function(BlogPostStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostState value)? $default, { + TResult Function(BlogPostStateLoading value)? loading, + TResult Function(BlogPostStateLoaded value)? loaded, + TResult Function(BlogPostStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BlogPostStateCopyWith<$Res> { + factory $BlogPostStateCopyWith( + BlogPostState value, $Res Function(BlogPostState) then) = + _$BlogPostStateCopyWithImpl<$Res, BlogPostState>; +} + +/// @nodoc +class _$BlogPostStateCopyWithImpl<$Res, $Val extends BlogPostState> + implements $BlogPostStateCopyWith<$Res> { + _$BlogPostStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$BlogPostStateImplCopyWith<$Res> { + factory _$$BlogPostStateImplCopyWith( + _$BlogPostStateImpl value, $Res Function(_$BlogPostStateImpl) then) = + __$$BlogPostStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BlogPostStateImplCopyWithImpl<$Res> + extends _$BlogPostStateCopyWithImpl<$Res, _$BlogPostStateImpl> + implements _$$BlogPostStateImplCopyWith<$Res> { + __$$BlogPostStateImplCopyWithImpl( + _$BlogPostStateImpl _value, $Res Function(_$BlogPostStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$BlogPostStateImpl implements _BlogPostState { + const _$BlogPostStateImpl(); + + @override + String toString() { + return 'BlogPostState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$BlogPostStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(BlogPostModel blogPost) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(BlogPostModel blogPost)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(BlogPostModel blogPost)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostState value) $default, { + required TResult Function(BlogPostStateLoading value) loading, + required TResult Function(BlogPostStateLoaded value) loaded, + required TResult Function(BlogPostStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostState value)? $default, { + TResult? Function(BlogPostStateLoading value)? loading, + TResult? Function(BlogPostStateLoaded value)? loaded, + TResult? Function(BlogPostStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostState value)? $default, { + TResult Function(BlogPostStateLoading value)? loading, + TResult Function(BlogPostStateLoaded value)? loaded, + TResult Function(BlogPostStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _BlogPostState implements BlogPostState { + const factory _BlogPostState() = _$BlogPostStateImpl; +} + +/// @nodoc +abstract class _$$BlogPostStateLoadingImplCopyWith<$Res> { + factory _$$BlogPostStateLoadingImplCopyWith(_$BlogPostStateLoadingImpl value, + $Res Function(_$BlogPostStateLoadingImpl) then) = + __$$BlogPostStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BlogPostStateLoadingImplCopyWithImpl<$Res> + extends _$BlogPostStateCopyWithImpl<$Res, _$BlogPostStateLoadingImpl> + implements _$$BlogPostStateLoadingImplCopyWith<$Res> { + __$$BlogPostStateLoadingImplCopyWithImpl(_$BlogPostStateLoadingImpl _value, + $Res Function(_$BlogPostStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$BlogPostStateLoadingImpl implements BlogPostStateLoading { + const _$BlogPostStateLoadingImpl(); + + @override + String toString() { + return 'BlogPostState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(BlogPostModel blogPost) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(BlogPostModel blogPost)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(BlogPostModel blogPost)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostState value) $default, { + required TResult Function(BlogPostStateLoading value) loading, + required TResult Function(BlogPostStateLoaded value) loaded, + required TResult Function(BlogPostStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostState value)? $default, { + TResult? Function(BlogPostStateLoading value)? loading, + TResult? Function(BlogPostStateLoaded value)? loaded, + TResult? Function(BlogPostStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostState value)? $default, { + TResult Function(BlogPostStateLoading value)? loading, + TResult Function(BlogPostStateLoaded value)? loaded, + TResult Function(BlogPostStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class BlogPostStateLoading implements BlogPostState { + const factory BlogPostStateLoading() = _$BlogPostStateLoadingImpl; +} + +/// @nodoc +abstract class _$$BlogPostStateLoadedImplCopyWith<$Res> { + factory _$$BlogPostStateLoadedImplCopyWith(_$BlogPostStateLoadedImpl value, + $Res Function(_$BlogPostStateLoadedImpl) then) = + __$$BlogPostStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({BlogPostModel blogPost}); + + $BlogPostModelCopyWith<$Res> get blogPost; +} + +/// @nodoc +class __$$BlogPostStateLoadedImplCopyWithImpl<$Res> + extends _$BlogPostStateCopyWithImpl<$Res, _$BlogPostStateLoadedImpl> + implements _$$BlogPostStateLoadedImplCopyWith<$Res> { + __$$BlogPostStateLoadedImplCopyWithImpl(_$BlogPostStateLoadedImpl _value, + $Res Function(_$BlogPostStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? blogPost = null, + }) { + return _then(_$BlogPostStateLoadedImpl( + blogPost: null == blogPost + ? _value.blogPost + : blogPost // ignore: cast_nullable_to_non_nullable + as BlogPostModel, + )); + } + + @override + @pragma('vm:prefer-inline') + $BlogPostModelCopyWith<$Res> get blogPost { + return $BlogPostModelCopyWith<$Res>(_value.blogPost, (value) { + return _then(_value.copyWith(blogPost: value)); + }); + } +} + +/// @nodoc + +class _$BlogPostStateLoadedImpl implements BlogPostStateLoaded { + const _$BlogPostStateLoadedImpl({required this.blogPost}); + + @override + final BlogPostModel blogPost; + + @override + String toString() { + return 'BlogPostState.loaded(blogPost: $blogPost)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostStateLoadedImpl && + (identical(other.blogPost, blogPost) || + other.blogPost == blogPost)); + } + + @override + int get hashCode => Object.hash(runtimeType, blogPost); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BlogPostStateLoadedImplCopyWith<_$BlogPostStateLoadedImpl> get copyWith => + __$$BlogPostStateLoadedImplCopyWithImpl<_$BlogPostStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(BlogPostModel blogPost) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(blogPost); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(BlogPostModel blogPost)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(blogPost); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(BlogPostModel blogPost)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(blogPost); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostState value) $default, { + required TResult Function(BlogPostStateLoading value) loading, + required TResult Function(BlogPostStateLoaded value) loaded, + required TResult Function(BlogPostStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostState value)? $default, { + TResult? Function(BlogPostStateLoading value)? loading, + TResult? Function(BlogPostStateLoaded value)? loaded, + TResult? Function(BlogPostStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostState value)? $default, { + TResult Function(BlogPostStateLoading value)? loading, + TResult Function(BlogPostStateLoaded value)? loaded, + TResult Function(BlogPostStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class BlogPostStateLoaded implements BlogPostState { + const factory BlogPostStateLoaded({required final BlogPostModel blogPost}) = + _$BlogPostStateLoadedImpl; + + BlogPostModel get blogPost; + @JsonKey(ignore: true) + _$$BlogPostStateLoadedImplCopyWith<_$BlogPostStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$BlogPostStateErrorImplCopyWith<$Res> { + factory _$$BlogPostStateErrorImplCopyWith(_$BlogPostStateErrorImpl value, + $Res Function(_$BlogPostStateErrorImpl) then) = + __$$BlogPostStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$BlogPostStateErrorImplCopyWithImpl<$Res> + extends _$BlogPostStateCopyWithImpl<$Res, _$BlogPostStateErrorImpl> + implements _$$BlogPostStateErrorImplCopyWith<$Res> { + __$$BlogPostStateErrorImplCopyWithImpl(_$BlogPostStateErrorImpl _value, + $Res Function(_$BlogPostStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$BlogPostStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$BlogPostStateErrorImpl implements BlogPostStateError { + const _$BlogPostStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'BlogPostState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BlogPostStateErrorImplCopyWith<_$BlogPostStateErrorImpl> get copyWith => + __$$BlogPostStateErrorImplCopyWithImpl<_$BlogPostStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(BlogPostModel blogPost) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(BlogPostModel blogPost)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(BlogPostModel blogPost)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostState value) $default, { + required TResult Function(BlogPostStateLoading value) loading, + required TResult Function(BlogPostStateLoaded value) loaded, + required TResult Function(BlogPostStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostState value)? $default, { + TResult? Function(BlogPostStateLoading value)? loading, + TResult? Function(BlogPostStateLoaded value)? loaded, + TResult? Function(BlogPostStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostState value)? $default, { + TResult Function(BlogPostStateLoading value)? loading, + TResult Function(BlogPostStateLoaded value)? loaded, + TResult Function(BlogPostStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class BlogPostStateError implements BlogPostState { + const factory BlogPostStateError({required final String errorMessage}) = + _$BlogPostStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$BlogPostStateErrorImplCopyWith<_$BlogPostStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/feed/blog_post_screen/blog_post_screen.dart b/lib/features/blog_post/presentation/pages/blog_post_screen.dart similarity index 61% rename from lib/presentation/feed/blog_post_screen/blog_post_screen.dart rename to lib/features/blog_post/presentation/pages/blog_post_screen.dart index 37a2ce2..ad82dec 100644 --- a/lib/presentation/feed/blog_post_screen/blog_post_screen.dart +++ b/lib/features/blog_post/presentation/pages/blog_post_screen.dart @@ -1,64 +1,40 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/blog_post_bloc.dart'; -import 'models/blog_post_model.dart'; -import 'widgets/comment_widget.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; +import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_cubit.dart'; +import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_state.dart'; +import 'package:eatvio_app/locator_service.dart'; import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; import 'package:eatvio_app/widgets/custom_outlined_button.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; class BlogPostScreen extends StatelessWidget { - const BlogPostScreen({Key? key}) : super(key: key); + final String blogPostID; - static Widget builder(BuildContext context, String blog_postID) { - return BlocProvider( - create: (context) => BlogPostBloc( - BlogPostState( - blog_postModelObj: BlogPostModel( - blog_postID: blog_postID.toString(), - ), - ), - )..add( - BlogPostInitialEvent(), - ), - child: BlogPostScreen(), - ); - } + const BlogPostScreen({super.key, required this.blogPostID}); Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is BlogPostInitialState) { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } else if (state is BlogPostLoadedState) { - // Данные загружены, можно строить экран. - return _buildBlogPost(context, state); - } else if (state is BlogPostErrorState) { - // Произошла ошибка при загрузке данных. - return Center( - child: Text(state.errorMessage), - ); - } else { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - // Другие состояния, если они есть. - } - }, + return BlocProvider( + create: (context) => sl()..loadBlogPost(blogPostID), + child: BlocBuilder( + builder: (context, state) { + if (state is BlogPostStateLoaded) { + return _buildBlogPost(context, state); + } else { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } + }, + ), ); } - _buildBlogPost(BuildContext context, BlogPostLoadedState state) { + _buildBlogPost(BuildContext context, BlogPostStateLoaded state) { return SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, @@ -82,8 +58,8 @@ class BlogPostScreen extends StatelessWidget { ); } - _buildHeaderRow(BuildContext context, BlogPostLoadedState state) { - final String name = state.author?['name']; + _buildHeaderRow(BuildContext context, BlogPostStateLoaded state) { + final String name = state.blogPost.title; return Container( margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), padding: EdgeInsets.symmetric( @@ -121,7 +97,7 @@ class BlogPostScreen extends StatelessWidget { ), ), CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.author?['profile_photo_path'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.blogPost.author_avatar_path ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -141,7 +117,7 @@ class BlogPostScreen extends StatelessWidget { ); } - _buildBlogPostData(BuildContext context, BlogPostLoadedState state) { + _buildBlogPostData(BuildContext context, BlogPostStateLoaded state) { return Container( margin: EdgeInsets.only( left: 16.h, @@ -161,79 +137,90 @@ class BlogPostScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Row( - children: [ - Text( - state.blog_post?['title'], - style: CustomTextStyles.titleMediumBlack, - ), - Spacer(), - PopupMenuButton( - onSelected: (value) => tapMenu(value, context, state), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'edit', - child: Text('Редактировать'), - ), - PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), - ], - ), - ], - ), - SizedBox(height: 8.0), - _buildImage(state), - SizedBox(height: 16.0), - Text( - state.blog_post?['description'], - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 16.0), - Align( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Text( + state.blogPost.title, + style: CustomTextStyles.titleMediumBlack, + ), + Spacer(), + PopupMenuButton( + onSelected: (value) => tapMenu(value, context, state), + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: 'edit', + child: Text('Редактировать'), + ), + PopupMenuItem( + value: 'delete', + child: Text('Удалить'), + ), + ], + ), + ], + ), + SizedBox(height: 8.0), + _buildImage(state), + SizedBox(height: 16.0), + Text( + state.blogPost.description, + style: CustomTextStyles.bodyMediumBluegray800, + ), + SizedBox(height: 16.0), + Align( alignment: Alignment.topLeft, child: Text( - DateFormat('dd.MM.yyyy').format(DateTime.parse(state.blog_post?['updated_at'])), + DateFormat('dd.MM.yyyy').format(state.blogPost.updatedAt), style: theme.textTheme.bodyMedium, - )), - SizedBox(height: 16.0), - Row(children: [ - Padding( - padding: EdgeInsets.only(left: 24), - child: Row(children: [ - Padding( - padding: EdgeInsets.only(right: 8), - child: Icon(Icons.favorite_outline), - ), - Text( - "Нравится", - style: CustomTextStyles.titleMediumSemiBold, - ) - ]), + ), ), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 24), - child: Row(children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon(Icons.share_outlined), + SizedBox(height: 8), + Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 24), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 8), + child: Icon(Icons.favorite_outline), + ), + Text( + "Нравится", + style: CustomTextStyles.titleMediumSemiBold, + ), + ], ), - Text( - "Поделиться", - style: CustomTextStyles.titleMediumSemiBold, - ) - ])) - ]), - ]), + ), + Spacer(), + Padding( + padding: EdgeInsets.only(right: 24), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: Icon(Icons.share_outlined), + ), + Text( + "Поделиться", + style: CustomTextStyles.titleMediumSemiBold, + ), + ], + ), + ), + ], + ), + ], + ), ); } - _buildImage(BlogPostLoadedState state) { + _buildImage(BlogPostStateLoaded state) { return CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.blog_post?['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.blogPost.image ?? ""), imageBuilder: (context, imageProvider) => Stack( children: [ ClipRRect( @@ -290,7 +277,7 @@ class BlogPostScreen extends StatelessWidget { ), SizedBox(width: 4.0), Text( - '${state.comments?.length}', + '42', style: TextStyle(color: Colors.white), ), ], @@ -306,18 +293,18 @@ class BlogPostScreen extends StatelessWidget { ); } - void tapMenu(String value, BuildContext context, BlogPostLoadedState state) { + void tapMenu(String value, BuildContext context, BlogPostStateLoaded state) { if (value == 'edit') { - GoRouter.of(context).goNamed( + GoRouter.of(context).pushNamed( 'blogPostEditScreen', - extra: state.blog_post?['id'].toString(), + extra: state.blogPost.id.toString(), ); } else if (value == 'delete') { - context.read().add(DeleteEntry(state.blog_post?['id'])); + // context.read().add(DeleteEntry(state.blog_post?['id'])); } } - _buildTextField(BuildContext context, BlogPostLoadedState state) { + _buildTextField(BuildContext context, BlogPostStateLoaded state) { return Container( margin: EdgeInsets.only( left: 16.h, @@ -343,7 +330,7 @@ class BlogPostScreen extends StatelessWidget { Column( children: [ CustomTextFormField( - controller: state.commentController, + // controller: state.commentController, maxLines: 4, ), SizedBox(height: 15.h), @@ -354,9 +341,11 @@ class BlogPostScreen extends StatelessWidget { decoration: BoxDecoration( color: Colors.transparent, ), - onPressed: () => context.read().add(CreateComment(state.commentController!.text)), + /* onPressed: () => context + .read() + .add(CreateComment(state.commentController!.text)),*/ // Установите прозрачный фон - ) + ), ], ), ], @@ -364,9 +353,9 @@ class BlogPostScreen extends StatelessWidget { ); } - _buildCommentSection(BuildContext context, BlogPostLoadedState state) { - if (state.comments != null && state.comments!.isNotEmpty) { - return Column( + _buildCommentSection(BuildContext context, BlogPostStateLoaded state) { + /* if (state.comments != null && state.comments!.isNotEmpty) { + return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ for (int i = 0; i < state.comments!.length; i++) @@ -380,15 +369,14 @@ class BlogPostScreen extends StatelessWidget { ], ); } else { - // Return a message or placeholder widget when there are no comments - return Center( - child: Text('No comments available'), - ); - } - } - - /// Navigates to the previous screen. - onTapArrowleftone(BuildContext context) { - GoRouter.of(context).pop(); + // Return a message or placeholder widget when there are no comments*/ + return Center( + child: Text('No comments available'), + ); } } + +/// Navigates to the previous screen. +onTapArrowleftone(BuildContext context) { + GoRouter.of(context).pop(); +} diff --git a/lib/features/blog_post/repositories/blog_post_repository.dart b/lib/features/blog_post/repositories/blog_post_repository.dart new file mode 100644 index 0000000..b0c5a7a --- /dev/null +++ b/lib/features/blog_post/repositories/blog_post_repository.dart @@ -0,0 +1,16 @@ +import 'package:eatvio_app/features/blog_post/models/blog_post_model.dart'; +import 'package:eatvio_app/features/blog_post/services/blog_post_service.dart'; + +class BlogPostRepository { + final BlogPostService blogPostService; + + BlogPostRepository({required this.blogPostService}); + + Future getBlogPost(String blogPostID) async { + try { + return await blogPostService.getBlogPost(blogPostID); + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/blog_post/services/blog_post_service.dart b/lib/features/blog_post/services/blog_post_service.dart new file mode 100644 index 0000000..dfbc361 --- /dev/null +++ b/lib/features/blog_post/services/blog_post_service.dart @@ -0,0 +1,13 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/blog_post/models/blog_post_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'blog_post_service.g.dart'; + +@RestApi() +abstract class BlogPostService { + factory BlogPostService(Dio dio, {String baseUrl}) = _BlogPostService; + + @GET('/api/blogPosts/show/{id}') + Future getBlogPost(@Path() String id); +} diff --git a/lib/features/blog_post/services/blog_post_service.g.dart b/lib/features/blog_post/services/blog_post_service.g.dart new file mode 100644 index 0000000..5ea30fc --- /dev/null +++ b/lib/features/blog_post/services/blog_post_service.g.dart @@ -0,0 +1,77 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'blog_post_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _BlogPostService implements BlogPostService { + _BlogPostService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future getBlogPost(String id) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/show/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = BlogPostModel.fromJson(_result.data!); + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart b/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart new file mode 100644 index 0000000..d935cd6 --- /dev/null +++ b/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart @@ -0,0 +1,18 @@ +/* +import 'package:freezed_annotation/freezed_annotation.dart'; + +part '../../../presentation/feed/blog_post_create_screen/models/blog_post_create_credentials_model.freezed.dart'; +part '../../../presentation/feed/blog_post_create_screen/models/blog_post_create_credentials_model.g.dart'; + +@freezed +class BlogPostCreateCredentialsModel with _$BlogPostCreateCredentialsModel { + const factory BlogPostCreateCredentialsModel({ + required String title, + required String description, + @JsonKey(name: 'youtube_url') required String youtubeUrl, + @Default('active') String status, + }) = _BlogPostCreateCredentialsModel; + + factory BlogPostCreateCredentialsModel.fromJson(Map json) => _$BlogPostCreateCredentialsModelFromJson(json); +} +*/ diff --git a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart new file mode 100644 index 0000000..226bfa1 --- /dev/null +++ b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart @@ -0,0 +1,209 @@ +import 'dart:io'; + +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; + +import '../../../../presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart'; +import '../../../../presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart'; + +class BlogPostCreateScreen extends StatefulWidget { + const BlogPostCreateScreen({Key? key}) : super(key: key); + + static Widget builder(BuildContext context) { + final blog_postID = ModalRoute.of(context)!.settings.arguments; + return BlocProvider( + create: (context) => BlogPostCreateBloc(BlogPostCreateState(blog_postModelObj: BlogPostCreateModel(blog_postID: blog_postID.toString()))) + ..add(BlogPostCreateInitialEvent()), + child: BlogPostCreateScreen(), + ); + } + + @override + State createState() => _BlogPostCreateScreenState(); +} + +class _BlogPostCreateScreenState extends State { + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is BlogPostCreateInitialState) { + // Это начальное состояние, данные ещё не загружены. + return Container( + color: Colors.white, + ); + } else if (state is BlogPostCreateLoadedState) { + // Данные загружены, можно строить экран. + return _buildBlogPostCreate(context, state); + } else if (state is BlogPostCreateErrorState) { + // Произошла ошибка при загрузке данных. + return Center(child: Text(state.errorMessage)); + } else { + // Другие состояния, если они есть. + return Container(); // Пустой контейнер для необработанных состояний. + } + }, + ); + } + + _buildBlogPostCreate(BuildContext context, BlogPostCreateLoadedState state) { + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar(), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: SizedBox( + width: MediaQuery.of(context).size.width - 32, + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: appTheme.blueA400, + onPressed: () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text), + label: Text( + 'Создать', + style: theme.textTheme.titleSmall, + ), + ), + ), + body: SingleChildScrollView( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Заголовок'), + SizedBox(height: 8), + CustomTextFormField( + controller: state.title, + validator: _validateTitle, + ), + SizedBox(height: 16), + Text('Описание'), + SizedBox(height: 8), + CustomTextFormField( + controller: state.description, + validator: _validateDescription, + maxLines: 6, + minLines: 1, + ), + SizedBox(height: 16), + Text('Ссылка на видео'), + SizedBox(height: 8), + CustomTextFormField( + controller: state.youtubeURL, + validator: _validateYouTubeLink, + ), + SizedBox(height: 16), + Text('Изображение поста'), + SizedBox(height: 8), + _buildAddPhoto(context, state), + SizedBox(height: 80), + ], + ), + ), + ); + } +} + +_submitForm(BuildContext context, String title, String description, String youtubeURL) async { + String? titleError = _validateTitle(title); + String? descriptionError = _validateDescription(description); + String? youtubeURLError = _validateYouTubeLink(youtubeURL); + + if (titleError != null || descriptionError != null || youtubeURLError != null) { + // Display error messages or handle invalid input as needed + // For example, show a snackbar with the error message + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(titleError ?? descriptionError ?? youtubeURLError!)), + ); + } else { + // Proceed with form submission + context.read().add(CreateBlogPost()); + } +} + +_buildAddPhoto(BuildContext context, BlogPostCreateLoadedState state) { + bool isLoading = state.isLoading; + return GestureDetector( + onTap: addImage(context, isLoading), + child: Stack( + children: [ + if (state.image == null) + Container( + height: 128, + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadius.circular(16), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.photo_library, + color: appTheme.blueGray300, + ), + SizedBox(width: 8), + Text( + "Добавить фото", + selectionColor: appTheme.blueA400, + ), + ], + ), + ), + if (state.image != null) + ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image( + image: FileImage( + File(state.image!.path), + ), + ), + ) + ], + ), + ); +} + +addImage(BuildContext context, bool isLoading) { + if (!isLoading) { + return () async { + final picker = ImagePicker(); + XFile? image = await picker.pickImage(source: ImageSource.gallery); + if (image != null) { + context.read().add(UploadImages(image)); + } + }; + } +} + +String? _validateTitle(value) { + if (value!.isEmpty) { + return 'Пожалуйста, введите заголовок'; + } + return null; +} + +String? _validateDescription(value) { + if (value!.isEmpty) { + return 'Пожалуйста, введите описание'; + } + return null; +} + +String? _validateYouTubeLink(value) { + if (value!.isEmpty) { + return 'Пожалуйста, введите ссылку'; + } else if (!_isValidUrl(value)) { + return 'Пожалуйста, введите корректную ссылку'; + } + return null; +} + +bool _isValidUrl(String url) { + final RegExp urlRegExp = new RegExp(r"^(http|https):\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$"); + return urlRegExp.hasMatch(url); +} diff --git a/lib/features/blog_post_create/repositories/blog_repository.dart b/lib/features/blog_post_create/repositories/blog_repository.dart new file mode 100644 index 0000000..3d1846a --- /dev/null +++ b/lib/features/blog_post_create/repositories/blog_repository.dart @@ -0,0 +1,21 @@ +/* +import 'package:eatvio_app/features/blog_post_create/models/blog_post_create_credentials_model.dart'; +import 'package:eatvio_app/features/blog_post_create/services/blog_service.dart'; + +class BlogRepository { + final BlogService blogService; + + BlogRepository({ + required this.blogService, + }); + + Future createBlogPost(BlogPostCreateCredentialsModel model) async { + try { + return (await blogService.createBlogPost(model)); + } catch (e) { + print(e); + throw (e); + } + } +} +*/ diff --git a/lib/features/blog_post_create/services/blog_service.dart b/lib/features/blog_post_create/services/blog_service.dart new file mode 100644 index 0000000..4b11062 --- /dev/null +++ b/lib/features/blog_post_create/services/blog_service.dart @@ -0,0 +1,16 @@ +/* +import 'package:eatvio_app/features/blog_post_create/models/blog_post_create_credentials_model.dart'; +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'blog_service.g.dart'; + +@RestApi() +abstract class BlogService { + factory BlogService(Dio dio, {String baseUrl}) = _BlogService; + + @POST('/blog_post/create') + Future createBlogPost( + BlogPostCreateCredentialsModel model); +} +*/ diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart new file mode 100644 index 0000000..8b2a0f5 --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart @@ -0,0 +1,13 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart'; + +class NewMessagesCubit extends Cubit { + int _messagesCount = 0; + + NewMessagesCubit() : super(const NewMessagesState.empty()); + + incrementCounter() { + _messagesCount++; + emit(NewMessagesState.loaded(messagesCount: _messagesCount)); + } +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart new file mode 100644 index 0000000..4ed4856 --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'new_messages_state.freezed.dart'; + +@freezed +abstract class NewMessagesState with _$NewMessagesState { + const factory NewMessagesState() = _NewMessagesState; + + const factory NewMessagesState.empty() = NewMessagesStateEmpty; + + const factory NewMessagesState.loaded({ + required int messagesCount, + }) = NewMessagesStateLoaded; + + const factory NewMessagesState.error({ + required String errorMessage, + }) = NewMessagesStateError; +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.freezed.dart b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.freezed.dart new file mode 100644 index 0000000..02a1c4b --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.freezed.dart @@ -0,0 +1,616 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'new_messages_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$NewMessagesState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int messagesCount) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int messagesCount)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int messagesCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_NewMessagesState value) $default, { + required TResult Function(NewMessagesStateEmpty value) empty, + required TResult Function(NewMessagesStateLoaded value) loaded, + required TResult Function(NewMessagesStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NewMessagesState value)? $default, { + TResult? Function(NewMessagesStateEmpty value)? empty, + TResult? Function(NewMessagesStateLoaded value)? loaded, + TResult? Function(NewMessagesStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NewMessagesState value)? $default, { + TResult Function(NewMessagesStateEmpty value)? empty, + TResult Function(NewMessagesStateLoaded value)? loaded, + TResult Function(NewMessagesStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NewMessagesStateCopyWith<$Res> { + factory $NewMessagesStateCopyWith( + NewMessagesState value, $Res Function(NewMessagesState) then) = + _$NewMessagesStateCopyWithImpl<$Res, NewMessagesState>; +} + +/// @nodoc +class _$NewMessagesStateCopyWithImpl<$Res, $Val extends NewMessagesState> + implements $NewMessagesStateCopyWith<$Res> { + _$NewMessagesStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$NewMessagesStateImplCopyWith<$Res> { + factory _$$NewMessagesStateImplCopyWith(_$NewMessagesStateImpl value, + $Res Function(_$NewMessagesStateImpl) then) = + __$$NewMessagesStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$NewMessagesStateImplCopyWithImpl<$Res> + extends _$NewMessagesStateCopyWithImpl<$Res, _$NewMessagesStateImpl> + implements _$$NewMessagesStateImplCopyWith<$Res> { + __$$NewMessagesStateImplCopyWithImpl(_$NewMessagesStateImpl _value, + $Res Function(_$NewMessagesStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$NewMessagesStateImpl implements _NewMessagesState { + const _$NewMessagesStateImpl(); + + @override + String toString() { + return 'NewMessagesState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$NewMessagesStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int messagesCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int messagesCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int messagesCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NewMessagesState value) $default, { + required TResult Function(NewMessagesStateEmpty value) empty, + required TResult Function(NewMessagesStateLoaded value) loaded, + required TResult Function(NewMessagesStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NewMessagesState value)? $default, { + TResult? Function(NewMessagesStateEmpty value)? empty, + TResult? Function(NewMessagesStateLoaded value)? loaded, + TResult? Function(NewMessagesStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NewMessagesState value)? $default, { + TResult Function(NewMessagesStateEmpty value)? empty, + TResult Function(NewMessagesStateLoaded value)? loaded, + TResult Function(NewMessagesStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _NewMessagesState implements NewMessagesState { + const factory _NewMessagesState() = _$NewMessagesStateImpl; +} + +/// @nodoc +abstract class _$$NewMessagesStateEmptyImplCopyWith<$Res> { + factory _$$NewMessagesStateEmptyImplCopyWith( + _$NewMessagesStateEmptyImpl value, + $Res Function(_$NewMessagesStateEmptyImpl) then) = + __$$NewMessagesStateEmptyImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$NewMessagesStateEmptyImplCopyWithImpl<$Res> + extends _$NewMessagesStateCopyWithImpl<$Res, _$NewMessagesStateEmptyImpl> + implements _$$NewMessagesStateEmptyImplCopyWith<$Res> { + __$$NewMessagesStateEmptyImplCopyWithImpl(_$NewMessagesStateEmptyImpl _value, + $Res Function(_$NewMessagesStateEmptyImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$NewMessagesStateEmptyImpl implements NewMessagesStateEmpty { + const _$NewMessagesStateEmptyImpl(); + + @override + String toString() { + return 'NewMessagesState.empty()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NewMessagesStateEmptyImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int messagesCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return empty(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int messagesCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return empty?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int messagesCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (empty != null) { + return empty(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NewMessagesState value) $default, { + required TResult Function(NewMessagesStateEmpty value) empty, + required TResult Function(NewMessagesStateLoaded value) loaded, + required TResult Function(NewMessagesStateError value) error, + }) { + return empty(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NewMessagesState value)? $default, { + TResult? Function(NewMessagesStateEmpty value)? empty, + TResult? Function(NewMessagesStateLoaded value)? loaded, + TResult? Function(NewMessagesStateError value)? error, + }) { + return empty?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NewMessagesState value)? $default, { + TResult Function(NewMessagesStateEmpty value)? empty, + TResult Function(NewMessagesStateLoaded value)? loaded, + TResult Function(NewMessagesStateError value)? error, + required TResult orElse(), + }) { + if (empty != null) { + return empty(this); + } + return orElse(); + } +} + +abstract class NewMessagesStateEmpty implements NewMessagesState { + const factory NewMessagesStateEmpty() = _$NewMessagesStateEmptyImpl; +} + +/// @nodoc +abstract class _$$NewMessagesStateLoadedImplCopyWith<$Res> { + factory _$$NewMessagesStateLoadedImplCopyWith( + _$NewMessagesStateLoadedImpl value, + $Res Function(_$NewMessagesStateLoadedImpl) then) = + __$$NewMessagesStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({int messagesCount}); +} + +/// @nodoc +class __$$NewMessagesStateLoadedImplCopyWithImpl<$Res> + extends _$NewMessagesStateCopyWithImpl<$Res, _$NewMessagesStateLoadedImpl> + implements _$$NewMessagesStateLoadedImplCopyWith<$Res> { + __$$NewMessagesStateLoadedImplCopyWithImpl( + _$NewMessagesStateLoadedImpl _value, + $Res Function(_$NewMessagesStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? messagesCount = null, + }) { + return _then(_$NewMessagesStateLoadedImpl( + messagesCount: null == messagesCount + ? _value.messagesCount + : messagesCount // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$NewMessagesStateLoadedImpl implements NewMessagesStateLoaded { + const _$NewMessagesStateLoadedImpl({required this.messagesCount}); + + @override + final int messagesCount; + + @override + String toString() { + return 'NewMessagesState.loaded(messagesCount: $messagesCount)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NewMessagesStateLoadedImpl && + (identical(other.messagesCount, messagesCount) || + other.messagesCount == messagesCount)); + } + + @override + int get hashCode => Object.hash(runtimeType, messagesCount); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NewMessagesStateLoadedImplCopyWith<_$NewMessagesStateLoadedImpl> + get copyWith => __$$NewMessagesStateLoadedImplCopyWithImpl< + _$NewMessagesStateLoadedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int messagesCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(messagesCount); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int messagesCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(messagesCount); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int messagesCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(messagesCount); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NewMessagesState value) $default, { + required TResult Function(NewMessagesStateEmpty value) empty, + required TResult Function(NewMessagesStateLoaded value) loaded, + required TResult Function(NewMessagesStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NewMessagesState value)? $default, { + TResult? Function(NewMessagesStateEmpty value)? empty, + TResult? Function(NewMessagesStateLoaded value)? loaded, + TResult? Function(NewMessagesStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NewMessagesState value)? $default, { + TResult Function(NewMessagesStateEmpty value)? empty, + TResult Function(NewMessagesStateLoaded value)? loaded, + TResult Function(NewMessagesStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class NewMessagesStateLoaded implements NewMessagesState { + const factory NewMessagesStateLoaded({required final int messagesCount}) = + _$NewMessagesStateLoadedImpl; + + int get messagesCount; + @JsonKey(ignore: true) + _$$NewMessagesStateLoadedImplCopyWith<_$NewMessagesStateLoadedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$NewMessagesStateErrorImplCopyWith<$Res> { + factory _$$NewMessagesStateErrorImplCopyWith( + _$NewMessagesStateErrorImpl value, + $Res Function(_$NewMessagesStateErrorImpl) then) = + __$$NewMessagesStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$NewMessagesStateErrorImplCopyWithImpl<$Res> + extends _$NewMessagesStateCopyWithImpl<$Res, _$NewMessagesStateErrorImpl> + implements _$$NewMessagesStateErrorImplCopyWith<$Res> { + __$$NewMessagesStateErrorImplCopyWithImpl(_$NewMessagesStateErrorImpl _value, + $Res Function(_$NewMessagesStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$NewMessagesStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$NewMessagesStateErrorImpl implements NewMessagesStateError { + const _$NewMessagesStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'NewMessagesState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NewMessagesStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NewMessagesStateErrorImplCopyWith<_$NewMessagesStateErrorImpl> + get copyWith => __$$NewMessagesStateErrorImplCopyWithImpl< + _$NewMessagesStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int messagesCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int messagesCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int messagesCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NewMessagesState value) $default, { + required TResult Function(NewMessagesStateEmpty value) empty, + required TResult Function(NewMessagesStateLoaded value) loaded, + required TResult Function(NewMessagesStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NewMessagesState value)? $default, { + TResult? Function(NewMessagesStateEmpty value)? empty, + TResult? Function(NewMessagesStateLoaded value)? loaded, + TResult? Function(NewMessagesStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NewMessagesState value)? $default, { + TResult Function(NewMessagesStateEmpty value)? empty, + TResult Function(NewMessagesStateLoaded value)? loaded, + TResult Function(NewMessagesStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class NewMessagesStateError implements NewMessagesState { + const factory NewMessagesStateError({required final String errorMessage}) = + _$NewMessagesStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$NewMessagesStateErrorImplCopyWith<_$NewMessagesStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart new file mode 100644 index 0000000..ba5634c --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart @@ -0,0 +1,13 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart'; + +class NotificationsCubit extends Cubit { + int _notificationsCount = 0; + + NotificationsCubit() : super(const NotificationsState.empty()); + + incrementCounter() { + _notificationsCount++; + emit(NotificationsState.loaded(notificationsCount: _notificationsCount)); + } +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart new file mode 100644 index 0000000..0f20a05 --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'notifications_state.freezed.dart'; + +@freezed +abstract class NotificationsState with _$NotificationsState { + const factory NotificationsState() = _NotificationsState; + + const factory NotificationsState.empty() = NotificationsStateEmpty; + + const factory NotificationsState.loaded({ + required int notificationsCount, + }) = NotificationsStateLoaded; + + const factory NotificationsState.error({ + required String errorMessage, + }) = NotificationsStateError; +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart new file mode 100644 index 0000000..0deeebb --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart @@ -0,0 +1,621 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'notifications_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$NotificationsState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int notificationsCount) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int notificationsCount)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int notificationsCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_NotificationsState value) $default, { + required TResult Function(NotificationsStateEmpty value) empty, + required TResult Function(NotificationsStateLoaded value) loaded, + required TResult Function(NotificationsStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NotificationsState value)? $default, { + TResult? Function(NotificationsStateEmpty value)? empty, + TResult? Function(NotificationsStateLoaded value)? loaded, + TResult? Function(NotificationsStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NotificationsState value)? $default, { + TResult Function(NotificationsStateEmpty value)? empty, + TResult Function(NotificationsStateLoaded value)? loaded, + TResult Function(NotificationsStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NotificationsStateCopyWith<$Res> { + factory $NotificationsStateCopyWith( + NotificationsState value, $Res Function(NotificationsState) then) = + _$NotificationsStateCopyWithImpl<$Res, NotificationsState>; +} + +/// @nodoc +class _$NotificationsStateCopyWithImpl<$Res, $Val extends NotificationsState> + implements $NotificationsStateCopyWith<$Res> { + _$NotificationsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$NotificationsStateImplCopyWith<$Res> { + factory _$$NotificationsStateImplCopyWith(_$NotificationsStateImpl value, + $Res Function(_$NotificationsStateImpl) then) = + __$$NotificationsStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$NotificationsStateImplCopyWithImpl<$Res> + extends _$NotificationsStateCopyWithImpl<$Res, _$NotificationsStateImpl> + implements _$$NotificationsStateImplCopyWith<$Res> { + __$$NotificationsStateImplCopyWithImpl(_$NotificationsStateImpl _value, + $Res Function(_$NotificationsStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$NotificationsStateImpl implements _NotificationsState { + const _$NotificationsStateImpl(); + + @override + String toString() { + return 'NotificationsState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$NotificationsStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int notificationsCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int notificationsCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int notificationsCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NotificationsState value) $default, { + required TResult Function(NotificationsStateEmpty value) empty, + required TResult Function(NotificationsStateLoaded value) loaded, + required TResult Function(NotificationsStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NotificationsState value)? $default, { + TResult? Function(NotificationsStateEmpty value)? empty, + TResult? Function(NotificationsStateLoaded value)? loaded, + TResult? Function(NotificationsStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NotificationsState value)? $default, { + TResult Function(NotificationsStateEmpty value)? empty, + TResult Function(NotificationsStateLoaded value)? loaded, + TResult Function(NotificationsStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _NotificationsState implements NotificationsState { + const factory _NotificationsState() = _$NotificationsStateImpl; +} + +/// @nodoc +abstract class _$$NotificationsStateEmptyImplCopyWith<$Res> { + factory _$$NotificationsStateEmptyImplCopyWith( + _$NotificationsStateEmptyImpl value, + $Res Function(_$NotificationsStateEmptyImpl) then) = + __$$NotificationsStateEmptyImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$NotificationsStateEmptyImplCopyWithImpl<$Res> + extends _$NotificationsStateCopyWithImpl<$Res, + _$NotificationsStateEmptyImpl> + implements _$$NotificationsStateEmptyImplCopyWith<$Res> { + __$$NotificationsStateEmptyImplCopyWithImpl( + _$NotificationsStateEmptyImpl _value, + $Res Function(_$NotificationsStateEmptyImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$NotificationsStateEmptyImpl implements NotificationsStateEmpty { + const _$NotificationsStateEmptyImpl(); + + @override + String toString() { + return 'NotificationsState.empty()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NotificationsStateEmptyImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int notificationsCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return empty(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int notificationsCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return empty?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int notificationsCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (empty != null) { + return empty(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NotificationsState value) $default, { + required TResult Function(NotificationsStateEmpty value) empty, + required TResult Function(NotificationsStateLoaded value) loaded, + required TResult Function(NotificationsStateError value) error, + }) { + return empty(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NotificationsState value)? $default, { + TResult? Function(NotificationsStateEmpty value)? empty, + TResult? Function(NotificationsStateLoaded value)? loaded, + TResult? Function(NotificationsStateError value)? error, + }) { + return empty?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NotificationsState value)? $default, { + TResult Function(NotificationsStateEmpty value)? empty, + TResult Function(NotificationsStateLoaded value)? loaded, + TResult Function(NotificationsStateError value)? error, + required TResult orElse(), + }) { + if (empty != null) { + return empty(this); + } + return orElse(); + } +} + +abstract class NotificationsStateEmpty implements NotificationsState { + const factory NotificationsStateEmpty() = _$NotificationsStateEmptyImpl; +} + +/// @nodoc +abstract class _$$NotificationsStateLoadedImplCopyWith<$Res> { + factory _$$NotificationsStateLoadedImplCopyWith( + _$NotificationsStateLoadedImpl value, + $Res Function(_$NotificationsStateLoadedImpl) then) = + __$$NotificationsStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({int notificationsCount}); +} + +/// @nodoc +class __$$NotificationsStateLoadedImplCopyWithImpl<$Res> + extends _$NotificationsStateCopyWithImpl<$Res, + _$NotificationsStateLoadedImpl> + implements _$$NotificationsStateLoadedImplCopyWith<$Res> { + __$$NotificationsStateLoadedImplCopyWithImpl( + _$NotificationsStateLoadedImpl _value, + $Res Function(_$NotificationsStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? notificationsCount = null, + }) { + return _then(_$NotificationsStateLoadedImpl( + notificationsCount: null == notificationsCount + ? _value.notificationsCount + : notificationsCount // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { + const _$NotificationsStateLoadedImpl({required this.notificationsCount}); + + @override + final int notificationsCount; + + @override + String toString() { + return 'NotificationsState.loaded(notificationsCount: $notificationsCount)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NotificationsStateLoadedImpl && + (identical(other.notificationsCount, notificationsCount) || + other.notificationsCount == notificationsCount)); + } + + @override + int get hashCode => Object.hash(runtimeType, notificationsCount); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NotificationsStateLoadedImplCopyWith<_$NotificationsStateLoadedImpl> + get copyWith => __$$NotificationsStateLoadedImplCopyWithImpl< + _$NotificationsStateLoadedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int notificationsCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(notificationsCount); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int notificationsCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(notificationsCount); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int notificationsCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(notificationsCount); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NotificationsState value) $default, { + required TResult Function(NotificationsStateEmpty value) empty, + required TResult Function(NotificationsStateLoaded value) loaded, + required TResult Function(NotificationsStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NotificationsState value)? $default, { + TResult? Function(NotificationsStateEmpty value)? empty, + TResult? Function(NotificationsStateLoaded value)? loaded, + TResult? Function(NotificationsStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NotificationsState value)? $default, { + TResult Function(NotificationsStateEmpty value)? empty, + TResult Function(NotificationsStateLoaded value)? loaded, + TResult Function(NotificationsStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class NotificationsStateLoaded implements NotificationsState { + const factory NotificationsStateLoaded( + {required final int notificationsCount}) = _$NotificationsStateLoadedImpl; + + int get notificationsCount; + @JsonKey(ignore: true) + _$$NotificationsStateLoadedImplCopyWith<_$NotificationsStateLoadedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$NotificationsStateErrorImplCopyWith<$Res> { + factory _$$NotificationsStateErrorImplCopyWith( + _$NotificationsStateErrorImpl value, + $Res Function(_$NotificationsStateErrorImpl) then) = + __$$NotificationsStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$NotificationsStateErrorImplCopyWithImpl<$Res> + extends _$NotificationsStateCopyWithImpl<$Res, + _$NotificationsStateErrorImpl> + implements _$$NotificationsStateErrorImplCopyWith<$Res> { + __$$NotificationsStateErrorImplCopyWithImpl( + _$NotificationsStateErrorImpl _value, + $Res Function(_$NotificationsStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$NotificationsStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$NotificationsStateErrorImpl implements NotificationsStateError { + const _$NotificationsStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'NotificationsState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NotificationsStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NotificationsStateErrorImplCopyWith<_$NotificationsStateErrorImpl> + get copyWith => __$$NotificationsStateErrorImplCopyWithImpl< + _$NotificationsStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() empty, + required TResult Function(int notificationsCount) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? empty, + TResult? Function(int notificationsCount)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? empty, + TResult Function(int notificationsCount)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_NotificationsState value) $default, { + required TResult Function(NotificationsStateEmpty value) empty, + required TResult Function(NotificationsStateLoaded value) loaded, + required TResult Function(NotificationsStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_NotificationsState value)? $default, { + TResult? Function(NotificationsStateEmpty value)? empty, + TResult? Function(NotificationsStateLoaded value)? loaded, + TResult? Function(NotificationsStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_NotificationsState value)? $default, { + TResult Function(NotificationsStateEmpty value)? empty, + TResult Function(NotificationsStateLoaded value)? loaded, + TResult Function(NotificationsStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class NotificationsStateError implements NotificationsState { + const factory NotificationsStateError({required final String errorMessage}) = + _$NotificationsStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$NotificationsStateErrorImplCopyWith<_$NotificationsStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/widgets/bottom_navigation_bar_widget.dart b/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart similarity index 60% rename from lib/widgets/bottom_navigation_bar_widget.dart rename to lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart index 68197c1..5b89028 100644 --- a/lib/widgets/bottom_navigation_bar_widget.dart +++ b/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart @@ -1,6 +1,11 @@ +import 'package:badges/badges.dart' as badges; import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart'; import 'package:eatvio_app/widgets/custom_navigation_menu.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; @@ -51,7 +56,7 @@ class _BottomNavigationBarWidgetState extends State { items: [ PopupMenuItem( child: CustomNavigationMenu(), - ) + ), ], position: RelativeRect.fromLTRB(size.width, size.height, 0, 0), ); @@ -113,36 +118,56 @@ class _BottomNavigationBarWidgetState extends State { ), BottomNavigationBarItem( label: "chat".tr, - icon: SvgPicture.asset( - ImageConstant.imgChat, - width: 24, - height: 24, - ), - activeIcon: SvgPicture.asset( - ImageConstant.imgChat, - width: 24, - height: 24, - colorFilter: ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, - ), + icon: BlocBuilder( + builder: (BuildContext context, NewMessagesState state) { + return badges.Badge( + position: badges.BadgePosition.topEnd(), + badgeContent: Text( + (state is NewMessagesStateLoaded) ? state.messagesCount.toString() : '0', + style: TextStyle( + color: Colors.white, + ), + ), + child: SvgPicture.asset( + ImageConstant.imgChat, + width: 24, + height: 24, + colorFilter: currentBottomNavBarIndex == 3 + ? ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ) + : null, + ), + ); + }, ), ), BottomNavigationBarItem( label: '', - icon: SvgPicture.asset( - ImageConstant.imgBell, - width: 24, - height: 24, - ), - activeIcon: SvgPicture.asset( - ImageConstant.imgBell, - width: 24, - height: 24, - colorFilter: ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, - ), + icon: BlocBuilder( + builder: (BuildContext context, NotificationsState state) { + return badges.Badge( + position: badges.BadgePosition.topEnd(), + badgeContent: Text( + (state is NotificationsStateLoaded) ? state.notificationsCount.toString() : '0', + style: TextStyle( + color: Colors.white, + ), + ), + child: SvgPicture.asset( + ImageConstant.imgBell, + colorFilter: currentBottomNavBarIndex == 4 + ? ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ) + : null, + width: 24, + height: 24, + ), + ); + }, ), ), BottomNavigationBarItem( diff --git a/lib/features/calendar/models/calendar_entry_model.dart b/lib/features/calendar/models/calendar_entry_model.dart new file mode 100644 index 0000000..0973f97 --- /dev/null +++ b/lib/features/calendar/models/calendar_entry_model.dart @@ -0,0 +1,22 @@ +/// This class is used in the [userprofile_item_widget] screen. +// ignore_for_file: must_be_immutable + +class CalendarEntryModel { + String? date; + String? status; + String id; + bool is_current_day_included_in_the_chosen_diet_progression; + + CalendarEntryModel({ + this.date, + this.status, + required this.id, + required this.is_current_day_included_in_the_chosen_diet_progression, + }) { + date = date; + status = status; + id = id; + is_current_day_included_in_the_chosen_diet_progression = + is_current_day_included_in_the_chosen_diet_progression; + } +} diff --git a/lib/features/calendar/models/calendar_model.dart b/lib/features/calendar/models/calendar_model.dart new file mode 100644 index 0000000..65fc834 --- /dev/null +++ b/lib/features/calendar/models/calendar_model.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'calendar_model.freezed.dart'; +part 'calendar_model.g.dart'; + +@freezed +class CalendarModel with _$CalendarModel { + const factory CalendarModel({ + required String date, + required bool is_current_day_included_in_the_chosen_diet_progression, + Object? diary, + }) = _CalendarModel; + + factory CalendarModel.fromJson(Map json) => + _$CalendarModelFromJson(json); +} diff --git a/lib/features/calendar/models/calendar_model.freezed.dart b/lib/features/calendar/models/calendar_model.freezed.dart new file mode 100644 index 0000000..5e47f84 --- /dev/null +++ b/lib/features/calendar/models/calendar_model.freezed.dart @@ -0,0 +1,202 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'calendar_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +CalendarModel _$CalendarModelFromJson(Map json) { + return _CalendarModel.fromJson(json); +} + +/// @nodoc +mixin _$CalendarModel { + String get date => throw _privateConstructorUsedError; + bool get is_current_day_included_in_the_chosen_diet_progression => + throw _privateConstructorUsedError; + Object? get diary => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $CalendarModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CalendarModelCopyWith<$Res> { + factory $CalendarModelCopyWith( + CalendarModel value, $Res Function(CalendarModel) then) = + _$CalendarModelCopyWithImpl<$Res, CalendarModel>; + @useResult + $Res call( + {String date, + bool is_current_day_included_in_the_chosen_diet_progression, + Object? diary}); +} + +/// @nodoc +class _$CalendarModelCopyWithImpl<$Res, $Val extends CalendarModel> + implements $CalendarModelCopyWith<$Res> { + _$CalendarModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? is_current_day_included_in_the_chosen_diet_progression = null, + Object? diary = freezed, + }) { + return _then(_value.copyWith( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + is_current_day_included_in_the_chosen_diet_progression: null == + is_current_day_included_in_the_chosen_diet_progression + ? _value.is_current_day_included_in_the_chosen_diet_progression + : is_current_day_included_in_the_chosen_diet_progression // ignore: cast_nullable_to_non_nullable + as bool, + diary: freezed == diary ? _value.diary : diary, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$CalendarModelImplCopyWith<$Res> + implements $CalendarModelCopyWith<$Res> { + factory _$$CalendarModelImplCopyWith( + _$CalendarModelImpl value, $Res Function(_$CalendarModelImpl) then) = + __$$CalendarModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String date, + bool is_current_day_included_in_the_chosen_diet_progression, + Object? diary}); +} + +/// @nodoc +class __$$CalendarModelImplCopyWithImpl<$Res> + extends _$CalendarModelCopyWithImpl<$Res, _$CalendarModelImpl> + implements _$$CalendarModelImplCopyWith<$Res> { + __$$CalendarModelImplCopyWithImpl( + _$CalendarModelImpl _value, $Res Function(_$CalendarModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? is_current_day_included_in_the_chosen_diet_progression = null, + Object? diary = freezed, + }) { + return _then(_$CalendarModelImpl( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + is_current_day_included_in_the_chosen_diet_progression: null == + is_current_day_included_in_the_chosen_diet_progression + ? _value.is_current_day_included_in_the_chosen_diet_progression + : is_current_day_included_in_the_chosen_diet_progression // ignore: cast_nullable_to_non_nullable + as bool, + diary: freezed == diary ? _value.diary : diary, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$CalendarModelImpl implements _CalendarModel { + const _$CalendarModelImpl( + {required this.date, + required this.is_current_day_included_in_the_chosen_diet_progression, + this.diary}); + + factory _$CalendarModelImpl.fromJson(Map json) => + _$$CalendarModelImplFromJson(json); + + @override + final String date; + @override + final bool is_current_day_included_in_the_chosen_diet_progression; + @override + final Object? diary; + + @override + String toString() { + return 'CalendarModel(date: $date, is_current_day_included_in_the_chosen_diet_progression: $is_current_day_included_in_the_chosen_diet_progression, diary: $diary)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CalendarModelImpl && + (identical(other.date, date) || other.date == date) && + (identical( + other + .is_current_day_included_in_the_chosen_diet_progression, + is_current_day_included_in_the_chosen_diet_progression) || + other.is_current_day_included_in_the_chosen_diet_progression == + is_current_day_included_in_the_chosen_diet_progression) && + const DeepCollectionEquality().equals(other.diary, diary)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + date, + is_current_day_included_in_the_chosen_diet_progression, + const DeepCollectionEquality().hash(diary)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CalendarModelImplCopyWith<_$CalendarModelImpl> get copyWith => + __$$CalendarModelImplCopyWithImpl<_$CalendarModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$CalendarModelImplToJson( + this, + ); + } +} + +abstract class _CalendarModel implements CalendarModel { + const factory _CalendarModel( + {required final String date, + required final bool + is_current_day_included_in_the_chosen_diet_progression, + final Object? diary}) = _$CalendarModelImpl; + + factory _CalendarModel.fromJson(Map json) = + _$CalendarModelImpl.fromJson; + + @override + String get date; + @override + bool get is_current_day_included_in_the_chosen_diet_progression; + @override + Object? get diary; + @override + @JsonKey(ignore: true) + _$$CalendarModelImplCopyWith<_$CalendarModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/calendar/models/calendar_model.g.dart b/lib/features/calendar/models/calendar_model.g.dart new file mode 100644 index 0000000..65fd006 --- /dev/null +++ b/lib/features/calendar/models/calendar_model.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'calendar_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$CalendarModelImpl _$$CalendarModelImplFromJson(Map json) => + _$CalendarModelImpl( + date: json['date'] as String, + is_current_day_included_in_the_chosen_diet_progression: + json['is_current_day_included_in_the_chosen_diet_progression'] + as bool, + diary: json['diary'], + ); + +Map _$$CalendarModelImplToJson(_$CalendarModelImpl instance) => + { + 'date': instance.date, + 'is_current_day_included_in_the_chosen_diet_progression': + instance.is_current_day_included_in_the_chosen_diet_progression, + 'diary': instance.diary, + }; diff --git a/lib/features/calendar/presentation/bloc/calendar_cubit.dart b/lib/features/calendar/presentation/bloc/calendar_cubit.dart new file mode 100644 index 0000000..2b76ab1 --- /dev/null +++ b/lib/features/calendar/presentation/bloc/calendar_cubit.dart @@ -0,0 +1,20 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; +import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart'; + +class CalendarCubit extends Cubit { + final CalendarRepository calendarRepository; + + CalendarCubit({required this.calendarRepository}) + : super(const CalendarState.loading()); + + loadCalendarList() async { + emit(const CalendarState.loading()); + try { + final calendarList = await calendarRepository.getCalendar(); + emit(CalendarState.loaded(calendarList: calendarList)); + } catch (e) { + emit(CalendarState.error(errorMessage: e.toString())); + } + } +} diff --git a/lib/features/calendar/presentation/bloc/calendar_state.dart b/lib/features/calendar/presentation/bloc/calendar_state.dart new file mode 100644 index 0000000..6dbf606 --- /dev/null +++ b/lib/features/calendar/presentation/bloc/calendar_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'calendar_state.freezed.dart'; + +@freezed +abstract class CalendarState with _$CalendarState { + const factory CalendarState() = _CalendarState; + + const factory CalendarState.loading() = CalendarStateLoading; + + const factory CalendarState.loaded({ + required List calendarList, + }) = CalendarStateLoaded; + + const factory CalendarState.error({ + required String errorMessage, + }) = CalendarStateError; +} diff --git a/lib/features/calendar/presentation/bloc/calendar_state.freezed.dart b/lib/features/calendar/presentation/bloc/calendar_state.freezed.dart new file mode 100644 index 0000000..c71d522 --- /dev/null +++ b/lib/features/calendar/presentation/bloc/calendar_state.freezed.dart @@ -0,0 +1,621 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'calendar_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$CalendarState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List calendarList) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List calendarList)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List calendarList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_CalendarState value) $default, { + required TResult Function(CalendarStateLoading value) loading, + required TResult Function(CalendarStateLoaded value) loaded, + required TResult Function(CalendarStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CalendarState value)? $default, { + TResult? Function(CalendarStateLoading value)? loading, + TResult? Function(CalendarStateLoaded value)? loaded, + TResult? Function(CalendarStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CalendarState value)? $default, { + TResult Function(CalendarStateLoading value)? loading, + TResult Function(CalendarStateLoaded value)? loaded, + TResult Function(CalendarStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CalendarStateCopyWith<$Res> { + factory $CalendarStateCopyWith( + CalendarState value, $Res Function(CalendarState) then) = + _$CalendarStateCopyWithImpl<$Res, CalendarState>; +} + +/// @nodoc +class _$CalendarStateCopyWithImpl<$Res, $Val extends CalendarState> + implements $CalendarStateCopyWith<$Res> { + _$CalendarStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$CalendarStateImplCopyWith<$Res> { + factory _$$CalendarStateImplCopyWith( + _$CalendarStateImpl value, $Res Function(_$CalendarStateImpl) then) = + __$$CalendarStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$CalendarStateImplCopyWithImpl<$Res> + extends _$CalendarStateCopyWithImpl<$Res, _$CalendarStateImpl> + implements _$$CalendarStateImplCopyWith<$Res> { + __$$CalendarStateImplCopyWithImpl( + _$CalendarStateImpl _value, $Res Function(_$CalendarStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$CalendarStateImpl implements _CalendarState { + const _$CalendarStateImpl(); + + @override + String toString() { + return 'CalendarState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$CalendarStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List calendarList) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List calendarList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List calendarList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CalendarState value) $default, { + required TResult Function(CalendarStateLoading value) loading, + required TResult Function(CalendarStateLoaded value) loaded, + required TResult Function(CalendarStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CalendarState value)? $default, { + TResult? Function(CalendarStateLoading value)? loading, + TResult? Function(CalendarStateLoaded value)? loaded, + TResult? Function(CalendarStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CalendarState value)? $default, { + TResult Function(CalendarStateLoading value)? loading, + TResult Function(CalendarStateLoaded value)? loaded, + TResult Function(CalendarStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _CalendarState implements CalendarState { + const factory _CalendarState() = _$CalendarStateImpl; +} + +/// @nodoc +abstract class _$$CalendarStateLoadingImplCopyWith<$Res> { + factory _$$CalendarStateLoadingImplCopyWith(_$CalendarStateLoadingImpl value, + $Res Function(_$CalendarStateLoadingImpl) then) = + __$$CalendarStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$CalendarStateLoadingImplCopyWithImpl<$Res> + extends _$CalendarStateCopyWithImpl<$Res, _$CalendarStateLoadingImpl> + implements _$$CalendarStateLoadingImplCopyWith<$Res> { + __$$CalendarStateLoadingImplCopyWithImpl(_$CalendarStateLoadingImpl _value, + $Res Function(_$CalendarStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$CalendarStateLoadingImpl implements CalendarStateLoading { + const _$CalendarStateLoadingImpl(); + + @override + String toString() { + return 'CalendarState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CalendarStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List calendarList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List calendarList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List calendarList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CalendarState value) $default, { + required TResult Function(CalendarStateLoading value) loading, + required TResult Function(CalendarStateLoaded value) loaded, + required TResult Function(CalendarStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CalendarState value)? $default, { + TResult? Function(CalendarStateLoading value)? loading, + TResult? Function(CalendarStateLoaded value)? loaded, + TResult? Function(CalendarStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CalendarState value)? $default, { + TResult Function(CalendarStateLoading value)? loading, + TResult Function(CalendarStateLoaded value)? loaded, + TResult Function(CalendarStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class CalendarStateLoading implements CalendarState { + const factory CalendarStateLoading() = _$CalendarStateLoadingImpl; +} + +/// @nodoc +abstract class _$$CalendarStateLoadedImplCopyWith<$Res> { + factory _$$CalendarStateLoadedImplCopyWith(_$CalendarStateLoadedImpl value, + $Res Function(_$CalendarStateLoadedImpl) then) = + __$$CalendarStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({List calendarList}); +} + +/// @nodoc +class __$$CalendarStateLoadedImplCopyWithImpl<$Res> + extends _$CalendarStateCopyWithImpl<$Res, _$CalendarStateLoadedImpl> + implements _$$CalendarStateLoadedImplCopyWith<$Res> { + __$$CalendarStateLoadedImplCopyWithImpl(_$CalendarStateLoadedImpl _value, + $Res Function(_$CalendarStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? calendarList = null, + }) { + return _then(_$CalendarStateLoadedImpl( + calendarList: null == calendarList + ? _value._calendarList + : calendarList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$CalendarStateLoadedImpl implements CalendarStateLoaded { + const _$CalendarStateLoadedImpl( + {required final List calendarList}) + : _calendarList = calendarList; + + final List _calendarList; + @override + List get calendarList { + if (_calendarList is EqualUnmodifiableListView) return _calendarList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_calendarList); + } + + @override + String toString() { + return 'CalendarState.loaded(calendarList: $calendarList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CalendarStateLoadedImpl && + const DeepCollectionEquality() + .equals(other._calendarList, _calendarList)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_calendarList)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CalendarStateLoadedImplCopyWith<_$CalendarStateLoadedImpl> get copyWith => + __$$CalendarStateLoadedImplCopyWithImpl<_$CalendarStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List calendarList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(calendarList); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List calendarList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(calendarList); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List calendarList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(calendarList); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CalendarState value) $default, { + required TResult Function(CalendarStateLoading value) loading, + required TResult Function(CalendarStateLoaded value) loaded, + required TResult Function(CalendarStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CalendarState value)? $default, { + TResult? Function(CalendarStateLoading value)? loading, + TResult? Function(CalendarStateLoaded value)? loaded, + TResult? Function(CalendarStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CalendarState value)? $default, { + TResult Function(CalendarStateLoading value)? loading, + TResult Function(CalendarStateLoaded value)? loaded, + TResult Function(CalendarStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class CalendarStateLoaded implements CalendarState { + const factory CalendarStateLoaded( + {required final List calendarList}) = + _$CalendarStateLoadedImpl; + + List get calendarList; + @JsonKey(ignore: true) + _$$CalendarStateLoadedImplCopyWith<_$CalendarStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$CalendarStateErrorImplCopyWith<$Res> { + factory _$$CalendarStateErrorImplCopyWith(_$CalendarStateErrorImpl value, + $Res Function(_$CalendarStateErrorImpl) then) = + __$$CalendarStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$CalendarStateErrorImplCopyWithImpl<$Res> + extends _$CalendarStateCopyWithImpl<$Res, _$CalendarStateErrorImpl> + implements _$$CalendarStateErrorImplCopyWith<$Res> { + __$$CalendarStateErrorImplCopyWithImpl(_$CalendarStateErrorImpl _value, + $Res Function(_$CalendarStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$CalendarStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$CalendarStateErrorImpl implements CalendarStateError { + const _$CalendarStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'CalendarState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CalendarStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CalendarStateErrorImplCopyWith<_$CalendarStateErrorImpl> get copyWith => + __$$CalendarStateErrorImplCopyWithImpl<_$CalendarStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List calendarList) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List calendarList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List calendarList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CalendarState value) $default, { + required TResult Function(CalendarStateLoading value) loading, + required TResult Function(CalendarStateLoaded value) loaded, + required TResult Function(CalendarStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CalendarState value)? $default, { + TResult? Function(CalendarStateLoading value)? loading, + TResult? Function(CalendarStateLoaded value)? loaded, + TResult? Function(CalendarStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CalendarState value)? $default, { + TResult Function(CalendarStateLoading value)? loading, + TResult Function(CalendarStateLoaded value)? loaded, + TResult Function(CalendarStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class CalendarStateError implements CalendarState { + const factory CalendarStateError({required final String errorMessage}) = + _$CalendarStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$CalendarStateErrorImplCopyWith<_$CalendarStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart new file mode 100644 index 0000000..bcd365c --- /dev/null +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -0,0 +1,283 @@ +// ignore_for_file: unused_local_variable + +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; + +// ignore: must_be_immutable +class CalendarScreen extends StatelessWidget { + CalendarScreen({Key? key}) : super(key: key); + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is CalendarStateLoaded) { + return _buildCalendar(context, state); + } else if (state is CalendarStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } else if (state is CalendarStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text("Неопределенная ошибка"), + ), + ), + ); + }, + ); + } + + Widget _buildCalendar(BuildContext context, CalendarStateLoaded state) { + return Stack(alignment: Alignment.bottomCenter, children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + backgroundColor: Colors.white, + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 5.v), + child: Column( + children: [ + SizedBox(height: 20.v), + _buildCalendarBody(context, state), + SizedBox(height: 20.v), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ]); + } + + _buildCalendarBody(BuildContext context, CalendarStateLoaded state) { + return ListView.separated( + padding: EdgeInsets.all(8), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) { + return SizedBox( + height: 2.v, + ); + }, + itemCount: state.calendarList.length, + itemBuilder: (context, index) { + Map diary = {}; + if (state.calendarList[index].diary is List) { + diary['status'] = 'Скоро'; + return InkWell( + borderRadius: BorderRadiusStyle.circleBorder8, + child: Ink( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadiusStyle.circleBorder8, + color: state.calendarList[index] + .is_current_day_included_in_the_chosen_diet_progression + ? Color.fromRGBO(59, 130, 246, .2) + : Color.fromRGBO(126, 136, 151, .1), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + formatDate(state.calendarList[index].date), + style: theme.textTheme.titleMedium, + ), + SizedBox(height: 2.v), + if (state.calendarList[index] + .is_current_day_included_in_the_chosen_diet_progression) + Container( + padding: EdgeInsets.all( + 4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(13, 110, 253, 1), + borderRadius: BorderRadius.circular( + 24.0), // Закругленные углы + ), + child: Text( + 'Посмотреть диету на день', + style: CustomTextStyles + .titleSmallBold, // Предполагается, что текст белый + ), + ), + if (!state.calendarList[index] + .is_current_day_included_in_the_chosen_diet_progression) + Container( + padding: EdgeInsets.all( + 4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(108, 117, 125, 1), + borderRadius: BorderRadius.circular( + 24.0), // Закругленные углы + ), + child: Text( + 'Cкоро', + style: CustomTextStyles + .titleSmallBold, // Предполагается, что текст белый + ), + ), + ], + ), + ), + ], + ), + ), + ); + } else { + diary = state.calendarList[index].diary as Map; + print(state.calendarList[index]); + return InkWell( + borderRadius: BorderRadiusStyle.circleBorder8, + onTap: () => GoRouter.of(context).go( + '/diary-screen', + extra: diary['id'].toString(), + ), + child: Ink( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadiusStyle.circleBorder8, + color: getBackgroundColor(diary['state']), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + formatDate(state.calendarList[index].date), + style: theme.textTheme.titleMedium, + ), + SizedBox(height: 2.v), + Row(children: [ + Container( + padding: EdgeInsets.all( + 4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: diary['state'] == 'finished' + ? Color.fromRGBO(1, 154, 62, 1) + : Color.fromRGBO(154, 74, 1, 1), + borderRadius: BorderRadius.circular( + 24.0), // Закругленные углы + ), + child: Text( + _getStateText(diary['state'] ?? ''), + style: CustomTextStyles + .titleSmallBold, // Предполагается, что текст белый + ), + ), + SizedBox(width: 4), + if (diary['state'] == 'started') + Container( + padding: EdgeInsets.all( + 4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(13, 110, 253, 1), + borderRadius: BorderRadius.circular( + 24.0), // Закругленные углы + ), + child: Text( + 'Заполнить отчет', + style: CustomTextStyles + .titleSmallBold, // Предполагается, что текст белый + ), + ), + if (diary['state'] == 'finished') + Container( + padding: EdgeInsets.all( + 4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(13, 110, 253, 1), + borderRadius: BorderRadius.circular( + 24.0), // Закругленные углы + ), + child: Text( + 'Изменить отчет', + style: CustomTextStyles + .titleSmallBold, // Предполагается, что текст белый + ), + ), + ]), + ], + ), + ), + ], + ), + ), + ); + } + }, + ); + } +} + +String _getStateText(String state) { + switch (state) { + case 'finished': + return 'Готово'; + case 'started': + return 'В процессе'; + default: + return ''; // Возвращаем пустую строку, если состояние не распознано + } +} + +String formatDate(String dateString) { + // Преобразуем строку в объект DateTime + DateTime dateTime = DateTime.parse(dateString); + + // Форматируем дату + String formattedDate = DateFormat('d MMMM', 'ru_RU').format(dateTime); + + // Возвращаем результат в нужном формате + return '$formattedDate'; +} + +Color getBackgroundColor(String? status) { + switch (status) { + case 'finished': + return Color.fromRGBO(1, 154, 62, .1); + case 'started': + return Color.fromRGBO(154, 74, 1, .1); + default: + return Color.fromRGBO(126, 136, 151, .1); + } +} diff --git a/lib/features/calendar/repositories/calendar_repository.dart b/lib/features/calendar/repositories/calendar_repository.dart new file mode 100644 index 0000000..fd9f734 --- /dev/null +++ b/lib/features/calendar/repositories/calendar_repository.dart @@ -0,0 +1,16 @@ +import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; +import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; + +class CalendarRepository { + final CalendarService calendarService; + + CalendarRepository({required this.calendarService}); + + Future> getCalendar() async { + try { + return await calendarService.getCalendar(); + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/calendar/services/calendar_service.dart b/lib/features/calendar/services/calendar_service.dart new file mode 100644 index 0000000..2974f73 --- /dev/null +++ b/lib/features/calendar/services/calendar_service.dart @@ -0,0 +1,13 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'calendar_service.g.dart'; + +@RestApi() +abstract class CalendarService { + factory CalendarService(Dio dio, {String baseUrl}) = _CalendarService; + + @GET('/api/calendar/index') + Future> getCalendar(); +} diff --git a/lib/features/calendar/services/calendar_service.g.dart b/lib/features/calendar/services/calendar_service.g.dart new file mode 100644 index 0000000..4dec81f --- /dev/null +++ b/lib/features/calendar/services/calendar_service.g.dart @@ -0,0 +1,79 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'calendar_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _CalendarService implements CalendarService { + _CalendarService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future> getCalendar() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/calendar/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + var _value = _result.data! + .map((dynamic i) => CalendarModel.fromJson(i as Map)) + .toList(); + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/chat/models/chat_message_model.dart b/lib/features/chat/models/chat_message_model.dart index 220df3b..23f03f9 100644 --- a/lib/features/chat/models/chat_message_model.dart +++ b/lib/features/chat/models/chat_message_model.dart @@ -1,7 +1,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'chat_message_model.freezed.dart'; - part 'chat_message_model.g.dart'; @freezed @@ -9,7 +8,7 @@ class ChatMessageModel with _$ChatMessageModel { const factory ChatMessageModel({ required int id, required String data, - @JsonKey(name: 'media_data') required List mediaData, + @JsonKey(name: 'media_data') required List? mediaData, @JsonKey(name: 'author_id') required int authorId, @JsonKey(name: 'updated_at') required String updatedAt, }) = _ChatMessageModel; diff --git a/lib/features/chat/models/chat_message_model.freezed.dart b/lib/features/chat/models/chat_message_model.freezed.dart index 6185608..76a91cb 100644 --- a/lib/features/chat/models/chat_message_model.freezed.dart +++ b/lib/features/chat/models/chat_message_model.freezed.dart @@ -23,7 +23,7 @@ mixin _$ChatMessageModel { int get id => throw _privateConstructorUsedError; String get data => throw _privateConstructorUsedError; @JsonKey(name: 'media_data') - List get mediaData => throw _privateConstructorUsedError; + List? get mediaData => throw _privateConstructorUsedError; @JsonKey(name: 'author_id') int get authorId => throw _privateConstructorUsedError; @JsonKey(name: 'updated_at') @@ -44,7 +44,7 @@ abstract class $ChatMessageModelCopyWith<$Res> { $Res call( {int id, String data, - @JsonKey(name: 'media_data') List mediaData, + @JsonKey(name: 'media_data') List? mediaData, @JsonKey(name: 'author_id') int authorId, @JsonKey(name: 'updated_at') String updatedAt}); } @@ -64,7 +64,7 @@ class _$ChatMessageModelCopyWithImpl<$Res, $Val extends ChatMessageModel> $Res call({ Object? id = null, Object? data = null, - Object? mediaData = null, + Object? mediaData = freezed, Object? authorId = null, Object? updatedAt = null, }) { @@ -77,10 +77,10 @@ class _$ChatMessageModelCopyWithImpl<$Res, $Val extends ChatMessageModel> ? _value.data : data // ignore: cast_nullable_to_non_nullable as String, - mediaData: null == mediaData + mediaData: freezed == mediaData ? _value.mediaData : mediaData // ignore: cast_nullable_to_non_nullable - as List, + as List?, authorId: null == authorId ? _value.authorId : authorId // ignore: cast_nullable_to_non_nullable @@ -104,7 +104,7 @@ abstract class _$$ChatMessageModelImplCopyWith<$Res> $Res call( {int id, String data, - @JsonKey(name: 'media_data') List mediaData, + @JsonKey(name: 'media_data') List? mediaData, @JsonKey(name: 'author_id') int authorId, @JsonKey(name: 'updated_at') String updatedAt}); } @@ -122,7 +122,7 @@ class __$$ChatMessageModelImplCopyWithImpl<$Res> $Res call({ Object? id = null, Object? data = null, - Object? mediaData = null, + Object? mediaData = freezed, Object? authorId = null, Object? updatedAt = null, }) { @@ -135,10 +135,10 @@ class __$$ChatMessageModelImplCopyWithImpl<$Res> ? _value.data : data // ignore: cast_nullable_to_non_nullable as String, - mediaData: null == mediaData + mediaData: freezed == mediaData ? _value._mediaData : mediaData // ignore: cast_nullable_to_non_nullable - as List, + as List?, authorId: null == authorId ? _value.authorId : authorId // ignore: cast_nullable_to_non_nullable @@ -157,7 +157,7 @@ class _$ChatMessageModelImpl implements _ChatMessageModel { const _$ChatMessageModelImpl( {required this.id, required this.data, - @JsonKey(name: 'media_data') required final List mediaData, + @JsonKey(name: 'media_data') required final List? mediaData, @JsonKey(name: 'author_id') required this.authorId, @JsonKey(name: 'updated_at') required this.updatedAt}) : _mediaData = mediaData; @@ -169,13 +169,15 @@ class _$ChatMessageModelImpl implements _ChatMessageModel { final int id; @override final String data; - final List _mediaData; + final List? _mediaData; @override @JsonKey(name: 'media_data') - List get mediaData { + List? get mediaData { + final value = _mediaData; + if (value == null) return null; if (_mediaData is EqualUnmodifiableListView) return _mediaData; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_mediaData); + return EqualUnmodifiableListView(value); } @override @@ -229,7 +231,7 @@ abstract class _ChatMessageModel implements ChatMessageModel { const factory _ChatMessageModel( {required final int id, required final String data, - @JsonKey(name: 'media_data') required final List mediaData, + @JsonKey(name: 'media_data') required final List? mediaData, @JsonKey(name: 'author_id') required final int authorId, @JsonKey(name: 'updated_at') required final String updatedAt}) = _$ChatMessageModelImpl; @@ -243,7 +245,7 @@ abstract class _ChatMessageModel implements ChatMessageModel { String get data; @override @JsonKey(name: 'media_data') - List get mediaData; + List? get mediaData; @override @JsonKey(name: 'author_id') int get authorId; diff --git a/lib/features/chat/models/chat_message_model.g.dart b/lib/features/chat/models/chat_message_model.g.dart index 8b28b74..3a8d182 100644 --- a/lib/features/chat/models/chat_message_model.g.dart +++ b/lib/features/chat/models/chat_message_model.g.dart @@ -11,7 +11,7 @@ _$ChatMessageModelImpl _$$ChatMessageModelImplFromJson( _$ChatMessageModelImpl( id: (json['id'] as num).toInt(), data: json['data'] as String, - mediaData: json['media_data'] as List, + mediaData: json['media_data'] as List?, authorId: (json['author_id'] as num).toInt(), updatedAt: json['updated_at'] as String, ); diff --git a/lib/features/chat/models/chat_messages_model.dart b/lib/features/chat/models/chat_messages_model.dart new file mode 100644 index 0000000..84a51b4 --- /dev/null +++ b/lib/features/chat/models/chat_messages_model.dart @@ -0,0 +1,17 @@ +import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; +import 'package:eatvio_app/features/chat/models/chat_meta_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_messages_model.freezed.dart'; + +part 'chat_messages_model.g.dart'; + +@freezed +class ChatMessagesModel with _$ChatMessagesModel { + const factory ChatMessagesModel({ + @JsonKey(name: 'data') required List messagesList, + required ChatMetaModel meta, + }) = _ChatMessagesModel; + + factory ChatMessagesModel.fromJson(Map json) => _$ChatMessagesModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_messages_model.freezed.dart b/lib/features/chat/models/chat_messages_model.freezed.dart new file mode 100644 index 0000000..a970241 --- /dev/null +++ b/lib/features/chat/models/chat_messages_model.freezed.dart @@ -0,0 +1,203 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'chat_messages_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ChatMessagesModel _$ChatMessagesModelFromJson(Map json) { + return _ChatMessagesModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatMessagesModel { + @JsonKey(name: 'data') + List get messagesList => throw _privateConstructorUsedError; + ChatMetaModel get meta => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatMessagesModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatMessagesModelCopyWith<$Res> { + factory $ChatMessagesModelCopyWith( + ChatMessagesModel value, $Res Function(ChatMessagesModel) then) = + _$ChatMessagesModelCopyWithImpl<$Res, ChatMessagesModel>; + @useResult + $Res call( + {@JsonKey(name: 'data') List messagesList, + ChatMetaModel meta}); + + $ChatMetaModelCopyWith<$Res> get meta; +} + +/// @nodoc +class _$ChatMessagesModelCopyWithImpl<$Res, $Val extends ChatMessagesModel> + implements $ChatMessagesModelCopyWith<$Res> { + _$ChatMessagesModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? messagesList = null, + Object? meta = null, + }) { + return _then(_value.copyWith( + messagesList: null == messagesList + ? _value.messagesList + : messagesList // ignore: cast_nullable_to_non_nullable + as List, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as ChatMetaModel, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ChatMetaModelCopyWith<$Res> get meta { + return $ChatMetaModelCopyWith<$Res>(_value.meta, (value) { + return _then(_value.copyWith(meta: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ChatMessagesModelImplCopyWith<$Res> + implements $ChatMessagesModelCopyWith<$Res> { + factory _$$ChatMessagesModelImplCopyWith(_$ChatMessagesModelImpl value, + $Res Function(_$ChatMessagesModelImpl) then) = + __$$ChatMessagesModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: 'data') List messagesList, + ChatMetaModel meta}); + + @override + $ChatMetaModelCopyWith<$Res> get meta; +} + +/// @nodoc +class __$$ChatMessagesModelImplCopyWithImpl<$Res> + extends _$ChatMessagesModelCopyWithImpl<$Res, _$ChatMessagesModelImpl> + implements _$$ChatMessagesModelImplCopyWith<$Res> { + __$$ChatMessagesModelImplCopyWithImpl(_$ChatMessagesModelImpl _value, + $Res Function(_$ChatMessagesModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? messagesList = null, + Object? meta = null, + }) { + return _then(_$ChatMessagesModelImpl( + messagesList: null == messagesList + ? _value._messagesList + : messagesList // ignore: cast_nullable_to_non_nullable + as List, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as ChatMetaModel, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatMessagesModelImpl implements _ChatMessagesModel { + const _$ChatMessagesModelImpl( + {@JsonKey(name: 'data') + required final List messagesList, + required this.meta}) + : _messagesList = messagesList; + + factory _$ChatMessagesModelImpl.fromJson(Map json) => + _$$ChatMessagesModelImplFromJson(json); + + final List _messagesList; + @override + @JsonKey(name: 'data') + List get messagesList { + if (_messagesList is EqualUnmodifiableListView) return _messagesList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_messagesList); + } + + @override + final ChatMetaModel meta; + + @override + String toString() { + return 'ChatMessagesModel(messagesList: $messagesList, meta: $meta)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatMessagesModelImpl && + const DeepCollectionEquality() + .equals(other._messagesList, _messagesList) && + (identical(other.meta, meta) || other.meta == meta)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_messagesList), meta); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatMessagesModelImplCopyWith<_$ChatMessagesModelImpl> get copyWith => + __$$ChatMessagesModelImplCopyWithImpl<_$ChatMessagesModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ChatMessagesModelImplToJson( + this, + ); + } +} + +abstract class _ChatMessagesModel implements ChatMessagesModel { + const factory _ChatMessagesModel( + {@JsonKey(name: 'data') + required final List messagesList, + required final ChatMetaModel meta}) = _$ChatMessagesModelImpl; + + factory _ChatMessagesModel.fromJson(Map json) = + _$ChatMessagesModelImpl.fromJson; + + @override + @JsonKey(name: 'data') + List get messagesList; + @override + ChatMetaModel get meta; + @override + @JsonKey(ignore: true) + _$$ChatMessagesModelImplCopyWith<_$ChatMessagesModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_messages_model.g.dart b/lib/features/chat/models/chat_messages_model.g.dart new file mode 100644 index 0000000..6216cd8 --- /dev/null +++ b/lib/features/chat/models/chat_messages_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_messages_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatMessagesModelImpl _$$ChatMessagesModelImplFromJson( + Map json) => + _$ChatMessagesModelImpl( + messagesList: (json['data'] as List) + .map((e) => ChatMessageModel.fromJson(e as Map)) + .toList(), + meta: ChatMetaModel.fromJson(json['meta'] as Map), + ); + +Map _$$ChatMessagesModelImplToJson( + _$ChatMessagesModelImpl instance) => + { + 'data': instance.messagesList, + 'meta': instance.meta, + }; diff --git a/lib/features/chat/models/chat_meta_model.dart b/lib/features/chat/models/chat_meta_model.dart new file mode 100644 index 0000000..b1e68a4 --- /dev/null +++ b/lib/features/chat/models/chat_meta_model.dart @@ -0,0 +1,13 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_meta_model.freezed.dart'; +part 'chat_meta_model.g.dart'; + +@freezed +class ChatMetaModel with _$ChatMetaModel { + const factory ChatMetaModel({ + @JsonKey(name: "last_page") required int lastPage, + }) = _ChatMetaModel; + + factory ChatMetaModel.fromJson(Map json) => _$ChatMetaModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_meta_model.freezed.dart b/lib/features/chat/models/chat_meta_model.freezed.dart new file mode 100644 index 0000000..11ecb9e --- /dev/null +++ b/lib/features/chat/models/chat_meta_model.freezed.dart @@ -0,0 +1,158 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'chat_meta_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ChatMetaModel _$ChatMetaModelFromJson(Map json) { + return _ChatMetaModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatMetaModel { + @JsonKey(name: "last_page") + int get lastPage => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatMetaModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatMetaModelCopyWith<$Res> { + factory $ChatMetaModelCopyWith( + ChatMetaModel value, $Res Function(ChatMetaModel) then) = + _$ChatMetaModelCopyWithImpl<$Res, ChatMetaModel>; + @useResult + $Res call({@JsonKey(name: "last_page") int lastPage}); +} + +/// @nodoc +class _$ChatMetaModelCopyWithImpl<$Res, $Val extends ChatMetaModel> + implements $ChatMetaModelCopyWith<$Res> { + _$ChatMetaModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? lastPage = null, + }) { + return _then(_value.copyWith( + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatMetaModelImplCopyWith<$Res> + implements $ChatMetaModelCopyWith<$Res> { + factory _$$ChatMetaModelImplCopyWith( + _$ChatMetaModelImpl value, $Res Function(_$ChatMetaModelImpl) then) = + __$$ChatMetaModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonKey(name: "last_page") int lastPage}); +} + +/// @nodoc +class __$$ChatMetaModelImplCopyWithImpl<$Res> + extends _$ChatMetaModelCopyWithImpl<$Res, _$ChatMetaModelImpl> + implements _$$ChatMetaModelImplCopyWith<$Res> { + __$$ChatMetaModelImplCopyWithImpl( + _$ChatMetaModelImpl _value, $Res Function(_$ChatMetaModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? lastPage = null, + }) { + return _then(_$ChatMetaModelImpl( + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatMetaModelImpl implements _ChatMetaModel { + const _$ChatMetaModelImpl( + {@JsonKey(name: "last_page") required this.lastPage}); + + factory _$ChatMetaModelImpl.fromJson(Map json) => + _$$ChatMetaModelImplFromJson(json); + + @override + @JsonKey(name: "last_page") + final int lastPage; + + @override + String toString() { + return 'ChatMetaModel(lastPage: $lastPage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatMetaModelImpl && + (identical(other.lastPage, lastPage) || + other.lastPage == lastPage)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, lastPage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatMetaModelImplCopyWith<_$ChatMetaModelImpl> get copyWith => + __$$ChatMetaModelImplCopyWithImpl<_$ChatMetaModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatMetaModelImplToJson( + this, + ); + } +} + +abstract class _ChatMetaModel implements ChatMetaModel { + const factory _ChatMetaModel( + {@JsonKey(name: "last_page") required final int lastPage}) = + _$ChatMetaModelImpl; + + factory _ChatMetaModel.fromJson(Map json) = + _$ChatMetaModelImpl.fromJson; + + @override + @JsonKey(name: "last_page") + int get lastPage; + @override + @JsonKey(ignore: true) + _$$ChatMetaModelImplCopyWith<_$ChatMetaModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_meta_model.g.dart b/lib/features/chat/models/chat_meta_model.g.dart new file mode 100644 index 0000000..7126e2d --- /dev/null +++ b/lib/features/chat/models/chat_meta_model.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_meta_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatMetaModelImpl _$$ChatMetaModelImplFromJson(Map json) => + _$ChatMetaModelImpl( + lastPage: (json['last_page'] as num).toInt(), + ); + +Map _$$ChatMetaModelImplToJson(_$ChatMetaModelImpl instance) => + { + 'last_page': instance.lastPage, + }; diff --git a/lib/features/chat/models/chat_room_model.dart b/lib/features/chat/models/chat_room_model.dart index 1fa5afe..f9e9a41 100644 --- a/lib/features/chat/models/chat_room_model.dart +++ b/lib/features/chat/models/chat_room_model.dart @@ -1,10 +1,8 @@ -import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart'; import 'package:eatvio_app/features/chat/models/chat_user_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'chat_room_model.freezed.dart'; - part 'chat_room_model.g.dart'; @freezed @@ -12,7 +10,6 @@ class ChatRoomModel with _$ChatRoomModel { const factory ChatRoomModel({ required String id, @JsonKey(name: 'chat_room_setting') required ChatRoomSettingsModel chatRoomSettings, - required List messages, required Map users, }) = _ChatRoomModel; diff --git a/lib/features/chat/models/chat_room_model.freezed.dart b/lib/features/chat/models/chat_room_model.freezed.dart index b8b4ce4..5a0b6e6 100644 --- a/lib/features/chat/models/chat_room_model.freezed.dart +++ b/lib/features/chat/models/chat_room_model.freezed.dart @@ -24,7 +24,6 @@ mixin _$ChatRoomModel { @JsonKey(name: 'chat_room_setting') ChatRoomSettingsModel get chatRoomSettings => throw _privateConstructorUsedError; - List get messages => throw _privateConstructorUsedError; Map get users => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -43,7 +42,6 @@ abstract class $ChatRoomModelCopyWith<$Res> { {String id, @JsonKey(name: 'chat_room_setting') ChatRoomSettingsModel chatRoomSettings, - List messages, Map users}); $ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings; @@ -64,7 +62,6 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel> $Res call({ Object? id = null, Object? chatRoomSettings = null, - Object? messages = null, Object? users = null, }) { return _then(_value.copyWith( @@ -76,10 +73,6 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel> ? _value.chatRoomSettings : chatRoomSettings // ignore: cast_nullable_to_non_nullable as ChatRoomSettingsModel, - messages: null == messages - ? _value.messages - : messages // ignore: cast_nullable_to_non_nullable - as List, users: null == users ? _value.users : users // ignore: cast_nullable_to_non_nullable @@ -109,7 +102,6 @@ abstract class _$$ChatRoomModelImplCopyWith<$Res> {String id, @JsonKey(name: 'chat_room_setting') ChatRoomSettingsModel chatRoomSettings, - List messages, Map users}); @override @@ -129,7 +121,6 @@ class __$$ChatRoomModelImplCopyWithImpl<$Res> $Res call({ Object? id = null, Object? chatRoomSettings = null, - Object? messages = null, Object? users = null, }) { return _then(_$ChatRoomModelImpl( @@ -141,10 +132,6 @@ class __$$ChatRoomModelImplCopyWithImpl<$Res> ? _value.chatRoomSettings : chatRoomSettings // ignore: cast_nullable_to_non_nullable as ChatRoomSettingsModel, - messages: null == messages - ? _value._messages - : messages // ignore: cast_nullable_to_non_nullable - as List, users: null == users ? _value._users : users // ignore: cast_nullable_to_non_nullable @@ -159,10 +146,8 @@ class _$ChatRoomModelImpl implements _ChatRoomModel { const _$ChatRoomModelImpl( {required this.id, @JsonKey(name: 'chat_room_setting') required this.chatRoomSettings, - required final List messages, required final Map users}) - : _messages = messages, - _users = users; + : _users = users; factory _$ChatRoomModelImpl.fromJson(Map json) => _$$ChatRoomModelImplFromJson(json); @@ -172,14 +157,6 @@ class _$ChatRoomModelImpl implements _ChatRoomModel { @override @JsonKey(name: 'chat_room_setting') final ChatRoomSettingsModel chatRoomSettings; - final List _messages; - @override - List get messages { - if (_messages is EqualUnmodifiableListView) return _messages; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_messages); - } - final Map _users; @override Map get users { @@ -190,7 +167,7 @@ class _$ChatRoomModelImpl implements _ChatRoomModel { @override String toString() { - return 'ChatRoomModel(id: $id, chatRoomSettings: $chatRoomSettings, messages: $messages, users: $users)'; + return 'ChatRoomModel(id: $id, chatRoomSettings: $chatRoomSettings, users: $users)'; } @override @@ -201,17 +178,12 @@ class _$ChatRoomModelImpl implements _ChatRoomModel { (identical(other.id, id) || other.id == id) && (identical(other.chatRoomSettings, chatRoomSettings) || other.chatRoomSettings == chatRoomSettings) && - const DeepCollectionEquality().equals(other._messages, _messages) && const DeepCollectionEquality().equals(other._users, _users)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash( - runtimeType, - id, - chatRoomSettings, - const DeepCollectionEquality().hash(_messages), + int get hashCode => Object.hash(runtimeType, id, chatRoomSettings, const DeepCollectionEquality().hash(_users)); @JsonKey(ignore: true) @@ -233,7 +205,6 @@ abstract class _ChatRoomModel implements ChatRoomModel { {required final String id, @JsonKey(name: 'chat_room_setting') required final ChatRoomSettingsModel chatRoomSettings, - required final List messages, required final Map users}) = _$ChatRoomModelImpl; factory _ChatRoomModel.fromJson(Map json) = @@ -245,8 +216,6 @@ abstract class _ChatRoomModel implements ChatRoomModel { @JsonKey(name: 'chat_room_setting') ChatRoomSettingsModel get chatRoomSettings; @override - List get messages; - @override Map get users; @override @JsonKey(ignore: true) diff --git a/lib/features/chat/models/chat_room_model.g.dart b/lib/features/chat/models/chat_room_model.g.dart index 4ab3867..68d3195 100644 --- a/lib/features/chat/models/chat_room_model.g.dart +++ b/lib/features/chat/models/chat_room_model.g.dart @@ -11,9 +11,6 @@ _$ChatRoomModelImpl _$$ChatRoomModelImplFromJson(Map json) => id: json['id'] as String, chatRoomSettings: ChatRoomSettingsModel.fromJson( json['chat_room_setting'] as Map), - messages: (json['messages'] as List) - .map((e) => ChatMessageModel.fromJson(e as Map)) - .toList(), users: (json['users'] as Map).map( (k, e) => MapEntry(k, ChatUserModel.fromJson(e as Map)), @@ -24,6 +21,5 @@ Map _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) => { 'id': instance.id, 'chat_room_setting': instance.chatRoomSettings, - 'messages': instance.messages, 'users': instance.users, }; diff --git a/lib/features/chat/models/chat_room_settings_model.dart b/lib/features/chat/models/chat_room_settings_model.dart index 7262c9a..de41f22 100644 --- a/lib/features/chat/models/chat_room_settings_model.dart +++ b/lib/features/chat/models/chat_room_settings_model.dart @@ -1,7 +1,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'chat_room_settings_model.freezed.dart'; - part 'chat_room_settings_model.g.dart'; @freezed diff --git a/lib/features/chat/models/chat_user_model.dart b/lib/features/chat/models/chat_user_model.dart index dd8bf02..4ead086 100644 --- a/lib/features/chat/models/chat_user_model.dart +++ b/lib/features/chat/models/chat_user_model.dart @@ -1,7 +1,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'chat_user_model.freezed.dart'; - part 'chat_user_model.g.dart'; @freezed @@ -9,10 +8,8 @@ class ChatUserModel with _$ChatUserModel { const factory ChatUserModel({ required int id, required String name, - @JsonKey(name: 'profile_photo_path') - String? profilePhotoPath, - @JsonKey(name: 'profile_photo_url') - String? profilePhotoUrl, + @JsonKey(name: 'profile_photo_path') String? profilePhotoPath, + @JsonKey(name: 'profile_photo_url') String? profilePhotoUrl, }) = _ChatUserModel; factory ChatUserModel.fromJson(Map json) => _$ChatUserModelFromJson(json); diff --git a/lib/features/chat/models/websocket_info_model.dart b/lib/features/chat/models/websocket_info_model.dart index 9fe8abc..ed6167a 100644 --- a/lib/features/chat/models/websocket_info_model.dart +++ b/lib/features/chat/models/websocket_info_model.dart @@ -1,12 +1,17 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'websocket_info_model.freezed.dart'; - part 'websocket_info_model.g.dart'; @freezed class WebsocketInfoModel with _$WebsocketInfoModel { - const factory WebsocketInfoModel() = _WebsocketInfoModel; + const factory WebsocketInfoModel({ + required String key, + required String host, + required String port, + required String cluster, + @JsonKey(name: 'user_id') required int userId, + }) = _WebsocketInfoModel; factory WebsocketInfoModel.fromJson(Map json) => _$WebsocketInfoModelFromJson(json); } diff --git a/lib/features/chat/models/websocket_info_model.freezed.dart b/lib/features/chat/models/websocket_info_model.freezed.dart index fd9ef4b..cd383a2 100644 --- a/lib/features/chat/models/websocket_info_model.freezed.dart +++ b/lib/features/chat/models/websocket_info_model.freezed.dart @@ -20,7 +20,17 @@ WebsocketInfoModel _$WebsocketInfoModelFromJson(Map json) { /// @nodoc mixin _$WebsocketInfoModel { + String get key => throw _privateConstructorUsedError; + String get host => throw _privateConstructorUsedError; + String get port => throw _privateConstructorUsedError; + String get cluster => throw _privateConstructorUsedError; + @JsonKey(name: 'user_id') + int get userId => throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WebsocketInfoModelCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc @@ -28,6 +38,13 @@ abstract class $WebsocketInfoModelCopyWith<$Res> { factory $WebsocketInfoModelCopyWith( WebsocketInfoModel value, $Res Function(WebsocketInfoModel) then) = _$WebsocketInfoModelCopyWithImpl<$Res, WebsocketInfoModel>; + @useResult + $Res call( + {String key, + String host, + String port, + String cluster, + @JsonKey(name: 'user_id') int userId}); } /// @nodoc @@ -39,13 +56,55 @@ class _$WebsocketInfoModelCopyWithImpl<$Res, $Val extends WebsocketInfoModel> final $Val _value; // ignore: unused_field final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? key = null, + Object? host = null, + Object? port = null, + Object? cluster = null, + Object? userId = null, + }) { + return _then(_value.copyWith( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + host: null == host + ? _value.host + : host // ignore: cast_nullable_to_non_nullable + as String, + port: null == port + ? _value.port + : port // ignore: cast_nullable_to_non_nullable + as String, + cluster: null == cluster + ? _value.cluster + : cluster // ignore: cast_nullable_to_non_nullable + as String, + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } } /// @nodoc -abstract class _$$WebsocketInfoModelImplCopyWith<$Res> { +abstract class _$$WebsocketInfoModelImplCopyWith<$Res> + implements $WebsocketInfoModelCopyWith<$Res> { factory _$$WebsocketInfoModelImplCopyWith(_$WebsocketInfoModelImpl value, $Res Function(_$WebsocketInfoModelImpl) then) = __$$WebsocketInfoModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String key, + String host, + String port, + String cluster, + @JsonKey(name: 'user_id') int userId}); } /// @nodoc @@ -55,30 +114,94 @@ class __$$WebsocketInfoModelImplCopyWithImpl<$Res> __$$WebsocketInfoModelImplCopyWithImpl(_$WebsocketInfoModelImpl _value, $Res Function(_$WebsocketInfoModelImpl) _then) : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? key = null, + Object? host = null, + Object? port = null, + Object? cluster = null, + Object? userId = null, + }) { + return _then(_$WebsocketInfoModelImpl( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + host: null == host + ? _value.host + : host // ignore: cast_nullable_to_non_nullable + as String, + port: null == port + ? _value.port + : port // ignore: cast_nullable_to_non_nullable + as String, + cluster: null == cluster + ? _value.cluster + : cluster // ignore: cast_nullable_to_non_nullable + as String, + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as int, + )); + } } /// @nodoc @JsonSerializable() class _$WebsocketInfoModelImpl implements _WebsocketInfoModel { - const _$WebsocketInfoModelImpl(); + const _$WebsocketInfoModelImpl( + {required this.key, + required this.host, + required this.port, + required this.cluster, + @JsonKey(name: 'user_id') required this.userId}); factory _$WebsocketInfoModelImpl.fromJson(Map json) => _$$WebsocketInfoModelImplFromJson(json); + @override + final String key; + @override + final String host; + @override + final String port; + @override + final String cluster; + @override + @JsonKey(name: 'user_id') + final int userId; + @override String toString() { - return 'WebsocketInfoModel()'; + return 'WebsocketInfoModel(key: $key, host: $host, port: $port, cluster: $cluster, userId: $userId)'; } @override bool operator ==(Object other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is _$WebsocketInfoModelImpl); + (other.runtimeType == runtimeType && + other is _$WebsocketInfoModelImpl && + (identical(other.key, key) || other.key == key) && + (identical(other.host, host) || other.host == host) && + (identical(other.port, port) || other.port == port) && + (identical(other.cluster, cluster) || other.cluster == cluster) && + (identical(other.userId, userId) || other.userId == userId)); } @JsonKey(ignore: true) @override - int get hashCode => runtimeType.hashCode; + int get hashCode => + Object.hash(runtimeType, key, host, port, cluster, userId); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$WebsocketInfoModelImplCopyWith<_$WebsocketInfoModelImpl> get copyWith => + __$$WebsocketInfoModelImplCopyWithImpl<_$WebsocketInfoModelImpl>( + this, _$identity); @override Map toJson() { @@ -89,8 +212,30 @@ class _$WebsocketInfoModelImpl implements _WebsocketInfoModel { } abstract class _WebsocketInfoModel implements WebsocketInfoModel { - const factory _WebsocketInfoModel() = _$WebsocketInfoModelImpl; + const factory _WebsocketInfoModel( + {required final String key, + required final String host, + required final String port, + required final String cluster, + @JsonKey(name: 'user_id') required final int userId}) = + _$WebsocketInfoModelImpl; factory _WebsocketInfoModel.fromJson(Map json) = _$WebsocketInfoModelImpl.fromJson; + + @override + String get key; + @override + String get host; + @override + String get port; + @override + String get cluster; + @override + @JsonKey(name: 'user_id') + int get userId; + @override + @JsonKey(ignore: true) + _$$WebsocketInfoModelImplCopyWith<_$WebsocketInfoModelImpl> get copyWith => + throw _privateConstructorUsedError; } diff --git a/lib/features/chat/models/websocket_info_model.g.dart b/lib/features/chat/models/websocket_info_model.g.dart index 6573c3c..b2bb124 100644 --- a/lib/features/chat/models/websocket_info_model.g.dart +++ b/lib/features/chat/models/websocket_info_model.g.dart @@ -8,8 +8,20 @@ part of 'websocket_info_model.dart'; _$WebsocketInfoModelImpl _$$WebsocketInfoModelImplFromJson( Map json) => - _$WebsocketInfoModelImpl(); + _$WebsocketInfoModelImpl( + key: json['key'] as String, + host: json['host'] as String, + port: json['port'] as String, + cluster: json['cluster'] as String, + userId: (json['user_id'] as num).toInt(), + ); Map _$$WebsocketInfoModelImplToJson( _$WebsocketInfoModelImpl instance) => - {}; + { + 'key': instance.key, + 'host': instance.host, + 'port': instance.port, + 'cluster': instance.cluster, + 'user_id': instance.userId, + }; diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart index f66069e..aaf9a4e 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart @@ -1,20 +1,152 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:dart_pusher_channels/dart_pusher_channels.dart'; +import 'package:easy_debounce/easy_debounce.dart'; +import 'package:eatvio_app/core/constants/constants.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; +import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class ChatRoomCubit extends Cubit { final ChatRepository chatRepository; + final InitializationCubit initializationCubit; + + int currentPage = 1; + late final int lastPage; + bool isLoading = false; + + late final PusherChannelsClient client; + late final PrivateChannel privateChatChannel; ChatRoomCubit({ required this.chatRepository, + required this.initializationCubit, }) : super(ChatRoomState.loading()); + loadNextPage(String chatId) async { + if (currentPage < lastPage && !isLoading) { + isLoading = true; + + emit(ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: (state as ChatRoomStateLoaded).chatMessages, + isTyping: (state as ChatRoomStateLoaded).isTyping, + isLoading: isLoading, + )); + + try { + final chatMessages = await chatRepository.getChatMessages(chatId, currentPage + 1); + + isLoading = false; + emit(ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: [...(state as ChatRoomStateLoaded).chatMessages, ...chatMessages.messagesList], + isTyping: (state as ChatRoomStateLoaded).isTyping, + isLoading: isLoading, + )); + + currentPage++; + } catch (e) { + print(e); + emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); + } + } + } + initChat(String chatId) async { try { - final chatRoomModel = await chatRepository.getChatRoom(chatId); - emit(ChatRoomState.loaded(chatRoomModel: chatRoomModel)); + final chatRoom = await chatRepository.getChatRoom(chatId); + + final chatMessages = await chatRepository.getChatMessages(chatId, currentPage); + lastPage = chatMessages.meta.lastPage; + + await subscribeToChatChannel(initCubit: initializationCubit, chatId: chatId); + + emit(ChatRoomState.loaded( + chatRoom: chatRoom, + chatMessages: chatMessages.messagesList, + isTyping: false, + isLoading: isLoading, + )); } catch (e) { + print(e); emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); } } + + Future subscribeToChatChannel({ + required InitializationCubit initCubit, + required String chatId, + }) async { + client = (initCubit.state as InitializationStateSuccess).client; + + privateChatChannel = await client.privateChannel( + 'private-direct-chat.$chatId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', + }, + ), + ); + + privateChatChannel.subscribe(); + + privateChatChannel.bind('App\\Events\\ChatMessageUpdated').listen((event) { + List messagesList = [ + ChatMessageModel.fromJson(jsonDecode(event.data)['message']), + ...(state as ChatRoomStateLoaded).chatMessages, + ]; + emit( + ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: messagesList, + isTyping: (state as ChatRoomStateLoaded).isTyping, + isLoading: isLoading, + ), + ); + }); + + privateChatChannel.bind('client-typing').listen((event) { + emit( + ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: (state as ChatRoomStateLoaded).chatMessages, + isTyping: true, + isLoading: isLoading, + ), + ); + EasyDebounce.debounce( + 'client-typing', + Duration(seconds: 3), + () => emit( + ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: (state as ChatRoomStateLoaded).chatMessages, + isTyping: false, + isLoading: isLoading, + ), + ), + ); + }); + } + + sendMessage({ + required String chatId, + required String data, + required List filesList, + }) async { + await chatRepository.sendMessage(chatId: chatId, data: data); + } + + @override + Future close() async { + privateChatChannel.unsubscribe(); + super.close(); + } } diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart index 89184a6..24113e6 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -10,7 +11,10 @@ abstract class ChatRoomState with _$ChatRoomState { const factory ChatRoomState.loading() = ChatRoomStateLoading; const factory ChatRoomState.loaded({ - required ChatRoomModel chatRoomModel, + required ChatRoomModel chatRoom, + required List chatMessages, + required bool isTyping, + required bool isLoading, }) = ChatRoomStateLoaded; const factory ChatRoomState.error({ diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart index 5bd9ae8..43bf9df 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart @@ -20,7 +20,9 @@ mixin _$ChatRoomState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading) + loaded, required TResult Function(String errorMessage) error, }) => throw _privateConstructorUsedError; @@ -28,7 +30,9 @@ mixin _$ChatRoomState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult? Function(String errorMessage)? error, }) => throw _privateConstructorUsedError; @@ -36,7 +40,9 @@ mixin _$ChatRoomState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) => @@ -126,7 +132,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading) + loaded, required TResult Function(String errorMessage) error, }) { return $default(); @@ -137,7 +145,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult? Function(String errorMessage)? error, }) { return $default?.call(); @@ -148,7 +158,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -241,7 +253,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading) + loaded, required TResult Function(String errorMessage) error, }) { return loading(); @@ -252,7 +266,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult? Function(String errorMessage)? error, }) { return loading?.call(); @@ -263,7 +279,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -321,9 +339,13 @@ abstract class _$$ChatRoomStateLoadedImplCopyWith<$Res> { $Res Function(_$ChatRoomStateLoadedImpl) then) = __$$ChatRoomStateLoadedImplCopyWithImpl<$Res>; @useResult - $Res call({ChatRoomModel chatRoomModel}); + $Res call( + {ChatRoomModel chatRoom, + List chatMessages, + bool isTyping, + bool isLoading}); - $ChatRoomModelCopyWith<$Res> get chatRoomModel; + $ChatRoomModelCopyWith<$Res> get chatRoom; } /// @nodoc @@ -337,21 +359,36 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? chatRoomModel = null, + Object? chatRoom = null, + Object? chatMessages = null, + Object? isTyping = null, + Object? isLoading = null, }) { return _then(_$ChatRoomStateLoadedImpl( - chatRoomModel: null == chatRoomModel - ? _value.chatRoomModel - : chatRoomModel // ignore: cast_nullable_to_non_nullable + chatRoom: null == chatRoom + ? _value.chatRoom + : chatRoom // ignore: cast_nullable_to_non_nullable as ChatRoomModel, + chatMessages: null == chatMessages + ? _value._chatMessages + : chatMessages // ignore: cast_nullable_to_non_nullable + as List, + isTyping: null == isTyping + ? _value.isTyping + : isTyping // ignore: cast_nullable_to_non_nullable + as bool, + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, )); } @override @pragma('vm:prefer-inline') - $ChatRoomModelCopyWith<$Res> get chatRoomModel { - return $ChatRoomModelCopyWith<$Res>(_value.chatRoomModel, (value) { - return _then(_value.copyWith(chatRoomModel: value)); + $ChatRoomModelCopyWith<$Res> get chatRoom { + return $ChatRoomModelCopyWith<$Res>(_value.chatRoom, (value) { + return _then(_value.copyWith(chatRoom: value)); }); } } @@ -359,14 +396,31 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res> /// @nodoc class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { - const _$ChatRoomStateLoadedImpl({required this.chatRoomModel}); + const _$ChatRoomStateLoadedImpl( + {required this.chatRoom, + required final List chatMessages, + required this.isTyping, + required this.isLoading}) + : _chatMessages = chatMessages; @override - final ChatRoomModel chatRoomModel; + final ChatRoomModel chatRoom; + final List _chatMessages; + @override + List get chatMessages { + if (_chatMessages is EqualUnmodifiableListView) return _chatMessages; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_chatMessages); + } + + @override + final bool isTyping; + @override + final bool isLoading; @override String toString() { - return 'ChatRoomState.loaded(chatRoomModel: $chatRoomModel)'; + return 'ChatRoomState.loaded(chatRoom: $chatRoom, chatMessages: $chatMessages, isTyping: $isTyping, isLoading: $isLoading)'; } @override @@ -374,12 +428,19 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ChatRoomStateLoadedImpl && - (identical(other.chatRoomModel, chatRoomModel) || - other.chatRoomModel == chatRoomModel)); + (identical(other.chatRoom, chatRoom) || + other.chatRoom == chatRoom) && + const DeepCollectionEquality() + .equals(other._chatMessages, _chatMessages) && + (identical(other.isTyping, isTyping) || + other.isTyping == isTyping) && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading)); } @override - int get hashCode => Object.hash(runtimeType, chatRoomModel); + int get hashCode => Object.hash(runtimeType, chatRoom, + const DeepCollectionEquality().hash(_chatMessages), isTyping, isLoading); @JsonKey(ignore: true) @override @@ -393,10 +454,12 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading) + loaded, required TResult Function(String errorMessage) error, }) { - return loaded(chatRoomModel); + return loaded(chatRoom, chatMessages, isTyping, isLoading); } @override @@ -404,10 +467,12 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult? Function(String errorMessage)? error, }) { - return loaded?.call(chatRoomModel); + return loaded?.call(chatRoom, chatMessages, isTyping, isLoading); } @override @@ -415,12 +480,14 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { if (loaded != null) { - return loaded(chatRoomModel); + return loaded(chatRoom, chatMessages, isTyping, isLoading); } return orElse(); } @@ -465,9 +532,15 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { abstract class ChatRoomStateLoaded implements ChatRoomState { const factory ChatRoomStateLoaded( - {required final ChatRoomModel chatRoomModel}) = _$ChatRoomStateLoadedImpl; + {required final ChatRoomModel chatRoom, + required final List chatMessages, + required final bool isTyping, + required final bool isLoading}) = _$ChatRoomStateLoadedImpl; - ChatRoomModel get chatRoomModel; + ChatRoomModel get chatRoom; + List get chatMessages; + bool get isTyping; + bool get isLoading; @JsonKey(ignore: true) _$$ChatRoomStateLoadedImplCopyWith<_$ChatRoomStateLoadedImpl> get copyWith => throw _privateConstructorUsedError; @@ -541,7 +614,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading) + loaded, required TResult Function(String errorMessage) error, }) { return error(errorMessage); @@ -552,7 +627,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult? Function(String errorMessage)? error, }) { return error?.call(errorMessage); @@ -563,7 +640,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(ChatRoomModel chatRoom, + List chatMessages, bool isTyping, bool isLoading)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index c6ad9be..e6822c5 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -1,12 +1,13 @@ +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget.dart'; import 'package:eatvio_app/locator_service.dart'; import 'package:flutter/cupertino.dart'; -import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; +import 'package:lazy_load_scrollview/lazy_load_scrollview.dart'; -class ChatScreen extends StatelessWidget { +class ChatScreen extends StatefulWidget { final String chatId; const ChatScreen({ @@ -14,21 +15,28 @@ class ChatScreen extends StatelessWidget { super.key, }); + @override + State createState() => _ChatScreenState(); +} + +class _ChatScreenState extends State { + final scrollController = ScrollController(); + final TextEditingController textEditingController = TextEditingController(); + Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => sl()..initChat(chatId), + create: (BuildContext context) => sl()..initChat(widget.chatId), child: BlocBuilder( builder: (context, state) { - if (state is ChatRoomStateLoading) { - return Scaffold( - body: Center( - child: CupertinoActivityIndicator(), - ), - ); - } else if (state is ChatRoomStateLoaded) { + if (state is ChatRoomStateLoaded) { return _buildChat(context, state); } else if (state is ChatRoomStateError) { - return Center(child: Text(state.errorMessage)); + return Scaffold( + appBar: AppBar(), + body: Center( + child: Text(state.errorMessage), + ), + ); } else { return Scaffold( body: Center( @@ -42,16 +50,11 @@ class ChatScreen extends StatelessWidget { } _buildChat(BuildContext context, ChatRoomStateLoaded state) { - mediaQueryData = MediaQuery.of(context); return Scaffold( resizeToAvoidBottomInset: true, - backgroundColor: PrimaryColors().gray50, appBar: AppBar( titleSpacing: 0, centerTitle: false, - backgroundColor: Colors.white, - forceMaterialTransparency: true, - elevation: 0, title: Row( children: [ Container( @@ -63,7 +66,7 @@ class ChatScreen extends StatelessWidget { shape: BoxShape.circle, ), child: Text( - state.chatRoomModel.users['to_chat_user']!.name.split(' ').first[0] + state.chatRoomModel.users['to_chat_user']!.name.split(' ')[1][0], + state.chatRoom.users['to_chat_user']!.name.split(' ').first[0] + state.chatRoom.users['to_chat_user']!.name.split(' ')[1][0], style: TextStyle( color: Color(0xFF7F9CF5), fontWeight: FontWeight.w400, @@ -72,129 +75,172 @@ class ChatScreen extends StatelessWidget { ), ), SizedBox(width: 16), - Text( - state.chatRoomModel.users['to_chat_user']!.name, - style: CustomTextStyles.titleSmallBold.copyWith( - color: PrimaryColors().blueGray800, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + state.chatRoom.users['to_chat_user']!.name, + style: CustomTextStyles.titleSmallBold.copyWith( + color: PrimaryColors().blueGray800, + ), + ), + AnimatedCrossFade( + firstChild: Text( + 'Печатает...', + style: CustomTextStyles.bodySmallMulishPrimary, + ), + firstCurve: Curves.easeIn, + secondCurve: Curves.easeOut, + secondChild: const SizedBox.shrink(), + crossFadeState: state.isTyping ? CrossFadeState.showFirst : CrossFadeState.showSecond, + duration: Duration(milliseconds: 150), + ), + ], + ), + ], + ), + ), + body: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Container( + color: Color(0xFFF0F2F5), + width: double.maxFinite, + child: LazyLoadScrollView( + onEndOfPage: () => context.read().loadNextPage(widget.chatId), + isLoading: state.isLoading, + scrollOffset: MediaQuery.of(context).size.height.toInt(), + child: CustomScrollView( + physics: BouncingScrollPhysics(), + controller: scrollController, + reverse: true, + slivers: [ + SliverPadding( + padding: EdgeInsets.symmetric(vertical: 16), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index < state.chatMessages.length) { + return ChatBubbleWidget( + text: state.chatMessages[index].data.trim(), + isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId, + mediaData: state.chatMessages[index].mediaData ?? [], + ); + } else { + return Padding( + padding: const EdgeInsets.all(8), + child: Center(child: CupertinoActivityIndicator()), + ); + } + }, + childCount: state.chatMessages.length + (state.isLoading ? 1 : 0), + ), + ), + ), + ], + ), + ), + ), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: 8), + InkWell( + onTap: () {}, + borderRadius: BorderRadius.circular(16), + child: Ink( + height: 32, + width: 32, + child: Icon( + Icons.attach_file_rounded, + size: 28, + color: Color(0xFF858E99), + ), + ), + ), + SizedBox(width: 8), + SizedBox( + width: mediaQueryData.size.width - 96, + child: TextFormField( + controller: textEditingController, + maxLines: 5, + minLines: 1, + keyboardType: TextInputType.multiline, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), + hintText: 'Сообщение', + hintStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Color(0xFFAEAEB2), + ), + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + ), + ), + ), + SizedBox(width: 8), + InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () { + if (textEditingController.text.isNotEmpty) { + context.read().sendMessage( + chatId: widget.chatId, + data: textEditingController.text.trim(), + filesList: [], + ); + setState(() { + textEditingController.clear(); + }); + } + }, + child: Ink( + height: 32, + width: 32, + child: Icon( + Icons.send_outlined, + size: 28, + color: Color(0xFF858E99), + ), + ), + ), + SizedBox(width: 8), + ], ), ), ], ), ), - body: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: Container( - color: Color(0xFFF0F2F5), - width: double.maxFinite, - child: CustomScrollView( - reverse: true, - slivers: [ - SliverPadding( - padding: EdgeInsets.symmetric(vertical: 16), - sliver: SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) => ChatBubbleWidget( - text: state.chatRoomModel.messages[state.chatRoomModel.messages.length - index - 1].data, - isCurrentUser: state.chatRoomModel.users['to_chat_user']!.id != - state.chatRoomModel.messages[state.chatRoomModel.messages.length - index - 1].authorId, - mediaData: state.chatRoomModel.messages[state.chatRoomModel.messages.length - index - 1].mediaData, - ), - childCount: state.chatRoomModel.messages.length, - ), - ), - ), - ], - ), - ), - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(width: 8), - InkWell( - onTap: () {}, - borderRadius: BorderRadiusStyle.circleBorder17, - child: Ink( - height: 32, - width: 32, - child: Icon( - Icons.attach_file_rounded, - size: 28, - color: Color(0xFF858E99), - ), - ), - ), - SizedBox(width: 8), - SizedBox( - width: mediaQueryData.size.width - 96, - child: TextFormField( - maxLines: 5, - minLines: 1, - keyboardType: TextInputType.multiline, - style: TextStyle( - fontSize: 16, - fontFamily: 'Mulish', - fontWeight: FontWeight.w400, - color: Colors.black, - ), - decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), - hintText: 'Сообщение', - hintStyle: TextStyle( - fontSize: 16, - fontFamily: 'Mulish', - fontWeight: FontWeight.w400, - color: Color(0xFFAEAEB2), - ), - filled: true, - border: OutlineInputBorder( - borderRadius: BorderRadiusStyle.circleBorder17, - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadiusStyle.circleBorder17, - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadiusStyle.circleBorder17, - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - ), - ), - ), - SizedBox(width: 8), - InkWell( - borderRadius: BorderRadiusStyle.circleBorder17, - onTap: () {}, - child: Ink( - height: 32, - width: 32, - child: Icon( - Icons.send_outlined, - size: 28, - color: Color(0xFF858E99), - ), - ), - ), - SizedBox(width: 8), - ], - ), - ), - ], - ), ); } } diff --git a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart index ba44ade..0985a2f 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart @@ -1,16 +1,17 @@ +import 'dart:convert'; + import 'package:eatvio_app/app_router.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:go_router/go_router.dart'; part 'chat_select_event.dart'; part 'chat_select_state.dart'; @@ -26,18 +27,24 @@ class ChatSelectBloc extends Bloc { List fillChatEntryList(List chatRooms) { List chats = []; for (int i = 0; i < chatRooms.length; i++) { - String text = chatRooms[i]['last_message']['data']; - if (chatRooms[i]['last_message']['is_author_from_user']) { + String text = chatRooms[i]['last_message'] is List ? '' : chatRooms[i]['last_message']['data']; + if (chatRooms[i]['last_message'] is! List && chatRooms[i]['last_message']['is_author_message_auth_user'] != null) { text = "Вы: " + text; } - chats.add(ChatItemModel( + chats.add( + ChatItemModel( id: chatRooms[i]['id'], - userImage: chatRooms[i]['users']['to_chat_user'] - ['profile_photo_path'], username: chatRooms[i]['users']['to_chat_user']['name'], - dateText: DateFormat('dd.MM').format( - DateTime.parse(chatRooms[i]['last_message']['updated_at'])), - greetingText: text)); + dateText: chatRooms[i]['last_message'] is List + ? '' + : DateFormat('dd.MM').format( + DateTime.parse( + chatRooms[i]['last_message']['updated_at'], + ), + ), + greetingText: text, + ), + ); } return chats; } @@ -53,7 +60,7 @@ class ChatSelectBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/chat/index'), + Uri.parse(baseUrl + '/api/chat/index'), headers: { 'Authorization': 'Bearer $token', }, @@ -63,20 +70,23 @@ class ChatSelectBloc extends Bloc { if (data is Map && data.containsKey('chatRooms')) { if (state is ChatSelectLoadedState) { var currentState = state as ChatSelectLoadedState; - emit(currentState.copyWith( - chatSelectModelObj: currentState.chatSelectModelObj, - chatRooms: currentState.chatRooms, - )); + emit( + currentState.copyWith( + chatSelectModelObj: currentState.chatSelectModelObj, + chatRooms: currentState.chatRooms, + ), + ); } else { - emit(ChatSelectLoadedState( - chatRooms: fillChatEntryList(data['chatRooms']), - //chatRooms: [], - )); + emit( + ChatSelectLoadedState( + chatRooms: fillChatEntryList(data['chatRooms']), + //chatRooms: [], + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку - emit(ChatSelectErrorState( - 'Некоторые необходимые данные отсутствуют.')); + emit(ChatSelectErrorState('Некоторые необходимые данные отсутствуют.')); } } else { // Статус ответа не равен 200, обрабатываем ошибку diff --git a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart index e5f1262..9484c0f 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart @@ -12,6 +12,7 @@ class ChatSelectState extends Equatable { @override List get props => [chatSelectModelObj]; + ChatSelectState copyWith({ChatSelectModel? chatSelectModelObj}) { return ChatSelectState( chatSelectModelObj: chatSelectModelObj ?? this.chatSelectModelObj, @@ -20,8 +21,7 @@ class ChatSelectState extends Equatable { } class ChatSelectInitialState extends ChatSelectState { - ChatSelectInitialState({required ChatSelectModel chatSelectModelObj}) - : super(chatSelectModelObj: chatSelectModelObj); + ChatSelectInitialState({required ChatSelectModel chatSelectModelObj}) : super(chatSelectModelObj: chatSelectModelObj); } class ChatSelectLoadedState extends ChatSelectState { @@ -30,11 +30,14 @@ class ChatSelectLoadedState extends ChatSelectState { this.searchController, this.chatSelectModelObj, }) : super(chatSelectModelObj: null); + List? chatRooms; TextEditingController? searchController; ChatSelectModel? chatSelectModelObj; + @override List get props => [chatSelectModelObj, chatRooms, searchController]; + ChatSelectLoadedState copyWith({ ChatSelectModel? chatSelectModelObj, TextEditingController? searchController, diff --git a/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart index 939bb42..15f6c44 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart @@ -1,33 +1,31 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class CustomSearchView extends StatelessWidget { - CustomSearchView( - {Key? key, - this.alignment, - this.width, - this.scrollPadding, - this.controller, - this.focusNode, - this.autofocus = false, - this.textStyle, - this.textInputType = TextInputType.text, - this.maxLines, - this.hintText, - this.hintStyle, - this.prefix, - this.prefixConstraints, - this.suffix, - this.suffixConstraints, - this.contentPadding, - this.borderDecoration, - this.fillColor, - this.filled = true, - this.validator, - this.onChanged}) - : super( - key: key, - ); + CustomSearchView({ + Key? key, + this.alignment, + this.width, + this.scrollPadding, + this.controller, + this.focusNode, + this.autofocus = false, + this.textStyle, + this.textInputType = TextInputType.text, + this.maxLines, + this.hintText, + this.hintStyle, + this.prefix, + this.prefixConstraints, + this.suffix, + this.suffixConstraints, + this.contentPadding, + this.borderDecoration, + this.fillColor, + this.filled = true, + this.validator, + this.onChanged, + }) : super(key: key); final Alignment? alignment; @@ -73,13 +71,12 @@ class CustomSearchView extends StatelessWidget { @override Widget build(BuildContext context) { - return alignment != null ? Align(alignment: alignment ?? Alignment.center, child: searchViewWidget(context)) : searchViewWidget(context); + return searchViewWidget(context); } searchViewWidget(BuildContext context) => SizedBox( width: width ?? double.maxFinite, child: TextFormField( - scrollPadding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), controller: controller, focusNode: focusNode, onTapOutside: (event) => onTapOutside(), @@ -106,7 +103,7 @@ class CustomSearchView extends StatelessWidget { hintStyle: hintStyle ?? CustomTextStyles.bodySmallMulishBluegray800, prefixIcon: prefix ?? Padding( - padding: EdgeInsets.only(left: 10), + padding: EdgeInsets.only(left: 12), child: Icon( Icons.search, color: Color(0xFF7B8794), @@ -130,17 +127,17 @@ class CustomSearchView extends StatelessWidget { filled: filled, border: borderDecoration ?? OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), + borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ), enabledBorder: borderDecoration ?? OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), + borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ), focusedBorder: borderDecoration ?? OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), + borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ), ); diff --git a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart index fe468f3..9fea543 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart @@ -1,25 +1,19 @@ +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'bloc/chat_select_bloc.dart'; -import 'models/chat_select_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; import 'chat_search_view.dart'; -import 'package:flutter/material.dart'; +import 'models/chat_select_model.dart'; class ChatSelectScreen extends StatelessWidget { const ChatSelectScreen({Key? key}) : super(key: key); static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => ChatSelectBloc( - ChatSelectState( - chatSelectModelObj: ChatSelectModel(), - ), - )..add( - ChatSelectInitialEvent(), - ), + create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), child: ChatSelectScreen(), ); } @@ -37,24 +31,29 @@ class ChatSelectScreen extends StatelessWidget { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, - forceMaterialTransparency: true, toolbarHeight: 0, ), body: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ - SliverAppBar( - backgroundColor: Colors.white, - stretchTriggerOffset: 1, - forceMaterialTransparency: true, - floating: true, - snap: true, - title: CustomSearchView( - controller: state.searchController, - fillColor: Color(0xFFF0F2F5), - hintText: "Поиск", - hintStyle: TextStyle( - color: Color(0xFF7B8794), + SliverPadding( + padding: const EdgeInsets.only(top: 8), + sliver: SliverAppBar( + automaticallyImplyLeading: false, + stretchTriggerOffset: 1, + scrolledUnderElevation: 0, + floating: true, + snap: true, + title: Padding( + padding: const EdgeInsets.only(top: 8), + child: CustomSearchView( + controller: state.searchController, + fillColor: Color(0xFFF0F2F5), + hintText: "Поиск", + hintStyle: TextStyle( + color: Color(0xFF7B8794), + ), + ), ), ), ), @@ -64,7 +63,10 @@ class ChatSelectScreen extends StatelessWidget { ), ); } else if (state is ChatSelectErrorState) { - return Center(child: Text(state.errorMessage)); + return Padding( + padding: const EdgeInsets.all(16), + child: Center(child: Text(state.errorMessage)), + ); } else { return Scaffold( body: Center( @@ -84,7 +86,7 @@ _buildChatList(BuildContext context, ChatSelectLoadedState state) { physics: NeverScrollableScrollPhysics(), separatorBuilder: (context, index) { return SizedBox( - height: 10.v, + height: 8, ); }, itemCount: state.chatRooms?.length ?? 0, diff --git a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart index 6738afb..cffee89 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart @@ -4,26 +4,23 @@ import 'package:eatvio_app/core/app_export.dart'; // ignore_for_file: must_be_immutable class ChatItemModel { - ChatItemModel( - {this.userImage, - this.username, - this.dateText, - this.greetingText, - required this.id}) { + String? userImage; + String? username; + String? dateText; + String? greetingText; + String id; + + ChatItemModel({ + this.userImage, + this.username, + this.dateText, + this.greetingText, + required this.id, + }) { userImage = userImage ?? ImageConstant.imageNotFound; username = username; dateText = dateText; greetingText = greetingText; id = id; } - - String? userImage; - - String? username; - - String? dateText; - - String? greetingText; - - String id; } diff --git a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart index c95b52e..e87ffa2 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart @@ -5,9 +5,12 @@ import 'package:equatable/equatable.dart'; /// This class defines the variables used in the [chat_select_screen], /// and is typically used to hold data that is passed between different parts of the application. + class ChatSelectModel extends Equatable { ChatSelectModel({this.chatList = const []}); + List chatList; + ChatSelectModel copyWith({List? chatList}) { return ChatSelectModel( chatList: chatList ?? this.chatList, diff --git a/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart index fbd6b1b..03c8371 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart @@ -1,8 +1,8 @@ // ignore_for_file: must_be_immutable +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; import 'package:flutter/material.dart'; -import 'package:eatvio_app/core/app_export.dart'; import 'package:go_router/go_router.dart'; class ChatEntryWidget extends StatelessWidget { @@ -15,15 +15,16 @@ class ChatEntryWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () => GoRouter.of(context).goNamed( + return InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => GoRouter.of(context).pushNamed( 'chatScreen', extra: chatEntryObj.id.toString(), ), - child: Container( + child: Ink( padding: EdgeInsets.all(16), decoration: BoxDecoration( - borderRadius: BorderRadiusStyle.circleBorder8, + borderRadius: BorderRadius.circular(16), color: Color(0xFFF6FAFF), ), child: Row( @@ -47,7 +48,7 @@ class ChatEntryWidget extends StatelessWidget { ), ), ), - SizedBox(width: 8), + SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -74,17 +75,17 @@ class ChatEntryWidget extends StatelessWidget { chatEntryObj.dateText!, style: theme.textTheme.bodyMedium, ), - ) + ), ], ), SizedBox(height: 6.v), Text( - chatEntryObj.greetingText!, + chatEntryObj.greetingText!.trim(), style: CustomTextStyles.bodyMediumBluegray800, ), ], ), - ) + ), ], ), ), diff --git a/lib/features/chat/presentation/pages/photo_view_screen.dart b/lib/features/chat/presentation/pages/photo_view_screen.dart index 229ced5..a070103 100644 --- a/lib/features/chat/presentation/pages/photo_view_screen.dart +++ b/lib/features/chat/presentation/pages/photo_view_screen.dart @@ -1,7 +1,7 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dismissible_page/dismissible_page.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view_gallery.dart'; @@ -34,37 +34,32 @@ class _PhotoViewScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.black, - appBar: AppBar( - centerTitle: true, - systemOverlayStyle: SystemUiOverlayStyle( - statusBarColor: Colors.black, - statusBarBrightness: Brightness.dark, - statusBarIconBrightness: Brightness.light, + return DismissiblePage( + minScale: 1, + onDismissed: () => GoRouter.of(context).pop(), + direction: DismissiblePageDismissDirection.vertical, + isFullScreen: true, + child: PhotoViewGallery.builder( + backgroundDecoration: BoxDecoration( + color: Colors.transparent, ), - backgroundColor: Colors.black, - foregroundColor: Colors.white, - title: Text( - (imageIndex + 1).toString() + ' из ' + widget.imageUrls.length.toString(), - ), - ), - body: Dismissible( - direction: DismissDirection.vertical, - key: const Key('key'), - onDismissed: (_) => GoRouter.of(context).pop(), - resizeDuration: Duration(microseconds: 1), - child: Container( - child: PhotoViewGallery.builder( - scrollPhysics: const BouncingScrollPhysics(), - builder: (BuildContext context, int index) { - return PhotoViewGalleryPageOptions( - imageProvider: NetworkImage(widget.imageUrls[index]), - initialScale: PhotoViewComputedScale.contained, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes(tag: widget.imageUrls[index]), - errorBuilder: (context, object, stackTrace) { - return Column( + scrollPhysics: const BouncingScrollPhysics(), + builder: (BuildContext context, int index) { + return PhotoViewGalleryPageOptions( + imageProvider: CachedNetworkImageProvider( + widget.imageUrls[index], + ), + initialScale: PhotoViewComputedScale.contained, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.imageUrls[index], + transitionOnUserGestures: true, + ), + errorBuilder: (context, object, stackTrace) { + return Scaffold( + backgroundColor: Colors.black, + body: SafeArea( + child: Column( children: [ SizedBox(height: 32), Text('Файл'), @@ -88,7 +83,7 @@ class _PhotoViewScreenState extends State { color: Colors.white, ), title: Text( - widget.imageUrls[index].replaceAll(dotenv.env['STORAGE_URL']! + 'chat_files/', ''), + widget.imageUrls[index].replaceAll(baseUrl + '/storage/' + 'chat_files/', ''), style: TextStyle( color: Colors.white, fontSize: 12, @@ -96,28 +91,28 @@ class _PhotoViewScreenState extends State { ), ), ], - ); - }, + ), + ), ); }, - itemCount: widget.imageUrls.length, - loadingBuilder: (context, event) => Center( - child: Container( - width: 20.0, - height: 20.0, - child: CircularProgressIndicator( - value: event == null ? 0 : event.cumulativeBytesLoaded / event.expectedTotalBytes!, - ), - ), + ); + }, + itemCount: widget.imageUrls.length, + loadingBuilder: (context, event) => Center( + child: Container( + width: 20.0, + height: 20.0, + child: CircularProgressIndicator( + value: event == null ? 0 : event.cumulativeBytesLoaded / event.expectedTotalBytes!, ), - pageController: pageController, - onPageChanged: (page) { - setState(() { - imageIndex = page; - }); - }, ), ), + pageController: pageController, + onPageChanged: (page) { + setState(() { + imageIndex = page; + }); + }, ), ); } diff --git a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart index 127795c..555aa23 100644 --- a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart +++ b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart @@ -1,8 +1,9 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dismissible_page/dismissible_page.dart'; +import 'package:eatvio_app/core/constants/constants.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:eatvio_app/theme/app_decoration.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:go_router/go_router.dart'; import 'package:url_launcher/url_launcher.dart'; class ChatBubbleWidget extends StatelessWidget { @@ -10,12 +11,12 @@ class ChatBubbleWidget extends StatelessWidget { super.key, required this.text, required this.isCurrentUser, - this.mediaData, + required this.mediaData, }); final String text; final bool isCurrentUser; - final List? mediaData; + final List mediaData; @override Widget build(BuildContext context) { @@ -25,29 +26,30 @@ class ChatBubbleWidget extends StatelessWidget { alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, child: DecoratedBox( decoration: BoxDecoration( - color: isCurrentUser ? Color(0xFFF6FAFF) : Colors.white, + color: isCurrentUser ? Color(0xFF7F9CF5) : Colors.white, borderRadius: BorderRadiusStyle.circleBorder17, ), child: Padding( padding: const EdgeInsets.all(12), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (mediaData != null) + if (mediaData.isNotEmpty) CustomScrollView( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), slivers: [ SliverList.separated( itemBuilder: (BuildContext context, int index) { - if (!mediaData![index].toString().contains('.png') && - !mediaData![index].toString().contains('.jpg') && - !mediaData![index].toString().contains('.jpeg')) { + if (!mediaData[index].toString().contains('.png') && + !mediaData[index].toString().contains('.jpg') && + !mediaData[index].toString().contains('.jpeg')) { return ListTile( contentPadding: EdgeInsets.zero, horizontalTitleGap: 8, onTap: () async { - if (!await launchUrl(Uri.parse(dotenv.env['STORAGE_URL']! + mediaData![index].toString()))) { - throw Exception('Could not launch ${mediaData![index].toString()}'); + if (!await launchUrl(Uri.parse(baseUrl + '/storage/' + mediaData[index].toString()))) { + throw Exception('Could not launch ${mediaData[index].toString()}'); } }, leading: Icon( @@ -59,7 +61,7 @@ class ChatBubbleWidget extends StatelessWidget { color: Color(0xFF2F80ED), ), title: Text( - mediaData![index].toString().replaceAll('chat_files/', ''), + mediaData[index].toString().replaceAll('chat_files/', ''), maxLines: 2, style: TextStyle( color: Color(0xFF323F4B), @@ -71,33 +73,36 @@ class ChatBubbleWidget extends StatelessWidget { } return GestureDetector( onTap: () { - GoRouter.of(context).pushNamed( - 'photoViewScreen', - extra: mediaData!.map((e) => dotenv.env['STORAGE_URL']! + e.toString()).toList(), - pathParameters: { - 'index': index.toString(), - }, + context.pushTransparentRoute( + PhotoViewScreen( + imageUrls: mediaData.map((e) => baseUrl + '/storage/' + e.toString()).toList(), + index: index, + ), ); }, - child: ClipRRect( - borderRadius: BorderRadiusStyle.roundedBorder8, - child: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + '${mediaData![index]}', + child: Hero( + tag: baseUrl + '/storage/' + '${mediaData[index]}', + transitionOnUserGestures: true, + child: ClipRRect( + borderRadius: BorderRadiusStyle.roundedBorder8, + child: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + '${mediaData[index]}', + ), ), ), ); }, separatorBuilder: (BuildContext context, int index) => const SizedBox(height: 8), - itemCount: mediaData!.length, + itemCount: mediaData.length, ), ], ), - if (mediaData!.length > 0 && text.isNotEmpty) SizedBox(height: 8), + if (mediaData.length > 0 && text.isNotEmpty) SizedBox(height: 8), if (text.isNotEmpty) Text( text, style: TextStyle( - color: Color(0xFF323F4B), + color: isCurrentUser ? Colors.white : Color(0xFF323F4B), ), ), ], diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart index 137aa87..c35847f 100644 --- a/lib/features/chat/repositories/chat_repository.dart +++ b/lib/features/chat/repositories/chat_repository.dart @@ -1,3 +1,6 @@ +import 'dart:io'; + +import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; @@ -9,23 +12,47 @@ class ChatRepository { required this.chatService, }); - /// TODO use "dartz" package because need Either for error handling - Future getChatRoom(String chatId) async { + Future sendMessage({ + required String chatId, + String? data, + List? filesList, + }) async { try { - return (await chatService.getChatRoomModel(chatId))['chatRoom']!; + await chatService.sendMessage( + id: chatId, + data: data, + filesList: filesList, + ); } catch (e) { print(e); - throw (e); + rethrow; + } + } + + Future getChatRoom(String chatId) async { + try { + return (await chatService.getChatRoom(id: chatId))['chatRoom']!; + } catch (e) { + print(e); + rethrow; + } + } + + Future getChatMessages(String chatId, int page) async { + try { + return (await chatService.getChatMessages(id: chatId, page: page)); + } catch (e) { + print(e); + rethrow; } } - /// TODO use "dartz" package because need Either for error handling Future getWebsocket() async { try { return (await chatService.getWebsocket()); } catch (e) { print(e); - throw (e); + rethrow; } } } diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart index 5b27ccf..888aaba 100644 --- a/lib/features/chat/services/chat_service.dart +++ b/lib/features/chat/services/chat_service.dart @@ -1,5 +1,8 @@ -import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; +import 'dart:io'; + import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; +import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; import 'package:retrofit/retrofit.dart'; @@ -9,9 +12,24 @@ part 'chat_service.g.dart'; abstract class ChatService { factory ChatService(Dio dio, {String baseUrl}) = _ChatService; - @GET('/chat/show/{id}') - Future> getChatRoomModel(@Path() String id); + @GET('/api/chat/show/{id}') + Future> getChatRoom({ + @Path() required String id, + }); - @GET('/profile/ws/params') + @POST('/api/chat/{id}/message/send') + Future sendMessage({ + @Path() required String id, + @Part() String? data, + @Part() List? filesList, + }); + + @GET('/api/chat/show/{id}/messages?page={page}') + Future getChatMessages({ + @Path() required String id, + @Path() required int page, + }); + + @GET('/api/profile/ws/params') Future getWebsocket(); } diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart index db9fdea..2f0674b 100644 --- a/lib/features/chat/services/chat_service.g.dart +++ b/lib/features/chat/services/chat_service.g.dart @@ -6,7 +6,7 @@ part of 'chat_service.dart'; // RetrofitGenerator // ************************************************************************** -// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element class _ChatService implements ChatService { _ChatService( @@ -19,7 +19,7 @@ class _ChatService implements ChatService { String? baseUrl; @override - Future> getChatRoomModel(String id) async { + Future> getChatRoom({required String id}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; @@ -32,7 +32,7 @@ class _ChatService implements ChatService { ) .compose( _dio.options, - '/chat/show/${id}', + '/api/chat/show/${id}', queryParameters: queryParameters, data: _data, ) @@ -41,9 +41,82 @@ class _ChatService implements ChatService { _dio.options.baseUrl, baseUrl, )))); - var value = _result.data!.map((k, dynamic v) => + var _value = _result.data!.map((k, dynamic v) => MapEntry(k, ChatRoomModel.fromJson(v as Map))); - return value; + return _value; + } + + @override + Future sendMessage({ + required String id, + String? data, + List? filesList, + }) async { + final _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + if (data != null) { + _data.fields.add(MapEntry( + 'data', + data, + )); + } + if (filesList != null) { + _data.files.addAll(filesList.map((i) => MapEntry( + 'filesList', + MultipartFile.fromFileSync( + i.path, + filename: i.path.split(Platform.pathSeparator).last, + )))); + } + await _dio.fetch(_setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/${id}/message/send', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + } + + @override + Future getChatMessages({ + required String id, + required int page, + }) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/show/${id}/messages?page=${page}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = ChatMessagesModel.fromJson(_result.data!); + return _value; } @override @@ -60,7 +133,7 @@ class _ChatService implements ChatService { ) .compose( _dio.options, - '/profile/ws/params', + '/api/profile/ws/params', queryParameters: queryParameters, data: _data, ) @@ -69,8 +142,8 @@ class _ChatService implements ChatService { _dio.options.baseUrl, baseUrl, )))); - final value = WebsocketInfoModel.fromJson(_result.data!); - return value; + final _value = WebsocketInfoModel.fromJson(_result.data!); + return _value; } RequestOptions _setStreamType(RequestOptions requestOptions) { diff --git a/lib/features/diary/models/diary_model.dart b/lib/features/diary/models/diary_model.dart new file mode 100644 index 0000000..3a89936 --- /dev/null +++ b/lib/features/diary/models/diary_model.dart @@ -0,0 +1,21 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import './meal.dart'; + +part 'diary_model.freezed.dart'; +part 'diary_model.g.dart'; + +@freezed +class DiaryModel with _$DiaryModel { + const factory DiaryModel({ + required int id, + required DateTime date, + required int closed, + required List meals, + String? comment, + DateTime? wakeup, + DateTime? retire, + }) = _DiaryModel; + + factory DiaryModel.fromJson(Map json) => + _$DiaryModelFromJson(json); +} diff --git a/lib/features/diary/models/diary_model.freezed.dart b/lib/features/diary/models/diary_model.freezed.dart new file mode 100644 index 0000000..3fe59e1 --- /dev/null +++ b/lib/features/diary/models/diary_model.freezed.dart @@ -0,0 +1,283 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'diary_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +DiaryModel _$DiaryModelFromJson(Map json) { + return _DiaryModel.fromJson(json); +} + +/// @nodoc +mixin _$DiaryModel { + int get id => throw _privateConstructorUsedError; + DateTime get date => throw _privateConstructorUsedError; + int get closed => throw _privateConstructorUsedError; + List get meals => throw _privateConstructorUsedError; + String? get comment => throw _privateConstructorUsedError; + DateTime? get wakeup => throw _privateConstructorUsedError; + DateTime? get retire => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DiaryModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DiaryModelCopyWith<$Res> { + factory $DiaryModelCopyWith( + DiaryModel value, $Res Function(DiaryModel) then) = + _$DiaryModelCopyWithImpl<$Res, DiaryModel>; + @useResult + $Res call( + {int id, + DateTime date, + int closed, + List meals, + String? comment, + DateTime? wakeup, + DateTime? retire}); +} + +/// @nodoc +class _$DiaryModelCopyWithImpl<$Res, $Val extends DiaryModel> + implements $DiaryModelCopyWith<$Res> { + _$DiaryModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? date = null, + Object? closed = null, + Object? meals = null, + Object? comment = freezed, + Object? wakeup = freezed, + Object? retire = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + closed: null == closed + ? _value.closed + : closed // ignore: cast_nullable_to_non_nullable + as int, + meals: null == meals + ? _value.meals + : meals // ignore: cast_nullable_to_non_nullable + as List, + comment: freezed == comment + ? _value.comment + : comment // ignore: cast_nullable_to_non_nullable + as String?, + wakeup: freezed == wakeup + ? _value.wakeup + : wakeup // ignore: cast_nullable_to_non_nullable + as DateTime?, + retire: freezed == retire + ? _value.retire + : retire // ignore: cast_nullable_to_non_nullable + as DateTime?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$DiaryModelImplCopyWith<$Res> + implements $DiaryModelCopyWith<$Res> { + factory _$$DiaryModelImplCopyWith( + _$DiaryModelImpl value, $Res Function(_$DiaryModelImpl) then) = + __$$DiaryModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + DateTime date, + int closed, + List meals, + String? comment, + DateTime? wakeup, + DateTime? retire}); +} + +/// @nodoc +class __$$DiaryModelImplCopyWithImpl<$Res> + extends _$DiaryModelCopyWithImpl<$Res, _$DiaryModelImpl> + implements _$$DiaryModelImplCopyWith<$Res> { + __$$DiaryModelImplCopyWithImpl( + _$DiaryModelImpl _value, $Res Function(_$DiaryModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? date = null, + Object? closed = null, + Object? meals = null, + Object? comment = freezed, + Object? wakeup = freezed, + Object? retire = freezed, + }) { + return _then(_$DiaryModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + closed: null == closed + ? _value.closed + : closed // ignore: cast_nullable_to_non_nullable + as int, + meals: null == meals + ? _value._meals + : meals // ignore: cast_nullable_to_non_nullable + as List, + comment: freezed == comment + ? _value.comment + : comment // ignore: cast_nullable_to_non_nullable + as String?, + wakeup: freezed == wakeup + ? _value.wakeup + : wakeup // ignore: cast_nullable_to_non_nullable + as DateTime?, + retire: freezed == retire + ? _value.retire + : retire // ignore: cast_nullable_to_non_nullable + as DateTime?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DiaryModelImpl implements _DiaryModel { + const _$DiaryModelImpl( + {required this.id, + required this.date, + required this.closed, + required final List meals, + this.comment, + this.wakeup, + this.retire}) + : _meals = meals; + + factory _$DiaryModelImpl.fromJson(Map json) => + _$$DiaryModelImplFromJson(json); + + @override + final int id; + @override + final DateTime date; + @override + final int closed; + final List _meals; + @override + List get meals { + if (_meals is EqualUnmodifiableListView) return _meals; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_meals); + } + + @override + final String? comment; + @override + final DateTime? wakeup; + @override + final DateTime? retire; + + @override + String toString() { + return 'DiaryModel(id: $id, date: $date, closed: $closed, meals: $meals, comment: $comment, wakeup: $wakeup, retire: $retire)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DiaryModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.date, date) || other.date == date) && + (identical(other.closed, closed) || other.closed == closed) && + const DeepCollectionEquality().equals(other._meals, _meals) && + (identical(other.comment, comment) || other.comment == comment) && + (identical(other.wakeup, wakeup) || other.wakeup == wakeup) && + (identical(other.retire, retire) || other.retire == retire)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, date, closed, + const DeepCollectionEquality().hash(_meals), comment, wakeup, retire); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith => + __$$DiaryModelImplCopyWithImpl<_$DiaryModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DiaryModelImplToJson( + this, + ); + } +} + +abstract class _DiaryModel implements DiaryModel { + const factory _DiaryModel( + {required final int id, + required final DateTime date, + required final int closed, + required final List meals, + final String? comment, + final DateTime? wakeup, + final DateTime? retire}) = _$DiaryModelImpl; + + factory _DiaryModel.fromJson(Map json) = + _$DiaryModelImpl.fromJson; + + @override + int get id; + @override + DateTime get date; + @override + int get closed; + @override + List get meals; + @override + String? get comment; + @override + DateTime? get wakeup; + @override + DateTime? get retire; + @override + @JsonKey(ignore: true) + _$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/diary_model.g.dart b/lib/features/diary/models/diary_model.g.dart new file mode 100644 index 0000000..1a13c7d --- /dev/null +++ b/lib/features/diary/models/diary_model.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'diary_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$DiaryModelImpl _$$DiaryModelImplFromJson(Map json) => + _$DiaryModelImpl( + id: (json['id'] as num).toInt(), + date: DateTime.parse(json['date'] as String), + closed: (json['closed'] as num).toInt(), + meals: (json['meals'] as List) + .map((e) => Meal.fromJson(e as Map)) + .toList(), + comment: json['comment'] as String?, + wakeup: json['wakeup'] == null + ? null + : DateTime.parse(json['wakeup'] as String), + retire: json['retire'] == null + ? null + : DateTime.parse(json['retire'] as String), + ); + +Map _$$DiaryModelImplToJson(_$DiaryModelImpl instance) => + { + 'id': instance.id, + 'date': instance.date.toIso8601String(), + 'closed': instance.closed, + 'meals': instance.meals, + 'comment': instance.comment, + 'wakeup': instance.wakeup?.toIso8601String(), + 'retire': instance.retire?.toIso8601String(), + }; diff --git a/lib/features/diary/models/meal.dart b/lib/features/diary/models/meal.dart new file mode 100644 index 0000000..dbf3d06 --- /dev/null +++ b/lib/features/diary/models/meal.dart @@ -0,0 +1,22 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import './portion.dart'; +import './photo.dart'; + +part 'meal.freezed.dart'; + +part 'meal.g.dart'; + +@freezed +class Meal with _$Meal { + const factory Meal({ + required int id, + required String time, + required int type, + required int satiety, + required int mood, + required List portions, + required List photos, + }) = _Meal; + + factory Meal.fromJson(Map json) => _$MealFromJson(json); +} diff --git a/lib/features/diary/models/meal.freezed.dart b/lib/features/diary/models/meal.freezed.dart new file mode 100644 index 0000000..2c249b0 --- /dev/null +++ b/lib/features/diary/models/meal.freezed.dart @@ -0,0 +1,291 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'meal.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Meal _$MealFromJson(Map json) { + return _Meal.fromJson(json); +} + +/// @nodoc +mixin _$Meal { + int get id => throw _privateConstructorUsedError; + String get time => throw _privateConstructorUsedError; + int get type => throw _privateConstructorUsedError; + int get satiety => throw _privateConstructorUsedError; + int get mood => throw _privateConstructorUsedError; + List get portions => throw _privateConstructorUsedError; + List get photos => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MealCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MealCopyWith<$Res> { + factory $MealCopyWith(Meal value, $Res Function(Meal) then) = + _$MealCopyWithImpl<$Res, Meal>; + @useResult + $Res call( + {int id, + String time, + int type, + int satiety, + int mood, + List portions, + List photos}); +} + +/// @nodoc +class _$MealCopyWithImpl<$Res, $Val extends Meal> + implements $MealCopyWith<$Res> { + _$MealCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? time = null, + Object? type = null, + Object? satiety = null, + Object? mood = null, + Object? portions = null, + Object? photos = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + time: null == time + ? _value.time + : time // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as int, + satiety: null == satiety + ? _value.satiety + : satiety // ignore: cast_nullable_to_non_nullable + as int, + mood: null == mood + ? _value.mood + : mood // ignore: cast_nullable_to_non_nullable + as int, + portions: null == portions + ? _value.portions + : portions // ignore: cast_nullable_to_non_nullable + as List, + photos: null == photos + ? _value.photos + : photos // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MealImplCopyWith<$Res> implements $MealCopyWith<$Res> { + factory _$$MealImplCopyWith( + _$MealImpl value, $Res Function(_$MealImpl) then) = + __$$MealImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String time, + int type, + int satiety, + int mood, + List portions, + List photos}); +} + +/// @nodoc +class __$$MealImplCopyWithImpl<$Res> + extends _$MealCopyWithImpl<$Res, _$MealImpl> + implements _$$MealImplCopyWith<$Res> { + __$$MealImplCopyWithImpl(_$MealImpl _value, $Res Function(_$MealImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? time = null, + Object? type = null, + Object? satiety = null, + Object? mood = null, + Object? portions = null, + Object? photos = null, + }) { + return _then(_$MealImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + time: null == time + ? _value.time + : time // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as int, + satiety: null == satiety + ? _value.satiety + : satiety // ignore: cast_nullable_to_non_nullable + as int, + mood: null == mood + ? _value.mood + : mood // ignore: cast_nullable_to_non_nullable + as int, + portions: null == portions + ? _value._portions + : portions // ignore: cast_nullable_to_non_nullable + as List, + photos: null == photos + ? _value._photos + : photos // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$MealImpl implements _Meal { + const _$MealImpl( + {required this.id, + required this.time, + required this.type, + required this.satiety, + required this.mood, + required final List portions, + required final List photos}) + : _portions = portions, + _photos = photos; + + factory _$MealImpl.fromJson(Map json) => + _$$MealImplFromJson(json); + + @override + final int id; + @override + final String time; + @override + final int type; + @override + final int satiety; + @override + final int mood; + final List _portions; + @override + List get portions { + if (_portions is EqualUnmodifiableListView) return _portions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_portions); + } + + final List _photos; + @override + List get photos { + if (_photos is EqualUnmodifiableListView) return _photos; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_photos); + } + + @override + String toString() { + return 'Meal(id: $id, time: $time, type: $type, satiety: $satiety, mood: $mood, portions: $portions, photos: $photos)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MealImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.time, time) || other.time == time) && + (identical(other.type, type) || other.type == type) && + (identical(other.satiety, satiety) || other.satiety == satiety) && + (identical(other.mood, mood) || other.mood == mood) && + const DeepCollectionEquality().equals(other._portions, _portions) && + const DeepCollectionEquality().equals(other._photos, _photos)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + time, + type, + satiety, + mood, + const DeepCollectionEquality().hash(_portions), + const DeepCollectionEquality().hash(_photos)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MealImplCopyWith<_$MealImpl> get copyWith => + __$$MealImplCopyWithImpl<_$MealImpl>(this, _$identity); + + @override + Map toJson() { + return _$$MealImplToJson( + this, + ); + } +} + +abstract class _Meal implements Meal { + const factory _Meal( + {required final int id, + required final String time, + required final int type, + required final int satiety, + required final int mood, + required final List portions, + required final List photos}) = _$MealImpl; + + factory _Meal.fromJson(Map json) = _$MealImpl.fromJson; + + @override + int get id; + @override + String get time; + @override + int get type; + @override + int get satiety; + @override + int get mood; + @override + List get portions; + @override + List get photos; + @override + @JsonKey(ignore: true) + _$$MealImplCopyWith<_$MealImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/meal.g.dart b/lib/features/diary/models/meal.g.dart new file mode 100644 index 0000000..5536ed9 --- /dev/null +++ b/lib/features/diary/models/meal.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'meal.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$MealImpl _$$MealImplFromJson(Map json) => _$MealImpl( + id: (json['id'] as num).toInt(), + time: json['time'] as String, + type: (json['type'] as num).toInt(), + satiety: (json['satiety'] as num).toInt(), + mood: (json['mood'] as num).toInt(), + portions: (json['portions'] as List) + .map((e) => Portion.fromJson(e as Map)) + .toList(), + photos: (json['photos'] as List) + .map((e) => Photo.fromJson(e as Map)) + .toList(), + ); + +Map _$$MealImplToJson(_$MealImpl instance) => + { + 'id': instance.id, + 'time': instance.time, + 'type': instance.type, + 'satiety': instance.satiety, + 'mood': instance.mood, + 'portions': instance.portions, + 'photos': instance.photos, + }; diff --git a/lib/features/diary/models/photo.dart b/lib/features/diary/models/photo.dart new file mode 100644 index 0000000..d3e4f69 --- /dev/null +++ b/lib/features/diary/models/photo.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'photo.freezed.dart'; + +part 'photo.g.dart'; + +@freezed +class Photo with _$Photo { + const factory Photo({ + required int id, + @JsonKey(name: 'original_name') required String originalName, + required String path, + }) = _Photo; + + factory Photo.fromJson(Map json) => _$PhotoFromJson(json); +} diff --git a/lib/features/diary/models/photo.freezed.dart b/lib/features/diary/models/photo.freezed.dart new file mode 100644 index 0000000..2d9c70b --- /dev/null +++ b/lib/features/diary/models/photo.freezed.dart @@ -0,0 +1,195 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'photo.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Photo _$PhotoFromJson(Map json) { + return _Photo.fromJson(json); +} + +/// @nodoc +mixin _$Photo { + int get id => throw _privateConstructorUsedError; + @JsonKey(name: 'original_name') + String get originalName => throw _privateConstructorUsedError; + String get path => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PhotoCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PhotoCopyWith<$Res> { + factory $PhotoCopyWith(Photo value, $Res Function(Photo) then) = + _$PhotoCopyWithImpl<$Res, Photo>; + @useResult + $Res call( + {int id, + @JsonKey(name: 'original_name') String originalName, + String path}); +} + +/// @nodoc +class _$PhotoCopyWithImpl<$Res, $Val extends Photo> + implements $PhotoCopyWith<$Res> { + _$PhotoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? originalName = null, + Object? path = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + originalName: null == originalName + ? _value.originalName + : originalName // ignore: cast_nullable_to_non_nullable + as String, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PhotoImplCopyWith<$Res> implements $PhotoCopyWith<$Res> { + factory _$$PhotoImplCopyWith( + _$PhotoImpl value, $Res Function(_$PhotoImpl) then) = + __$$PhotoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + @JsonKey(name: 'original_name') String originalName, + String path}); +} + +/// @nodoc +class __$$PhotoImplCopyWithImpl<$Res> + extends _$PhotoCopyWithImpl<$Res, _$PhotoImpl> + implements _$$PhotoImplCopyWith<$Res> { + __$$PhotoImplCopyWithImpl( + _$PhotoImpl _value, $Res Function(_$PhotoImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? originalName = null, + Object? path = null, + }) { + return _then(_$PhotoImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + originalName: null == originalName + ? _value.originalName + : originalName // ignore: cast_nullable_to_non_nullable + as String, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$PhotoImpl implements _Photo { + const _$PhotoImpl( + {required this.id, + @JsonKey(name: 'original_name') required this.originalName, + required this.path}); + + factory _$PhotoImpl.fromJson(Map json) => + _$$PhotoImplFromJson(json); + + @override + final int id; + @override + @JsonKey(name: 'original_name') + final String originalName; + @override + final String path; + + @override + String toString() { + return 'Photo(id: $id, originalName: $originalName, path: $path)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PhotoImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.originalName, originalName) || + other.originalName == originalName) && + (identical(other.path, path) || other.path == path)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, originalName, path); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PhotoImplCopyWith<_$PhotoImpl> get copyWith => + __$$PhotoImplCopyWithImpl<_$PhotoImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PhotoImplToJson( + this, + ); + } +} + +abstract class _Photo implements Photo { + const factory _Photo( + {required final int id, + @JsonKey(name: 'original_name') required final String originalName, + required final String path}) = _$PhotoImpl; + + factory _Photo.fromJson(Map json) = _$PhotoImpl.fromJson; + + @override + int get id; + @override + @JsonKey(name: 'original_name') + String get originalName; + @override + String get path; + @override + @JsonKey(ignore: true) + _$$PhotoImplCopyWith<_$PhotoImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/photo.g.dart b/lib/features/diary/models/photo.g.dart new file mode 100644 index 0000000..cacf65a --- /dev/null +++ b/lib/features/diary/models/photo.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'photo.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$PhotoImpl _$$PhotoImplFromJson(Map json) => _$PhotoImpl( + id: (json['id'] as num).toInt(), + originalName: json['original_name'] as String, + path: json['path'] as String, + ); + +Map _$$PhotoImplToJson(_$PhotoImpl instance) => + { + 'id': instance.id, + 'original_name': instance.originalName, + 'path': instance.path, + }; diff --git a/lib/features/diary/models/portion.dart b/lib/features/diary/models/portion.dart new file mode 100644 index 0000000..51ec5bb --- /dev/null +++ b/lib/features/diary/models/portion.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'portion.freezed.dart'; + +part 'portion.g.dart'; + +@freezed +class Portion with _$Portion { + const factory Portion({ + required int id, + required String product_name, + required int quantity, + required String portion, + }) = _Portion; + + factory Portion.fromJson(Map json) => + _$PortionFromJson(json); +} diff --git a/lib/features/diary/models/portion.freezed.dart b/lib/features/diary/models/portion.freezed.dart new file mode 100644 index 0000000..a7a35a2 --- /dev/null +++ b/lib/features/diary/models/portion.freezed.dart @@ -0,0 +1,206 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'portion.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Portion _$PortionFromJson(Map json) { + return _Portion.fromJson(json); +} + +/// @nodoc +mixin _$Portion { + int get id => throw _privateConstructorUsedError; + String get product_name => throw _privateConstructorUsedError; + int get quantity => throw _privateConstructorUsedError; + String get portion => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PortionCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PortionCopyWith<$Res> { + factory $PortionCopyWith(Portion value, $Res Function(Portion) then) = + _$PortionCopyWithImpl<$Res, Portion>; + @useResult + $Res call({int id, String product_name, int quantity, String portion}); +} + +/// @nodoc +class _$PortionCopyWithImpl<$Res, $Val extends Portion> + implements $PortionCopyWith<$Res> { + _$PortionCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? product_name = null, + Object? quantity = null, + Object? portion = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + product_name: null == product_name + ? _value.product_name + : product_name // ignore: cast_nullable_to_non_nullable + as String, + quantity: null == quantity + ? _value.quantity + : quantity // ignore: cast_nullable_to_non_nullable + as int, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PortionImplCopyWith<$Res> implements $PortionCopyWith<$Res> { + factory _$$PortionImplCopyWith( + _$PortionImpl value, $Res Function(_$PortionImpl) then) = + __$$PortionImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int id, String product_name, int quantity, String portion}); +} + +/// @nodoc +class __$$PortionImplCopyWithImpl<$Res> + extends _$PortionCopyWithImpl<$Res, _$PortionImpl> + implements _$$PortionImplCopyWith<$Res> { + __$$PortionImplCopyWithImpl( + _$PortionImpl _value, $Res Function(_$PortionImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? product_name = null, + Object? quantity = null, + Object? portion = null, + }) { + return _then(_$PortionImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + product_name: null == product_name + ? _value.product_name + : product_name // ignore: cast_nullable_to_non_nullable + as String, + quantity: null == quantity + ? _value.quantity + : quantity // ignore: cast_nullable_to_non_nullable + as int, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$PortionImpl implements _Portion { + const _$PortionImpl( + {required this.id, + required this.product_name, + required this.quantity, + required this.portion}); + + factory _$PortionImpl.fromJson(Map json) => + _$$PortionImplFromJson(json); + + @override + final int id; + @override + final String product_name; + @override + final int quantity; + @override + final String portion; + + @override + String toString() { + return 'Portion(id: $id, product_name: $product_name, quantity: $quantity, portion: $portion)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PortionImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.product_name, product_name) || + other.product_name == product_name) && + (identical(other.quantity, quantity) || + other.quantity == quantity) && + (identical(other.portion, portion) || other.portion == portion)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, product_name, quantity, portion); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PortionImplCopyWith<_$PortionImpl> get copyWith => + __$$PortionImplCopyWithImpl<_$PortionImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PortionImplToJson( + this, + ); + } +} + +abstract class _Portion implements Portion { + const factory _Portion( + {required final int id, + required final String product_name, + required final int quantity, + required final String portion}) = _$PortionImpl; + + factory _Portion.fromJson(Map json) = _$PortionImpl.fromJson; + + @override + int get id; + @override + String get product_name; + @override + int get quantity; + @override + String get portion; + @override + @JsonKey(ignore: true) + _$$PortionImplCopyWith<_$PortionImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/portion.g.dart b/lib/features/diary/models/portion.g.dart new file mode 100644 index 0000000..c8bd109 --- /dev/null +++ b/lib/features/diary/models/portion.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'portion.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$PortionImpl _$$PortionImplFromJson(Map json) => + _$PortionImpl( + id: (json['id'] as num).toInt(), + product_name: json['product_name'] as String, + quantity: (json['quantity'] as num).toInt(), + portion: json['portion'] as String, + ); + +Map _$$PortionImplToJson(_$PortionImpl instance) => + { + 'id': instance.id, + 'product_name': instance.product_name, + 'quantity': instance.quantity, + 'portion': instance.portion, + }; diff --git a/lib/features/diary/models/product.dart b/lib/features/diary/models/product.dart new file mode 100644 index 0000000..d054257 --- /dev/null +++ b/lib/features/diary/models/product.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'product.freezed.dart'; + +part 'product.g.dart'; + +@freezed +class Product with _$Product { + const factory Product({ + required int id, + required String name, + }) = _Product; + + factory Product.fromJson(Map json) => + _$ProductFromJson(json); +} diff --git a/lib/features/diary/models/product.freezed.dart b/lib/features/diary/models/product.freezed.dart new file mode 100644 index 0000000..d30ada3 --- /dev/null +++ b/lib/features/diary/models/product.freezed.dart @@ -0,0 +1,164 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'product.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Product _$ProductFromJson(Map json) { + return _Product.fromJson(json); +} + +/// @nodoc +mixin _$Product { + int get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ProductCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductCopyWith<$Res> { + factory $ProductCopyWith(Product value, $Res Function(Product) then) = + _$ProductCopyWithImpl<$Res, Product>; + @useResult + $Res call({int id, String name}); +} + +/// @nodoc +class _$ProductCopyWithImpl<$Res, $Val extends Product> + implements $ProductCopyWith<$Res> { + _$ProductCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ProductImplCopyWith<$Res> implements $ProductCopyWith<$Res> { + factory _$$ProductImplCopyWith( + _$ProductImpl value, $Res Function(_$ProductImpl) then) = + __$$ProductImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int id, String name}); +} + +/// @nodoc +class __$$ProductImplCopyWithImpl<$Res> + extends _$ProductCopyWithImpl<$Res, _$ProductImpl> + implements _$$ProductImplCopyWith<$Res> { + __$$ProductImplCopyWithImpl( + _$ProductImpl _value, $Res Function(_$ProductImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + }) { + return _then(_$ProductImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ProductImpl implements _Product { + const _$ProductImpl({required this.id, required this.name}); + + factory _$ProductImpl.fromJson(Map json) => + _$$ProductImplFromJson(json); + + @override + final int id; + @override + final String name; + + @override + String toString() { + return 'Product(id: $id, name: $name)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, name); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ProductImplCopyWith<_$ProductImpl> get copyWith => + __$$ProductImplCopyWithImpl<_$ProductImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ProductImplToJson( + this, + ); + } +} + +abstract class _Product implements Product { + const factory _Product({required final int id, required final String name}) = + _$ProductImpl; + + factory _Product.fromJson(Map json) = _$ProductImpl.fromJson; + + @override + int get id; + @override + String get name; + @override + @JsonKey(ignore: true) + _$$ProductImplCopyWith<_$ProductImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/product.g.dart b/lib/features/diary/models/product.g.dart new file mode 100644 index 0000000..7433110 --- /dev/null +++ b/lib/features/diary/models/product.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'product.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ProductImpl _$$ProductImplFromJson(Map json) => + _$ProductImpl( + id: (json['id'] as num).toInt(), + name: json['name'] as String, + ); + +Map _$$ProductImplToJson(_$ProductImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + }; diff --git a/lib/features/diary/presentation/bloc/diary_bloc.dart b/lib/features/diary/presentation/bloc/diary_bloc.dart new file mode 100644 index 0000000..7803117 --- /dev/null +++ b/lib/features/diary/presentation/bloc/diary_bloc.dart @@ -0,0 +1,531 @@ +import 'dart:async'; +import 'package:eatvio_app/features/diary/models/diary_model.dart'; +import 'package:eatvio_app/features/diary/models/meal.dart'; +import 'package:eatvio_app/features/diary/models/product.dart'; +import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; +import 'package:intl/intl.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import '/core/app_export.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; + +part 'diary_event.dart'; + +/// A bloc that manages the state of a Diary according to the event that is dispatched to it. +class DiaryBloc extends Bloc { + final DiaryRepository diaryRepository; + + DiaryBloc({required this.diaryRepository}) + : super(const DiaryState.loading()) { + on(loadDiary); + on(loadDiaryById); + on(_changeSatiety); // пользователь нажимает на шкалу сытости + on(_changeMood); // пользователь нажимает на шкалу настроения + on(_changeMealTime); // пользовательяет времяа пиши + on(_changeMeal); + on(_changePortion); + on(_changeWakeup); // пользователь выбирает время пробуждения + on(_changeRetire); // пользователь выбирает время отхода ко сну + on(_toggleMood); + on(_toggleWakeup); + on(_addPortion); //пользователь нажимает "Добавить продукт" + on(_removePortion); + on( + _removeImage, + ); // пользователь нажимает на крестик около продукта + on(_uploadImages); //пользователь нажимает "Добавить фото" + on( + _inputProduct, + ); + on(_finishDay); + on(_sendModeration); + on(_clearInput); + } + + loadDiary( + LoadDiary event, + Emitter emit, + ) async { + emit(const DiaryState.loading()); + try { + Map data = await diaryRepository.getDiaryID(); + + final int? diaryID = data['id']; + final DiaryModel diary = await diaryRepository.getDiary(diaryID ?? 45); + final Meal currentMeal = diary.meals[0]; + + List portionList = [ + SelectionPopupModel(title: "gr"), + SelectionPopupModel(title: "pcs") + ]; + + final Map chartData = + await diaryRepository.getChartData(diaryID ?? 45); + final Map dailyNutritionIntake = + chartData['dailyNutritionIntake']!; + final Map dailyNutritionRecommendations = + chartData['dailyNutritionRecommendation']!; + final double ccal = dailyNutritionIntake['energy']! / + dailyNutritionRecommendations['energy']! * + 50; + final double proteins = dailyNutritionIntake['proteins']! / + dailyNutritionRecommendations['proteins']! * + 50; + final double fats = dailyNutritionIntake['fats']! / + dailyNutritionRecommendations['fats']! * + 50; + final double carbs = dailyNutritionIntake['carbohydrates']! / + dailyNutritionRecommendations['carbohydrates']! * + 50; + + Color getColor(double value) { + if (value >= 99.1) { + return Colors.red; + } else { + return Colors.blue; + } + } + + final List chartDataCounted = [ + NutritionData('Калории', ccal, getColor(ccal)), + NutritionData('Белки', proteins, getColor(proteins)), + NutritionData('Жиры', fats, getColor(fats)), + NutritionData('Углеводы', carbs, getColor(carbs)), + ]; + + List mealList = [ + SelectionPopupModel(title: "Прием пищи 1", id: 1), + SelectionPopupModel(title: "Прием пищи 2", id: 2), + SelectionPopupModel(title: "Прием пищи 3", id: 3), + SelectionPopupModel(title: "Прием пищи 4", id: 4), + SelectionPopupModel(title: "Прием пищи 5", id: 5), + SelectionPopupModel(title: "Прием пищи 6", id: 6), + ]; + + emit(DiaryState.loaded( + diary: diary, + currentMeal: currentMeal, + portions: currentMeal.portions, + portionList: portionList, + portionController: portionList[0], + mealList: mealList, + chartData: chartData, + chartDataCounted: chartDataCounted, + selectedMood: currentMeal.mood, + selectedSatiety: currentMeal.satiety, + wakeupController: TimeOfDay.now(), + retireController: TimeOfDay.now(), + commentController: TextEditingController(), + product_nameController: TextEditingController(), + productQuantityController: TextEditingController(), + caloriesController: TextEditingController(), + fatsController: TextEditingController(), + proteinsController: TextEditingController(), + carbsController: TextEditingController(), + wakeupExpanded: false, + moderationExpanded: false, + moodExpanded: false, + isLoading: false, + isAdded: false, + autocompleteList: [], + recommendedChartValues: [1, 1, 1, 1], + consumedChartValues: [1, 1, 1, 1])); + } catch (e) { + emit(DiaryState.error(errorMessage: e.toString())); + } + } + + loadDiaryById( + LoadDiaryById event, + Emitter emit, + ) async { + emit(const DiaryState.loading()); + try { + final int diaryID = int.parse(event.id ?? "0"); + final DiaryModel diary = await diaryRepository.getDiary(diaryID); + final Meal currentMeal = diary.meals[0]; + + List portionList = [ + SelectionPopupModel(title: "gr"), + SelectionPopupModel(title: "pcs") + ]; + + final Map chartData = + await diaryRepository.getChartData(diaryID); + final Map dailyNutritionIntake = + chartData['dailyNutritionIntake']!; + final Map dailyNutritionRecommendations = + chartData['dailyNutritionRecommendation']!; + final double ccal = dailyNutritionIntake['energy']! / + dailyNutritionRecommendations['energy']! * + 50; + final double proteins = dailyNutritionIntake['proteins']! / + dailyNutritionRecommendations['proteins']! * + 50; + final double fats = dailyNutritionIntake['fats']! / + dailyNutritionRecommendations['fats']! * + 50; + final double carbs = dailyNutritionIntake['carbohydrates']! / + dailyNutritionRecommendations['carbohydrates']! * + 50; + + Color getColor(double value) { + if (value >= 99.1) { + return Colors.red; + } else { + return Colors.blue; + } + } + + final List chartDataCounted = [ + NutritionData('Калории', ccal, getColor(ccal)), + NutritionData('Белки', proteins, getColor(proteins)), + NutritionData('Жиры', fats, getColor(fats)), + NutritionData('Углеводы', carbs, getColor(carbs)), + ]; + + List mealList = [ + SelectionPopupModel(title: "Прием пищи 1", id: 1), + SelectionPopupModel(title: "Прием пищи 2", id: 2), + SelectionPopupModel(title: "Прием пищи 3", id: 3), + SelectionPopupModel(title: "Прием пищи 4", id: 4), + SelectionPopupModel(title: "Прием пищи 5", id: 5), + SelectionPopupModel(title: "Прием пищи 6", id: 6), + ]; + + emit(DiaryState.loaded( + diary: diary, + currentMeal: currentMeal, + portions: currentMeal.portions, + portionList: portionList, + portionController: portionList[0], + mealList: mealList, + chartData: chartData, + chartDataCounted: chartDataCounted, + selectedMood: currentMeal.mood, + selectedSatiety: currentMeal.satiety, + wakeupController: TimeOfDay.now(), + retireController: TimeOfDay.now(), + commentController: TextEditingController(), + product_nameController: TextEditingController(), + productQuantityController: TextEditingController(), + caloriesController: TextEditingController(), + fatsController: TextEditingController(), + proteinsController: TextEditingController(), + carbsController: TextEditingController(), + wakeupExpanded: false, + moderationExpanded: false, + moodExpanded: false, + isLoading: false, + isAdded: false, + autocompleteList: [], + recommendedChartValues: [1, 1, 1, 1], + consumedChartValues: [1, 1, 1, 1])); + } catch (e) { + emit(DiaryState.error(errorMessage: e.toString())); + } + } + + Future _changeSatiety( + ChangeSatiety event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + var updatedState = currentState.copyWith( + selectedSatiety: event.selectedElement, + ); + diaryRepository.changeSatiety( + event.selectedElement, + currentState.currentMeal.id, + currentState.diary.id, + ); + emit(updatedState); + } + } + + Future _changeMood( + ChangeMood event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + var updatedState = currentState.copyWith( + selectedMood: event.selectedElement, + ); + + diaryRepository.changeMood( + event.selectedElement, + currentState.currentMeal.id, + currentState.diary.id, + ); + + emit(updatedState); // Передаем обновленное состояние в emit + } + } + + FutureOr _changeWakeup( + WakeupEvent event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + var updatedState = + currentState.copyWith(wakeupController: event.selectedTime); + final DateFormat formatter = DateFormat('HH:mm'); + final String wakeupString = formatter.format(DateTime( + 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + await diaryRepository.changeWakeup( + currentState.diary.id, + wakeupString, + ); + emit(updatedState); + } + } + + FutureOr _changeRetire( + RetireEvent event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + var updatedState = + currentState.copyWith(retireController: event.selectedTime); + final DateFormat formatter = DateFormat('HH:mm'); + final String retireString = formatter.format(DateTime( + 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + await diaryRepository.changeRetire( + currentState.diary.id, + retireString, + ); + emit(updatedState); + } + } + + FutureOr _changeMealTime( + ChangeMealTime event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + var updatedState = currentState.copyWith(mealTimeController: event.time); + emit(updatedState); + } + } + + FutureOr _changeMeal( + ChangeMeal event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + final currentState = state as DiaryStateLoaded; + final Meal meal = currentState.diary.meals + .firstWhere((meal) => meal.type == event.value.id); + DiaryStateLoaded updatedState = currentState.copyWith( + currentMeal: meal, + portions: meal.portions, + mealTimeController: toTime(meal.time), + selectedMood: meal.mood, + selectedSatiety: meal.satiety, + ); + emit(updatedState); + } + } + + Future _inputProduct( + ProductInput event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + final Map> productNutritionalValues = + await diaryRepository.inputProduct(event.input); + var updatedState = currentState.copyWith( + product_nameController: TextEditingController(text: event.input), + autocompleteList: + productNutritionalValues['product_nutritional_value'] ?? [], + ); + if (event.input.length > 3) { + updatedState = updatedState.copyWith(moderationExpanded: true); + } else { + updatedState = updatedState.copyWith(moderationExpanded: false); + } + + emit(updatedState); + } + } + + FutureOr _addPortion( + AddPortionEvent event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + await diaryRepository.addPortion( + currentState.diary.id, + currentState.currentMeal.id, + currentState.product_nameController.text, + currentState.portionController.title, + int.parse(currentState.productQuantityController.text), + ); + add(LoadDiary()); + } + } + + Future _removePortion( + RemovePortionEvent event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + await diaryRepository.removePortion( + currentState.diary.id, + currentState.currentMeal.id, + event.portionId, + ); + } + add(LoadDiary()); + } + + Future _uploadImages( + UploadImages event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + emit(currentState.copyWith(isLoading: true)); + await diaryRepository.uploadImage( + event.image.path, + currentState.diary.id, + currentState.currentMeal.id, + ); + add(LoadDiary()); + } + } + + FutureOr _sendModeration( + SendModeration event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + await diaryRepository.sendModeration( + event.name, + event.energyOn100gr, + event.proteinsOn100gr, + event.fatsOn100gr, + event.carbohydratesOn100gr, + ); + } + } + + FutureOr _clearInput( + ClearInput event, + Emitter emit, + ) { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + DiaryStateLoaded updatedState = currentState.copyWith(); + emit(updatedState); + } + } + + FutureOr _changePortion( + ChangePortion event, + Emitter emit, + ) { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + DiaryStateLoaded updatedState = currentState.copyWith( + portionController: event.value, + ); + emit(updatedState); + } + } + + FutureOr _toggleMood( + ToggleMoodExpandedEvent event, + Emitter emit, + ) { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + emit(currentState.copyWith(moodExpanded: !currentState.moodExpanded)); + } + } + + FutureOr _toggleWakeup( + ToggleWakeupExpandedEvent event, + Emitter emit, + ) { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + emit(currentState.copyWith(wakeupExpanded: !currentState.wakeupExpanded)); + } + } + + FutureOr _removeImage( + RemoveImageEvent event, + Emitter emit, + ) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + await diaryRepository.removeImage( + currentState.diary.id, + currentState.currentMeal.id, + int.parse(event.photoID), + event.path, + ); + add(LoadDiary()); + } + } + + Future _finishDay(FinishDay event, Emitter emit) async { + if (state is DiaryStateLoaded) { + var currentState = state as DiaryStateLoaded; + + await diaryRepository.finishDay( + currentState.diary.id, + // currentState.wakeupController, + // currentState.retireController, + // currentState.commentController.text, + ); + add(LoadDiary()); + } + } + + TimeOfDay toTime(String timeStr) { + List timeParts = timeStr.split(":"); + int hour = int.parse(timeParts[0]); + int minute = int.parse(timeParts[1]); + + TimeOfDay timeOfDay = TimeOfDay(hour: hour, minute: minute); + return timeOfDay; + } + + int compareTypes(a, b) { + return a['type'].compareTo(b['type']); + } + + List fillPortion() { + return [ + SelectionPopupModel(id: 0, title: "порций", isSelected: true), + SelectionPopupModel(id: 1, title: "грамм"), + ]; + } +} + +int convertToInt(dynamic value) { + if (value is int) { + return value; + } else if (value is double) { + return value.toInt(); + } else { + throw FormatException('Unexpected value type: ${value.runtimeType}'); + } +} diff --git a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_event.dart b/lib/features/diary/presentation/bloc/diary_event.dart similarity index 61% rename from lib/presentation/diary/diary_edit_screen/bloc/diary_edit_event.dart rename to lib/features/diary/presentation/bloc/diary_event.dart index 8185fa2..4faa190 100644 --- a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_event.dart +++ b/lib/features/diary/presentation/bloc/diary_event.dart @@ -1,58 +1,63 @@ // ignore_for_file: must_be_immutable -part of 'diary_edit_bloc.dart'; +part of 'diary_bloc.dart'; /// Abstract class for all events that can be dispatched from the -///DiaryEdit widget. +///Diary widget. /// /// Events must be immutable and implement the [Equatable] interface. @immutable -abstract class DiaryEditEvent extends Equatable {} +abstract class DiaryEvent extends Equatable {} -/// Event that is dispatched when the DiaryEdit widget is first created. -class DiaryEditInitialEvent extends DiaryEditEvent { +/// Event that is dispatched when the Diary widget is first created. +class LoadDiary extends DiaryEvent { @override List get props => []; } -class ChangeSatiety extends DiaryEditEvent { +class LoadDiaryById extends DiaryEvent { + LoadDiaryById( + this.id, + ); + final String? id; + @override + List get props => []; +} + +class ChangeSatiety extends DiaryEvent { ChangeSatiety( this.selectedElement, ); final int selectedElement; - @override List get props => [selectedElement]; } -class ChangeMood extends DiaryEditEvent { +class ChangeMood extends DiaryEvent { ChangeMood( this.selectedElement, ); final int selectedElement; - @override List get props => [selectedElement]; } -class ChangeMealTime extends DiaryEditEvent { +class ChangeMealTime extends DiaryEvent { ChangeMealTime(this.time); final TimeOfDay time; - @override List get props => [time]; } -class AddComment extends DiaryEditEvent { +class AddComment extends DiaryEvent { AddComment(this.diaryId, this.comment); final String comment; final int diaryId; - @override List get props => [comment, diaryId]; } -class WakeupEvent extends DiaryEditEvent { +class WakeupEvent extends DiaryEvent { WakeupEvent(this.selectedTime); final TimeOfDay selectedTime; @@ -60,7 +65,7 @@ class WakeupEvent extends DiaryEditEvent { List get props => [selectedTime]; } -class RetireEvent extends DiaryEditEvent { +class RetireEvent extends DiaryEvent { RetireEvent(this.selectedTime); final TimeOfDay selectedTime; @@ -68,37 +73,37 @@ class RetireEvent extends DiaryEditEvent { List get props => [selectedTime]; } -class ToggleMoodExpandedEvent extends DiaryEditEvent { +class ToggleMoodExpandedEvent extends DiaryEvent { @override List get props => []; } -class ToggleWakeupExpandedEvent extends DiaryEditEvent { +class ToggleWakeupExpandedEvent extends DiaryEvent { @override List get props => []; } -class AddPortionEvent extends DiaryEditEvent { +class AddPortionEvent extends DiaryEvent { AddPortionEvent(); @override List get props => []; } -class RemovePortionEvent extends DiaryEditEvent { +class RemovePortionEvent extends DiaryEvent { RemovePortionEvent(this.portionId); final int portionId; @override List get props => [portionId]; } -class UploadImages extends DiaryEditEvent { +class UploadImages extends DiaryEvent { UploadImages(this.image); final XFile image; @override List get props => [image]; } -class RemoveImageEvent extends DiaryEditEvent { +class RemoveImageEvent extends DiaryEvent { RemoveImageEvent(this.photoID, this.path); final String photoID; final String path; @@ -106,60 +111,55 @@ class RemoveImageEvent extends DiaryEditEvent { List get props => [photoID, path]; } -class ProductInput extends DiaryEditEvent { +class ProductInput extends DiaryEvent { ProductInput(this.input); final String input; @override List get props => [input]; } -class ChangeMeal extends DiaryEditEvent { - ChangeMeal({required this.value, required this.meals}); - +class ChangeMeal extends DiaryEvent { + ChangeMeal({required this.value}); SelectionPopupModel value; - List? meals; @override - List get props => [value, meals]; + List get props => [value]; } - -class ClearInput extends DiaryEditEvent { +class ClearInput extends DiaryEvent { ClearInput({required this.value}); - TextEditingController value; @override List get props => [value]; } -class ChangePortion extends DiaryEditEvent { +class ChangePortion extends DiaryEvent { ChangePortion({required this.value}); - SelectionPopupModel value; @override List get props => [value]; } -class FinishDay extends DiaryEditEvent { +class FinishDay extends DiaryEvent { FinishDay(); - @override List get props => []; } -class RefreshEvent extends DiaryEditEvent { +class RefreshEvent extends DiaryEvent { RefreshEvent(); @override List get props => []; } -class SendModeration extends DiaryEditEvent { - SendModeration( - {required this.name, - required this.energyOn100gr, - required this.proteinsOn100gr, - required this.fatsOn100gr, - required this.carbohydratesOn100gr}); +class SendModeration extends DiaryEvent { + SendModeration({ + required this.name, + required this.energyOn100gr, + required this.proteinsOn100gr, + required this.fatsOn100gr, + required this.carbohydratesOn100gr, + }); String name; String energyOn100gr; String proteinsOn100gr; diff --git a/lib/features/diary/presentation/bloc/diary_state.dart b/lib/features/diary/presentation/bloc/diary_state.dart new file mode 100644 index 0000000..b0aebfb --- /dev/null +++ b/lib/features/diary/presentation/bloc/diary_state.dart @@ -0,0 +1,63 @@ +import 'package:eatvio_app/features/diary/models/diary_model.dart'; +import 'package:eatvio_app/features/diary/models/meal.dart'; +import 'package:eatvio_app/features/diary/models/portion.dart'; +import 'package:eatvio_app/features/diary/models/product.dart'; +import 'package:flutter/material.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../../../../data/models/selectionPopupModel/selection_popup_model.dart'; + +part 'diary_state.freezed.dart'; + +@freezed +abstract class DiaryState with _$DiaryState { + const factory DiaryState() = _DiaryState; + + const factory DiaryState.loading({ + int? id, + }) = DiaryStateLoading; + + const factory DiaryState.loaded({ + required DiaryModel diary, + String? diaryDate, + required List recommendedChartValues, + required List consumedChartValues, + required List portions, + required List mealList, + required List portionList, + required List autocompleteList, + required Map chartData, + required Meal currentMeal, + required SelectionPopupModel portionController, + required TimeOfDay wakeupController, + required TimeOfDay retireController, + TimeOfDay? mealTimeController, + required TextEditingController commentController, + required TextEditingController product_nameController, + required TextEditingController productQuantityController, + required TextEditingController caloriesController, + required TextEditingController fatsController, + required TextEditingController proteinsController, + required TextEditingController carbsController, + required int selectedMood, + required int selectedSatiety, + required bool wakeupExpanded, + required bool moderationExpanded, + required bool moodExpanded, + required bool isLoading, + required bool isAdded, + List? chartDataCounted, + }) = DiaryStateLoaded; + + const factory DiaryState.error({ + required String errorMessage, + }) = DiaryStateError; +} + +class NutritionData { + NutritionData(this.category, this.nutrition, this.color); + + final String category; + final double nutrition; + final Color color; +} diff --git a/lib/features/diary/presentation/bloc/diary_state.freezed.dart b/lib/features/diary/presentation/bloc/diary_state.freezed.dart new file mode 100644 index 0000000..5a9bbc1 --- /dev/null +++ b/lib/features/diary/presentation/bloc/diary_state.freezed.dart @@ -0,0 +1,1664 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'diary_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$DiaryState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function(int? id) loading, + required TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted) + loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function(int? id)? loading, + TResult? Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function(int? id)? loading, + TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_DiaryState value) $default, { + required TResult Function(DiaryStateLoading value) loading, + required TResult Function(DiaryStateLoaded value) loaded, + required TResult Function(DiaryStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_DiaryState value)? $default, { + TResult? Function(DiaryStateLoading value)? loading, + TResult? Function(DiaryStateLoaded value)? loaded, + TResult? Function(DiaryStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_DiaryState value)? $default, { + TResult Function(DiaryStateLoading value)? loading, + TResult Function(DiaryStateLoaded value)? loaded, + TResult Function(DiaryStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DiaryStateCopyWith<$Res> { + factory $DiaryStateCopyWith( + DiaryState value, $Res Function(DiaryState) then) = + _$DiaryStateCopyWithImpl<$Res, DiaryState>; +} + +/// @nodoc +class _$DiaryStateCopyWithImpl<$Res, $Val extends DiaryState> + implements $DiaryStateCopyWith<$Res> { + _$DiaryStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$DiaryStateImplCopyWith<$Res> { + factory _$$DiaryStateImplCopyWith( + _$DiaryStateImpl value, $Res Function(_$DiaryStateImpl) then) = + __$$DiaryStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$DiaryStateImplCopyWithImpl<$Res> + extends _$DiaryStateCopyWithImpl<$Res, _$DiaryStateImpl> + implements _$$DiaryStateImplCopyWith<$Res> { + __$$DiaryStateImplCopyWithImpl( + _$DiaryStateImpl _value, $Res Function(_$DiaryStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$DiaryStateImpl implements _DiaryState { + const _$DiaryStateImpl(); + + @override + String toString() { + return 'DiaryState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$DiaryStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function(int? id) loading, + required TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted) + loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function(int? id)? loading, + TResult? Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function(int? id)? loading, + TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_DiaryState value) $default, { + required TResult Function(DiaryStateLoading value) loading, + required TResult Function(DiaryStateLoaded value) loaded, + required TResult Function(DiaryStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_DiaryState value)? $default, { + TResult? Function(DiaryStateLoading value)? loading, + TResult? Function(DiaryStateLoaded value)? loaded, + TResult? Function(DiaryStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_DiaryState value)? $default, { + TResult Function(DiaryStateLoading value)? loading, + TResult Function(DiaryStateLoaded value)? loaded, + TResult Function(DiaryStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _DiaryState implements DiaryState { + const factory _DiaryState() = _$DiaryStateImpl; +} + +/// @nodoc +abstract class _$$DiaryStateLoadingImplCopyWith<$Res> { + factory _$$DiaryStateLoadingImplCopyWith(_$DiaryStateLoadingImpl value, + $Res Function(_$DiaryStateLoadingImpl) then) = + __$$DiaryStateLoadingImplCopyWithImpl<$Res>; + @useResult + $Res call({int? id}); +} + +/// @nodoc +class __$$DiaryStateLoadingImplCopyWithImpl<$Res> + extends _$DiaryStateCopyWithImpl<$Res, _$DiaryStateLoadingImpl> + implements _$$DiaryStateLoadingImplCopyWith<$Res> { + __$$DiaryStateLoadingImplCopyWithImpl(_$DiaryStateLoadingImpl _value, + $Res Function(_$DiaryStateLoadingImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + }) { + return _then(_$DiaryStateLoadingImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int?, + )); + } +} + +/// @nodoc + +class _$DiaryStateLoadingImpl implements DiaryStateLoading { + const _$DiaryStateLoadingImpl({this.id}); + + @override + final int? id; + + @override + String toString() { + return 'DiaryState.loading(id: $id)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DiaryStateLoadingImpl && + (identical(other.id, id) || other.id == id)); + } + + @override + int get hashCode => Object.hash(runtimeType, id); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DiaryStateLoadingImplCopyWith<_$DiaryStateLoadingImpl> get copyWith => + __$$DiaryStateLoadingImplCopyWithImpl<_$DiaryStateLoadingImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function(int? id) loading, + required TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted) + loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(id); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function(int? id)? loading, + TResult? Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(id); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function(int? id)? loading, + TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(id); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_DiaryState value) $default, { + required TResult Function(DiaryStateLoading value) loading, + required TResult Function(DiaryStateLoaded value) loaded, + required TResult Function(DiaryStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_DiaryState value)? $default, { + TResult? Function(DiaryStateLoading value)? loading, + TResult? Function(DiaryStateLoaded value)? loaded, + TResult? Function(DiaryStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_DiaryState value)? $default, { + TResult Function(DiaryStateLoading value)? loading, + TResult Function(DiaryStateLoaded value)? loaded, + TResult Function(DiaryStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class DiaryStateLoading implements DiaryState { + const factory DiaryStateLoading({final int? id}) = _$DiaryStateLoadingImpl; + + int? get id; + @JsonKey(ignore: true) + _$$DiaryStateLoadingImplCopyWith<_$DiaryStateLoadingImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$DiaryStateLoadedImplCopyWith<$Res> { + factory _$$DiaryStateLoadedImplCopyWith(_$DiaryStateLoadedImpl value, + $Res Function(_$DiaryStateLoadedImpl) then) = + __$$DiaryStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call( + {DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted}); + + $DiaryModelCopyWith<$Res> get diary; + $MealCopyWith<$Res> get currentMeal; + $SelectionPopupModelCopyWith<$Res> get portionController; +} + +/// @nodoc +class __$$DiaryStateLoadedImplCopyWithImpl<$Res> + extends _$DiaryStateCopyWithImpl<$Res, _$DiaryStateLoadedImpl> + implements _$$DiaryStateLoadedImplCopyWith<$Res> { + __$$DiaryStateLoadedImplCopyWithImpl(_$DiaryStateLoadedImpl _value, + $Res Function(_$DiaryStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? diary = null, + Object? diaryDate = freezed, + Object? recommendedChartValues = null, + Object? consumedChartValues = null, + Object? portions = null, + Object? mealList = null, + Object? portionList = null, + Object? autocompleteList = null, + Object? chartData = null, + Object? currentMeal = null, + Object? portionController = null, + Object? wakeupController = null, + Object? retireController = null, + Object? mealTimeController = freezed, + Object? commentController = null, + Object? product_nameController = null, + Object? productQuantityController = null, + Object? caloriesController = null, + Object? fatsController = null, + Object? proteinsController = null, + Object? carbsController = null, + Object? selectedMood = null, + Object? selectedSatiety = null, + Object? wakeupExpanded = null, + Object? moderationExpanded = null, + Object? moodExpanded = null, + Object? isLoading = null, + Object? isAdded = null, + Object? chartDataCounted = freezed, + }) { + return _then(_$DiaryStateLoadedImpl( + diary: null == diary + ? _value.diary + : diary // ignore: cast_nullable_to_non_nullable + as DiaryModel, + diaryDate: freezed == diaryDate + ? _value.diaryDate + : diaryDate // ignore: cast_nullable_to_non_nullable + as String?, + recommendedChartValues: null == recommendedChartValues + ? _value._recommendedChartValues + : recommendedChartValues // ignore: cast_nullable_to_non_nullable + as List, + consumedChartValues: null == consumedChartValues + ? _value._consumedChartValues + : consumedChartValues // ignore: cast_nullable_to_non_nullable + as List, + portions: null == portions + ? _value._portions + : portions // ignore: cast_nullable_to_non_nullable + as List, + mealList: null == mealList + ? _value._mealList + : mealList // ignore: cast_nullable_to_non_nullable + as List, + portionList: null == portionList + ? _value._portionList + : portionList // ignore: cast_nullable_to_non_nullable + as List, + autocompleteList: null == autocompleteList + ? _value._autocompleteList + : autocompleteList // ignore: cast_nullable_to_non_nullable + as List, + chartData: null == chartData + ? _value._chartData + : chartData // ignore: cast_nullable_to_non_nullable + as Map, + currentMeal: null == currentMeal + ? _value.currentMeal + : currentMeal // ignore: cast_nullable_to_non_nullable + as Meal, + portionController: null == portionController + ? _value.portionController + : portionController // ignore: cast_nullable_to_non_nullable + as SelectionPopupModel, + wakeupController: null == wakeupController + ? _value.wakeupController + : wakeupController // ignore: cast_nullable_to_non_nullable + as TimeOfDay, + retireController: null == retireController + ? _value.retireController + : retireController // ignore: cast_nullable_to_non_nullable + as TimeOfDay, + mealTimeController: freezed == mealTimeController + ? _value.mealTimeController + : mealTimeController // ignore: cast_nullable_to_non_nullable + as TimeOfDay?, + commentController: null == commentController + ? _value.commentController + : commentController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + product_nameController: null == product_nameController + ? _value.product_nameController + : product_nameController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + productQuantityController: null == productQuantityController + ? _value.productQuantityController + : productQuantityController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + caloriesController: null == caloriesController + ? _value.caloriesController + : caloriesController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + fatsController: null == fatsController + ? _value.fatsController + : fatsController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + proteinsController: null == proteinsController + ? _value.proteinsController + : proteinsController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + carbsController: null == carbsController + ? _value.carbsController + : carbsController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + selectedMood: null == selectedMood + ? _value.selectedMood + : selectedMood // ignore: cast_nullable_to_non_nullable + as int, + selectedSatiety: null == selectedSatiety + ? _value.selectedSatiety + : selectedSatiety // ignore: cast_nullable_to_non_nullable + as int, + wakeupExpanded: null == wakeupExpanded + ? _value.wakeupExpanded + : wakeupExpanded // ignore: cast_nullable_to_non_nullable + as bool, + moderationExpanded: null == moderationExpanded + ? _value.moderationExpanded + : moderationExpanded // ignore: cast_nullable_to_non_nullable + as bool, + moodExpanded: null == moodExpanded + ? _value.moodExpanded + : moodExpanded // ignore: cast_nullable_to_non_nullable + as bool, + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, + isAdded: null == isAdded + ? _value.isAdded + : isAdded // ignore: cast_nullable_to_non_nullable + as bool, + chartDataCounted: freezed == chartDataCounted + ? _value._chartDataCounted + : chartDataCounted // ignore: cast_nullable_to_non_nullable + as List?, + )); + } + + @override + @pragma('vm:prefer-inline') + $DiaryModelCopyWith<$Res> get diary { + return $DiaryModelCopyWith<$Res>(_value.diary, (value) { + return _then(_value.copyWith(diary: value)); + }); + } + + @override + @pragma('vm:prefer-inline') + $MealCopyWith<$Res> get currentMeal { + return $MealCopyWith<$Res>(_value.currentMeal, (value) { + return _then(_value.copyWith(currentMeal: value)); + }); + } + + @override + @pragma('vm:prefer-inline') + $SelectionPopupModelCopyWith<$Res> get portionController { + return $SelectionPopupModelCopyWith<$Res>(_value.portionController, + (value) { + return _then(_value.copyWith(portionController: value)); + }); + } +} + +/// @nodoc + +class _$DiaryStateLoadedImpl implements DiaryStateLoaded { + const _$DiaryStateLoadedImpl( + {required this.diary, + this.diaryDate, + required final List recommendedChartValues, + required final List consumedChartValues, + required final List portions, + required final List mealList, + required final List portionList, + required final List autocompleteList, + required final Map chartData, + required this.currentMeal, + required this.portionController, + required this.wakeupController, + required this.retireController, + this.mealTimeController, + required this.commentController, + required this.product_nameController, + required this.productQuantityController, + required this.caloriesController, + required this.fatsController, + required this.proteinsController, + required this.carbsController, + required this.selectedMood, + required this.selectedSatiety, + required this.wakeupExpanded, + required this.moderationExpanded, + required this.moodExpanded, + required this.isLoading, + required this.isAdded, + final List? chartDataCounted}) + : _recommendedChartValues = recommendedChartValues, + _consumedChartValues = consumedChartValues, + _portions = portions, + _mealList = mealList, + _portionList = portionList, + _autocompleteList = autocompleteList, + _chartData = chartData, + _chartDataCounted = chartDataCounted; + + @override + final DiaryModel diary; + @override + final String? diaryDate; + final List _recommendedChartValues; + @override + List get recommendedChartValues { + if (_recommendedChartValues is EqualUnmodifiableListView) + return _recommendedChartValues; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_recommendedChartValues); + } + + final List _consumedChartValues; + @override + List get consumedChartValues { + if (_consumedChartValues is EqualUnmodifiableListView) + return _consumedChartValues; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_consumedChartValues); + } + + final List _portions; + @override + List get portions { + if (_portions is EqualUnmodifiableListView) return _portions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_portions); + } + + final List _mealList; + @override + List get mealList { + if (_mealList is EqualUnmodifiableListView) return _mealList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_mealList); + } + + final List _portionList; + @override + List get portionList { + if (_portionList is EqualUnmodifiableListView) return _portionList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_portionList); + } + + final List _autocompleteList; + @override + List get autocompleteList { + if (_autocompleteList is EqualUnmodifiableListView) + return _autocompleteList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_autocompleteList); + } + + final Map _chartData; + @override + Map get chartData { + if (_chartData is EqualUnmodifiableMapView) return _chartData; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_chartData); + } + + @override + final Meal currentMeal; + @override + final SelectionPopupModel portionController; + @override + final TimeOfDay wakeupController; + @override + final TimeOfDay retireController; + @override + final TimeOfDay? mealTimeController; + @override + final TextEditingController commentController; + @override + final TextEditingController product_nameController; + @override + final TextEditingController productQuantityController; + @override + final TextEditingController caloriesController; + @override + final TextEditingController fatsController; + @override + final TextEditingController proteinsController; + @override + final TextEditingController carbsController; + @override + final int selectedMood; + @override + final int selectedSatiety; + @override + final bool wakeupExpanded; + @override + final bool moderationExpanded; + @override + final bool moodExpanded; + @override + final bool isLoading; + @override + final bool isAdded; + final List? _chartDataCounted; + @override + List? get chartDataCounted { + final value = _chartDataCounted; + if (value == null) return null; + if (_chartDataCounted is EqualUnmodifiableListView) + return _chartDataCounted; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'DiaryState.loaded(diary: $diary, diaryDate: $diaryDate, recommendedChartValues: $recommendedChartValues, consumedChartValues: $consumedChartValues, portions: $portions, mealList: $mealList, portionList: $portionList, autocompleteList: $autocompleteList, chartData: $chartData, currentMeal: $currentMeal, portionController: $portionController, wakeupController: $wakeupController, retireController: $retireController, mealTimeController: $mealTimeController, commentController: $commentController, product_nameController: $product_nameController, productQuantityController: $productQuantityController, caloriesController: $caloriesController, fatsController: $fatsController, proteinsController: $proteinsController, carbsController: $carbsController, selectedMood: $selectedMood, selectedSatiety: $selectedSatiety, wakeupExpanded: $wakeupExpanded, moderationExpanded: $moderationExpanded, moodExpanded: $moodExpanded, isLoading: $isLoading, isAdded: $isAdded, chartDataCounted: $chartDataCounted)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DiaryStateLoadedImpl && + (identical(other.diary, diary) || other.diary == diary) && + (identical(other.diaryDate, diaryDate) || + other.diaryDate == diaryDate) && + const DeepCollectionEquality().equals( + other._recommendedChartValues, _recommendedChartValues) && + const DeepCollectionEquality() + .equals(other._consumedChartValues, _consumedChartValues) && + const DeepCollectionEquality().equals(other._portions, _portions) && + const DeepCollectionEquality().equals(other._mealList, _mealList) && + const DeepCollectionEquality() + .equals(other._portionList, _portionList) && + const DeepCollectionEquality() + .equals(other._autocompleteList, _autocompleteList) && + const DeepCollectionEquality() + .equals(other._chartData, _chartData) && + (identical(other.currentMeal, currentMeal) || + other.currentMeal == currentMeal) && + (identical(other.portionController, portionController) || + other.portionController == portionController) && + (identical(other.wakeupController, wakeupController) || + other.wakeupController == wakeupController) && + (identical(other.retireController, retireController) || + other.retireController == retireController) && + (identical(other.mealTimeController, mealTimeController) || + other.mealTimeController == mealTimeController) && + (identical(other.commentController, commentController) || + other.commentController == commentController) && + (identical(other.product_nameController, product_nameController) || + other.product_nameController == product_nameController) && + (identical(other.productQuantityController, + productQuantityController) || + other.productQuantityController == productQuantityController) && + (identical(other.caloriesController, caloriesController) || + other.caloriesController == caloriesController) && + (identical(other.fatsController, fatsController) || + other.fatsController == fatsController) && + (identical(other.proteinsController, proteinsController) || + other.proteinsController == proteinsController) && + (identical(other.carbsController, carbsController) || + other.carbsController == carbsController) && + (identical(other.selectedMood, selectedMood) || + other.selectedMood == selectedMood) && + (identical(other.selectedSatiety, selectedSatiety) || + other.selectedSatiety == selectedSatiety) && + (identical(other.wakeupExpanded, wakeupExpanded) || + other.wakeupExpanded == wakeupExpanded) && + (identical(other.moderationExpanded, moderationExpanded) || + other.moderationExpanded == moderationExpanded) && + (identical(other.moodExpanded, moodExpanded) || + other.moodExpanded == moodExpanded) && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading) && + (identical(other.isAdded, isAdded) || other.isAdded == isAdded) && + const DeepCollectionEquality() + .equals(other._chartDataCounted, _chartDataCounted)); + } + + @override + int get hashCode => Object.hashAll([ + runtimeType, + diary, + diaryDate, + const DeepCollectionEquality().hash(_recommendedChartValues), + const DeepCollectionEquality().hash(_consumedChartValues), + const DeepCollectionEquality().hash(_portions), + const DeepCollectionEquality().hash(_mealList), + const DeepCollectionEquality().hash(_portionList), + const DeepCollectionEquality().hash(_autocompleteList), + const DeepCollectionEquality().hash(_chartData), + currentMeal, + portionController, + wakeupController, + retireController, + mealTimeController, + commentController, + product_nameController, + productQuantityController, + caloriesController, + fatsController, + proteinsController, + carbsController, + selectedMood, + selectedSatiety, + wakeupExpanded, + moderationExpanded, + moodExpanded, + isLoading, + isAdded, + const DeepCollectionEquality().hash(_chartDataCounted) + ]); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DiaryStateLoadedImplCopyWith<_$DiaryStateLoadedImpl> get copyWith => + __$$DiaryStateLoadedImplCopyWithImpl<_$DiaryStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function(int? id) loading, + required TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted) + loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded( + diary, + diaryDate, + recommendedChartValues, + consumedChartValues, + portions, + mealList, + portionList, + autocompleteList, + chartData, + currentMeal, + portionController, + wakeupController, + retireController, + mealTimeController, + commentController, + product_nameController, + productQuantityController, + caloriesController, + fatsController, + proteinsController, + carbsController, + selectedMood, + selectedSatiety, + wakeupExpanded, + moderationExpanded, + moodExpanded, + isLoading, + isAdded, + chartDataCounted); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function(int? id)? loading, + TResult? Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call( + diary, + diaryDate, + recommendedChartValues, + consumedChartValues, + portions, + mealList, + portionList, + autocompleteList, + chartData, + currentMeal, + portionController, + wakeupController, + retireController, + mealTimeController, + commentController, + product_nameController, + productQuantityController, + caloriesController, + fatsController, + proteinsController, + carbsController, + selectedMood, + selectedSatiety, + wakeupExpanded, + moderationExpanded, + moodExpanded, + isLoading, + isAdded, + chartDataCounted); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function(int? id)? loading, + TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded( + diary, + diaryDate, + recommendedChartValues, + consumedChartValues, + portions, + mealList, + portionList, + autocompleteList, + chartData, + currentMeal, + portionController, + wakeupController, + retireController, + mealTimeController, + commentController, + product_nameController, + productQuantityController, + caloriesController, + fatsController, + proteinsController, + carbsController, + selectedMood, + selectedSatiety, + wakeupExpanded, + moderationExpanded, + moodExpanded, + isLoading, + isAdded, + chartDataCounted); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_DiaryState value) $default, { + required TResult Function(DiaryStateLoading value) loading, + required TResult Function(DiaryStateLoaded value) loaded, + required TResult Function(DiaryStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_DiaryState value)? $default, { + TResult? Function(DiaryStateLoading value)? loading, + TResult? Function(DiaryStateLoaded value)? loaded, + TResult? Function(DiaryStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_DiaryState value)? $default, { + TResult Function(DiaryStateLoading value)? loading, + TResult Function(DiaryStateLoaded value)? loaded, + TResult Function(DiaryStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class DiaryStateLoaded implements DiaryState { + const factory DiaryStateLoaded( + {required final DiaryModel diary, + final String? diaryDate, + required final List recommendedChartValues, + required final List consumedChartValues, + required final List portions, + required final List mealList, + required final List portionList, + required final List autocompleteList, + required final Map chartData, + required final Meal currentMeal, + required final SelectionPopupModel portionController, + required final TimeOfDay wakeupController, + required final TimeOfDay retireController, + final TimeOfDay? mealTimeController, + required final TextEditingController commentController, + required final TextEditingController product_nameController, + required final TextEditingController productQuantityController, + required final TextEditingController caloriesController, + required final TextEditingController fatsController, + required final TextEditingController proteinsController, + required final TextEditingController carbsController, + required final int selectedMood, + required final int selectedSatiety, + required final bool wakeupExpanded, + required final bool moderationExpanded, + required final bool moodExpanded, + required final bool isLoading, + required final bool isAdded, + final List? chartDataCounted}) = _$DiaryStateLoadedImpl; + + DiaryModel get diary; + String? get diaryDate; + List get recommendedChartValues; + List get consumedChartValues; + List get portions; + List get mealList; + List get portionList; + List get autocompleteList; + Map get chartData; + Meal get currentMeal; + SelectionPopupModel get portionController; + TimeOfDay get wakeupController; + TimeOfDay get retireController; + TimeOfDay? get mealTimeController; + TextEditingController get commentController; + TextEditingController get product_nameController; + TextEditingController get productQuantityController; + TextEditingController get caloriesController; + TextEditingController get fatsController; + TextEditingController get proteinsController; + TextEditingController get carbsController; + int get selectedMood; + int get selectedSatiety; + bool get wakeupExpanded; + bool get moderationExpanded; + bool get moodExpanded; + bool get isLoading; + bool get isAdded; + List? get chartDataCounted; + @JsonKey(ignore: true) + _$$DiaryStateLoadedImplCopyWith<_$DiaryStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$DiaryStateErrorImplCopyWith<$Res> { + factory _$$DiaryStateErrorImplCopyWith(_$DiaryStateErrorImpl value, + $Res Function(_$DiaryStateErrorImpl) then) = + __$$DiaryStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$DiaryStateErrorImplCopyWithImpl<$Res> + extends _$DiaryStateCopyWithImpl<$Res, _$DiaryStateErrorImpl> + implements _$$DiaryStateErrorImplCopyWith<$Res> { + __$$DiaryStateErrorImplCopyWithImpl( + _$DiaryStateErrorImpl _value, $Res Function(_$DiaryStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$DiaryStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$DiaryStateErrorImpl implements DiaryStateError { + const _$DiaryStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'DiaryState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DiaryStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DiaryStateErrorImplCopyWith<_$DiaryStateErrorImpl> get copyWith => + __$$DiaryStateErrorImplCopyWithImpl<_$DiaryStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function(int? id) loading, + required TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted) + loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function(int? id)? loading, + TResult? Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function(int? id)? loading, + TResult Function( + DiaryModel diary, + String? diaryDate, + List recommendedChartValues, + List consumedChartValues, + List portions, + List mealList, + List portionList, + List autocompleteList, + Map chartData, + Meal currentMeal, + SelectionPopupModel portionController, + TimeOfDay wakeupController, + TimeOfDay retireController, + TimeOfDay? mealTimeController, + TextEditingController commentController, + TextEditingController product_nameController, + TextEditingController productQuantityController, + TextEditingController caloriesController, + TextEditingController fatsController, + TextEditingController proteinsController, + TextEditingController carbsController, + int selectedMood, + int selectedSatiety, + bool wakeupExpanded, + bool moderationExpanded, + bool moodExpanded, + bool isLoading, + bool isAdded, + List? chartDataCounted)? + loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_DiaryState value) $default, { + required TResult Function(DiaryStateLoading value) loading, + required TResult Function(DiaryStateLoaded value) loaded, + required TResult Function(DiaryStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_DiaryState value)? $default, { + TResult? Function(DiaryStateLoading value)? loading, + TResult? Function(DiaryStateLoaded value)? loaded, + TResult? Function(DiaryStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_DiaryState value)? $default, { + TResult Function(DiaryStateLoading value)? loading, + TResult Function(DiaryStateLoaded value)? loaded, + TResult Function(DiaryStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class DiaryStateError implements DiaryState { + const factory DiaryStateError({required final String errorMessage}) = + _$DiaryStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$DiaryStateErrorImplCopyWith<_$DiaryStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/presentation/pages/diary_recommendations_scree.dart b/lib/features/diary/presentation/pages/diary_recommendations_scree.dart new file mode 100644 index 0000000..b2dcfca --- /dev/null +++ b/lib/features/diary/presentation/pages/diary_recommendations_scree.dart @@ -0,0 +1,116 @@ +// ignore_for_file: unused_local_variable + +import 'package:eatvio_app/features/diary/models/portion.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; +import 'package:eatvio_app/core/app_export.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; + +// ignore: must_be_immutable +class DiaryRecommendationsScreen extends StatelessWidget { + final String? diary_recommendationsID; + + const DiaryRecommendationsScreen({ + this.diary_recommendationsID, + super.key, + }); + + Widget build(BuildContext context) { + if (diary_recommendationsID != "0") { + context.read().add(LoadDiaryById(diary_recommendationsID)); + } + return BlocBuilder( + builder: (context, state) { + if (state is DiaryStateLoaded) { + return _buildDiaryRecommendations(context, state); + } else if (state is DiaryStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } else if (state is DiaryStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text("Неопределенная ошибка"), + ), + ), + ); + }, + ); + } + + Widget _buildDiaryRecommendations( + BuildContext context, DiaryStateLoaded state) { + final Portion product = + new Portion(id: 1, product_name: "", quantity: 1, portion: ""); + return Stack( + alignment: Alignment.bottomCenter, + children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + backgroundColor: Color.fromARGB(255, 240, 242, 245), + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 5.v), + child: Column( + children: [ + Scaffold( + appBar: AppBar( + title: Text(product.product_name), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Название продукта: ${product.product_name}', + style: TextStyle(fontSize: 24)), + SizedBox(height: 16), + Text( + 'Количество: ${product.quantity} ${product.portion}', + style: TextStyle(fontSize: 18)), + // Добавьте другие детали о продукте по необходимости + ], + ), + ), + ) + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart new file mode 100644 index 0000000..74a00ed --- /dev/null +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -0,0 +1,1153 @@ +// ignore_for_file: unused_local_variable + +import 'package:carousel_slider_plus/carousel_slider_plus.dart'; +import 'package:eatvio_app/features/diary/models/diary_model.dart'; +import 'package:eatvio_app/features/diary/models/meal.dart'; +import 'package:eatvio_app/features/diary/models/photo.dart'; +import 'package:eatvio_app/features/diary/models/portion.dart'; +import 'package:eatvio_app/features/diary/models/product.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; +import 'package:eatvio_app/widgets/custom_edit_drop_down.dart'; +import 'package:eatvio_app/widgets/custom_scale_element.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; + +// ignore: must_be_immutable +class DiaryScreen extends StatelessWidget { + final String? diaryID; + + const DiaryScreen({ + this.diaryID, + super.key, + }); + + Widget build(BuildContext context) { + if (diaryID != "0") { + context.read().add(LoadDiaryById(diaryID)); + } + return BlocBuilder( + builder: (context, state) { + if (state is DiaryStateLoaded) { + return _buildDiary(context, state); + } else if (state is DiaryStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } else if (state is DiaryStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text("Неопределенная ошибка"), + ), + ), + ); + }, + ); + } + + Widget _buildDiary(BuildContext context, DiaryStateLoaded state) { + return RefreshIndicator( + onRefresh: refreshPage(context), + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + backgroundColor: Color.fromARGB(255, 240, 242, 245), + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 5.v), + child: Column( + children: [ + _buildHeaderRow(context, state), + SizedBox(height: 8.v), + _buildWakupRetire(context, state), + SizedBox(height: 8.v), + _buildMeal(context, state), + SizedBox(height: 8.v), + _buildMood(context, state), + SizedBox(height: 8.v), + _buildNutritionChart(context, state), + SizedBox(height: 8.v), + // _buildComment(context, state), + // SizedBox(height: 8.v), + _buildEndDay(context), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ); + } + + _buildNutritionChart(BuildContext context, DiaryStateLoaded state) { + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Column( + children: [ + Text( + "Ваш КБЖУ", + style: theme.textTheme.titleMedium, + textAlign: TextAlign.center, + ), + Text( + "от дневной суточной нормы", + ), + Transform.rotate( + angle: -1.5708, + child: ClipRect( + child: Align( + alignment: Alignment.centerRight, + widthFactor: 0.5, + child: SfCircularChart( + series: [ + RadialBarSeries( + dataSource: state.chartDataCounted, + xValueMapper: (NutritionData data, _) => data.category, + yValueMapper: (NutritionData data, _) => data.nutrition, + pointColorMapper: (NutritionData data, _) => data.color, + trackColor: Color.fromRGBO(59, 130, 246, 1), + trackOpacity: 0.1, + gap: "8%", + radius: "110%", + innerRadius: + '20%', // Измените значение по вашему усмотрению + ) + ], + ), + ), + )), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(style: theme.textTheme.titleMedium, 'Углеводы'), + Text(style: theme.textTheme.titleMedium, 'Жиры'), + Text(style: theme.textTheme.titleMedium, 'Белки'), + Text(style: theme.textTheme.titleMedium, 'Калории'), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '${state.chartData['dailyNutritionIntake']['carbohydrates'].toStringAsFixed(1)} из ${state.chartData['dailyNutritionRecommendation']['carbohydrates'].toStringAsFixed(1)} грамм'), + SizedBox(height: 8.v), + Text( + '${state.chartData['dailyNutritionIntake']['fats'].toStringAsFixed(1)} из ${state.chartData['dailyNutritionRecommendation']['fats'].toStringAsFixed(1)} грамм'), + SizedBox(height: 8.v), + Text( + '${state.chartData['dailyNutritionIntake']['proteins'].toStringAsFixed(1)} из ${state.chartData['dailyNutritionRecommendation']['proteins'].toStringAsFixed(1)} грамм'), + SizedBox(height: 8.v), + Text( + '${state.chartData['dailyNutritionIntake']['energy'].toStringAsFixed(1)} из ${state.chartData['dailyNutritionRecommendation']['energy'].toStringAsFixed(1)} Ккал'), + ], + ), + ], + ), + ], + ), + ); + } + + _buildEndDay(BuildContext context) { + return Container( + height: 48, + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.only(left: 4, right: 4), + child: FloatingActionButton.extended( + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: appTheme.blueA400, + onPressed: () => onFinishDayPressed, + label: Text( + 'Закончить день', + style: theme.textTheme.titleSmall, + ), + ), + ); + } + + refreshPage(BuildContext context) { + return () async { + context.read().add(RefreshEvent()); + }; + } + + /// Section Widget + _buildHeaderRow(BuildContext context, DiaryStateLoaded state) { + final day = state.diary.id; + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(top: 1.v), + child: Column( + children: [ + Align( + alignment: Alignment.centerRight, + child: Text( + "$day день", + style: CustomTextStyles.titleMediumBlack, + ), + ), + ], + ), + ), + ], + ), + ); + } + + /// Section Widget + _buildAddProduct(BuildContext context, DiaryState state) { + return Container( + height: 48, + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.only(left: 4, right: 4), + child: FloatingActionButton.extended( + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: appTheme.blueA400, + onPressed: () => addProduct, + label: Text( + 'Добавить продукт', + style: theme.textTheme.titleSmall, + ), + ), + ); + } + + addProduct(BuildContext context) { + return () { + context.read().add(AddPortionEvent()); + }; + } + + /// Section Widget + _buildAddPhoto(BuildContext context, DiaryStateLoaded state) { + bool isLoading = state.isLoading; + if (state.currentMeal.photos.isEmpty) + return GestureDetector( + onTap: addImage(context, isLoading), + child: Stack( + children: [ + if (!isLoading) + Container( + margin: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 40.h, + vertical: 80.v, + ), + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only( + left: 7.h, + top: 5.v, + ), + child: Text( + "Добавить фото", + selectionColor: appTheme.blueA400, + ), + ), + Spacer(), + Icon( + Icons.photo_library, + color: appTheme.blueGray300, + ), + ], + ), + ), + if (isLoading) + Container( + margin: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 40.h, + vertical: 80.v, + ), + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Center( + child: CircularProgressIndicator( + color: appTheme + .blueGray300), // Замените на свой прелоадер при необходимости + ), + ), + ], + ), + ); + else + return Container(); + } + + addImage(BuildContext context, bool isLoading) { + if (!isLoading) { + return () async { + final picker = ImagePicker(); + List? images = await picker.pickMultiImage(); + if (images.isNotEmpty) { + for (var image in images) { + context.read().add(UploadImages(image)); + } + } + }; + } + } + + _buildMeal(BuildContext context, DiaryStateLoaded state) { + final digitsOnly = FilteringTextInputFormatter.digitsOnly; + List _options = + state.autocompleteList.map((Product item) => item.name).toList(); + FocusNode focusNodeName = FocusNode(); + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Время приема пищи", + style: CustomTextStyles.bodyMediumBlack900, + ), + Expanded( + // Adding Expanded widget + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width - 260, + ), + child: GestureDetector( + onTap: () => _selectMealTime(context, state), + child: AbsorbPointer( + child: CustomTextFormField( + hintText: state.mealTimeController + ?.format(context) + .toString(), + autofocus: false, + ), + ), + ), + ), + ), + ), + ], + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: BlocSelector( + selector: (state) { + if (state is DiaryStateLoaded) + return state.diary; + else + return null; + }, + builder: (context, diary) { + return CustomDropDown( + items: state.mealList, + contentPadding: EdgeInsets.symmetric( + horizontal: 10.h, + vertical: 9.v, + ), + defaultValue: state.mealList[0], + onChanged: changeMeal(context, state), + ); + }, + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: RawAutocomplete( + optionsBuilder: buildOptions(_options), + fieldViewBuilder: ( + BuildContext context, + TextEditingController productEditingController, + FocusNode focusNodeName, + VoidCallback onFieldSubmitted, + ) { + if (state.isAdded) { + print("Clear"); + } + return CustomTextFormField( + hintText: "Введите название продукта", + controller: productEditingController, + focusNode: focusNodeName, + onChanged: getAutocomplete(context, focusNodeName), + ); + }, + optionsViewBuilder: ( + BuildContext context, + AutocompleteOnSelected onSelected, + Iterable options, + ) { + return Align( + alignment: Alignment.topLeft, + child: Material( + elevation: 4.0, + child: SizedBox( + height: 200.0, + child: ListView.builder( + padding: const EdgeInsets.all(8.0), + itemCount: options.length, + itemBuilder: (BuildContext context, int index) { + final String option = options.elementAt(index); + return GestureDetector( + onTap: selectProduct(onSelected, option, state), + child: ListTile( + title: Text(option), + ), + ); + }, + ), + ), + ), + ); + }, + ), + ), + SizedBox(height: 20.v), + if (state.moderationExpanded) + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: GestureDetector( + onTap: () => openCaloriesDialog(context, state), + child: Text("Отправить на модерацию"), + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CustomTextFormField( + width: 150.h, + hintText: "Кол-во", + textInputAction: TextInputAction.done, + // focusNode: focusNodeQuantity, + controller: state.productQuantityController, + keyboardType: TextInputType.number, + inputFormatters: [digitsOnly], + ), + Padding( + padding: EdgeInsets.only(left: 30.h), + child: BlocSelector( + selector: (state) { + if (state is DiaryStateLoaded) { + return state.diary; + } else + return null; + }, + builder: (context, diary) { + return CustomDropDown( + items: state.portionList, + defaultValue: state.portionController, + onChanged: changePortion(context, state), + ); + }, + ), + ), + ], + ), + ), + ), + SizedBox(height: 24.v), + _buildAddProduct(context, state), + SizedBox(height: 24.v), + ...state.portions + .map((portion) => _buildProduct(context, portion)) + .toList(), + SizedBox(height: 24.v), + _buildCarousel(context, state), + SizedBox(height: 24.v), + _buildAddPhoto(context, state), + SizedBox(height: 24.v), + Text( + "Ваша сытость после приёма пищи", + style: CustomTextStyles.bodyMediumBlack900, + ), + SizedBox(height: 15.v), + BlocBuilder( + builder: (context, state) { + if (state is DiaryStateLoaded) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("😭"), + ScaleElement( + color: Colors.red, + isSelected: state.selectedSatiety == 0, + onTap: changeSatiety(context, 0), + ), + ScaleElement( + color: Colors.orange, + isSelected: state.selectedSatiety == 1, + onTap: changeSatiety(context, 1), + ), + ScaleElement( + color: Colors.yellow, + isSelected: state.selectedSatiety == 2, + onTap: changeSatiety(context, 2), + ), + ScaleElement( + color: Colors.lime, + isSelected: state.selectedSatiety == 3, + onTap: changeSatiety(context, 3), + ), + ScaleElement( + color: Colors.lightGreen, + isSelected: state.selectedSatiety == 4, + onTap: changeSatiety(context, 4), + ), + ScaleElement( + color: Colors.green, + isSelected: state.selectedSatiety == 5, + onTap: changeSatiety(context, 5), + ), + Text("😊"), + // Остальные элементы шкалы + ], + ); + } else { + return Container(); // Возвращаем пустой контейнер, если состояние не является DiaryState + } + }, + ), + ], + ), + ); + } + + openCaloriesDialog(BuildContext context, DiaryStateLoaded state) { + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: Text('Введите информацию о продукте'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CustomTextFormField( + hintText: "Название", + controller: state.product_nameController, + ), + SizedBox(height: 10.v), + CustomTextFormField( + hintText: "Энергетическая ценность на 100", + keyboardType: TextInputType.number, + controller: state.caloriesController, + ), + SizedBox(height: 10.v), + CustomTextFormField( + hintText: "Белки на 100г", + keyboardType: TextInputType.number, + controller: state.proteinsController, + ), + SizedBox(height: 10.v), + CustomTextFormField( + hintText: "Жиры на 100г", + keyboardType: TextInputType.number, + controller: state.fatsController, + ), + SizedBox(height: 10.v), + CustomTextFormField( + hintText: "Углеводы на 100г", + keyboardType: TextInputType.number, + controller: state.carbsController, + ), + ], + ), + actions: [ + TextButton( + onPressed: popDialog(context), + child: Text('Отмена'), + ), + TextButton( + onPressed: triggerModeration( + context, + state.product_nameController.text, + state.caloriesController.text, + state.proteinsController.text, + state.fatsController.text, + state.carbsController.text, + dialogContext, + ), + child: Text('Отправить'), + ), + ], + ); + }, + ); + } + + triggerModeration( + BuildContext context, + String name, + String energyOn100gr, + String proteinsOn100gr, + String fatsOn100gr, + String carbohydratesOn100gr, + BuildContext dialogContext, + ) { + return () { + context.read().add( + SendModeration( + name: name, + energyOn100gr: energyOn100gr, + proteinsOn100gr: proteinsOn100gr, + fatsOn100gr: fatsOn100gr, + carbohydratesOn100gr: carbohydratesOn100gr, + ), + ); + Navigator.of(dialogContext).pop(); + }; + } + + popDialog(BuildContext dialogContext) { + return () { + Navigator.of(dialogContext) + .pop(); // Dismiss the dialog on Cancel button press + }; + } + + changeSatiety(BuildContext context, int satiety) { + return () { + context.read().add(ChangeSatiety(satiety)); + }; + } + + selectProduct(AutocompleteOnSelected onSelected, String option, + DiaryStateLoaded state) { + state.product_nameController.text = option; + return () { + onSelected(option); + }; + } + + getAutocomplete(BuildContext context, FocusNode focusNode) { + return (value) { + if (value.length > 2) { + context.read().add(ProductInput(value)); + } + }; + } + + buildOptions(List _options) { + return (TextEditingValue textEditingValue) { + return _options.where((String option) { + return true; + }); + }; + } + + changeMeal(BuildContext context, DiaryStateLoaded state) { + return (value) { + context.read().add(ChangeMeal(value: value)); + }; + } + + changePortion(BuildContext context, DiaryStateLoaded state) { + return (value) { + context.read().add(ChangePortion(value: value)); + }; + } + + _buildCarousel(BuildContext context, DiaryStateLoaded state) { + if (state.currentMeal.photos.isEmpty) { + return Text("Фото нет"); + } else { + return CarouselSlider( + options: CarouselOptions(height: 200.0), + items: state.currentMeal.photos.map((photo) { + return _buildPhoto(context, photo, state); + }).toList(), + ); + } + } + + _buildProduct(BuildContext context, Portion portion) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 8.h, + vertical: 6.v, + ), + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only( + left: 7.h, + top: 5.v, + ), + child: Text( + portion.product_name.length > 8 + ? portion.product_name.substring(0, 8) + : portion.product_name, + style: CustomTextStyles.titleMedium16, + ), + ), + Padding( + padding: EdgeInsets.only( + left: 20.h, + top: 3.v, + bottom: 3.v, + ), + child: Text( + portion.quantity.toString() + ' ' + portion.portion.toString().tr, + ), + ), + Spacer(), + GestureDetector( + onTap: removePortion(context, portion), + child: Padding( + padding: const EdgeInsets.only(right: 10), + child: Icon( + Icons.close, + color: appTheme.blueGray300, + ), + ), + ), + ], + ), + ); + } + + _buildPhoto(BuildContext context, Photo photo, DiaryStateLoaded state) { + return Stack( + children: [ + Container( + margin: EdgeInsets.symmetric(horizontal: 10.h, vertical: 10.h), + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Image.network( + baseUrl + '/storage/' + photo.path, + fit: BoxFit.cover, // Чтобы изображение занимало весь контейнер + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + height: 50.h, // Высота затемненной области + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.black.withOpacity(0.7), // Цвет затемнения + Colors.transparent, + ], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: Icon(Icons.photo_outlined), + color: Colors.white, + onPressed: addImage(context, state.isLoading), + ), + IconButton( + icon: Icon(Icons.delete_outlined), + color: Colors.white, + onPressed: removePhoto(context, photo), + ), + ], + ), + ), + ), + ], + ); + } + + removePortion(BuildContext context, Portion portion) { + return () { + context.read().add(RemovePortionEvent(portion.id)); + }; + } + + removePhoto(BuildContext context, Photo photo) { + return () { + context + .read() + .add(RemoveImageEvent(photo.id.toString(), photo.path)); + }; + } + + /* _buildComment(BuildContext context, DiaryStateLoaded state) { + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Дополнительная информация для консультанта", + style: theme.textTheme.titleMedium, + textAlign: TextAlign.center, + ), + SizedBox(height: 20.v), + Container( + width: 320.h, + child: CustomTextFormField( + autofocus: false, + hintText: "Введите информацию для консультанта", + maxLines: 7, + borderDecoration: InputBorder.none, + controller: state.commentController, + ), + ), + ], + ), + ); + } */ + + _buildWakupRetire(BuildContext context, DiaryStateLoaded state) { + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Column( + children: [ + GestureDetector( + onTap: toggleWakeup(context), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + r"Подъем \ отход ко сну", + style: CustomTextStyles.bodyMediumBlack900, + ), + Icon(state.wakeupExpanded + ? Icons.arrow_drop_up + : Icons.arrow_drop_down), + ], + ), + ), + if (state.wakeupExpanded) + Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Column( + children: [ + SizedBox(height: 20.v), + GestureDetector( + onTap: () => _selectWakeupTime(context, state), + child: AbsorbPointer( + child: CustomTextFormField( + hintText: + state.wakeupController.format(context).toString(), + prefix: Icon(Icons.sunny), + autofocus: false, + ), + ), + ), + SizedBox(height: 20.v), + GestureDetector( + onTap: () => _selectRetireTime(context, state), + child: AbsorbPointer( + child: CustomTextFormField( + hintText: + state.retireController.format(context).toString(), + prefix: Icon(Icons.bed), + autofocus: false, + ), + ), + ), + SizedBox(height: 20.v), + ], + ), + ), + ], + ), + ); + } + + toggleWakeup(BuildContext context) { + return () { + BlocProvider.of(context).add(ToggleWakeupExpandedEvent()); + }; + } + + /// Section Widget + + Function() onFinishDayPressed(BuildContext context) { + return () { + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: Text("Подтвердите действие"), + content: Text("Вы уверены, что хотите завершить день?"), + actions: [ + TextButton( + child: Text("Отмена"), + onPressed: closeDialog(dialogContext), + ), + TextButton( + child: Text("Подтвердить"), + onPressed: sendFinishDayData(dialogContext, context), + ), + ], + ); + }, + ); + }; + } + + Function() sendFinishDayData( + BuildContext dialogContext, BuildContext context) { + return () { + closeDialog(dialogContext); + context.read().add(FinishDay()); + }; + } + + Function() closeDialog(BuildContext dialogContext) { + return () { + Navigator.of(dialogContext).pop(); + }; + } + + _buildMood(BuildContext context, DiaryStateLoaded state) { + return Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + child: Column( + children: [ + GestureDetector( + onTap: toggleMood(context), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Ваше настроение после приема пищи", + style: CustomTextStyles.bodyMediumBlack900, + ), + Icon(state.moodExpanded + ? Icons.arrow_drop_up + : Icons.arrow_drop_down), + ], + ), + ), + if (state.moodExpanded) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("😭"), + ScaleElement( + color: Colors.red, + isSelected: state.selectedMood == 0, + onTap: changeMood(context, 0), + ), + ScaleElement( + color: Colors.orange, + isSelected: state.selectedMood == 1, + onTap: changeMood(context, 1), + ), + ScaleElement( + color: Colors.yellow, + isSelected: state.selectedMood == 2, + onTap: changeMood(context, 2), + ), + ScaleElement( + color: Colors.lime, + isSelected: state.selectedMood == 3, + onTap: changeMood(context, 3), + ), + ScaleElement( + color: Colors.lightGreen, + isSelected: state.selectedMood == 4, + onTap: changeMood(context, 4), + ), + ScaleElement( + color: Colors.green, + isSelected: state.selectedMood == 5, + onTap: changeMood(context, 5), + ), + Text("😊"), + // Остальные элементы шкалы + ], + ), + ], + ), + ); + } + + changeMood(BuildContext context, int satiety) { + return () { + context.read().add(ChangeMood(satiety)); + }; + } + + toggleMood(BuildContext context) { + return () { + BlocProvider.of(context).add(ToggleMoodExpandedEvent()); + }; + } + + Future _selectWakeupTime( + BuildContext context, DiaryStateLoaded state) async { + final TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: state.wakeupController, + ); + if (pickedTime != null && pickedTime != state.wakeupController) { + context.read().add(WakeupEvent(pickedTime)); + } + } + + Future _selectRetireTime( + BuildContext context, DiaryStateLoaded state) async { + final TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: state.retireController, + ); + if (pickedTime != null && pickedTime != state.retireController) { + context.read().add(RetireEvent(pickedTime)); + } + } + + Future _selectMealTime( + BuildContext context, DiaryStateLoaded state) async { + final TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: state.mealTimeController ?? TimeOfDay.now(), + ); + if (pickedTime != null && pickedTime != state.mealTimeController) { + context.read().add(ChangeMealTime(pickedTime)); + } + } +} + +bool checkConsumedValues( + List recommendedValues, List consumedValues) { + for (int i = 0; i < recommendedValues.length; i++) { + if (consumedValues[i] > recommendedValues[i]) { + // Если хотя бы одно потребленное значение превышает рекомендованное + return true; // Возвращаем false + } + } + // Если ни одно потребленное значение не превышает рекомендованное с соответствующим индексом + return false; // Возвращаем true +} + +List mealsToDropdown(List? meals) { + return meals! + .map((meal) => SelectionPopupModel( + id: meal.id, + title: "Прием пищи ${meal.type}", + isSelected: false, + )) + .toList(); +} diff --git a/lib/features/diary/repositories/diary_repository.dart b/lib/features/diary/repositories/diary_repository.dart new file mode 100644 index 0000000..04a8cad --- /dev/null +++ b/lib/features/diary/repositories/diary_repository.dart @@ -0,0 +1,200 @@ +import 'dart:io'; + +import 'package:eatvio_app/features/diary/models/diary_model.dart'; +import 'package:eatvio_app/features/diary/models/portion.dart'; +import 'package:eatvio_app/features/diary/models/product.dart'; +import 'package:eatvio_app/features/diary/services/diary_service.dart'; + +class DiaryRepository { + final DiaryService diaryService; + + DiaryRepository({required this.diaryService}); + + Future> getDiaryID() async { + try { + return await diaryService.getDiaryID(); + } catch (e) { + rethrow; + } + } + + Future getDiary(int diaryID) async { + try { + return (await diaryService.getDiary(diaryID))['diary']!; + } catch (e) { + rethrow; + } + } + + Future> getChartData(int diaryID) async { + try { + return (await diaryService.getChart(diaryID)); + } catch (e) { + rethrow; + } + } + + Future>> inputProduct(String name) async { + try { + return await diaryService.getInputProduct(name); + } catch (e) { + rethrow; + } + } + + Future changeSatiety(int satiety, int mealID, int diaryID) async { + try { + await diaryService.sendSatietyData( + diaryID, + mealID, + satiety, + ); + } catch (e) { + rethrow; + } + } + + Future changeMood(int mood, int mealID, int diaryID) async { + try { + await diaryService.sendMoodData( + diaryID, + mealID, + mood, + ); + } catch (e) { + rethrow; + } + } + + Future changeWakeup( + int diaryID, + String wakeup, + ) async { + try { + await diaryService.sendWakeupData( + diaryID, + wakeup, + ); + } catch (e) { + rethrow; + } + } + + Future changeRetire( + int diaryID, + String retire, + ) async { + try { + await diaryService.sendWakeupData( + diaryID, + retire, + ); + } catch (e) { + rethrow; + } + } + + Future> addPortion( + int diaryID, + int mealID, + String name, + String product, + int quantity, + ) async { + try { + return await diaryService.sendPortionData( + diaryID, + mealID, + name, + product, + quantity, + ); + } catch (e) { + rethrow; + } + } + + Future> sendModeration( + String name, + String energy_on_100gr, + String proteins_on_100gr, + String fats_on_100gr, + String carbohydrates_on_100gr, + ) async { + try { + return await diaryService.sendModerationData( + name, + double.parse(energy_on_100gr + ".0"), + double.parse(proteins_on_100gr + ".0"), + double.parse(fats_on_100gr + ".0"), + double.parse(carbohydrates_on_100gr + ".0"), + ); + } catch (e) { + rethrow; + } + } + + Future removePortion( + int diaryID, + int mealID, + int portionID, + ) async { + try { + await diaryService.sendRemovePortionData( + diaryID, + mealID, + portionID, + ); + } catch (e) { + rethrow; + } + } + + Future uploadImage( + String path, + int diaryID, + int mealID, + ) async { + try { + File file = File(path); + await diaryService.uploadImage( + diaryID, + mealID, + file, + ); + } catch (e) { + rethrow; + } + } + + Future removeImage( + int diaryID, + int mealID, + int photoID, + String path, + ) async { + try { + await diaryService.sendRemovePhotoData( + diaryID, + mealID, + path, + photoID, + ); + } catch (e) { + rethrow; + } + } + + Future finishDay( + int diaryID, + ) async { + try { + /*final formatter = DateFormat('HH:mm'); + final wakeupString = formatter.format(DateTime(2022, 1, 1, wakeup.hour, wakeup.minute)); + final retireString = formatter.format(DateTime(2022, 1, 1, retire.hour, retire.minute));*/ + await diaryService.sendFinishDay(diaryID); + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/diary/services/diary_service.dart b/lib/features/diary/services/diary_service.dart new file mode 100644 index 0000000..d7fa9a0 --- /dev/null +++ b/lib/features/diary/services/diary_service.dart @@ -0,0 +1,100 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/diary/models/diary_model.dart'; +import 'package:eatvio_app/features/diary/models/portion.dart'; +import 'package:eatvio_app/features/diary/models/product.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'diary_service.g.dart'; + +@RestApi() +abstract class DiaryService { + factory DiaryService(Dio dio, {String baseUrl}) = _DiaryService; + + @GET('/api/diary/index') + Future> getDiaryID(); + + @GET('/api/diary/{id}/show/') + Future> getDiary(@Path() int id); + + @GET('/api/diary/{id}/dailyNutritionData/') + Future getChart(@Path() int id); + + @GET('/api/diary/product_nutritional_values/filter') + Future>> getInputProduct(@Query('name') String name); + + @POST('/api/diary/{diary_id}/meal/{meal_id}/satiety/fill') + Future> sendSatietyData( + @Path() int diary_id, + @Path() int meal_id, + @Query('satiety') int satiety, + ); + + @POST('/api/diary/{diary_id}/meal/{meal_id}/mood/fill') + Future> sendMoodData( + @Path() int diary_id, + @Path() int meal_id, + @Query('mood') int mood, + ); + + @POST('/api/diary/{diary_id}/wakeup/fill') + Future sendWakeupData( + @Path() int diary_id, + @Query('wakeup') String wakeup, + ); + + @POST('/api/diary/{diary_id}/retire/fill') + Future sendRetireData( + @Path() int diary_id, + @Query('retire') String retire, + ); + + @POST('/api/diary/{diary_id}/meal/{meal_id}/portions/create') + Future> sendPortionData( + @Path() int diary_id, + @Path() int meal_id, + @Query('product_name') String product_name, + @Query('portion') String portion, + @Query('quantity') int quantity, + ); + + @POST('/api/diary/{diary_id}/meal/{meal_id}/photo/upload') + Future uploadImage( + @Path() int diary_id, + @Path() int meal_id, + @Part() File photo, + ); + + @POST('/api/diary/product_nutritional_values/sendToModeration') + Future> sendModerationData( + @Query('name') String product_name, + @Query('energy_on_100gr') double energy_on_100gr, + @Query('proteins_on_100gr') double proteins_on_100gr, + @Query('fats_on_100gr') double fats_on_100gr, + @Query('carbohydrates_on_100gr') double carbohydrates_on_100gr, + ); + + @POST('/api/diary/{diary_id}/finishDay') + Future sendFinishDay( + @Path() int diary_id, + //@Query('wakeUp') String wakeup, + //@Query('retire') String retire, + //@Query('comment') String comment, + ); + + @DELETE('/api/diary/{diary_id}/meal/{meal_id}/portions/{portion_id}/delete') + Future sendRemovePortionData( + @Path() int diary_id, + @Path() int meal_id, + @Path() int portion_id, + ); + + @DELETE('/api/diary/{diary_id}/meal/{meal_id}/photo/delete') + Future sendRemovePhotoData( + @Path() int diary_id, + @Path() int meal_id, + @Query('path') String path, + @Query('id') int photo_id, + ); +} diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart new file mode 100644 index 0000000..aba060c --- /dev/null +++ b/lib/features/diary/services/diary_service.g.dart @@ -0,0 +1,480 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'diary_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _DiaryService implements DiaryService { + _DiaryService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future> getDiaryID() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data!.cast(); + return _value; + } + + @override + Future> getDiary(int id) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${id}/show/', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + var _value = _result.data!.map((k, dynamic v) => + MapEntry(k, DiaryModel.fromJson(v as Map))); + return _value; + } + + @override + Future getChart(int id) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${id}/dailyNutritionData/', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data; + return _value; + } + + @override + Future>> getInputProduct(String name) async { + final _extra = {}; + final queryParameters = {r'name': name}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType>>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/filter', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + var _value = _result.data!.map((k, dynamic v) => MapEntry( + k, + (v as List) + .map((i) => Product.fromJson(i as Map)) + .toList())); + return _value; + } + + @override + Future> sendSatietyData( + int diary_id, + int meal_id, + int satiety, + ) async { + final _extra = {}; + final queryParameters = {r'satiety': satiety}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/satiety/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data!.cast(); + return _value; + } + + @override + Future> sendMoodData( + int diary_id, + int meal_id, + int mood, + ) async { + final _extra = {}; + final queryParameters = {r'mood': mood}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/mood/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data!.cast(); + return _value; + } + + @override + Future sendWakeupData( + int diary_id, + String wakeup, + ) async { + final _extra = {}; + final queryParameters = {r'wakeup': wakeup}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/wakeup/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = DiaryModel.fromJson(_result.data!); + return _value; + } + + @override + Future sendRetireData( + int diary_id, + String retire, + ) async { + final _extra = {}; + final queryParameters = {r'retire': retire}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/retire/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = DiaryModel.fromJson(_result.data!); + return _value; + } + + @override + Future> sendPortionData( + int diary_id, + int meal_id, + String product_name, + String portion, + int quantity, + ) async { + final _extra = {}; + final queryParameters = { + r'product_name': product_name, + r'portion': portion, + r'quantity': quantity, + }; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/portions/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + var _value = _result.data!.map((k, dynamic v) => + MapEntry(k, Portion.fromJson(v as Map))); + return _value; + } + + @override + Future uploadImage( + int diary_id, + int meal_id, + File photo, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = FormData(); + _data.files.add(MapEntry( + 'photo', + MultipartFile.fromFileSync( + photo.path, + filename: photo.path.split(Platform.pathSeparator).last, + ), + )); + await _dio.fetch(_setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/photo/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + } + + @override + Future> sendModerationData( + String product_name, + double energy_on_100gr, + double proteins_on_100gr, + double fats_on_100gr, + double carbohydrates_on_100gr, + ) async { + final _extra = {}; + final queryParameters = { + r'name': product_name, + r'energy_on_100gr': energy_on_100gr, + r'proteins_on_100gr': proteins_on_100gr, + r'fats_on_100gr': fats_on_100gr, + r'carbohydrates_on_100gr': carbohydrates_on_100gr, + }; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/sendToModeration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data!.cast(); + return _value; + } + + @override + Future sendFinishDay(int diary_id) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + await _dio.fetch(_setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/finishDay', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + } + + @override + Future sendRemovePortionData( + int diary_id, + int meal_id, + int portion_id, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + await _dio.fetch(_setStreamType(Options( + method: 'DELETE', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/portions/${portion_id}/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + } + + @override + Future sendRemovePhotoData( + int diary_id, + int meal_id, + String path, + int photo_id, + ) async { + final _extra = {}; + final queryParameters = { + r'path': path, + r'id': photo_id, + }; + final _headers = {}; + const Map? _data = null; + await _dio.fetch(_setStreamType(Options( + method: 'DELETE', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary_id}/meal/${meal_id}/photo/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart new file mode 100644 index 0000000..10fb6af --- /dev/null +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -0,0 +1,133 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'diets_pagination_model.freezed.dart'; +part 'diets_pagination_model.g.dart'; + +@freezed +class DietsPagination with _$DietsPagination { + const factory DietsPagination({ + @JsonKey(name: "data") required List data, + @JsonKey(name: "links") required Links links, + @JsonKey(name: "meta") required Meta meta, + }) = _DietsPagination; + + factory DietsPagination.fromJson(Map json) => _$DietsPaginationFromJson(json); +} + +@freezed +class Datum with _$Datum { + const factory Datum({ + @JsonKey(name: "id") required int id, + @JsonKey(name: "name") required String name, + @JsonKey(name: "image") required String image, + @JsonKey(name: "duration") required int duration, + @JsonKey(name: "state") required String state, + @JsonKey(name: "type") required Type type, + @JsonKey(name: "details") required String details, + @JsonKey(name: "daily_schedule") required List>> dailySchedule, + @JsonKey(name: "author") required Author author, + @JsonKey(name: "total_likes") required int totalLikes, + @JsonKey(name: "total_views") required int totalViews, + @JsonKey(name: "total_comments") required int totalComments, + }) = _Datum; + + factory Datum.fromJson(Map json) => _$DatumFromJson(json); +} + +@freezed +class Author with _$Author { + const factory Author({ + @JsonKey(name: "author_slug") required String authorSlug, + @JsonKey(name: "author_name") required String authorName, + @JsonKey(name: "author_profile_icon") required String authorProfileIcon, + @JsonKey(name: "author_is_me") required bool authorIsMe, + }) = _Author; + + factory Author.fromJson(Map json) => _$AuthorFromJson(json); +} + +@freezed +class DailySchedule with _$DailySchedule { + const factory DailySchedule({ + @JsonKey(name: "name") required String name, + @JsonKey(name: "uniq") required String uniq, + @JsonKey(name: "portion") required Portion portion, + @JsonKey(name: "quantity") required int quantity, + }) = _DailySchedule; + + factory DailySchedule.fromJson(Map json) => _$DailyScheduleFromJson(json); +} + +enum Portion { + @JsonValue("grams") + GRAMS, + @JsonValue("milliliters") + MILLILITERS, + @JsonValue("pcs") + PCS +} + +final portionValues = EnumValues({"grams": Portion.GRAMS, "milliliters": Portion.MILLILITERS, "pcs": Portion.PCS}); + +@freezed +class Type with _$Type { + const factory Type({ + @JsonKey(name: "alko") bool? alko, + @JsonKey(name: "veg") bool? veg, + @JsonKey(name: "corb") bool? corb, + @JsonKey(name: "meat") bool? meat, + }) = _Type; + + factory Type.fromJson(Map json) => _$TypeFromJson(json); +} + +@freezed +class Links with _$Links { + const factory Links({ + @JsonKey(name: "first") required String first, + @JsonKey(name: "last") required String last, + @JsonKey(name: "prev") required dynamic prev, + @JsonKey(name: "next") required dynamic next, + }) = _Links; + + factory Links.fromJson(Map json) => _$LinksFromJson(json); +} + +@freezed +class Meta with _$Meta { + const factory Meta({ + @JsonKey(name: "current_page") required int currentPage, + @JsonKey(name: "from") required int from, + @JsonKey(name: "last_page") required int lastPage, + @JsonKey(name: "links") required List links, + @JsonKey(name: "path") required String path, + @JsonKey(name: "per_page") required int perPage, + @JsonKey(name: "to") required int to, + @JsonKey(name: "total") required int total, + }) = _Meta; + + factory Meta.fromJson(Map json) => _$MetaFromJson(json); +} + +@freezed +class Link with _$Link { + const factory Link({ + @JsonKey(name: "url") required String? url, + @JsonKey(name: "label") required String label, + @JsonKey(name: "active") required bool active, + }) = _Link; + + factory Link.fromJson(Map json) => _$LinkFromJson(json); +} + +class EnumValues { + Map map; + late Map reverseMap; + + EnumValues(this.map); + + Map get reverse { + reverseMap = map.map((k, v) => MapEntry(v, k)); + return reverseMap; + } +} diff --git a/lib/features/feed/models/diets_pagination_model.freezed.dart b/lib/features/feed/models/diets_pagination_model.freezed.dart new file mode 100644 index 0000000..2c40267 --- /dev/null +++ b/lib/features/feed/models/diets_pagination_model.freezed.dart @@ -0,0 +1,2026 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'diets_pagination_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +DietsPagination _$DietsPaginationFromJson(Map json) { + return _DietsPagination.fromJson(json); +} + +/// @nodoc +mixin _$DietsPagination { + @JsonKey(name: "data") + List get data => throw _privateConstructorUsedError; + @JsonKey(name: "links") + Links get links => throw _privateConstructorUsedError; + @JsonKey(name: "meta") + Meta get meta => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DietsPaginationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DietsPaginationCopyWith<$Res> { + factory $DietsPaginationCopyWith( + DietsPagination value, $Res Function(DietsPagination) then) = + _$DietsPaginationCopyWithImpl<$Res, DietsPagination>; + @useResult + $Res call( + {@JsonKey(name: "data") List data, + @JsonKey(name: "links") Links links, + @JsonKey(name: "meta") Meta meta}); + + $LinksCopyWith<$Res> get links; + $MetaCopyWith<$Res> get meta; +} + +/// @nodoc +class _$DietsPaginationCopyWithImpl<$Res, $Val extends DietsPagination> + implements $DietsPaginationCopyWith<$Res> { + _$DietsPaginationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? data = null, + Object? links = null, + Object? meta = null, + }) { + return _then(_value.copyWith( + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as Links, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as Meta, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $LinksCopyWith<$Res> get links { + return $LinksCopyWith<$Res>(_value.links, (value) { + return _then(_value.copyWith(links: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $MetaCopyWith<$Res> get meta { + return $MetaCopyWith<$Res>(_value.meta, (value) { + return _then(_value.copyWith(meta: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$DietsPaginationImplCopyWith<$Res> + implements $DietsPaginationCopyWith<$Res> { + factory _$$DietsPaginationImplCopyWith(_$DietsPaginationImpl value, + $Res Function(_$DietsPaginationImpl) then) = + __$$DietsPaginationImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "data") List data, + @JsonKey(name: "links") Links links, + @JsonKey(name: "meta") Meta meta}); + + @override + $LinksCopyWith<$Res> get links; + @override + $MetaCopyWith<$Res> get meta; +} + +/// @nodoc +class __$$DietsPaginationImplCopyWithImpl<$Res> + extends _$DietsPaginationCopyWithImpl<$Res, _$DietsPaginationImpl> + implements _$$DietsPaginationImplCopyWith<$Res> { + __$$DietsPaginationImplCopyWithImpl( + _$DietsPaginationImpl _value, $Res Function(_$DietsPaginationImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? data = null, + Object? links = null, + Object? meta = null, + }) { + return _then(_$DietsPaginationImpl( + data: null == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as Links, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as Meta, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DietsPaginationImpl implements _DietsPagination { + const _$DietsPaginationImpl( + {@JsonKey(name: "data") required final List data, + @JsonKey(name: "links") required this.links, + @JsonKey(name: "meta") required this.meta}) + : _data = data; + + factory _$DietsPaginationImpl.fromJson(Map json) => + _$$DietsPaginationImplFromJson(json); + + final List _data; + @override + @JsonKey(name: "data") + List get data { + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_data); + } + + @override + @JsonKey(name: "links") + final Links links; + @override + @JsonKey(name: "meta") + final Meta meta; + + @override + String toString() { + return 'DietsPagination(data: $data, links: $links, meta: $meta)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DietsPaginationImpl && + const DeepCollectionEquality().equals(other._data, _data) && + (identical(other.links, links) || other.links == links) && + (identical(other.meta, meta) || other.meta == meta)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_data), links, meta); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DietsPaginationImplCopyWith<_$DietsPaginationImpl> get copyWith => + __$$DietsPaginationImplCopyWithImpl<_$DietsPaginationImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$DietsPaginationImplToJson( + this, + ); + } +} + +abstract class _DietsPagination implements DietsPagination { + const factory _DietsPagination( + {@JsonKey(name: "data") required final List data, + @JsonKey(name: "links") required final Links links, + @JsonKey(name: "meta") required final Meta meta}) = _$DietsPaginationImpl; + + factory _DietsPagination.fromJson(Map json) = + _$DietsPaginationImpl.fromJson; + + @override + @JsonKey(name: "data") + List get data; + @override + @JsonKey(name: "links") + Links get links; + @override + @JsonKey(name: "meta") + Meta get meta; + @override + @JsonKey(ignore: true) + _$$DietsPaginationImplCopyWith<_$DietsPaginationImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Datum _$DatumFromJson(Map json) { + return _Datum.fromJson(json); +} + +/// @nodoc +mixin _$Datum { + @JsonKey(name: "id") + int get id => throw _privateConstructorUsedError; + @JsonKey(name: "name") + String get name => throw _privateConstructorUsedError; + @JsonKey(name: "image") + String get image => throw _privateConstructorUsedError; + @JsonKey(name: "duration") + int get duration => throw _privateConstructorUsedError; + @JsonKey(name: "state") + String get state => throw _privateConstructorUsedError; + @JsonKey(name: "type") + Type get type => throw _privateConstructorUsedError; + @JsonKey(name: "details") + String get details => throw _privateConstructorUsedError; + @JsonKey(name: "daily_schedule") + List>> get dailySchedule => + throw _privateConstructorUsedError; + @JsonKey(name: "author") + Author get author => throw _privateConstructorUsedError; + @JsonKey(name: "total_likes") + int get totalLikes => throw _privateConstructorUsedError; + @JsonKey(name: "total_views") + int get totalViews => throw _privateConstructorUsedError; + @JsonKey(name: "total_comments") + int get totalComments => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DatumCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DatumCopyWith<$Res> { + factory $DatumCopyWith(Datum value, $Res Function(Datum) then) = + _$DatumCopyWithImpl<$Res, Datum>; + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "name") String name, + @JsonKey(name: "image") String image, + @JsonKey(name: "duration") int duration, + @JsonKey(name: "state") String state, + @JsonKey(name: "type") Type type, + @JsonKey(name: "details") String details, + @JsonKey(name: "daily_schedule") + List>> dailySchedule, + @JsonKey(name: "author") Author author, + @JsonKey(name: "total_likes") int totalLikes, + @JsonKey(name: "total_views") int totalViews, + @JsonKey(name: "total_comments") int totalComments}); + + $TypeCopyWith<$Res> get type; + $AuthorCopyWith<$Res> get author; +} + +/// @nodoc +class _$DatumCopyWithImpl<$Res, $Val extends Datum> + implements $DatumCopyWith<$Res> { + _$DatumCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + Object? duration = null, + Object? state = null, + Object? type = null, + Object? details = null, + Object? dailySchedule = null, + Object? author = null, + Object? totalLikes = null, + Object? totalViews = null, + Object? totalComments = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + duration: null == duration + ? _value.duration + : duration // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as Type, + details: null == details + ? _value.details + : details // ignore: cast_nullable_to_non_nullable + as String, + dailySchedule: null == dailySchedule + ? _value.dailySchedule + : dailySchedule // ignore: cast_nullable_to_non_nullable + as List>>, + author: null == author + ? _value.author + : author // ignore: cast_nullable_to_non_nullable + as Author, + totalLikes: null == totalLikes + ? _value.totalLikes + : totalLikes // ignore: cast_nullable_to_non_nullable + as int, + totalViews: null == totalViews + ? _value.totalViews + : totalViews // ignore: cast_nullable_to_non_nullable + as int, + totalComments: null == totalComments + ? _value.totalComments + : totalComments // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $TypeCopyWith<$Res> get type { + return $TypeCopyWith<$Res>(_value.type, (value) { + return _then(_value.copyWith(type: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $AuthorCopyWith<$Res> get author { + return $AuthorCopyWith<$Res>(_value.author, (value) { + return _then(_value.copyWith(author: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$DatumImplCopyWith<$Res> implements $DatumCopyWith<$Res> { + factory _$$DatumImplCopyWith( + _$DatumImpl value, $Res Function(_$DatumImpl) then) = + __$$DatumImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "name") String name, + @JsonKey(name: "image") String image, + @JsonKey(name: "duration") int duration, + @JsonKey(name: "state") String state, + @JsonKey(name: "type") Type type, + @JsonKey(name: "details") String details, + @JsonKey(name: "daily_schedule") + List>> dailySchedule, + @JsonKey(name: "author") Author author, + @JsonKey(name: "total_likes") int totalLikes, + @JsonKey(name: "total_views") int totalViews, + @JsonKey(name: "total_comments") int totalComments}); + + @override + $TypeCopyWith<$Res> get type; + @override + $AuthorCopyWith<$Res> get author; +} + +/// @nodoc +class __$$DatumImplCopyWithImpl<$Res> + extends _$DatumCopyWithImpl<$Res, _$DatumImpl> + implements _$$DatumImplCopyWith<$Res> { + __$$DatumImplCopyWithImpl( + _$DatumImpl _value, $Res Function(_$DatumImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + Object? duration = null, + Object? state = null, + Object? type = null, + Object? details = null, + Object? dailySchedule = null, + Object? author = null, + Object? totalLikes = null, + Object? totalViews = null, + Object? totalComments = null, + }) { + return _then(_$DatumImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + duration: null == duration + ? _value.duration + : duration // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as Type, + details: null == details + ? _value.details + : details // ignore: cast_nullable_to_non_nullable + as String, + dailySchedule: null == dailySchedule + ? _value._dailySchedule + : dailySchedule // ignore: cast_nullable_to_non_nullable + as List>>, + author: null == author + ? _value.author + : author // ignore: cast_nullable_to_non_nullable + as Author, + totalLikes: null == totalLikes + ? _value.totalLikes + : totalLikes // ignore: cast_nullable_to_non_nullable + as int, + totalViews: null == totalViews + ? _value.totalViews + : totalViews // ignore: cast_nullable_to_non_nullable + as int, + totalComments: null == totalComments + ? _value.totalComments + : totalComments // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DatumImpl implements _Datum { + const _$DatumImpl( + {@JsonKey(name: "id") required this.id, + @JsonKey(name: "name") required this.name, + @JsonKey(name: "image") required this.image, + @JsonKey(name: "duration") required this.duration, + @JsonKey(name: "state") required this.state, + @JsonKey(name: "type") required this.type, + @JsonKey(name: "details") required this.details, + @JsonKey(name: "daily_schedule") + required final List>> dailySchedule, + @JsonKey(name: "author") required this.author, + @JsonKey(name: "total_likes") required this.totalLikes, + @JsonKey(name: "total_views") required this.totalViews, + @JsonKey(name: "total_comments") required this.totalComments}) + : _dailySchedule = dailySchedule; + + factory _$DatumImpl.fromJson(Map json) => + _$$DatumImplFromJson(json); + + @override + @JsonKey(name: "id") + final int id; + @override + @JsonKey(name: "name") + final String name; + @override + @JsonKey(name: "image") + final String image; + @override + @JsonKey(name: "duration") + final int duration; + @override + @JsonKey(name: "state") + final String state; + @override + @JsonKey(name: "type") + final Type type; + @override + @JsonKey(name: "details") + final String details; + final List>> _dailySchedule; + @override + @JsonKey(name: "daily_schedule") + List>> get dailySchedule { + if (_dailySchedule is EqualUnmodifiableListView) return _dailySchedule; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_dailySchedule); + } + + @override + @JsonKey(name: "author") + final Author author; + @override + @JsonKey(name: "total_likes") + final int totalLikes; + @override + @JsonKey(name: "total_views") + final int totalViews; + @override + @JsonKey(name: "total_comments") + final int totalComments; + + @override + String toString() { + return 'Datum(id: $id, name: $name, image: $image, duration: $duration, state: $state, type: $type, details: $details, dailySchedule: $dailySchedule, author: $author, totalLikes: $totalLikes, totalViews: $totalViews, totalComments: $totalComments)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DatumImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.image, image) || other.image == image) && + (identical(other.duration, duration) || + other.duration == duration) && + (identical(other.state, state) || other.state == state) && + (identical(other.type, type) || other.type == type) && + (identical(other.details, details) || other.details == details) && + const DeepCollectionEquality() + .equals(other._dailySchedule, _dailySchedule) && + (identical(other.author, author) || other.author == author) && + (identical(other.totalLikes, totalLikes) || + other.totalLikes == totalLikes) && + (identical(other.totalViews, totalViews) || + other.totalViews == totalViews) && + (identical(other.totalComments, totalComments) || + other.totalComments == totalComments)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + name, + image, + duration, + state, + type, + details, + const DeepCollectionEquality().hash(_dailySchedule), + author, + totalLikes, + totalViews, + totalComments); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DatumImplCopyWith<_$DatumImpl> get copyWith => + __$$DatumImplCopyWithImpl<_$DatumImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DatumImplToJson( + this, + ); + } +} + +abstract class _Datum implements Datum { + const factory _Datum( + {@JsonKey(name: "id") required final int id, + @JsonKey(name: "name") required final String name, + @JsonKey(name: "image") required final String image, + @JsonKey(name: "duration") required final int duration, + @JsonKey(name: "state") required final String state, + @JsonKey(name: "type") required final Type type, + @JsonKey(name: "details") required final String details, + @JsonKey(name: "daily_schedule") + required final List>> dailySchedule, + @JsonKey(name: "author") required final Author author, + @JsonKey(name: "total_likes") required final int totalLikes, + @JsonKey(name: "total_views") required final int totalViews, + @JsonKey(name: "total_comments") required final int totalComments}) = + _$DatumImpl; + + factory _Datum.fromJson(Map json) = _$DatumImpl.fromJson; + + @override + @JsonKey(name: "id") + int get id; + @override + @JsonKey(name: "name") + String get name; + @override + @JsonKey(name: "image") + String get image; + @override + @JsonKey(name: "duration") + int get duration; + @override + @JsonKey(name: "state") + String get state; + @override + @JsonKey(name: "type") + Type get type; + @override + @JsonKey(name: "details") + String get details; + @override + @JsonKey(name: "daily_schedule") + List>> get dailySchedule; + @override + @JsonKey(name: "author") + Author get author; + @override + @JsonKey(name: "total_likes") + int get totalLikes; + @override + @JsonKey(name: "total_views") + int get totalViews; + @override + @JsonKey(name: "total_comments") + int get totalComments; + @override + @JsonKey(ignore: true) + _$$DatumImplCopyWith<_$DatumImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Author _$AuthorFromJson(Map json) { + return _Author.fromJson(json); +} + +/// @nodoc +mixin _$Author { + @JsonKey(name: "author_slug") + String get authorSlug => throw _privateConstructorUsedError; + @JsonKey(name: "author_name") + String get authorName => throw _privateConstructorUsedError; + @JsonKey(name: "author_profile_icon") + String get authorProfileIcon => throw _privateConstructorUsedError; + @JsonKey(name: "author_is_me") + bool get authorIsMe => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AuthorCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthorCopyWith<$Res> { + factory $AuthorCopyWith(Author value, $Res Function(Author) then) = + _$AuthorCopyWithImpl<$Res, Author>; + @useResult + $Res call( + {@JsonKey(name: "author_slug") String authorSlug, + @JsonKey(name: "author_name") String authorName, + @JsonKey(name: "author_profile_icon") String authorProfileIcon, + @JsonKey(name: "author_is_me") bool authorIsMe}); +} + +/// @nodoc +class _$AuthorCopyWithImpl<$Res, $Val extends Author> + implements $AuthorCopyWith<$Res> { + _$AuthorCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? authorSlug = null, + Object? authorName = null, + Object? authorProfileIcon = null, + Object? authorIsMe = null, + }) { + return _then(_value.copyWith( + authorSlug: null == authorSlug + ? _value.authorSlug + : authorSlug // ignore: cast_nullable_to_non_nullable + as String, + authorName: null == authorName + ? _value.authorName + : authorName // ignore: cast_nullable_to_non_nullable + as String, + authorProfileIcon: null == authorProfileIcon + ? _value.authorProfileIcon + : authorProfileIcon // ignore: cast_nullable_to_non_nullable + as String, + authorIsMe: null == authorIsMe + ? _value.authorIsMe + : authorIsMe // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthorImplCopyWith<$Res> implements $AuthorCopyWith<$Res> { + factory _$$AuthorImplCopyWith( + _$AuthorImpl value, $Res Function(_$AuthorImpl) then) = + __$$AuthorImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "author_slug") String authorSlug, + @JsonKey(name: "author_name") String authorName, + @JsonKey(name: "author_profile_icon") String authorProfileIcon, + @JsonKey(name: "author_is_me") bool authorIsMe}); +} + +/// @nodoc +class __$$AuthorImplCopyWithImpl<$Res> + extends _$AuthorCopyWithImpl<$Res, _$AuthorImpl> + implements _$$AuthorImplCopyWith<$Res> { + __$$AuthorImplCopyWithImpl( + _$AuthorImpl _value, $Res Function(_$AuthorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? authorSlug = null, + Object? authorName = null, + Object? authorProfileIcon = null, + Object? authorIsMe = null, + }) { + return _then(_$AuthorImpl( + authorSlug: null == authorSlug + ? _value.authorSlug + : authorSlug // ignore: cast_nullable_to_non_nullable + as String, + authorName: null == authorName + ? _value.authorName + : authorName // ignore: cast_nullable_to_non_nullable + as String, + authorProfileIcon: null == authorProfileIcon + ? _value.authorProfileIcon + : authorProfileIcon // ignore: cast_nullable_to_non_nullable + as String, + authorIsMe: null == authorIsMe + ? _value.authorIsMe + : authorIsMe // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthorImpl implements _Author { + const _$AuthorImpl( + {@JsonKey(name: "author_slug") required this.authorSlug, + @JsonKey(name: "author_name") required this.authorName, + @JsonKey(name: "author_profile_icon") required this.authorProfileIcon, + @JsonKey(name: "author_is_me") required this.authorIsMe}); + + factory _$AuthorImpl.fromJson(Map json) => + _$$AuthorImplFromJson(json); + + @override + @JsonKey(name: "author_slug") + final String authorSlug; + @override + @JsonKey(name: "author_name") + final String authorName; + @override + @JsonKey(name: "author_profile_icon") + final String authorProfileIcon; + @override + @JsonKey(name: "author_is_me") + final bool authorIsMe; + + @override + String toString() { + return 'Author(authorSlug: $authorSlug, authorName: $authorName, authorProfileIcon: $authorProfileIcon, authorIsMe: $authorIsMe)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthorImpl && + (identical(other.authorSlug, authorSlug) || + other.authorSlug == authorSlug) && + (identical(other.authorName, authorName) || + other.authorName == authorName) && + (identical(other.authorProfileIcon, authorProfileIcon) || + other.authorProfileIcon == authorProfileIcon) && + (identical(other.authorIsMe, authorIsMe) || + other.authorIsMe == authorIsMe)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, authorSlug, authorName, authorProfileIcon, authorIsMe); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AuthorImplCopyWith<_$AuthorImpl> get copyWith => + __$$AuthorImplCopyWithImpl<_$AuthorImpl>(this, _$identity); + + @override + Map toJson() { + return _$$AuthorImplToJson( + this, + ); + } +} + +abstract class _Author implements Author { + const factory _Author( + {@JsonKey(name: "author_slug") required final String authorSlug, + @JsonKey(name: "author_name") required final String authorName, + @JsonKey(name: "author_profile_icon") + required final String authorProfileIcon, + @JsonKey(name: "author_is_me") required final bool authorIsMe}) = + _$AuthorImpl; + + factory _Author.fromJson(Map json) = _$AuthorImpl.fromJson; + + @override + @JsonKey(name: "author_slug") + String get authorSlug; + @override + @JsonKey(name: "author_name") + String get authorName; + @override + @JsonKey(name: "author_profile_icon") + String get authorProfileIcon; + @override + @JsonKey(name: "author_is_me") + bool get authorIsMe; + @override + @JsonKey(ignore: true) + _$$AuthorImplCopyWith<_$AuthorImpl> get copyWith => + throw _privateConstructorUsedError; +} + +DailySchedule _$DailyScheduleFromJson(Map json) { + return _DailySchedule.fromJson(json); +} + +/// @nodoc +mixin _$DailySchedule { + @JsonKey(name: "name") + String get name => throw _privateConstructorUsedError; + @JsonKey(name: "uniq") + String get uniq => throw _privateConstructorUsedError; + @JsonKey(name: "portion") + Portion get portion => throw _privateConstructorUsedError; + @JsonKey(name: "quantity") + int get quantity => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DailyScheduleCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DailyScheduleCopyWith<$Res> { + factory $DailyScheduleCopyWith( + DailySchedule value, $Res Function(DailySchedule) then) = + _$DailyScheduleCopyWithImpl<$Res, DailySchedule>; + @useResult + $Res call( + {@JsonKey(name: "name") String name, + @JsonKey(name: "uniq") String uniq, + @JsonKey(name: "portion") Portion portion, + @JsonKey(name: "quantity") int quantity}); +} + +/// @nodoc +class _$DailyScheduleCopyWithImpl<$Res, $Val extends DailySchedule> + implements $DailyScheduleCopyWith<$Res> { + _$DailyScheduleCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? uniq = null, + Object? portion = null, + Object? quantity = null, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + uniq: null == uniq + ? _value.uniq + : uniq // ignore: cast_nullable_to_non_nullable + as String, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as Portion, + quantity: null == quantity + ? _value.quantity + : quantity // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$DailyScheduleImplCopyWith<$Res> + implements $DailyScheduleCopyWith<$Res> { + factory _$$DailyScheduleImplCopyWith( + _$DailyScheduleImpl value, $Res Function(_$DailyScheduleImpl) then) = + __$$DailyScheduleImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "name") String name, + @JsonKey(name: "uniq") String uniq, + @JsonKey(name: "portion") Portion portion, + @JsonKey(name: "quantity") int quantity}); +} + +/// @nodoc +class __$$DailyScheduleImplCopyWithImpl<$Res> + extends _$DailyScheduleCopyWithImpl<$Res, _$DailyScheduleImpl> + implements _$$DailyScheduleImplCopyWith<$Res> { + __$$DailyScheduleImplCopyWithImpl( + _$DailyScheduleImpl _value, $Res Function(_$DailyScheduleImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? uniq = null, + Object? portion = null, + Object? quantity = null, + }) { + return _then(_$DailyScheduleImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + uniq: null == uniq + ? _value.uniq + : uniq // ignore: cast_nullable_to_non_nullable + as String, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as Portion, + quantity: null == quantity + ? _value.quantity + : quantity // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DailyScheduleImpl implements _DailySchedule { + const _$DailyScheduleImpl( + {@JsonKey(name: "name") required this.name, + @JsonKey(name: "uniq") required this.uniq, + @JsonKey(name: "portion") required this.portion, + @JsonKey(name: "quantity") required this.quantity}); + + factory _$DailyScheduleImpl.fromJson(Map json) => + _$$DailyScheduleImplFromJson(json); + + @override + @JsonKey(name: "name") + final String name; + @override + @JsonKey(name: "uniq") + final String uniq; + @override + @JsonKey(name: "portion") + final Portion portion; + @override + @JsonKey(name: "quantity") + final int quantity; + + @override + String toString() { + return 'DailySchedule(name: $name, uniq: $uniq, portion: $portion, quantity: $quantity)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DailyScheduleImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.uniq, uniq) || other.uniq == uniq) && + (identical(other.portion, portion) || other.portion == portion) && + (identical(other.quantity, quantity) || + other.quantity == quantity)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, name, uniq, portion, quantity); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DailyScheduleImplCopyWith<_$DailyScheduleImpl> get copyWith => + __$$DailyScheduleImplCopyWithImpl<_$DailyScheduleImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DailyScheduleImplToJson( + this, + ); + } +} + +abstract class _DailySchedule implements DailySchedule { + const factory _DailySchedule( + {@JsonKey(name: "name") required final String name, + @JsonKey(name: "uniq") required final String uniq, + @JsonKey(name: "portion") required final Portion portion, + @JsonKey(name: "quantity") required final int quantity}) = + _$DailyScheduleImpl; + + factory _DailySchedule.fromJson(Map json) = + _$DailyScheduleImpl.fromJson; + + @override + @JsonKey(name: "name") + String get name; + @override + @JsonKey(name: "uniq") + String get uniq; + @override + @JsonKey(name: "portion") + Portion get portion; + @override + @JsonKey(name: "quantity") + int get quantity; + @override + @JsonKey(ignore: true) + _$$DailyScheduleImplCopyWith<_$DailyScheduleImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Type _$TypeFromJson(Map json) { + return _Type.fromJson(json); +} + +/// @nodoc +mixin _$Type { + @JsonKey(name: "alko") + bool? get alko => throw _privateConstructorUsedError; + @JsonKey(name: "veg") + bool? get veg => throw _privateConstructorUsedError; + @JsonKey(name: "corb") + bool? get corb => throw _privateConstructorUsedError; + @JsonKey(name: "meat") + bool? get meat => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $TypeCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TypeCopyWith<$Res> { + factory $TypeCopyWith(Type value, $Res Function(Type) then) = + _$TypeCopyWithImpl<$Res, Type>; + @useResult + $Res call( + {@JsonKey(name: "alko") bool? alko, + @JsonKey(name: "veg") bool? veg, + @JsonKey(name: "corb") bool? corb, + @JsonKey(name: "meat") bool? meat}); +} + +/// @nodoc +class _$TypeCopyWithImpl<$Res, $Val extends Type> + implements $TypeCopyWith<$Res> { + _$TypeCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? alko = freezed, + Object? veg = freezed, + Object? corb = freezed, + Object? meat = freezed, + }) { + return _then(_value.copyWith( + alko: freezed == alko + ? _value.alko + : alko // ignore: cast_nullable_to_non_nullable + as bool?, + veg: freezed == veg + ? _value.veg + : veg // ignore: cast_nullable_to_non_nullable + as bool?, + corb: freezed == corb + ? _value.corb + : corb // ignore: cast_nullable_to_non_nullable + as bool?, + meat: freezed == meat + ? _value.meat + : meat // ignore: cast_nullable_to_non_nullable + as bool?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$TypeImplCopyWith<$Res> implements $TypeCopyWith<$Res> { + factory _$$TypeImplCopyWith( + _$TypeImpl value, $Res Function(_$TypeImpl) then) = + __$$TypeImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "alko") bool? alko, + @JsonKey(name: "veg") bool? veg, + @JsonKey(name: "corb") bool? corb, + @JsonKey(name: "meat") bool? meat}); +} + +/// @nodoc +class __$$TypeImplCopyWithImpl<$Res> + extends _$TypeCopyWithImpl<$Res, _$TypeImpl> + implements _$$TypeImplCopyWith<$Res> { + __$$TypeImplCopyWithImpl(_$TypeImpl _value, $Res Function(_$TypeImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? alko = freezed, + Object? veg = freezed, + Object? corb = freezed, + Object? meat = freezed, + }) { + return _then(_$TypeImpl( + alko: freezed == alko + ? _value.alko + : alko // ignore: cast_nullable_to_non_nullable + as bool?, + veg: freezed == veg + ? _value.veg + : veg // ignore: cast_nullable_to_non_nullable + as bool?, + corb: freezed == corb + ? _value.corb + : corb // ignore: cast_nullable_to_non_nullable + as bool?, + meat: freezed == meat + ? _value.meat + : meat // ignore: cast_nullable_to_non_nullable + as bool?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$TypeImpl implements _Type { + const _$TypeImpl( + {@JsonKey(name: "alko") this.alko, + @JsonKey(name: "veg") this.veg, + @JsonKey(name: "corb") this.corb, + @JsonKey(name: "meat") this.meat}); + + factory _$TypeImpl.fromJson(Map json) => + _$$TypeImplFromJson(json); + + @override + @JsonKey(name: "alko") + final bool? alko; + @override + @JsonKey(name: "veg") + final bool? veg; + @override + @JsonKey(name: "corb") + final bool? corb; + @override + @JsonKey(name: "meat") + final bool? meat; + + @override + String toString() { + return 'Type(alko: $alko, veg: $veg, corb: $corb, meat: $meat)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TypeImpl && + (identical(other.alko, alko) || other.alko == alko) && + (identical(other.veg, veg) || other.veg == veg) && + (identical(other.corb, corb) || other.corb == corb) && + (identical(other.meat, meat) || other.meat == meat)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, alko, veg, corb, meat); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$TypeImplCopyWith<_$TypeImpl> get copyWith => + __$$TypeImplCopyWithImpl<_$TypeImpl>(this, _$identity); + + @override + Map toJson() { + return _$$TypeImplToJson( + this, + ); + } +} + +abstract class _Type implements Type { + const factory _Type( + {@JsonKey(name: "alko") final bool? alko, + @JsonKey(name: "veg") final bool? veg, + @JsonKey(name: "corb") final bool? corb, + @JsonKey(name: "meat") final bool? meat}) = _$TypeImpl; + + factory _Type.fromJson(Map json) = _$TypeImpl.fromJson; + + @override + @JsonKey(name: "alko") + bool? get alko; + @override + @JsonKey(name: "veg") + bool? get veg; + @override + @JsonKey(name: "corb") + bool? get corb; + @override + @JsonKey(name: "meat") + bool? get meat; + @override + @JsonKey(ignore: true) + _$$TypeImplCopyWith<_$TypeImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Links _$LinksFromJson(Map json) { + return _Links.fromJson(json); +} + +/// @nodoc +mixin _$Links { + @JsonKey(name: "first") + String get first => throw _privateConstructorUsedError; + @JsonKey(name: "last") + String get last => throw _privateConstructorUsedError; + @JsonKey(name: "prev") + dynamic get prev => throw _privateConstructorUsedError; + @JsonKey(name: "next") + dynamic get next => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LinksCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LinksCopyWith<$Res> { + factory $LinksCopyWith(Links value, $Res Function(Links) then) = + _$LinksCopyWithImpl<$Res, Links>; + @useResult + $Res call( + {@JsonKey(name: "first") String first, + @JsonKey(name: "last") String last, + @JsonKey(name: "prev") dynamic prev, + @JsonKey(name: "next") dynamic next}); +} + +/// @nodoc +class _$LinksCopyWithImpl<$Res, $Val extends Links> + implements $LinksCopyWith<$Res> { + _$LinksCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? first = null, + Object? last = null, + Object? prev = freezed, + Object? next = freezed, + }) { + return _then(_value.copyWith( + first: null == first + ? _value.first + : first // ignore: cast_nullable_to_non_nullable + as String, + last: null == last + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as String, + prev: freezed == prev + ? _value.prev + : prev // ignore: cast_nullable_to_non_nullable + as dynamic, + next: freezed == next + ? _value.next + : next // ignore: cast_nullable_to_non_nullable + as dynamic, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LinksImplCopyWith<$Res> implements $LinksCopyWith<$Res> { + factory _$$LinksImplCopyWith( + _$LinksImpl value, $Res Function(_$LinksImpl) then) = + __$$LinksImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "first") String first, + @JsonKey(name: "last") String last, + @JsonKey(name: "prev") dynamic prev, + @JsonKey(name: "next") dynamic next}); +} + +/// @nodoc +class __$$LinksImplCopyWithImpl<$Res> + extends _$LinksCopyWithImpl<$Res, _$LinksImpl> + implements _$$LinksImplCopyWith<$Res> { + __$$LinksImplCopyWithImpl( + _$LinksImpl _value, $Res Function(_$LinksImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? first = null, + Object? last = null, + Object? prev = freezed, + Object? next = freezed, + }) { + return _then(_$LinksImpl( + first: null == first + ? _value.first + : first // ignore: cast_nullable_to_non_nullable + as String, + last: null == last + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as String, + prev: freezed == prev + ? _value.prev + : prev // ignore: cast_nullable_to_non_nullable + as dynamic, + next: freezed == next + ? _value.next + : next // ignore: cast_nullable_to_non_nullable + as dynamic, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LinksImpl implements _Links { + const _$LinksImpl( + {@JsonKey(name: "first") required this.first, + @JsonKey(name: "last") required this.last, + @JsonKey(name: "prev") required this.prev, + @JsonKey(name: "next") required this.next}); + + factory _$LinksImpl.fromJson(Map json) => + _$$LinksImplFromJson(json); + + @override + @JsonKey(name: "first") + final String first; + @override + @JsonKey(name: "last") + final String last; + @override + @JsonKey(name: "prev") + final dynamic prev; + @override + @JsonKey(name: "next") + final dynamic next; + + @override + String toString() { + return 'Links(first: $first, last: $last, prev: $prev, next: $next)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LinksImpl && + (identical(other.first, first) || other.first == first) && + (identical(other.last, last) || other.last == last) && + const DeepCollectionEquality().equals(other.prev, prev) && + const DeepCollectionEquality().equals(other.next, next)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + first, + last, + const DeepCollectionEquality().hash(prev), + const DeepCollectionEquality().hash(next)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LinksImplCopyWith<_$LinksImpl> get copyWith => + __$$LinksImplCopyWithImpl<_$LinksImpl>(this, _$identity); + + @override + Map toJson() { + return _$$LinksImplToJson( + this, + ); + } +} + +abstract class _Links implements Links { + const factory _Links( + {@JsonKey(name: "first") required final String first, + @JsonKey(name: "last") required final String last, + @JsonKey(name: "prev") required final dynamic prev, + @JsonKey(name: "next") required final dynamic next}) = _$LinksImpl; + + factory _Links.fromJson(Map json) = _$LinksImpl.fromJson; + + @override + @JsonKey(name: "first") + String get first; + @override + @JsonKey(name: "last") + String get last; + @override + @JsonKey(name: "prev") + dynamic get prev; + @override + @JsonKey(name: "next") + dynamic get next; + @override + @JsonKey(ignore: true) + _$$LinksImplCopyWith<_$LinksImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Meta _$MetaFromJson(Map json) { + return _Meta.fromJson(json); +} + +/// @nodoc +mixin _$Meta { + @JsonKey(name: "current_page") + int get currentPage => throw _privateConstructorUsedError; + @JsonKey(name: "from") + int get from => throw _privateConstructorUsedError; + @JsonKey(name: "last_page") + int get lastPage => throw _privateConstructorUsedError; + @JsonKey(name: "links") + List get links => throw _privateConstructorUsedError; + @JsonKey(name: "path") + String get path => throw _privateConstructorUsedError; + @JsonKey(name: "per_page") + int get perPage => throw _privateConstructorUsedError; + @JsonKey(name: "to") + int get to => throw _privateConstructorUsedError; + @JsonKey(name: "total") + int get total => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MetaCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MetaCopyWith<$Res> { + factory $MetaCopyWith(Meta value, $Res Function(Meta) then) = + _$MetaCopyWithImpl<$Res, Meta>; + @useResult + $Res call( + {@JsonKey(name: "current_page") int currentPage, + @JsonKey(name: "from") int from, + @JsonKey(name: "last_page") int lastPage, + @JsonKey(name: "links") List links, + @JsonKey(name: "path") String path, + @JsonKey(name: "per_page") int perPage, + @JsonKey(name: "to") int to, + @JsonKey(name: "total") int total}); +} + +/// @nodoc +class _$MetaCopyWithImpl<$Res, $Val extends Meta> + implements $MetaCopyWith<$Res> { + _$MetaCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? currentPage = null, + Object? from = null, + Object? lastPage = null, + Object? links = null, + Object? path = null, + Object? perPage = null, + Object? to = null, + Object? total = null, + }) { + return _then(_value.copyWith( + currentPage: null == currentPage + ? _value.currentPage + : currentPage // ignore: cast_nullable_to_non_nullable + as int, + from: null == from + ? _value.from + : from // ignore: cast_nullable_to_non_nullable + as int, + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as List, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + perPage: null == perPage + ? _value.perPage + : perPage // ignore: cast_nullable_to_non_nullable + as int, + to: null == to + ? _value.to + : to // ignore: cast_nullable_to_non_nullable + as int, + total: null == total + ? _value.total + : total // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MetaImplCopyWith<$Res> implements $MetaCopyWith<$Res> { + factory _$$MetaImplCopyWith( + _$MetaImpl value, $Res Function(_$MetaImpl) then) = + __$$MetaImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "current_page") int currentPage, + @JsonKey(name: "from") int from, + @JsonKey(name: "last_page") int lastPage, + @JsonKey(name: "links") List links, + @JsonKey(name: "path") String path, + @JsonKey(name: "per_page") int perPage, + @JsonKey(name: "to") int to, + @JsonKey(name: "total") int total}); +} + +/// @nodoc +class __$$MetaImplCopyWithImpl<$Res> + extends _$MetaCopyWithImpl<$Res, _$MetaImpl> + implements _$$MetaImplCopyWith<$Res> { + __$$MetaImplCopyWithImpl(_$MetaImpl _value, $Res Function(_$MetaImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? currentPage = null, + Object? from = null, + Object? lastPage = null, + Object? links = null, + Object? path = null, + Object? perPage = null, + Object? to = null, + Object? total = null, + }) { + return _then(_$MetaImpl( + currentPage: null == currentPage + ? _value.currentPage + : currentPage // ignore: cast_nullable_to_non_nullable + as int, + from: null == from + ? _value.from + : from // ignore: cast_nullable_to_non_nullable + as int, + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + links: null == links + ? _value._links + : links // ignore: cast_nullable_to_non_nullable + as List, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + perPage: null == perPage + ? _value.perPage + : perPage // ignore: cast_nullable_to_non_nullable + as int, + to: null == to + ? _value.to + : to // ignore: cast_nullable_to_non_nullable + as int, + total: null == total + ? _value.total + : total // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$MetaImpl implements _Meta { + const _$MetaImpl( + {@JsonKey(name: "current_page") required this.currentPage, + @JsonKey(name: "from") required this.from, + @JsonKey(name: "last_page") required this.lastPage, + @JsonKey(name: "links") required final List links, + @JsonKey(name: "path") required this.path, + @JsonKey(name: "per_page") required this.perPage, + @JsonKey(name: "to") required this.to, + @JsonKey(name: "total") required this.total}) + : _links = links; + + factory _$MetaImpl.fromJson(Map json) => + _$$MetaImplFromJson(json); + + @override + @JsonKey(name: "current_page") + final int currentPage; + @override + @JsonKey(name: "from") + final int from; + @override + @JsonKey(name: "last_page") + final int lastPage; + final List _links; + @override + @JsonKey(name: "links") + List get links { + if (_links is EqualUnmodifiableListView) return _links; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_links); + } + + @override + @JsonKey(name: "path") + final String path; + @override + @JsonKey(name: "per_page") + final int perPage; + @override + @JsonKey(name: "to") + final int to; + @override + @JsonKey(name: "total") + final int total; + + @override + String toString() { + return 'Meta(currentPage: $currentPage, from: $from, lastPage: $lastPage, links: $links, path: $path, perPage: $perPage, to: $to, total: $total)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MetaImpl && + (identical(other.currentPage, currentPage) || + other.currentPage == currentPage) && + (identical(other.from, from) || other.from == from) && + (identical(other.lastPage, lastPage) || + other.lastPage == lastPage) && + const DeepCollectionEquality().equals(other._links, _links) && + (identical(other.path, path) || other.path == path) && + (identical(other.perPage, perPage) || other.perPage == perPage) && + (identical(other.to, to) || other.to == to) && + (identical(other.total, total) || other.total == total)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, currentPage, from, lastPage, + const DeepCollectionEquality().hash(_links), path, perPage, to, total); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MetaImplCopyWith<_$MetaImpl> get copyWith => + __$$MetaImplCopyWithImpl<_$MetaImpl>(this, _$identity); + + @override + Map toJson() { + return _$$MetaImplToJson( + this, + ); + } +} + +abstract class _Meta implements Meta { + const factory _Meta( + {@JsonKey(name: "current_page") required final int currentPage, + @JsonKey(name: "from") required final int from, + @JsonKey(name: "last_page") required final int lastPage, + @JsonKey(name: "links") required final List links, + @JsonKey(name: "path") required final String path, + @JsonKey(name: "per_page") required final int perPage, + @JsonKey(name: "to") required final int to, + @JsonKey(name: "total") required final int total}) = _$MetaImpl; + + factory _Meta.fromJson(Map json) = _$MetaImpl.fromJson; + + @override + @JsonKey(name: "current_page") + int get currentPage; + @override + @JsonKey(name: "from") + int get from; + @override + @JsonKey(name: "last_page") + int get lastPage; + @override + @JsonKey(name: "links") + List get links; + @override + @JsonKey(name: "path") + String get path; + @override + @JsonKey(name: "per_page") + int get perPage; + @override + @JsonKey(name: "to") + int get to; + @override + @JsonKey(name: "total") + int get total; + @override + @JsonKey(ignore: true) + _$$MetaImplCopyWith<_$MetaImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Link _$LinkFromJson(Map json) { + return _Link.fromJson(json); +} + +/// @nodoc +mixin _$Link { + @JsonKey(name: "url") + String? get url => throw _privateConstructorUsedError; + @JsonKey(name: "label") + String get label => throw _privateConstructorUsedError; + @JsonKey(name: "active") + bool get active => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LinkCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LinkCopyWith<$Res> { + factory $LinkCopyWith(Link value, $Res Function(Link) then) = + _$LinkCopyWithImpl<$Res, Link>; + @useResult + $Res call( + {@JsonKey(name: "url") String? url, + @JsonKey(name: "label") String label, + @JsonKey(name: "active") bool active}); +} + +/// @nodoc +class _$LinkCopyWithImpl<$Res, $Val extends Link> + implements $LinkCopyWith<$Res> { + _$LinkCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = freezed, + Object? label = null, + Object? active = null, + }) { + return _then(_value.copyWith( + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + active: null == active + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LinkImplCopyWith<$Res> implements $LinkCopyWith<$Res> { + factory _$$LinkImplCopyWith( + _$LinkImpl value, $Res Function(_$LinkImpl) then) = + __$$LinkImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "url") String? url, + @JsonKey(name: "label") String label, + @JsonKey(name: "active") bool active}); +} + +/// @nodoc +class __$$LinkImplCopyWithImpl<$Res> + extends _$LinkCopyWithImpl<$Res, _$LinkImpl> + implements _$$LinkImplCopyWith<$Res> { + __$$LinkImplCopyWithImpl(_$LinkImpl _value, $Res Function(_$LinkImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = freezed, + Object? label = null, + Object? active = null, + }) { + return _then(_$LinkImpl( + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + active: null == active + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LinkImpl implements _Link { + const _$LinkImpl( + {@JsonKey(name: "url") required this.url, + @JsonKey(name: "label") required this.label, + @JsonKey(name: "active") required this.active}); + + factory _$LinkImpl.fromJson(Map json) => + _$$LinkImplFromJson(json); + + @override + @JsonKey(name: "url") + final String? url; + @override + @JsonKey(name: "label") + final String label; + @override + @JsonKey(name: "active") + final bool active; + + @override + String toString() { + return 'Link(url: $url, label: $label, active: $active)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LinkImpl && + (identical(other.url, url) || other.url == url) && + (identical(other.label, label) || other.label == label) && + (identical(other.active, active) || other.active == active)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, url, label, active); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LinkImplCopyWith<_$LinkImpl> get copyWith => + __$$LinkImplCopyWithImpl<_$LinkImpl>(this, _$identity); + + @override + Map toJson() { + return _$$LinkImplToJson( + this, + ); + } +} + +abstract class _Link implements Link { + const factory _Link( + {@JsonKey(name: "url") required final String? url, + @JsonKey(name: "label") required final String label, + @JsonKey(name: "active") required final bool active}) = _$LinkImpl; + + factory _Link.fromJson(Map json) = _$LinkImpl.fromJson; + + @override + @JsonKey(name: "url") + String? get url; + @override + @JsonKey(name: "label") + String get label; + @override + @JsonKey(name: "active") + bool get active; + @override + @JsonKey(ignore: true) + _$$LinkImplCopyWith<_$LinkImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/diets_pagination_model.g.dart b/lib/features/feed/models/diets_pagination_model.g.dart new file mode 100644 index 0000000..0a74509 --- /dev/null +++ b/lib/features/feed/models/diets_pagination_model.g.dart @@ -0,0 +1,167 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'diets_pagination_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$DietsPaginationImpl _$$DietsPaginationImplFromJson( + Map json) => + _$DietsPaginationImpl( + data: (json['data'] as List) + .map((e) => Datum.fromJson(e as Map)) + .toList(), + links: Links.fromJson(json['links'] as Map), + meta: Meta.fromJson(json['meta'] as Map), + ); + +Map _$$DietsPaginationImplToJson( + _$DietsPaginationImpl instance) => + { + 'data': instance.data, + 'links': instance.links, + 'meta': instance.meta, + }; + +_$DatumImpl _$$DatumImplFromJson(Map json) => _$DatumImpl( + id: (json['id'] as num).toInt(), + name: json['name'] as String, + image: json['image'] as String, + duration: (json['duration'] as num).toInt(), + state: json['state'] as String, + type: Type.fromJson(json['type'] as Map), + details: json['details'] as String, + dailySchedule: (json['daily_schedule'] as List) + .map((e) => (e as List) + .map((e) => (e as List) + .map((e) => DailySchedule.fromJson(e as Map)) + .toList()) + .toList()) + .toList(), + author: Author.fromJson(json['author'] as Map), + totalLikes: (json['total_likes'] as num).toInt(), + totalViews: (json['total_views'] as num).toInt(), + totalComments: (json['total_comments'] as num).toInt(), + ); + +Map _$$DatumImplToJson(_$DatumImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + 'image': instance.image, + 'duration': instance.duration, + 'state': instance.state, + 'type': instance.type, + 'details': instance.details, + 'daily_schedule': instance.dailySchedule, + 'author': instance.author, + 'total_likes': instance.totalLikes, + 'total_views': instance.totalViews, + 'total_comments': instance.totalComments, + }; + +_$AuthorImpl _$$AuthorImplFromJson(Map json) => _$AuthorImpl( + authorSlug: json['author_slug'] as String, + authorName: json['author_name'] as String, + authorProfileIcon: json['author_profile_icon'] as String, + authorIsMe: json['author_is_me'] as bool, + ); + +Map _$$AuthorImplToJson(_$AuthorImpl instance) => + { + 'author_slug': instance.authorSlug, + 'author_name': instance.authorName, + 'author_profile_icon': instance.authorProfileIcon, + 'author_is_me': instance.authorIsMe, + }; + +_$DailyScheduleImpl _$$DailyScheduleImplFromJson(Map json) => + _$DailyScheduleImpl( + name: json['name'] as String, + uniq: json['uniq'] as String, + portion: $enumDecode(_$PortionEnumMap, json['portion']), + quantity: (json['quantity'] as num).toInt(), + ); + +Map _$$DailyScheduleImplToJson(_$DailyScheduleImpl instance) => + { + 'name': instance.name, + 'uniq': instance.uniq, + 'portion': _$PortionEnumMap[instance.portion]!, + 'quantity': instance.quantity, + }; + +const _$PortionEnumMap = { + Portion.GRAMS: 'grams', + Portion.MILLILITERS: 'milliliters', + Portion.PCS: 'pcs', +}; + +_$TypeImpl _$$TypeImplFromJson(Map json) => _$TypeImpl( + alko: json['alko'] as bool?, + veg: json['veg'] as bool?, + corb: json['corb'] as bool?, + meat: json['meat'] as bool?, + ); + +Map _$$TypeImplToJson(_$TypeImpl instance) => + { + 'alko': instance.alko, + 'veg': instance.veg, + 'corb': instance.corb, + 'meat': instance.meat, + }; + +_$LinksImpl _$$LinksImplFromJson(Map json) => _$LinksImpl( + first: json['first'] as String, + last: json['last'] as String, + prev: json['prev'], + next: json['next'], + ); + +Map _$$LinksImplToJson(_$LinksImpl instance) => + { + 'first': instance.first, + 'last': instance.last, + 'prev': instance.prev, + 'next': instance.next, + }; + +_$MetaImpl _$$MetaImplFromJson(Map json) => _$MetaImpl( + currentPage: (json['current_page'] as num).toInt(), + from: (json['from'] as num).toInt(), + lastPage: (json['last_page'] as num).toInt(), + links: (json['links'] as List) + .map((e) => Link.fromJson(e as Map)) + .toList(), + path: json['path'] as String, + perPage: (json['per_page'] as num).toInt(), + to: (json['to'] as num).toInt(), + total: (json['total'] as num).toInt(), + ); + +Map _$$MetaImplToJson(_$MetaImpl instance) => + { + 'current_page': instance.currentPage, + 'from': instance.from, + 'last_page': instance.lastPage, + 'links': instance.links, + 'path': instance.path, + 'per_page': instance.perPage, + 'to': instance.to, + 'total': instance.total, + }; + +_$LinkImpl _$$LinkImplFromJson(Map json) => _$LinkImpl( + url: json['url'] as String?, + label: json['label'] as String, + active: json['active'] as bool, + ); + +Map _$$LinkImplToJson(_$LinkImpl instance) => + { + 'url': instance.url, + 'label': instance.label, + 'active': instance.active, + }; diff --git a/lib/features/feed/models/feed_blog_post_model.dart b/lib/features/feed/models/feed_blog_post_model.dart new file mode 100644 index 0000000..b77fb3f --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_model.dart @@ -0,0 +1,20 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'feed_blog_post_model.freezed.dart'; +part 'feed_blog_post_model.g.dart'; + +@freezed +class FeedBlogPostModel with _$FeedBlogPostModel { + const factory FeedBlogPostModel({ + required int id, + required String state, + required String image, + required String description, + @JsonKey(name: "youtube_url") required String youtubeUrl, + @JsonKey(name: "created_at") required DateTime createdAt, + @JsonKey(name: "updated_at") required DateTime updatedAt, + required String title, + }) = _FeedBlogPostModel; + + factory FeedBlogPostModel.fromJson(Map json) => _$FeedBlogPostModelFromJson(json); +} diff --git a/lib/features/feed/models/feed_blog_post_model.freezed.dart b/lib/features/feed/models/feed_blog_post_model.freezed.dart new file mode 100644 index 0000000..4d753a1 --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_model.freezed.dart @@ -0,0 +1,310 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'feed_blog_post_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +FeedBlogPostModel _$FeedBlogPostModelFromJson(Map json) { + return _FeedBlogPostModel.fromJson(json); +} + +/// @nodoc +mixin _$FeedBlogPostModel { + int get id => throw _privateConstructorUsedError; + String get state => throw _privateConstructorUsedError; + String get image => throw _privateConstructorUsedError; + String get description => throw _privateConstructorUsedError; + @JsonKey(name: "youtube_url") + String get youtubeUrl => throw _privateConstructorUsedError; + @JsonKey(name: "created_at") + DateTime get createdAt => throw _privateConstructorUsedError; + @JsonKey(name: "updated_at") + DateTime get updatedAt => throw _privateConstructorUsedError; + String get title => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $FeedBlogPostModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FeedBlogPostModelCopyWith<$Res> { + factory $FeedBlogPostModelCopyWith( + FeedBlogPostModel value, $Res Function(FeedBlogPostModel) then) = + _$FeedBlogPostModelCopyWithImpl<$Res, FeedBlogPostModel>; + @useResult + $Res call( + {int id, + String state, + String image, + String description, + @JsonKey(name: "youtube_url") String youtubeUrl, + @JsonKey(name: "created_at") DateTime createdAt, + @JsonKey(name: "updated_at") DateTime updatedAt, + String title}); +} + +/// @nodoc +class _$FeedBlogPostModelCopyWithImpl<$Res, $Val extends FeedBlogPostModel> + implements $FeedBlogPostModelCopyWith<$Res> { + _$FeedBlogPostModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? state = null, + Object? image = null, + Object? description = null, + Object? youtubeUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + youtubeUrl: null == youtubeUrl + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$FeedBlogPostModelImplCopyWith<$Res> + implements $FeedBlogPostModelCopyWith<$Res> { + factory _$$FeedBlogPostModelImplCopyWith(_$FeedBlogPostModelImpl value, + $Res Function(_$FeedBlogPostModelImpl) then) = + __$$FeedBlogPostModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String state, + String image, + String description, + @JsonKey(name: "youtube_url") String youtubeUrl, + @JsonKey(name: "created_at") DateTime createdAt, + @JsonKey(name: "updated_at") DateTime updatedAt, + String title}); +} + +/// @nodoc +class __$$FeedBlogPostModelImplCopyWithImpl<$Res> + extends _$FeedBlogPostModelCopyWithImpl<$Res, _$FeedBlogPostModelImpl> + implements _$$FeedBlogPostModelImplCopyWith<$Res> { + __$$FeedBlogPostModelImplCopyWithImpl(_$FeedBlogPostModelImpl _value, + $Res Function(_$FeedBlogPostModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? state = null, + Object? image = null, + Object? description = null, + Object? youtubeUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + }) { + return _then(_$FeedBlogPostModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + youtubeUrl: null == youtubeUrl + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$FeedBlogPostModelImpl implements _FeedBlogPostModel { + const _$FeedBlogPostModelImpl( + {required this.id, + required this.state, + required this.image, + required this.description, + @JsonKey(name: "youtube_url") required this.youtubeUrl, + @JsonKey(name: "created_at") required this.createdAt, + @JsonKey(name: "updated_at") required this.updatedAt, + required this.title}); + + factory _$FeedBlogPostModelImpl.fromJson(Map json) => + _$$FeedBlogPostModelImplFromJson(json); + + @override + final int id; + @override + final String state; + @override + final String image; + @override + final String description; + @override + @JsonKey(name: "youtube_url") + final String youtubeUrl; + @override + @JsonKey(name: "created_at") + final DateTime createdAt; + @override + @JsonKey(name: "updated_at") + final DateTime updatedAt; + @override + final String title; + + @override + String toString() { + return 'FeedBlogPostModel(id: $id, state: $state, image: $image, description: $description, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FeedBlogPostModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.state, state) || other.state == state) && + (identical(other.image, image) || other.image == image) && + (identical(other.description, description) || + other.description == description) && + (identical(other.youtubeUrl, youtubeUrl) || + other.youtubeUrl == youtubeUrl) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && + (identical(other.title, title) || other.title == title)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, state, image, description, + youtubeUrl, createdAt, updatedAt, title); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FeedBlogPostModelImplCopyWith<_$FeedBlogPostModelImpl> get copyWith => + __$$FeedBlogPostModelImplCopyWithImpl<_$FeedBlogPostModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$FeedBlogPostModelImplToJson( + this, + ); + } +} + +abstract class _FeedBlogPostModel implements FeedBlogPostModel { + const factory _FeedBlogPostModel( + {required final int id, + required final String state, + required final String image, + required final String description, + @JsonKey(name: "youtube_url") required final String youtubeUrl, + @JsonKey(name: "created_at") required final DateTime createdAt, + @JsonKey(name: "updated_at") required final DateTime updatedAt, + required final String title}) = _$FeedBlogPostModelImpl; + + factory _FeedBlogPostModel.fromJson(Map json) = + _$FeedBlogPostModelImpl.fromJson; + + @override + int get id; + @override + String get state; + @override + String get image; + @override + String get description; + @override + @JsonKey(name: "youtube_url") + String get youtubeUrl; + @override + @JsonKey(name: "created_at") + DateTime get createdAt; + @override + @JsonKey(name: "updated_at") + DateTime get updatedAt; + @override + String get title; + @override + @JsonKey(ignore: true) + _$$FeedBlogPostModelImplCopyWith<_$FeedBlogPostModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/feed_blog_post_model.g.dart b/lib/features/feed/models/feed_blog_post_model.g.dart new file mode 100644 index 0000000..93cc70f --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_model.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'feed_blog_post_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$FeedBlogPostModelImpl _$$FeedBlogPostModelImplFromJson( + Map json) => + _$FeedBlogPostModelImpl( + id: (json['id'] as num).toInt(), + state: json['state'] as String, + image: json['image'] as String, + description: json['description'] as String, + youtubeUrl: json['youtube_url'] as String, + createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), + title: json['title'] as String, + ); + +Map _$$FeedBlogPostModelImplToJson( + _$FeedBlogPostModelImpl instance) => + { + 'id': instance.id, + 'state': instance.state, + 'image': instance.image, + 'description': instance.description, + 'youtube_url': instance.youtubeUrl, + 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), + 'title': instance.title, + }; diff --git a/lib/features/feed/models/feed_blog_post_settings_model.dart b/lib/features/feed/models/feed_blog_post_settings_model.dart new file mode 100644 index 0000000..a74f2d6 --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_settings_model.dart @@ -0,0 +1,15 @@ +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'feed_blog_post_settings_model.freezed.dart'; + +part 'feed_blog_post_settings_model.g.dart'; + +@freezed +class FeedBlogPostSettingsModel with _$FeedBlogPostSettingsModel { + const factory FeedBlogPostSettingsModel({ + @JsonKey(name: 'data') required List feedBlogPostList, + }) = _FeedBlogPostSettingsModel; + + factory FeedBlogPostSettingsModel.fromJson(Map json) => _$FeedBlogPostSettingsModelFromJson(json); +} diff --git a/lib/features/feed/models/feed_blog_post_settings_model.freezed.dart b/lib/features/feed/models/feed_blog_post_settings_model.freezed.dart new file mode 100644 index 0000000..7fd8a12 --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_settings_model.freezed.dart @@ -0,0 +1,175 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'feed_blog_post_settings_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +FeedBlogPostSettingsModel _$FeedBlogPostSettingsModelFromJson( + Map json) { + return _FeedBlogPostSettingsModel.fromJson(json); +} + +/// @nodoc +mixin _$FeedBlogPostSettingsModel { + @JsonKey(name: 'data') + List get feedBlogPostList => + throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $FeedBlogPostSettingsModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FeedBlogPostSettingsModelCopyWith<$Res> { + factory $FeedBlogPostSettingsModelCopyWith(FeedBlogPostSettingsModel value, + $Res Function(FeedBlogPostSettingsModel) then) = + _$FeedBlogPostSettingsModelCopyWithImpl<$Res, FeedBlogPostSettingsModel>; + @useResult + $Res call({@JsonKey(name: 'data') List feedBlogPostList}); +} + +/// @nodoc +class _$FeedBlogPostSettingsModelCopyWithImpl<$Res, + $Val extends FeedBlogPostSettingsModel> + implements $FeedBlogPostSettingsModelCopyWith<$Res> { + _$FeedBlogPostSettingsModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? feedBlogPostList = null, + }) { + return _then(_value.copyWith( + feedBlogPostList: null == feedBlogPostList + ? _value.feedBlogPostList + : feedBlogPostList // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$FeedBlogPostSettingsModelImplCopyWith<$Res> + implements $FeedBlogPostSettingsModelCopyWith<$Res> { + factory _$$FeedBlogPostSettingsModelImplCopyWith( + _$FeedBlogPostSettingsModelImpl value, + $Res Function(_$FeedBlogPostSettingsModelImpl) then) = + __$$FeedBlogPostSettingsModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonKey(name: 'data') List feedBlogPostList}); +} + +/// @nodoc +class __$$FeedBlogPostSettingsModelImplCopyWithImpl<$Res> + extends _$FeedBlogPostSettingsModelCopyWithImpl<$Res, + _$FeedBlogPostSettingsModelImpl> + implements _$$FeedBlogPostSettingsModelImplCopyWith<$Res> { + __$$FeedBlogPostSettingsModelImplCopyWithImpl( + _$FeedBlogPostSettingsModelImpl _value, + $Res Function(_$FeedBlogPostSettingsModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? feedBlogPostList = null, + }) { + return _then(_$FeedBlogPostSettingsModelImpl( + feedBlogPostList: null == feedBlogPostList + ? _value._feedBlogPostList + : feedBlogPostList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$FeedBlogPostSettingsModelImpl implements _FeedBlogPostSettingsModel { + const _$FeedBlogPostSettingsModelImpl( + {@JsonKey(name: 'data') + required final List feedBlogPostList}) + : _feedBlogPostList = feedBlogPostList; + + factory _$FeedBlogPostSettingsModelImpl.fromJson(Map json) => + _$$FeedBlogPostSettingsModelImplFromJson(json); + + final List _feedBlogPostList; + @override + @JsonKey(name: 'data') + List get feedBlogPostList { + if (_feedBlogPostList is EqualUnmodifiableListView) + return _feedBlogPostList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_feedBlogPostList); + } + + @override + String toString() { + return 'FeedBlogPostSettingsModel(feedBlogPostList: $feedBlogPostList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FeedBlogPostSettingsModelImpl && + const DeepCollectionEquality() + .equals(other._feedBlogPostList, _feedBlogPostList)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_feedBlogPostList)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FeedBlogPostSettingsModelImplCopyWith<_$FeedBlogPostSettingsModelImpl> + get copyWith => __$$FeedBlogPostSettingsModelImplCopyWithImpl< + _$FeedBlogPostSettingsModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$FeedBlogPostSettingsModelImplToJson( + this, + ); + } +} + +abstract class _FeedBlogPostSettingsModel implements FeedBlogPostSettingsModel { + const factory _FeedBlogPostSettingsModel( + {@JsonKey(name: 'data') + required final List feedBlogPostList}) = + _$FeedBlogPostSettingsModelImpl; + + factory _FeedBlogPostSettingsModel.fromJson(Map json) = + _$FeedBlogPostSettingsModelImpl.fromJson; + + @override + @JsonKey(name: 'data') + List get feedBlogPostList; + @override + @JsonKey(ignore: true) + _$$FeedBlogPostSettingsModelImplCopyWith<_$FeedBlogPostSettingsModelImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/feed_blog_post_settings_model.g.dart b/lib/features/feed/models/feed_blog_post_settings_model.g.dart new file mode 100644 index 0000000..3f48be1 --- /dev/null +++ b/lib/features/feed/models/feed_blog_post_settings_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'feed_blog_post_settings_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$FeedBlogPostSettingsModelImpl _$$FeedBlogPostSettingsModelImplFromJson( + Map json) => + _$FeedBlogPostSettingsModelImpl( + feedBlogPostList: (json['data'] as List) + .map((e) => FeedBlogPostModel.fromJson(e as Map)) + .toList(), + ); + +Map _$$FeedBlogPostSettingsModelImplToJson( + _$FeedBlogPostSettingsModelImpl instance) => + { + 'data': instance.feedBlogPostList, + }; diff --git a/lib/features/feed/models/recipes_model.dart b/lib/features/feed/models/recipes_model.dart new file mode 100644 index 0000000..1bc93d3 --- /dev/null +++ b/lib/features/feed/models/recipes_model.dart @@ -0,0 +1,49 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'recipes_model.freezed.dart'; +part 'recipes_model.g.dart'; + +@freezed +class Recipes with _$Recipes { + const factory Recipes({ + required int id, + required String image, + required String state, + @JsonKey(name: 'cooking_time') required int cookingTime, + required List ingredients, + required String description, + required List steps, + @JsonKey(name: 'video_url') required String videoUrl, + @JsonKey(name: 'created_at') required DateTime createdAt, + @JsonKey(name: 'updated_at') required DateTime updatedAt, + required String title, + required String type, + required String slug, + @JsonKey(name: 'total_comments') required int commentsCount, + @JsonKey(name: 'total_likes') required int likesCount, + @JsonKey(name: 'total_views') required int viewsCount, + }) = _Recipes; + + factory Recipes.fromJson(Map json) => _$RecipesFromJson(json); +} + +@freezed +class Ingredient with _$Ingredient { + const factory Ingredient({ + required String name, + String? unit, + required String portion, + }) = _Ingredient; + + factory Ingredient.fromJson(Map json) => _$IngredientFromJson(json); +} + +@freezed +class Step with _$Step { + const factory Step({ + required String image, + required String description, + }) = _Step; + + factory Step.fromJson(Map json) => _$StepFromJson(json); +} diff --git a/lib/features/feed/models/recipes_model.freezed.dart b/lib/features/feed/models/recipes_model.freezed.dart new file mode 100644 index 0000000..9843651 --- /dev/null +++ b/lib/features/feed/models/recipes_model.freezed.dart @@ -0,0 +1,835 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'recipes_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Recipes _$RecipesFromJson(Map json) { + return _Recipes.fromJson(json); +} + +/// @nodoc +mixin _$Recipes { + int get id => throw _privateConstructorUsedError; + String get image => throw _privateConstructorUsedError; + String get state => throw _privateConstructorUsedError; + @JsonKey(name: 'cooking_time') + int get cookingTime => throw _privateConstructorUsedError; + List get ingredients => throw _privateConstructorUsedError; + String get description => throw _privateConstructorUsedError; + List get steps => throw _privateConstructorUsedError; + @JsonKey(name: 'video_url') + String get videoUrl => throw _privateConstructorUsedError; + @JsonKey(name: 'created_at') + DateTime get createdAt => throw _privateConstructorUsedError; + @JsonKey(name: 'updated_at') + DateTime get updatedAt => throw _privateConstructorUsedError; + String get title => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; + String get slug => throw _privateConstructorUsedError; + @JsonKey(name: 'total_comments') + int get commentsCount => throw _privateConstructorUsedError; + @JsonKey(name: 'total_likes') + int get likesCount => throw _privateConstructorUsedError; + @JsonKey(name: 'total_views') + int get viewsCount => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RecipesCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RecipesCopyWith<$Res> { + factory $RecipesCopyWith(Recipes value, $Res Function(Recipes) then) = + _$RecipesCopyWithImpl<$Res, Recipes>; + @useResult + $Res call( + {int id, + String image, + String state, + @JsonKey(name: 'cooking_time') int cookingTime, + List ingredients, + String description, + List steps, + @JsonKey(name: 'video_url') String videoUrl, + @JsonKey(name: 'created_at') DateTime createdAt, + @JsonKey(name: 'updated_at') DateTime updatedAt, + String title, + String type, + String slug, + @JsonKey(name: 'total_comments') int commentsCount, + @JsonKey(name: 'total_likes') int likesCount, + @JsonKey(name: 'total_views') int viewsCount}); +} + +/// @nodoc +class _$RecipesCopyWithImpl<$Res, $Val extends Recipes> + implements $RecipesCopyWith<$Res> { + _$RecipesCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? image = null, + Object? state = null, + Object? cookingTime = null, + Object? ingredients = null, + Object? description = null, + Object? steps = null, + Object? videoUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + Object? type = null, + Object? slug = null, + Object? commentsCount = null, + Object? likesCount = null, + Object? viewsCount = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + cookingTime: null == cookingTime + ? _value.cookingTime + : cookingTime // ignore: cast_nullable_to_non_nullable + as int, + ingredients: null == ingredients + ? _value.ingredients + : ingredients // ignore: cast_nullable_to_non_nullable + as List, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + steps: null == steps + ? _value.steps + : steps // ignore: cast_nullable_to_non_nullable + as List, + videoUrl: null == videoUrl + ? _value.videoUrl + : videoUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + slug: null == slug + ? _value.slug + : slug // ignore: cast_nullable_to_non_nullable + as String, + commentsCount: null == commentsCount + ? _value.commentsCount + : commentsCount // ignore: cast_nullable_to_non_nullable + as int, + likesCount: null == likesCount + ? _value.likesCount + : likesCount // ignore: cast_nullable_to_non_nullable + as int, + viewsCount: null == viewsCount + ? _value.viewsCount + : viewsCount // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$RecipesImplCopyWith<$Res> implements $RecipesCopyWith<$Res> { + factory _$$RecipesImplCopyWith( + _$RecipesImpl value, $Res Function(_$RecipesImpl) then) = + __$$RecipesImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String image, + String state, + @JsonKey(name: 'cooking_time') int cookingTime, + List ingredients, + String description, + List steps, + @JsonKey(name: 'video_url') String videoUrl, + @JsonKey(name: 'created_at') DateTime createdAt, + @JsonKey(name: 'updated_at') DateTime updatedAt, + String title, + String type, + String slug, + @JsonKey(name: 'total_comments') int commentsCount, + @JsonKey(name: 'total_likes') int likesCount, + @JsonKey(name: 'total_views') int viewsCount}); +} + +/// @nodoc +class __$$RecipesImplCopyWithImpl<$Res> + extends _$RecipesCopyWithImpl<$Res, _$RecipesImpl> + implements _$$RecipesImplCopyWith<$Res> { + __$$RecipesImplCopyWithImpl( + _$RecipesImpl _value, $Res Function(_$RecipesImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? image = null, + Object? state = null, + Object? cookingTime = null, + Object? ingredients = null, + Object? description = null, + Object? steps = null, + Object? videoUrl = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? title = null, + Object? type = null, + Object? slug = null, + Object? commentsCount = null, + Object? likesCount = null, + Object? viewsCount = null, + }) { + return _then(_$RecipesImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + cookingTime: null == cookingTime + ? _value.cookingTime + : cookingTime // ignore: cast_nullable_to_non_nullable + as int, + ingredients: null == ingredients + ? _value._ingredients + : ingredients // ignore: cast_nullable_to_non_nullable + as List, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + steps: null == steps + ? _value._steps + : steps // ignore: cast_nullable_to_non_nullable + as List, + videoUrl: null == videoUrl + ? _value.videoUrl + : videoUrl // ignore: cast_nullable_to_non_nullable + as String, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + slug: null == slug + ? _value.slug + : slug // ignore: cast_nullable_to_non_nullable + as String, + commentsCount: null == commentsCount + ? _value.commentsCount + : commentsCount // ignore: cast_nullable_to_non_nullable + as int, + likesCount: null == likesCount + ? _value.likesCount + : likesCount // ignore: cast_nullable_to_non_nullable + as int, + viewsCount: null == viewsCount + ? _value.viewsCount + : viewsCount // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$RecipesImpl implements _Recipes { + const _$RecipesImpl( + {required this.id, + required this.image, + required this.state, + @JsonKey(name: 'cooking_time') required this.cookingTime, + required final List ingredients, + required this.description, + required final List steps, + @JsonKey(name: 'video_url') required this.videoUrl, + @JsonKey(name: 'created_at') required this.createdAt, + @JsonKey(name: 'updated_at') required this.updatedAt, + required this.title, + required this.type, + required this.slug, + @JsonKey(name: 'total_comments') required this.commentsCount, + @JsonKey(name: 'total_likes') required this.likesCount, + @JsonKey(name: 'total_views') required this.viewsCount}) + : _ingredients = ingredients, + _steps = steps; + + factory _$RecipesImpl.fromJson(Map json) => + _$$RecipesImplFromJson(json); + + @override + final int id; + @override + final String image; + @override + final String state; + @override + @JsonKey(name: 'cooking_time') + final int cookingTime; + final List _ingredients; + @override + List get ingredients { + if (_ingredients is EqualUnmodifiableListView) return _ingredients; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_ingredients); + } + + @override + final String description; + final List _steps; + @override + List get steps { + if (_steps is EqualUnmodifiableListView) return _steps; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_steps); + } + + @override + @JsonKey(name: 'video_url') + final String videoUrl; + @override + @JsonKey(name: 'created_at') + final DateTime createdAt; + @override + @JsonKey(name: 'updated_at') + final DateTime updatedAt; + @override + final String title; + @override + final String type; + @override + final String slug; + @override + @JsonKey(name: 'total_comments') + final int commentsCount; + @override + @JsonKey(name: 'total_likes') + final int likesCount; + @override + @JsonKey(name: 'total_views') + final int viewsCount; + + @override + String toString() { + return 'Recipes(id: $id, image: $image, state: $state, cookingTime: $cookingTime, ingredients: $ingredients, description: $description, steps: $steps, videoUrl: $videoUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title, type: $type, slug: $slug, commentsCount: $commentsCount, likesCount: $likesCount, viewsCount: $viewsCount)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RecipesImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.image, image) || other.image == image) && + (identical(other.state, state) || other.state == state) && + (identical(other.cookingTime, cookingTime) || + other.cookingTime == cookingTime) && + const DeepCollectionEquality() + .equals(other._ingredients, _ingredients) && + (identical(other.description, description) || + other.description == description) && + const DeepCollectionEquality().equals(other._steps, _steps) && + (identical(other.videoUrl, videoUrl) || + other.videoUrl == videoUrl) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && + (identical(other.title, title) || other.title == title) && + (identical(other.type, type) || other.type == type) && + (identical(other.slug, slug) || other.slug == slug) && + (identical(other.commentsCount, commentsCount) || + other.commentsCount == commentsCount) && + (identical(other.likesCount, likesCount) || + other.likesCount == likesCount) && + (identical(other.viewsCount, viewsCount) || + other.viewsCount == viewsCount)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + image, + state, + cookingTime, + const DeepCollectionEquality().hash(_ingredients), + description, + const DeepCollectionEquality().hash(_steps), + videoUrl, + createdAt, + updatedAt, + title, + type, + slug, + commentsCount, + likesCount, + viewsCount); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RecipesImplCopyWith<_$RecipesImpl> get copyWith => + __$$RecipesImplCopyWithImpl<_$RecipesImpl>(this, _$identity); + + @override + Map toJson() { + return _$$RecipesImplToJson( + this, + ); + } +} + +abstract class _Recipes implements Recipes { + const factory _Recipes( + {required final int id, + required final String image, + required final String state, + @JsonKey(name: 'cooking_time') required final int cookingTime, + required final List ingredients, + required final String description, + required final List steps, + @JsonKey(name: 'video_url') required final String videoUrl, + @JsonKey(name: 'created_at') required final DateTime createdAt, + @JsonKey(name: 'updated_at') required final DateTime updatedAt, + required final String title, + required final String type, + required final String slug, + @JsonKey(name: 'total_comments') required final int commentsCount, + @JsonKey(name: 'total_likes') required final int likesCount, + @JsonKey(name: 'total_views') required final int viewsCount}) = + _$RecipesImpl; + + factory _Recipes.fromJson(Map json) = _$RecipesImpl.fromJson; + + @override + int get id; + @override + String get image; + @override + String get state; + @override + @JsonKey(name: 'cooking_time') + int get cookingTime; + @override + List get ingredients; + @override + String get description; + @override + List get steps; + @override + @JsonKey(name: 'video_url') + String get videoUrl; + @override + @JsonKey(name: 'created_at') + DateTime get createdAt; + @override + @JsonKey(name: 'updated_at') + DateTime get updatedAt; + @override + String get title; + @override + String get type; + @override + String get slug; + @override + @JsonKey(name: 'total_comments') + int get commentsCount; + @override + @JsonKey(name: 'total_likes') + int get likesCount; + @override + @JsonKey(name: 'total_views') + int get viewsCount; + @override + @JsonKey(ignore: true) + _$$RecipesImplCopyWith<_$RecipesImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Ingredient _$IngredientFromJson(Map json) { + return _Ingredient.fromJson(json); +} + +/// @nodoc +mixin _$Ingredient { + String get name => throw _privateConstructorUsedError; + String? get unit => throw _privateConstructorUsedError; + String get portion => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $IngredientCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $IngredientCopyWith<$Res> { + factory $IngredientCopyWith( + Ingredient value, $Res Function(Ingredient) then) = + _$IngredientCopyWithImpl<$Res, Ingredient>; + @useResult + $Res call({String name, String? unit, String portion}); +} + +/// @nodoc +class _$IngredientCopyWithImpl<$Res, $Val extends Ingredient> + implements $IngredientCopyWith<$Res> { + _$IngredientCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? unit = freezed, + Object? portion = null, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + unit: freezed == unit + ? _value.unit + : unit // ignore: cast_nullable_to_non_nullable + as String?, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$IngredientImplCopyWith<$Res> + implements $IngredientCopyWith<$Res> { + factory _$$IngredientImplCopyWith( + _$IngredientImpl value, $Res Function(_$IngredientImpl) then) = + __$$IngredientImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String name, String? unit, String portion}); +} + +/// @nodoc +class __$$IngredientImplCopyWithImpl<$Res> + extends _$IngredientCopyWithImpl<$Res, _$IngredientImpl> + implements _$$IngredientImplCopyWith<$Res> { + __$$IngredientImplCopyWithImpl( + _$IngredientImpl _value, $Res Function(_$IngredientImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? unit = freezed, + Object? portion = null, + }) { + return _then(_$IngredientImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + unit: freezed == unit + ? _value.unit + : unit // ignore: cast_nullable_to_non_nullable + as String?, + portion: null == portion + ? _value.portion + : portion // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$IngredientImpl implements _Ingredient { + const _$IngredientImpl( + {required this.name, this.unit, required this.portion}); + + factory _$IngredientImpl.fromJson(Map json) => + _$$IngredientImplFromJson(json); + + @override + final String name; + @override + final String? unit; + @override + final String portion; + + @override + String toString() { + return 'Ingredient(name: $name, unit: $unit, portion: $portion)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$IngredientImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.unit, unit) || other.unit == unit) && + (identical(other.portion, portion) || other.portion == portion)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, name, unit, portion); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$IngredientImplCopyWith<_$IngredientImpl> get copyWith => + __$$IngredientImplCopyWithImpl<_$IngredientImpl>(this, _$identity); + + @override + Map toJson() { + return _$$IngredientImplToJson( + this, + ); + } +} + +abstract class _Ingredient implements Ingredient { + const factory _Ingredient( + {required final String name, + final String? unit, + required final String portion}) = _$IngredientImpl; + + factory _Ingredient.fromJson(Map json) = + _$IngredientImpl.fromJson; + + @override + String get name; + @override + String? get unit; + @override + String get portion; + @override + @JsonKey(ignore: true) + _$$IngredientImplCopyWith<_$IngredientImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Step _$StepFromJson(Map json) { + return _Step.fromJson(json); +} + +/// @nodoc +mixin _$Step { + String get image => throw _privateConstructorUsedError; + String get description => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $StepCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $StepCopyWith<$Res> { + factory $StepCopyWith(Step value, $Res Function(Step) then) = + _$StepCopyWithImpl<$Res, Step>; + @useResult + $Res call({String image, String description}); +} + +/// @nodoc +class _$StepCopyWithImpl<$Res, $Val extends Step> + implements $StepCopyWith<$Res> { + _$StepCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? image = null, + Object? description = null, + }) { + return _then(_value.copyWith( + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$StepImplCopyWith<$Res> implements $StepCopyWith<$Res> { + factory _$$StepImplCopyWith( + _$StepImpl value, $Res Function(_$StepImpl) then) = + __$$StepImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String image, String description}); +} + +/// @nodoc +class __$$StepImplCopyWithImpl<$Res> + extends _$StepCopyWithImpl<$Res, _$StepImpl> + implements _$$StepImplCopyWith<$Res> { + __$$StepImplCopyWithImpl(_$StepImpl _value, $Res Function(_$StepImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? image = null, + Object? description = null, + }) { + return _then(_$StepImpl( + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$StepImpl implements _Step { + const _$StepImpl({required this.image, required this.description}); + + factory _$StepImpl.fromJson(Map json) => + _$$StepImplFromJson(json); + + @override + final String image; + @override + final String description; + + @override + String toString() { + return 'Step(image: $image, description: $description)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$StepImpl && + (identical(other.image, image) || other.image == image) && + (identical(other.description, description) || + other.description == description)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, image, description); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$StepImplCopyWith<_$StepImpl> get copyWith => + __$$StepImplCopyWithImpl<_$StepImpl>(this, _$identity); + + @override + Map toJson() { + return _$$StepImplToJson( + this, + ); + } +} + +abstract class _Step implements Step { + const factory _Step( + {required final String image, + required final String description}) = _$StepImpl; + + factory _Step.fromJson(Map json) = _$StepImpl.fromJson; + + @override + String get image; + @override + String get description; + @override + @JsonKey(ignore: true) + _$$StepImplCopyWith<_$StepImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/recipes_model.g.dart b/lib/features/feed/models/recipes_model.g.dart new file mode 100644 index 0000000..edb4ed6 --- /dev/null +++ b/lib/features/feed/models/recipes_model.g.dart @@ -0,0 +1,76 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'recipes_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$RecipesImpl _$$RecipesImplFromJson(Map json) => + _$RecipesImpl( + id: (json['id'] as num).toInt(), + image: json['image'] as String, + state: json['state'] as String, + cookingTime: (json['cooking_time'] as num).toInt(), + ingredients: (json['ingredients'] as List) + .map((e) => Ingredient.fromJson(e as Map)) + .toList(), + description: json['description'] as String, + steps: (json['steps'] as List) + .map((e) => Step.fromJson(e as Map)) + .toList(), + videoUrl: json['video_url'] as String, + createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), + title: json['title'] as String, + type: json['type'] as String, + slug: json['slug'] as String, + commentsCount: (json['total_comments'] as num).toInt(), + likesCount: (json['total_likes'] as num).toInt(), + viewsCount: (json['total_views'] as num).toInt(), + ); + +Map _$$RecipesImplToJson(_$RecipesImpl instance) => + { + 'id': instance.id, + 'image': instance.image, + 'state': instance.state, + 'cooking_time': instance.cookingTime, + 'ingredients': instance.ingredients, + 'description': instance.description, + 'steps': instance.steps, + 'video_url': instance.videoUrl, + 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), + 'title': instance.title, + 'type': instance.type, + 'slug': instance.slug, + 'total_comments': instance.commentsCount, + 'total_likes': instance.likesCount, + 'total_views': instance.viewsCount, + }; + +_$IngredientImpl _$$IngredientImplFromJson(Map json) => + _$IngredientImpl( + name: json['name'] as String, + unit: json['unit'] as String?, + portion: json['portion'] as String, + ); + +Map _$$IngredientImplToJson(_$IngredientImpl instance) => + { + 'name': instance.name, + 'unit': instance.unit, + 'portion': instance.portion, + }; + +_$StepImpl _$$StepImplFromJson(Map json) => _$StepImpl( + image: json['image'] as String, + description: json['description'] as String, + ); + +Map _$$StepImplToJson(_$StepImpl instance) => + { + 'image': instance.image, + 'description': instance.description, + }; diff --git a/lib/features/feed/models/recipes_pagination_model.dart b/lib/features/feed/models/recipes_pagination_model.dart new file mode 100644 index 0000000..0d2abdc --- /dev/null +++ b/lib/features/feed/models/recipes_pagination_model.dart @@ -0,0 +1,25 @@ +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'recipes_pagination_model.freezed.dart'; +part 'recipes_pagination_model.g.dart'; + +@freezed +class RecipesPagination with _$RecipesPagination { + const factory RecipesPagination({ + @JsonKey(name: 'data') required List recipesList, + // @JsonKey(name: "current_page") required int currentPage, + // @JsonKey(name: "first_page_url") required String firstPageUrl, + // required int from, + // @JsonKey(name: "last_page") required int lastPage, + // @JsonKey(name: "last_page_url") required String lastPageUrl, + // @JsonKey(name: "next_page_url") required String nextPageUrl, + // required String path, + // @JsonKey(name: "per_page") required int perPage, + // @JsonKey(name: "prev_page_url") required dynamic prevPageUrl, + // required int to, + // required int total, + }) = _RecipesPagination; + + factory RecipesPagination.fromJson(Map json) => _$RecipesPaginationFromJson(json); +} diff --git a/lib/features/feed/models/recipes_pagination_model.freezed.dart b/lib/features/feed/models/recipes_pagination_model.freezed.dart new file mode 100644 index 0000000..2f0d43f --- /dev/null +++ b/lib/features/feed/models/recipes_pagination_model.freezed.dart @@ -0,0 +1,166 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'recipes_pagination_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +RecipesPagination _$RecipesPaginationFromJson(Map json) { + return _RecipesPagination.fromJson(json); +} + +/// @nodoc +mixin _$RecipesPagination { + @JsonKey(name: 'data') + List get recipesList => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RecipesPaginationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RecipesPaginationCopyWith<$Res> { + factory $RecipesPaginationCopyWith( + RecipesPagination value, $Res Function(RecipesPagination) then) = + _$RecipesPaginationCopyWithImpl<$Res, RecipesPagination>; + @useResult + $Res call({@JsonKey(name: 'data') List recipesList}); +} + +/// @nodoc +class _$RecipesPaginationCopyWithImpl<$Res, $Val extends RecipesPagination> + implements $RecipesPaginationCopyWith<$Res> { + _$RecipesPaginationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? recipesList = null, + }) { + return _then(_value.copyWith( + recipesList: null == recipesList + ? _value.recipesList + : recipesList // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$RecipesPaginationImplCopyWith<$Res> + implements $RecipesPaginationCopyWith<$Res> { + factory _$$RecipesPaginationImplCopyWith(_$RecipesPaginationImpl value, + $Res Function(_$RecipesPaginationImpl) then) = + __$$RecipesPaginationImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonKey(name: 'data') List recipesList}); +} + +/// @nodoc +class __$$RecipesPaginationImplCopyWithImpl<$Res> + extends _$RecipesPaginationCopyWithImpl<$Res, _$RecipesPaginationImpl> + implements _$$RecipesPaginationImplCopyWith<$Res> { + __$$RecipesPaginationImplCopyWithImpl(_$RecipesPaginationImpl _value, + $Res Function(_$RecipesPaginationImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? recipesList = null, + }) { + return _then(_$RecipesPaginationImpl( + recipesList: null == recipesList + ? _value._recipesList + : recipesList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$RecipesPaginationImpl implements _RecipesPagination { + const _$RecipesPaginationImpl( + {@JsonKey(name: 'data') required final List recipesList}) + : _recipesList = recipesList; + + factory _$RecipesPaginationImpl.fromJson(Map json) => + _$$RecipesPaginationImplFromJson(json); + + final List _recipesList; + @override + @JsonKey(name: 'data') + List get recipesList { + if (_recipesList is EqualUnmodifiableListView) return _recipesList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_recipesList); + } + + @override + String toString() { + return 'RecipesPagination(recipesList: $recipesList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RecipesPaginationImpl && + const DeepCollectionEquality() + .equals(other._recipesList, _recipesList)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_recipesList)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RecipesPaginationImplCopyWith<_$RecipesPaginationImpl> get copyWith => + __$$RecipesPaginationImplCopyWithImpl<_$RecipesPaginationImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$RecipesPaginationImplToJson( + this, + ); + } +} + +abstract class _RecipesPagination implements RecipesPagination { + const factory _RecipesPagination( + {@JsonKey(name: 'data') required final List recipesList}) = + _$RecipesPaginationImpl; + + factory _RecipesPagination.fromJson(Map json) = + _$RecipesPaginationImpl.fromJson; + + @override + @JsonKey(name: 'data') + List get recipesList; + @override + @JsonKey(ignore: true) + _$$RecipesPaginationImplCopyWith<_$RecipesPaginationImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/recipes_pagination_model.g.dart b/lib/features/feed/models/recipes_pagination_model.g.dart new file mode 100644 index 0000000..109f39d --- /dev/null +++ b/lib/features/feed/models/recipes_pagination_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'recipes_pagination_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$RecipesPaginationImpl _$$RecipesPaginationImplFromJson( + Map json) => + _$RecipesPaginationImpl( + recipesList: (json['data'] as List) + .map((e) => Recipes.fromJson(e as Map)) + .toList(), + ); + +Map _$$RecipesPaginationImplToJson( + _$RecipesPaginationImpl instance) => + { + 'data': instance.recipesList, + }; diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart new file mode 100644 index 0000000..c052c26 --- /dev/null +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart @@ -0,0 +1,18 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; +import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; + +class FeedCubit extends Cubit { + final FeedRepository feedRepository; + + FeedCubit({required this.feedRepository}) : super(const FeedState.loading()); + + loadFeedBlogPostList() async { + try { + final feedBlogPostList = await feedRepository.getFeedBlogPostList(); + emit(FeedState.loaded(feedBlogPostList: feedBlogPostList)); + } catch (e) { + emit(FeedState.error(errorMessage: e.toString())); + } + } +} diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_state.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_state.dart new file mode 100644 index 0000000..70e8c3b --- /dev/null +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'feed_state.freezed.dart'; + +@freezed +abstract class FeedState with _$FeedState { + const factory FeedState() = _FeedState; + + const factory FeedState.loading() = FeedStateLoading; + + const factory FeedState.loaded({ + required List feedBlogPostList, + }) = FeedStateLoaded; + + const factory FeedState.error({ + required String errorMessage, + }) = FeedStateError; +} diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_state.freezed.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_state.freezed.dart new file mode 100644 index 0000000..ab3385f --- /dev/null +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_state.freezed.dart @@ -0,0 +1,620 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'feed_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$FeedState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List feedBlogPostList) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List feedBlogPostList)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List feedBlogPostList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_FeedState value) $default, { + required TResult Function(FeedStateLoading value) loading, + required TResult Function(FeedStateLoaded value) loaded, + required TResult Function(FeedStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_FeedState value)? $default, { + TResult? Function(FeedStateLoading value)? loading, + TResult? Function(FeedStateLoaded value)? loaded, + TResult? Function(FeedStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_FeedState value)? $default, { + TResult Function(FeedStateLoading value)? loading, + TResult Function(FeedStateLoaded value)? loaded, + TResult Function(FeedStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FeedStateCopyWith<$Res> { + factory $FeedStateCopyWith(FeedState value, $Res Function(FeedState) then) = + _$FeedStateCopyWithImpl<$Res, FeedState>; +} + +/// @nodoc +class _$FeedStateCopyWithImpl<$Res, $Val extends FeedState> + implements $FeedStateCopyWith<$Res> { + _$FeedStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$FeedStateImplCopyWith<$Res> { + factory _$$FeedStateImplCopyWith( + _$FeedStateImpl value, $Res Function(_$FeedStateImpl) then) = + __$$FeedStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$FeedStateImplCopyWithImpl<$Res> + extends _$FeedStateCopyWithImpl<$Res, _$FeedStateImpl> + implements _$$FeedStateImplCopyWith<$Res> { + __$$FeedStateImplCopyWithImpl( + _$FeedStateImpl _value, $Res Function(_$FeedStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$FeedStateImpl implements _FeedState { + const _$FeedStateImpl(); + + @override + String toString() { + return 'FeedState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$FeedStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List feedBlogPostList) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List feedBlogPostList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List feedBlogPostList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_FeedState value) $default, { + required TResult Function(FeedStateLoading value) loading, + required TResult Function(FeedStateLoaded value) loaded, + required TResult Function(FeedStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_FeedState value)? $default, { + TResult? Function(FeedStateLoading value)? loading, + TResult? Function(FeedStateLoaded value)? loaded, + TResult? Function(FeedStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_FeedState value)? $default, { + TResult Function(FeedStateLoading value)? loading, + TResult Function(FeedStateLoaded value)? loaded, + TResult Function(FeedStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _FeedState implements FeedState { + const factory _FeedState() = _$FeedStateImpl; +} + +/// @nodoc +abstract class _$$FeedStateLoadingImplCopyWith<$Res> { + factory _$$FeedStateLoadingImplCopyWith(_$FeedStateLoadingImpl value, + $Res Function(_$FeedStateLoadingImpl) then) = + __$$FeedStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$FeedStateLoadingImplCopyWithImpl<$Res> + extends _$FeedStateCopyWithImpl<$Res, _$FeedStateLoadingImpl> + implements _$$FeedStateLoadingImplCopyWith<$Res> { + __$$FeedStateLoadingImplCopyWithImpl(_$FeedStateLoadingImpl _value, + $Res Function(_$FeedStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$FeedStateLoadingImpl implements FeedStateLoading { + const _$FeedStateLoadingImpl(); + + @override + String toString() { + return 'FeedState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$FeedStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List feedBlogPostList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List feedBlogPostList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List feedBlogPostList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_FeedState value) $default, { + required TResult Function(FeedStateLoading value) loading, + required TResult Function(FeedStateLoaded value) loaded, + required TResult Function(FeedStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_FeedState value)? $default, { + TResult? Function(FeedStateLoading value)? loading, + TResult? Function(FeedStateLoaded value)? loaded, + TResult? Function(FeedStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_FeedState value)? $default, { + TResult Function(FeedStateLoading value)? loading, + TResult Function(FeedStateLoaded value)? loaded, + TResult Function(FeedStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class FeedStateLoading implements FeedState { + const factory FeedStateLoading() = _$FeedStateLoadingImpl; +} + +/// @nodoc +abstract class _$$FeedStateLoadedImplCopyWith<$Res> { + factory _$$FeedStateLoadedImplCopyWith(_$FeedStateLoadedImpl value, + $Res Function(_$FeedStateLoadedImpl) then) = + __$$FeedStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({List feedBlogPostList}); +} + +/// @nodoc +class __$$FeedStateLoadedImplCopyWithImpl<$Res> + extends _$FeedStateCopyWithImpl<$Res, _$FeedStateLoadedImpl> + implements _$$FeedStateLoadedImplCopyWith<$Res> { + __$$FeedStateLoadedImplCopyWithImpl( + _$FeedStateLoadedImpl _value, $Res Function(_$FeedStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? feedBlogPostList = null, + }) { + return _then(_$FeedStateLoadedImpl( + feedBlogPostList: null == feedBlogPostList + ? _value._feedBlogPostList + : feedBlogPostList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$FeedStateLoadedImpl implements FeedStateLoaded { + const _$FeedStateLoadedImpl( + {required final List feedBlogPostList}) + : _feedBlogPostList = feedBlogPostList; + + final List _feedBlogPostList; + @override + List get feedBlogPostList { + if (_feedBlogPostList is EqualUnmodifiableListView) + return _feedBlogPostList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_feedBlogPostList); + } + + @override + String toString() { + return 'FeedState.loaded(feedBlogPostList: $feedBlogPostList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FeedStateLoadedImpl && + const DeepCollectionEquality() + .equals(other._feedBlogPostList, _feedBlogPostList)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_feedBlogPostList)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FeedStateLoadedImplCopyWith<_$FeedStateLoadedImpl> get copyWith => + __$$FeedStateLoadedImplCopyWithImpl<_$FeedStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List feedBlogPostList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(feedBlogPostList); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List feedBlogPostList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(feedBlogPostList); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List feedBlogPostList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(feedBlogPostList); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_FeedState value) $default, { + required TResult Function(FeedStateLoading value) loading, + required TResult Function(FeedStateLoaded value) loaded, + required TResult Function(FeedStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_FeedState value)? $default, { + TResult? Function(FeedStateLoading value)? loading, + TResult? Function(FeedStateLoaded value)? loaded, + TResult? Function(FeedStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_FeedState value)? $default, { + TResult Function(FeedStateLoading value)? loading, + TResult Function(FeedStateLoaded value)? loaded, + TResult Function(FeedStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class FeedStateLoaded implements FeedState { + const factory FeedStateLoaded( + {required final List feedBlogPostList}) = + _$FeedStateLoadedImpl; + + List get feedBlogPostList; + @JsonKey(ignore: true) + _$$FeedStateLoadedImplCopyWith<_$FeedStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$FeedStateErrorImplCopyWith<$Res> { + factory _$$FeedStateErrorImplCopyWith(_$FeedStateErrorImpl value, + $Res Function(_$FeedStateErrorImpl) then) = + __$$FeedStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$FeedStateErrorImplCopyWithImpl<$Res> + extends _$FeedStateCopyWithImpl<$Res, _$FeedStateErrorImpl> + implements _$$FeedStateErrorImplCopyWith<$Res> { + __$$FeedStateErrorImplCopyWithImpl( + _$FeedStateErrorImpl _value, $Res Function(_$FeedStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$FeedStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$FeedStateErrorImpl implements FeedStateError { + const _$FeedStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'FeedState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FeedStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FeedStateErrorImplCopyWith<_$FeedStateErrorImpl> get copyWith => + __$$FeedStateErrorImplCopyWithImpl<_$FeedStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List feedBlogPostList) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List feedBlogPostList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List feedBlogPostList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_FeedState value) $default, { + required TResult Function(FeedStateLoading value) loading, + required TResult Function(FeedStateLoaded value) loaded, + required TResult Function(FeedStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_FeedState value)? $default, { + TResult? Function(FeedStateLoading value)? loading, + TResult? Function(FeedStateLoaded value)? loaded, + TResult? Function(FeedStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_FeedState value)? $default, { + TResult Function(FeedStateLoading value)? loading, + TResult Function(FeedStateLoaded value)? loaded, + TResult Function(FeedStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class FeedStateError implements FeedState { + const factory FeedStateError({required final String errorMessage}) = + _$FeedStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$FeedStateErrorImplCopyWith<_$FeedStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart new file mode 100644 index 0000000..8cd8a52 --- /dev/null +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart @@ -0,0 +1,18 @@ +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart'; +import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class RecipesCubit extends Cubit { + final FeedRepository feedRepository; + + RecipesCubit({required this.feedRepository}) : super(const RecipesState.loading()); + + loadRecipesList() async { + try { + final recipesList = await feedRepository.getRecipes(); + emit(RecipesState.loaded(recipesList: recipesList)); + } catch (e) { + emit(RecipesState.error(errorMessage: e.toString())); + } + } +} diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart new file mode 100644 index 0000000..ecdf17c --- /dev/null +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'recipes_state.freezed.dart'; + +@freezed +abstract class RecipesState with _$RecipesState { + const factory RecipesState() = _RecipesState; + + const factory RecipesState.loading() = RecipesStateLoading; + + const factory RecipesState.loaded({ + required List recipesList, + }) = RecipesStateLoaded; + + const factory RecipesState.error({ + required String errorMessage, + }) = RecipesStateError; +} diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.freezed.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.freezed.dart new file mode 100644 index 0000000..e8aa88e --- /dev/null +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_state.freezed.dart @@ -0,0 +1,619 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'recipes_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$RecipesState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List recipesList) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List recipesList)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List recipesList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_RecipesState value) $default, { + required TResult Function(RecipesStateLoading value) loading, + required TResult Function(RecipesStateLoaded value) loaded, + required TResult Function(RecipesStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_RecipesState value)? $default, { + TResult? Function(RecipesStateLoading value)? loading, + TResult? Function(RecipesStateLoaded value)? loaded, + TResult? Function(RecipesStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_RecipesState value)? $default, { + TResult Function(RecipesStateLoading value)? loading, + TResult Function(RecipesStateLoaded value)? loaded, + TResult Function(RecipesStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RecipesStateCopyWith<$Res> { + factory $RecipesStateCopyWith( + RecipesState value, $Res Function(RecipesState) then) = + _$RecipesStateCopyWithImpl<$Res, RecipesState>; +} + +/// @nodoc +class _$RecipesStateCopyWithImpl<$Res, $Val extends RecipesState> + implements $RecipesStateCopyWith<$Res> { + _$RecipesStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$RecipesStateImplCopyWith<$Res> { + factory _$$RecipesStateImplCopyWith( + _$RecipesStateImpl value, $Res Function(_$RecipesStateImpl) then) = + __$$RecipesStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$RecipesStateImplCopyWithImpl<$Res> + extends _$RecipesStateCopyWithImpl<$Res, _$RecipesStateImpl> + implements _$$RecipesStateImplCopyWith<$Res> { + __$$RecipesStateImplCopyWithImpl( + _$RecipesStateImpl _value, $Res Function(_$RecipesStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$RecipesStateImpl implements _RecipesState { + const _$RecipesStateImpl(); + + @override + String toString() { + return 'RecipesState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$RecipesStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List recipesList) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List recipesList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List recipesList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_RecipesState value) $default, { + required TResult Function(RecipesStateLoading value) loading, + required TResult Function(RecipesStateLoaded value) loaded, + required TResult Function(RecipesStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_RecipesState value)? $default, { + TResult? Function(RecipesStateLoading value)? loading, + TResult? Function(RecipesStateLoaded value)? loaded, + TResult? Function(RecipesStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_RecipesState value)? $default, { + TResult Function(RecipesStateLoading value)? loading, + TResult Function(RecipesStateLoaded value)? loaded, + TResult Function(RecipesStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _RecipesState implements RecipesState { + const factory _RecipesState() = _$RecipesStateImpl; +} + +/// @nodoc +abstract class _$$RecipesStateLoadingImplCopyWith<$Res> { + factory _$$RecipesStateLoadingImplCopyWith(_$RecipesStateLoadingImpl value, + $Res Function(_$RecipesStateLoadingImpl) then) = + __$$RecipesStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$RecipesStateLoadingImplCopyWithImpl<$Res> + extends _$RecipesStateCopyWithImpl<$Res, _$RecipesStateLoadingImpl> + implements _$$RecipesStateLoadingImplCopyWith<$Res> { + __$$RecipesStateLoadingImplCopyWithImpl(_$RecipesStateLoadingImpl _value, + $Res Function(_$RecipesStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$RecipesStateLoadingImpl implements RecipesStateLoading { + const _$RecipesStateLoadingImpl(); + + @override + String toString() { + return 'RecipesState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RecipesStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List recipesList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List recipesList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List recipesList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_RecipesState value) $default, { + required TResult Function(RecipesStateLoading value) loading, + required TResult Function(RecipesStateLoaded value) loaded, + required TResult Function(RecipesStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_RecipesState value)? $default, { + TResult? Function(RecipesStateLoading value)? loading, + TResult? Function(RecipesStateLoaded value)? loaded, + TResult? Function(RecipesStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_RecipesState value)? $default, { + TResult Function(RecipesStateLoading value)? loading, + TResult Function(RecipesStateLoaded value)? loaded, + TResult Function(RecipesStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class RecipesStateLoading implements RecipesState { + const factory RecipesStateLoading() = _$RecipesStateLoadingImpl; +} + +/// @nodoc +abstract class _$$RecipesStateLoadedImplCopyWith<$Res> { + factory _$$RecipesStateLoadedImplCopyWith(_$RecipesStateLoadedImpl value, + $Res Function(_$RecipesStateLoadedImpl) then) = + __$$RecipesStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({List recipesList}); +} + +/// @nodoc +class __$$RecipesStateLoadedImplCopyWithImpl<$Res> + extends _$RecipesStateCopyWithImpl<$Res, _$RecipesStateLoadedImpl> + implements _$$RecipesStateLoadedImplCopyWith<$Res> { + __$$RecipesStateLoadedImplCopyWithImpl(_$RecipesStateLoadedImpl _value, + $Res Function(_$RecipesStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? recipesList = null, + }) { + return _then(_$RecipesStateLoadedImpl( + recipesList: null == recipesList + ? _value._recipesList + : recipesList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$RecipesStateLoadedImpl implements RecipesStateLoaded { + const _$RecipesStateLoadedImpl({required final List recipesList}) + : _recipesList = recipesList; + + final List _recipesList; + @override + List get recipesList { + if (_recipesList is EqualUnmodifiableListView) return _recipesList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_recipesList); + } + + @override + String toString() { + return 'RecipesState.loaded(recipesList: $recipesList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RecipesStateLoadedImpl && + const DeepCollectionEquality() + .equals(other._recipesList, _recipesList)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_recipesList)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RecipesStateLoadedImplCopyWith<_$RecipesStateLoadedImpl> get copyWith => + __$$RecipesStateLoadedImplCopyWithImpl<_$RecipesStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List recipesList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(recipesList); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List recipesList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(recipesList); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List recipesList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(recipesList); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_RecipesState value) $default, { + required TResult Function(RecipesStateLoading value) loading, + required TResult Function(RecipesStateLoaded value) loaded, + required TResult Function(RecipesStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_RecipesState value)? $default, { + TResult? Function(RecipesStateLoading value)? loading, + TResult? Function(RecipesStateLoaded value)? loaded, + TResult? Function(RecipesStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_RecipesState value)? $default, { + TResult Function(RecipesStateLoading value)? loading, + TResult Function(RecipesStateLoaded value)? loaded, + TResult Function(RecipesStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class RecipesStateLoaded implements RecipesState { + const factory RecipesStateLoaded({required final List recipesList}) = + _$RecipesStateLoadedImpl; + + List get recipesList; + @JsonKey(ignore: true) + _$$RecipesStateLoadedImplCopyWith<_$RecipesStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$RecipesStateErrorImplCopyWith<$Res> { + factory _$$RecipesStateErrorImplCopyWith(_$RecipesStateErrorImpl value, + $Res Function(_$RecipesStateErrorImpl) then) = + __$$RecipesStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$RecipesStateErrorImplCopyWithImpl<$Res> + extends _$RecipesStateCopyWithImpl<$Res, _$RecipesStateErrorImpl> + implements _$$RecipesStateErrorImplCopyWith<$Res> { + __$$RecipesStateErrorImplCopyWithImpl(_$RecipesStateErrorImpl _value, + $Res Function(_$RecipesStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$RecipesStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$RecipesStateErrorImpl implements RecipesStateError { + const _$RecipesStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'RecipesState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RecipesStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RecipesStateErrorImplCopyWith<_$RecipesStateErrorImpl> get copyWith => + __$$RecipesStateErrorImplCopyWithImpl<_$RecipesStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List recipesList) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List recipesList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List recipesList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_RecipesState value) $default, { + required TResult Function(RecipesStateLoading value) loading, + required TResult Function(RecipesStateLoaded value) loaded, + required TResult Function(RecipesStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_RecipesState value)? $default, { + TResult? Function(RecipesStateLoading value)? loading, + TResult? Function(RecipesStateLoaded value)? loaded, + TResult? Function(RecipesStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_RecipesState value)? $default, { + TResult Function(RecipesStateLoading value)? loading, + TResult Function(RecipesStateLoaded value)? loaded, + TResult Function(RecipesStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class RecipesStateError implements RecipesState { + const factory RecipesStateError({required final String errorMessage}) = + _$RecipesStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$RecipesStateErrorImplCopyWith<_$RecipesStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart new file mode 100644 index 0000000..ab7bf32 --- /dev/null +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -0,0 +1,259 @@ +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart'; +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; + +class FeedScreen extends StatefulWidget { + const FeedScreen({super.key}); + + @override + State createState() => _FeedScreenState(); +} + +class _FeedScreenState extends State { + final List chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты']; + + int _selectedChipIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + toolbarHeight: 0, + ), + backgroundColor: Colors.grey.shade200, + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)), + ), + backgroundColor: Colors.white, + foregroundColor: Colors.white, + automaticallyImplyLeading: false, + stretchTriggerOffset: 1, + floating: true, + snap: true, + scrolledUnderElevation: 0, + bottom: _chipGroup(), + title: Row( + children: [ + _searchBar(), + SizedBox(width: 12), + _addBlogPostButton(), + ], + ), + ), + ]; + }, + body: Builder( + builder: (BuildContext context) { + if (_selectedChipIndex == 0) + return _buildAllBlogPosts(); + else + return _buildAllRecipes(); + }, + ), + ), + ); + } + + _buildAllBlogPosts() { + return RefreshIndicator( + onRefresh: () => context.read().loadFeedBlogPostList(), + child: BlocBuilder( + builder: (BuildContext context, FeedState state) { + if (state is FeedStateLoaded) { + return ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return BlogPostWidget(feedBlogPostModel: state.feedBlogPostList[index]); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.feedBlogPostList.length, + ); + } else if (state is FeedStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } + }, + ), + ); + } + + _buildAllRecipes() { + return RefreshIndicator( + onRefresh: () => context.read().loadRecipesList(), + child: BlocBuilder( + builder: (BuildContext context, RecipesState state) { + if (state is RecipesStateLoaded) { + return ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return RecipesWidget(recipes: state.recipesList[index]); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.recipesList.length, + ); + } else if (state is RecipesStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } + }, + ), + ); + } + + _chipGroup() { + return PreferredSize( + preferredSize: Size(MediaQuery.of(context).size.width, 32), + child: Align( + alignment: Alignment.centerLeft, + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16), + scrollDirection: Axis.horizontal, + child: Row( + children: [ + _choiceChipWidget(0), + SizedBox(width: 8), + _choiceChipWidget(1), + SizedBox(width: 8), + _choiceChipWidget(2), + SizedBox(width: 8), + _choiceChipWidget(3), + SizedBox(width: 8), + _choiceChipWidget(4), + ], + ), + ), + ), + ); + } + + _addBlogPostButton() { + return InkWell( + onTap: () => GoRouter.of(context).pushNamed('blogPostCreateScreen'), + borderRadius: BorderRadius.circular(64), + child: Ink( + decoration: BoxDecoration( + color: appTheme.blueA400, + shape: BoxShape.circle, + ), + child: Icon( + Icons.add_rounded, + color: appTheme.gray100, + ), + width: 40, + height: 40, + ), + ); + } + + _searchBar() { + return SizedBox( + height: 40, + width: MediaQuery.of(context).size.width - 84, + child: TextFormField( + style: TextStyle( + fontSize: 12, + ), + decoration: InputDecoration( + hintText: 'Поиск', + hintStyle: TextStyle( + fontSize: 12, + color: appTheme.gray600, + fontWeight: FontWeight.w400, + ), + prefixIcon: Icon( + Icons.search, + color: appTheme.gray600, + size: 16, + ), + isDense: false, + contentPadding: EdgeInsets.all(8), + fillColor: appTheme.gray100, + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide.none, + ), + ), + ), + ); + } + + _choiceChipWidget(int index) { + return ChoiceChip( + selectedColor: appTheme.blueA400, + pressElevation: 0, + showCheckmark: false, + side: BorderSide.none, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + label: Text(chipsLabelList[index]), + labelStyle: TextStyle( + color: index == _selectedChipIndex ? Colors.white : appTheme.gray600, + fontWeight: FontWeight.w500, + fontSize: 12, + ), + selected: _selectedChipIndex == index, + backgroundColor: appTheme.gray100, + onSelected: (bool selected) { + setState(() { + _selectedChipIndex = index; + }); + }, + ); + } +} diff --git a/lib/features/feed/presentation/widgets/blog_post_widget.dart b/lib/features/feed/presentation/widgets/blog_post_widget.dart new file mode 100644 index 0000000..1139fe0 --- /dev/null +++ b/lib/features/feed/presentation/widgets/blog_post_widget.dart @@ -0,0 +1,160 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dismissible_page/dismissible_page.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class BlogPostWidget extends StatefulWidget { + final FeedBlogPostModel feedBlogPostModel; + + const BlogPostWidget({super.key, required this.feedBlogPostModel}); + + @override + State createState() => _BlogPostWidgetState(); +} + +class _BlogPostWidgetState extends State { + @override + Widget build(BuildContext context) { + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => GoRouter.of(context).pushNamed( + 'blogPostScreen', + extra: widget.feedBlogPostModel.id.toString(), + ), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + CircleAvatar(radius: 20), + SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Имя автора'), + Text('Время поста'), + ], + ), + ], + ), + ), + if (widget.feedBlogPostModel.title.isNotEmpty || widget.feedBlogPostModel.description.isNotEmpty) SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + widget.feedBlogPostModel.title, + style: TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + ), + if (widget.feedBlogPostModel.title.isNotEmpty && widget.feedBlogPostModel.description.isNotEmpty) SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + widget.feedBlogPostModel.description, + style: TextStyle( + color: Colors.black87, + ), + ), + ), + if (widget.feedBlogPostModel.title.isNotEmpty || widget.feedBlogPostModel.description.isNotEmpty) SizedBox(height: 8), + GestureDetector( + onTap: () { + context.pushTransparentRoute( + rootNavigator: true, + PhotoViewScreen( + imageUrls: [baseUrl + '/storage/' + widget.feedBlogPostModel.image], + index: 0, + ), + ); + }, + child: Hero( + tag: baseUrl + '/storage/' + widget.feedBlogPostModel.image, + child: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + widget.feedBlogPostModel.image, + ), + ), + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + _iconButton(Icons.favorite_border_rounded), + SizedBox(width: 8), + _iconButton(Icons.mode_comment_outlined), + SizedBox(width: 8), + _iconButton(Icons.reply_rounded), + Spacer(), + Icon( + Icons.visibility_rounded, + size: 16, + color: appTheme.gray500, + ), + SizedBox(width: 4), + Text( + '0', + style: TextStyle( + fontSize: 12, + color: appTheme.gray500, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + SizedBox(height: 8), + ], + ), + ), + ); + } + + _iconButton(IconData icon, [String? text]) { + return InkWell( + onTap: () {}, + borderRadius: BorderRadius.circular(16), + child: Ink( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: appTheme.gray100, + borderRadius: BorderRadius.circular(16), + ), + height: 32, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 20, + color: appTheme.gray600, + ), + if (text != null) SizedBox(width: 8), + if (text != null) + Text( + text, + style: TextStyle( + color: appTheme.gray600, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/feed/presentation/widgets/recipes_widget.dart b/lib/features/feed/presentation/widgets/recipes_widget.dart new file mode 100644 index 0000000..751612f --- /dev/null +++ b/lib/features/feed/presentation/widgets/recipes_widget.dart @@ -0,0 +1,187 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dismissible_page/dismissible_page.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class RecipesWidget extends StatefulWidget { + final Recipes recipes; + + const RecipesWidget({super.key, required this.recipes}); + + @override + State createState() => _RecipesWidgetState(); +} + +class _RecipesWidgetState extends State { + @override + Widget build(BuildContext context) { + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => GoRouter.of(context).pushNamed('aboutRecipesScreen', extra: widget.recipes), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.vertical(top: Radius.circular(12)), + child: GestureDetector( + onTap: () { + context.pushTransparentRoute( + rootNavigator: true, + PhotoViewScreen( + imageUrls: [baseUrl + '/storage/' + widget.recipes.image], + index: 0, + ), + ); + }, + child: Hero( + tag: baseUrl + '/storage/' + widget.recipes.image, + child: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + widget.recipes.image, + ), + ), + ), + ), + Positioned( + left: 8, + bottom: 8, + child: Wrap( + runSpacing: 8, + children: [ + _iconButton(Icons.fastfood, '139.9 ккал'), + SizedBox(width: 8), + _iconButton(Icons.timer_rounded, widget.recipes.cookingTime.toString() + ' минут'), + SizedBox(width: 8), + _iconButton(Icons.fast_forward_rounded, widget.recipes.steps.length.toString() + ' этапов'), + ], + ), + ), + Positioned( + left: 8, + top: 8, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + borderRadius: BorderRadius.circular(16), + ), + child: Row( + children: [ + Icon( + Icons.favorite_rounded, + size: 16, + color: Colors.black, + ), + SizedBox(width: 4), + Text( + '0', + style: TextStyle( + fontSize: 12, + color: Colors.black, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ), + Positioned( + right: 8, + top: 8, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + borderRadius: BorderRadius.circular(16), + ), + child: Row( + children: [ + Icon( + Icons.visibility_rounded, + size: 16, + color: Colors.black, + ), + SizedBox(width: 4), + Text( + '0', + style: TextStyle( + fontSize: 12, + color: Colors.black, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + widget.recipes.title, + style: TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + ), + SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + widget.recipes.description, + style: TextStyle( + color: Colors.black87, + ), + ), + ), + SizedBox(height: 12), + ], + ), + ), + ); + } + + _iconButton(IconData icon, [String? text]) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + borderRadius: BorderRadius.circular(16), + ), + height: 32, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 16, + color: Colors.black, + ), + if (text != null) SizedBox(width: 8), + if (text != null) + Text( + text, + style: TextStyle( + fontSize: 12, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/feed/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart new file mode 100644 index 0000000..0d2476f --- /dev/null +++ b/lib/features/feed/repositories/feed_repository.dart @@ -0,0 +1,34 @@ +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:eatvio_app/features/feed/services/feed_service.dart'; + +class FeedRepository { + final FeedService feedService; + + FeedRepository({required this.feedService}); + + Future> getFeedBlogPostList() async { + try { + return (await feedService.getBlocPostList()).feedBlogPostList; + } catch (e) { + rethrow; + } + } + + Future> getRecipes() async { + try { + return (await feedService.getRecipes()).recipesList; + } catch (e) { + rethrow; + } + } + + Future getDiets() async { + try { + return (await feedService.getDiets()); + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart new file mode 100644 index 0000000..0d848a5 --- /dev/null +++ b/lib/features/feed/services/feed_service.dart @@ -0,0 +1,21 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart'; +import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'feed_service.g.dart'; + +@RestApi() +abstract class FeedService { + factory FeedService(Dio dio, {String baseUrl}) = _FeedService; + + @GET('/api/blogPosts/index') + Future getBlocPostList(); + + @GET('/api/recipes/index') + Future getRecipes(); + + @GET('/api/diets/index') + Future getDiets(); +} diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart new file mode 100644 index 0000000..77b6577 --- /dev/null +++ b/lib/features/feed/services/feed_service.g.dart @@ -0,0 +1,131 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'feed_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _FeedService implements FeedService { + _FeedService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future getBlocPostList() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = FeedBlogPostSettingsModel.fromJson(_result.data!); + return _value; + } + + @override + Future getRecipes() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = RecipesPagination.fromJson(_result.data!); + return _value; + } + + @override + Future getDiets() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = DietsPagination.fromJson(_result.data!); + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/recipes/presentation/pages/about_recipes_screen.dart b/lib/features/recipes/presentation/pages/about_recipes_screen.dart new file mode 100644 index 0000000..fb4ae6b --- /dev/null +++ b/lib/features/recipes/presentation/pages/about_recipes_screen.dart @@ -0,0 +1,178 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/feed/models/recipes_model.dart' as step; +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:flutter/material.dart'; + +class AboutRecipesScreen extends StatelessWidget { + final Recipes recipes; + + const AboutRecipesScreen({super.key, required this.recipes}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + recipes.title, + style: TextStyle( + color: Colors.black, + fontSize: 24, + fontWeight: FontWeight.w500, + height: 1, + ), + ), + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Icon(Icons.timer_outlined), + SizedBox(width: 4), + Text( + recipes.cookingTime.toString() + ' минут', + style: TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + SizedBox(width: 16), + Icon(Icons.fast_forward_outlined), + SizedBox(width: 4), + Text( + recipes.steps.length.toString() + ' этапов', + style: TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + ], + ), + ), + SizedBox(height: 12), + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + recipes.image, + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Ингредиенты', + style: TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1, + ), + ), + ), + SizedBox(height: 12), + ListView.separated( + padding: const EdgeInsets.symmetric(horizontal: 16), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => _ingredient(recipes.ingredients[index]), + separatorBuilder: (context, index) => SizedBox(height: 4), + itemCount: recipes.ingredients.length, + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Пошаговый рецепт', + style: TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1, + ), + ), + ), + SizedBox(height: 12), + ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => _step(recipes.steps[index], index + 1), + separatorBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(16), + child: Container( + height: 0.4, + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(16), + ), + ), + ), + itemCount: recipes.steps.length, + ), + ], + ), + ), + ); + } + + _ingredient(Ingredient ingredient) { + return Text( + '• '+ ingredient.name + ' ' + ingredient.portion + ' ' + (ingredient.unit ?? ''), + style: TextStyle( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1.2, + ), + ); + } + + _step(step.Step step, int stepNumber) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Шаг ' + stepNumber.toString(), + style: TextStyle( + color: Colors.black54, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + step.description, + style: TextStyle( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1.2, + ), + ), + ), + SizedBox(height: 8), + if (step.image.length > 1) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: CachedNetworkImage(imageUrl: baseUrl + '/storage/' + step.image), + ), + ) + ], + ); + } +} diff --git a/lib/features/registration/consts/cities_list.dart b/lib/features/registration/consts/cities_list.dart new file mode 100644 index 0000000..0eea40d --- /dev/null +++ b/lib/features/registration/consts/cities_list.dart @@ -0,0 +1,1119 @@ +const List citiesList = const [ + "Абаза", + "Абакан", + "Абдулино", + "Абинск", + "Агидель", + "Агрыз", + "Адыгейск", + "Азнакаево", + "Азов", + "Ак-Довурак", + "Аксай", + "Алагир", + "Алапаевск", + "Алатырь", + "Алдан", + "Алейск", + "Александров", + "Александровск", + "Александровск-Сахалинский", + "Алексеевка", + "Алексин", + "Алзамай", + "АлупкаОспаривается", + "АлуштаОспаривается", + "Альметьевск", + "Амурск", + "Анадырь", + "Анапа", + "Ангарск", + "Андреаполь", + "Анжеро-Судженск", + "Анива", + "Апатиты", + "Апрелевка", + "Апшеронск", + "Арамиль", + "Аргун", + "Ардатов", + "Ардон", + "Арзамас", + "Аркадак", + "Армавир", + "АрмянскОспаривается", + "Арсеньев", + "Арск", + "Артём", + "Артёмовск", + "Артёмовский", + "Архангельск", + "Асбест", + "Асино", + "Астрахань", + "Аткарск", + "Ахтубинск", + "Ачинск", + "Аша", + "Бабаево", + "Бабушкин", + "Бавлы", + "Багратионовск", + "Байкальск", + "Баймак", + "Бакал", + "Баксан", + "Балабаново", + "Балаково", + "Балахна", + "Балашиха", + "Балашов", + "Балей", + "Балтийск", + "Барабинск", + "Барнаул", + "Барыш", + "Батайск", + "БахчисарайОспаривается", + "Бежецк", + "Белая Калитва", + "Белая Холуница", + "Белгород", + "Белебей", + "Белёв", + "Белинский", + "Белово", + "Белогорск", + "БелогорскОспаривается", + "Белозерск", + "Белокуриха", + "Беломорск", + "Белоозёрский", + "Белорецк", + "Белореченск", + "Белоусово", + "Белоярский", + "Белый", + "Бердск", + "Березники", + "Берёзовский", + "Берёзовский", + "Беслан", + "Бийск", + "Бикин", + "Билибино", + "Биробиджан", + "Бирск", + "Бирюсинск", + "Бирюч", + "Благовещенск", + "Благовещенск", + "Благодарный", + "Бобров", + "Богданович", + "Богородицк", + "Богородск", + "Боготол", + "Богучар", + "Бодайбо", + "Бокситогорск", + "Болгар", + "Бологое", + "Болотное", + "Болохово", + "Болхов", + "Большой Камень", + "Бор", + "Борзя", + "Борисоглебск", + "Боровичи", + "Боровск", + "Бородино", + "Братск", + "Бронницы", + "Брянск", + "Бугульма", + "Бугуруслан", + "Будённовск", + "Бузулук", + "Буинск", + "Буй", + "Буйнакск", + "Бутурлиновка", + "Валдай", + "Валуйки", + "Велиж", + "Великие Луки", + "Великий Новгород", + "Великий Устюг", + "Вельск", + "Венёв", + "Верещагино", + "Верея", + "Верхнеуральск", + "Верхний Тагил", + "Верхний Уфалей", + "Верхняя Пышма", + "Верхняя Салда", + "Верхняя Тура", + "Верхотурье", + "Верхоянск", + "Весьегонск", + "Ветлуга", + "Видное", + "Вилюйск", + "Вилючинск", + "Вихоревка", + "Вичуга", + "Владивосток", + "Владикавказ", + "Владимир", + "Волгоград", + "Волгодонск", + "Волгореченск", + "Волжск", + "Волжский", + "Вологда", + "Володарск", + "Волоколамск", + "Волосово", + "Волхов", + "Волчанск", + "Вольск", + "Воркута", + "Воронеж", + "Ворсма", + "Воскресенск", + "Воткинск", + "Всеволожск", + "Вуктыл", + "Выборг", + "Выкса", + "Высоковск", + "Высоцк", + "Вытегра", + "Вышний Волочёк", + "Вяземский", + "Вязники", + "Вязьма", + "Вятские Поляны", + "Гаврилов Посад", + "Гаврилов-Ям", + "Гагарин", + "Гаджиево", + "Гай", + "Галич", + "Гатчина", + "Гвардейск", + "Гдов", + "Геленджик", + "Георгиевск", + "Глазов", + "Голицыно", + "Горбатов", + "Горно-Алтайск", + "Горнозаводск", + "Горняк", + "Городец", + "Городище", + "Городовиковск", + "Гороховец", + "Горячий Ключ", + "Грайворон", + "Гремячинск", + "Грозный", + "Грязи", + "Грязовец", + "Губаха", + "Губкин", + "Губкинский", + "Гудермес", + "Гуково", + "Гулькевичи", + "Гурьевск", + "Гурьевск", + "Гусев", + "Гусиноозёрск", + "Гусь-Хрустальный", + "Давлеканово", + "Дагестанские Огни", + "Далматово", + "Дальнегорск", + "Дальнереченск", + "Данилов", + "Данков", + "Дегтярск", + "Дедовск", + "Демидов", + "Дербент", + "Десногорск", + "ДжанкойОспаривается", + "Дзержинск", + "Дзержинский", + "Дивногорск", + "Дигора", + "Димитровград", + "Дмитриев", + "Дмитров", + "Дмитровск", + "Дно", + "Добрянка", + "Долгопрудный", + "Долинск", + "Домодедово", + "Донецк", + "Донской", + "Дорогобуж", + "Дрезна", + "Дубна", + "Дубовка", + "Дудинка", + "Духовщина", + "Дюртюли", + "Дятьково", + "ЕвпаторияОспаривается", + "Егорьевск", + "Ейск", + "Екатеринбург", + "Елабуга", + "Елец", + "Елизово", + "Ельня", + "Еманжелинск", + "Емва", + "Енисейск", + "Ермолино", + "Ершов", + "Ессентуки", + "Ефремов", + "Железноводск", + "Железногорск", + "Железногорск", + "Железногорск-Илимский", + "Жердевка", + "Жигулёвск", + "Жиздра", + "Жирновск", + "Жуков", + "Жуковка", + "Жуковский", + "Завитинск", + "Заводоуковск", + "Заволжск", + "Заволжье", + "Задонск", + "Заинск", + "Закаменск", + "Заозёрный", + "Заозёрск", + "Западная Двина", + "Заполярный", + "Зарайск", + "Заречный", + "Заречный", + "Заринск", + "Звенигово", + "Звенигород", + "Зверево", + "Зеленогорск", + "Зеленоградск", + "Зеленодольск", + "Зеленокумск", + "Зерноград", + "Зея", + "Зима", + "Златоуст", + "Злынка", + "Змеиногорск", + "Знаменск", + "Зубцов", + "Зуевка", + "Ивангород", + "Иваново", + "Ивантеевка", + "Ивдель", + "Игарка", + "Ижевск", + "Избербаш", + "Изобильный", + "Иланский", + "Инза", + "Иннополис", + "Инсар", + "Инта", + "Ипатово", + "Ирбит", + "Иркутск", + "Исилькуль", + "Искитим", + "Истра", + "Ишим", + "Ишимбай", + "Йошкар-Ола", + "Кадников", + "Казань", + "Калач", + "Калач-на-Дону", + "Калачинск", + "Калининград", + "Калининск", + "Калтан", + "Калуга", + "Калязин", + "Камбарка", + "Каменка", + "Каменногорск", + "Каменск-Уральский", + "Каменск-Шахтинский", + "Камень-на-Оби", + "Камешково", + "Камызяк", + "Камышин", + "Камышлов", + "Канаш", + "Кандалакша", + "Канск", + "Карабаново", + "Карабаш", + "Карабулак", + "Карасук", + "Карачаевск", + "Карачев", + "Каргат", + "Каргополь", + "Карпинск", + "Карталы", + "Касимов", + "Касли", + "Каспийск", + "Катав-Ивановск", + "Катайск", + "Качканар", + "Кашин", + "Кашира", + "Кедровый", + "Кемерово", + "Кемь", + "КерчьОспаривается", + "Кизел", + "Кизилюрт", + "Кизляр", + "Кимовск", + "Кимры", + "Кингисепп", + "Кинель", + "Кинешма", + "Киреевск", + "Киренск", + "Киржач", + "Кириллов", + "Кириши", + "Киров", + "Киров", + "Кировград", + "Кирово-Чепецк", + "Кировск", + "Кировск", + "Кирс", + "Кирсанов", + "Киселёвск", + "Кисловодск", + "Клин", + "Клинцы", + "Княгинино", + "Ковдор", + "Ковров", + "Ковылкино", + "Когалым", + "Кодинск", + "Козельск", + "Козловка", + "Козьмодемьянск", + "Кола", + "Кологрив", + "Коломна", + "Колпашево", + "Кольчугино", + "Коммунар", + "Комсомольск", + "Комсомольск-на-Амуре", + "Конаково", + "Кондопога", + "Кондрово", + "Константиновск", + "Копейск", + "Кораблино", + "Кореновск", + "Коркино", + "Королёв", + "Короча", + "Корсаков", + "Коряжма", + "Костерёво", + "Костомукша", + "Кострома", + "Котельники", + "Котельниково", + "Котельнич", + "Котлас", + "Котово", + "Котовск", + "Кохма", + "Красавино", + "Красноармейск", + "Красноармейск", + "Красновишерск", + "Красногорск", + "Краснодар", + "Краснозаводск", + "Краснознаменск", + "Краснознаменск", + "Краснокаменск", + "Краснокамск", + "КрасноперекопскОспаривается", + "Краснослободск", + "Краснослободск", + "Краснотурьинск", + "Красноуральск", + "Красноуфимск", + "Красноярск", + "Красный Кут", + "Красный Сулин", + "Красный Холм", + "Кремёнки", + "Кропоткин", + "Крымск", + "Кстово", + "Кубинка", + "Кувандык", + "Кувшиново", + "Кудрово", + "Кудымкар", + "Кузнецк", + "Куйбышев", + "Кукмор", + "Кулебаки", + "Кумертау", + "Кунгур", + "Купино", + "Курган", + "Курганинск", + "Курильск", + "Курлово", + "Куровское", + "Курск", + "Куртамыш", + "Курчалой", + "Курчатов", + "Куса", + "Кушва", + "Кызыл", + "Кыштым", + "Кяхта", + "Лабинск", + "Лабытнанги", + "Лагань", + "Ладушкин", + "Лаишево", + "Лакинск", + "Лангепас", + "Лахденпохья", + "Лебедянь", + "Лениногорск", + "Ленинск", + "Ленинск-Кузнецкий", + "Ленск", + "Лермонтов", + "Лесной", + "Лесозаводск", + "Лесосибирск", + "Ливны", + "Ликино-Дулёво", + "Липецк", + "Липки", + "Лиски", + "Лихославль", + "Лобня", + "Лодейное Поле", + "Лосино-Петровский", + "Луга", + "Луза", + "Лукоянов", + "Луховицы", + "Лысково", + "Лысьва", + "Лыткарино", + "Льгов", + "Любань", + "Люберцы", + "Любим", + "Людиново", + "Лянтор", + "Магадан", + "Магас", + "Магнитогорск", + "Майкоп", + "Майский", + "Макаров", + "Макарьев", + "Макушино", + "Малая Вишера", + "Малгобек", + "Малмыж", + "Малоархангельск", + "Малоярославец", + "Мамадыш", + "Мамоново", + "Мантурово", + "Мариинск", + "Мариинский Посад", + "Маркс", + "Махачкала", + "Мглин", + "Мегион", + "Медвежьегорск", + "Медногорск", + "Медынь", + "Межгорье", + "Междуреченск", + "Мезень", + "Меленки", + "Мелеуз", + "Менделеевск", + "Мензелинск", + "Мещовск", + "Миасс", + "Микунь", + "Миллерово", + "Минеральные Воды", + "Минусинск", + "Миньяр", + "Мирный", + "Мирный", + "Михайлов", + "Михайловка", + "Михайловск", + "Михайловск", + "Мичуринск", + "Могоча", + "Можайск", + "Можга", + "Моздок", + "Мончегорск", + "Морозовск", + "Моршанск", + "Мосальск", + "Москва", + "Муравленко", + "Мураши", + "Мурино", + "Мурманск", + "Муром", + "Мценск", + "Мыски", + "Мытищи", + "Мышкин", + "Набережные Челны", + "Навашино", + "Наволоки", + "Надым", + "Назарово", + "Назрань", + "Называевск", + "Нальчик", + "Нариманов", + "Наро-Фоминск", + "Нарткала", + "Нарьян-Мар", + "Находка", + "Невель", + "Невельск", + "Невинномысск", + "Невьянск", + "Нелидово", + "Неман", + "Нерехта", + "Нерчинск", + "Нерюнгри", + "Нестеров", + "Нефтегорск", + "Нефтекамск", + "Нефтекумск", + "Нефтеюганск", + "Нея", + "Нижневартовск", + "Нижнекамск", + "Нижнеудинск", + "Нижние Серги", + "Нижний Ломов", + "Нижний Новгород", + "Нижний Тагил", + "Нижняя Салда", + "Нижняя Тура", + "Николаевск", + "Николаевск-на-Амуре", + "Никольск", + "Никольск", + "Никольское", + "Новая Ладога", + "Новая Ляля", + "Новоалександровск", + "Новоалтайск", + "Новоаннинский", + "Нововоронеж", + "Новодвинск", + "Новозыбков", + "Новокубанск", + "Новокузнецк", + "Новокуйбышевск", + "Новомичуринск", + "Новомосковск", + "Новопавловск", + "Новоржев", + "Новороссийск", + "Новосибирск", + "Новосиль", + "Новосокольники", + "Новотроицк", + "Новоузенск", + "Новоульяновск", + "Новоуральск", + "Новохопёрск", + "Новочебоксарск", + "Новочеркасск", + "Новошахтинск", + "Новый Оскол", + "Новый Уренгой", + "Ногинск", + "Нолинск", + "Норильск", + "Ноябрьск", + "Нурлат", + "Нытва", + "Нюрба", + "Нягань", + "Нязепетровск", + "Няндома", + "Облучье", + "Обнинск", + "Обоянь", + "Обь", + "Одинцово", + "Озёрск", + "Озёрск", + "Озёры", + "Октябрьск", + "Октябрьский", + "Окуловка", + "Олёкминск", + "Оленегорск", + "Олонец", + "Омск", + "Омутнинск", + "Онега", + "Опочка", + "Орёл", + "Оренбург", + "Орехово-Зуево", + "Орлов", + "Орск", + "Оса", + "Осинники", + "Осташков", + "Остров", + "Островной", + "Острогожск", + "Отрадное", + "Отрадный", + "Оха", + "Оханск", + "Очёр", + "Павлово", + "Павловск", + "Павловский Посад", + "Палласовка", + "Партизанск", + "Певек", + "Пенза", + "Первомайск", + "Первоуральск", + "Перевоз", + "Пересвет", + "Переславль-Залесский", + "Пермь", + "Пестово", + "Петров Вал", + "Петровск", + "Петровск-Забайкальский", + "Петрозаводск", + "Петропавловск-Камчатский", + "Петухово", + "Петушки", + "Печора", + "Печоры", + "Пикалёво", + "Пионерский", + "Питкяранта", + "Плавск", + "Пласт", + "Плёс", + "Поворино", + "Подольск", + "Подпорожье", + "Покачи", + "Покров", + "Покровск", + "Полевской", + "Полесск", + "Полысаево", + "Полярные Зори", + "Полярный", + "Поронайск", + "Порхов", + "Похвистнево", + "Почеп", + "Починок", + "Пошехонье", + "Правдинск", + "Приволжск", + "Приморск", + "Приморск", + "Приморско-Ахтарск", + "Приозерск", + "Прокопьевск", + "Пролетарск", + "Протвино", + "Прохладный", + "Псков", + "Пугачёв", + "Пудож", + "Пустошка", + "Пучеж", + "Пушкино", + "Пущино", + "Пыталово", + "Пыть-Ях", + "Пятигорск", + "Радужный", + "Радужный", + "Райчихинск", + "Раменское", + "Рассказово", + "Ревда", + "Реж", + "Реутов", + "Ржев", + "Родники", + "Рославль", + "Россошь", + "Ростов-на-Дону", + "Ростов", + "Рошаль", + "Ртищево", + "Рубцовск", + "Рудня", + "Руза", + "Рузаевка", + "Рыбинск", + "Рыбное", + "Рыльск", + "Ряжск", + "Рязань", + "СакиОспаривается", + "Салават", + "Салаир", + "Салехард", + "Сальск", + "Самара", + "Санкт-Петербург", + "Саранск", + "Сарапул", + "Саратов", + "Саров", + "Сасово", + "Сатка", + "Сафоново", + "Саяногорск", + "Саянск", + "Светлогорск", + "Светлоград", + "Светлый", + "Светогорск", + "Свирск", + "Свободный", + "Себеж", + "СевастопольОспаривается", + "Северо-Курильск", + "Северобайкальск", + "Северодвинск", + "Североморск", + "Североуральск", + "Северск", + "Севск", + "Сегежа", + "Сельцо", + "Семёнов", + "Семикаракорск", + "Семилуки", + "Сенгилей", + "Серафимович", + "Сергач", + "Сергиев Посад", + "Сердобск", + "Серов", + "Серпухов", + "Сертолово", + "Сибай", + "Сим", + "СимферопольОспаривается", + "Сковородино", + "Скопин", + "Славгород", + "Славск", + "Славянск-на-Кубани", + "Сланцы", + "Слободской", + "Слюдянка", + "Смоленск", + "Снежинск", + "Снежногорск", + "Собинка", + "Советск", + "Советск", + "Советск", + "Советская Гавань", + "Советский", + "Сокол", + "Солигалич", + "Соликамск", + "Солнечногорск", + "Соль-Илецк", + "Сольвычегодск", + "Сольцы", + "Сорочинск", + "Сорск", + "Сортавала", + "Сосенский", + "Сосновка", + "Сосновоборск", + "Сосновый Бор", + "Сосногорск", + "Сочи", + "Спас-Деменск", + "Спас-Клепики", + "Спасск", + "Спасск-Дальний", + "Спасск-Рязанский", + "Среднеколымск", + "Среднеуральск", + "Сретенск", + "Ставрополь", + "Старая Купавна", + "Старая Русса", + "Старица", + "Стародуб", + "Старый КрымОспаривается", + "Старый Оскол", + "Стерлитамак", + "Стрежевой", + "Строитель", + "Струнино", + "Ступино", + "Суворов", + "СудакОспаривается", + "Суджа", + "Судогда", + "Суздаль", + "Сунжа", + "Суоярви", + "Сураж", + "Сургут", + "Суровикино", + "Сурск", + "Сусуман", + "Сухиничи", + "Сухой Лог", + "Сызрань", + "Сыктывкар", + "Сысерть", + "Сычёвка", + "Сясьстрой", + "Тавда", + "Таганрог", + "Тайга", + "Тайшет", + "Талдом", + "Талица", + "Тамбов", + "Тара", + "Тарко-Сале", + "Таруса", + "Татарск", + "Таштагол", + "Тверь", + "Теберда", + "Тейково", + "Темников", + "Темрюк", + "Терек", + "Тетюши", + "Тимашёвск", + "Тихвин", + "Тихорецк", + "Тобольск", + "Тогучин", + "Тольятти", + "Томари", + "Томмот", + "Томск", + "Топки", + "Торжок", + "Торопец", + "Тосно", + "Тотьма", + "Трёхгорный", + "Троицк", + "Трубчевск", + "Туапсе", + "Туймазы", + "Тула", + "Тулун", + "Туран", + "Туринск", + "Тутаев", + "Тында", + "Тырныауз", + "Тюкалинск", + "Тюмень", + "Уварово", + "Углегорск", + "Углич", + "Удачный", + "Удомля", + "Ужур", + "Узловая", + "Улан-Удэ", + "Ульяновск", + "Унеча", + "Урай", + "Урень", + "Уржум", + "Урус-Мартан", + "Урюпинск", + "Усинск", + "Усмань", + "Усолье-Сибирское", + "Усолье", + "Уссурийск", + "Усть-Джегута", + "Усть-Илимск", + "Усть-Катав", + "Усть-Кут", + "Усть-Лабинск", + "Устюжна", + "Уфа", + "Ухта", + "Учалы", + "Уяр", + "Фатеж", + "ФеодосияОспаривается", + "Фокино", + "Фокино", + "Фролово", + "Фрязино", + "Фурманов", + "Хабаровск", + "Хадыженск", + "Ханты-Мансийск", + "Харабали", + "Харовск", + "Хасавюрт", + "Хвалынск", + "Хилок", + "Химки", + "Холм", + "Холмск", + "Хотьково", + "Цивильск", + "Цимлянск", + "Циолковский", + "Чадан", + "Чайковский", + "Чапаевск", + "Чаплыгин", + "Чебаркуль", + "Чебоксары", + "Чегем", + "Чекалин", + "Челябинск", + "Чердынь", + "Черемхово", + "Черепаново", + "Череповец", + "Черкесск", + "Чёрмоз", + "Черноголовка", + "Черногорск", + "Чернушка", + "Черняховск", + "Чехов", + "Чистополь", + "Чита", + "Чкаловск", + "Чудово", + "Чулым", + "Чусовой", + "Чухлома", + "Шагонар", + "Шадринск", + "Шали", + "Шарыпово", + "Шарья", + "Шатура", + "Шахты", + "Шахунья", + "Шацк", + "Шебекино", + "Шелехов", + "Шенкурск", + "Шилка", + "Шимановск", + "Шиханы", + "Шлиссельбург", + "Шумерля", + "Шумиха", + "Шуя", + "Щёкино", + "ЩёлкиноОспаривается", + "Щёлково", + "Щигры", + "Щучье", + "Электрогорск", + "Электросталь", + "Электроугли", + "Элиста", + "Энгельс", + "Эртиль", + "Югорск", + "Южа", + "Южно-Сахалинск", + "Южно-Сухокумск", + "Южноуральск", + "Юрга", + "Юрьев-Польский", + "Юрьевец", + "Юрюзань", + "Юхнов", + "Ядрин", + "Якутск", + "ЯлтаОспаривается", + "Ялуторовск", + "Янаул", + "Яранск", + "Яровое", + "Ярославль", + "Ярцево", + "Ясногорск", + "Ясный", + "Яхрома", +]; diff --git a/lib/features/registration/models/location_model.dart b/lib/features/registration/models/location_model.dart new file mode 100644 index 0000000..cc6b107 --- /dev/null +++ b/lib/features/registration/models/location_model.dart @@ -0,0 +1,15 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'location_model.g.dart'; + +part 'location_model.freezed.dart'; + +@freezed +class LocationModel with _$LocationModel { + const factory LocationModel({ + required List locations, + @JsonKey(name: 'response_body') required String responseBody, + }) = _LocationModel; + + factory LocationModel.fromJson(Map json) => _$LocationModelFromJson(json); +} diff --git a/lib/features/registration/models/location_model.freezed.dart b/lib/features/registration/models/location_model.freezed.dart new file mode 100644 index 0000000..f640ca2 --- /dev/null +++ b/lib/features/registration/models/location_model.freezed.dart @@ -0,0 +1,189 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'location_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +LocationModel _$LocationModelFromJson(Map json) { + return _LocationModel.fromJson(json); +} + +/// @nodoc +mixin _$LocationModel { + List get locations => throw _privateConstructorUsedError; + @JsonKey(name: 'response_body') + String get responseBody => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LocationModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LocationModelCopyWith<$Res> { + factory $LocationModelCopyWith( + LocationModel value, $Res Function(LocationModel) then) = + _$LocationModelCopyWithImpl<$Res, LocationModel>; + @useResult + $Res call( + {List locations, + @JsonKey(name: 'response_body') String responseBody}); +} + +/// @nodoc +class _$LocationModelCopyWithImpl<$Res, $Val extends LocationModel> + implements $LocationModelCopyWith<$Res> { + _$LocationModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locations = null, + Object? responseBody = null, + }) { + return _then(_value.copyWith( + locations: null == locations + ? _value.locations + : locations // ignore: cast_nullable_to_non_nullable + as List, + responseBody: null == responseBody + ? _value.responseBody + : responseBody // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LocationModelImplCopyWith<$Res> + implements $LocationModelCopyWith<$Res> { + factory _$$LocationModelImplCopyWith( + _$LocationModelImpl value, $Res Function(_$LocationModelImpl) then) = + __$$LocationModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {List locations, + @JsonKey(name: 'response_body') String responseBody}); +} + +/// @nodoc +class __$$LocationModelImplCopyWithImpl<$Res> + extends _$LocationModelCopyWithImpl<$Res, _$LocationModelImpl> + implements _$$LocationModelImplCopyWith<$Res> { + __$$LocationModelImplCopyWithImpl( + _$LocationModelImpl _value, $Res Function(_$LocationModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locations = null, + Object? responseBody = null, + }) { + return _then(_$LocationModelImpl( + locations: null == locations + ? _value._locations + : locations // ignore: cast_nullable_to_non_nullable + as List, + responseBody: null == responseBody + ? _value.responseBody + : responseBody // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LocationModelImpl implements _LocationModel { + const _$LocationModelImpl( + {required final List locations, + @JsonKey(name: 'response_body') required this.responseBody}) + : _locations = locations; + + factory _$LocationModelImpl.fromJson(Map json) => + _$$LocationModelImplFromJson(json); + + final List _locations; + @override + List get locations { + if (_locations is EqualUnmodifiableListView) return _locations; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_locations); + } + + @override + @JsonKey(name: 'response_body') + final String responseBody; + + @override + String toString() { + return 'LocationModel(locations: $locations, responseBody: $responseBody)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LocationModelImpl && + const DeepCollectionEquality() + .equals(other._locations, _locations) && + (identical(other.responseBody, responseBody) || + other.responseBody == responseBody)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, + const DeepCollectionEquality().hash(_locations), responseBody); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LocationModelImplCopyWith<_$LocationModelImpl> get copyWith => + __$$LocationModelImplCopyWithImpl<_$LocationModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$LocationModelImplToJson( + this, + ); + } +} + +abstract class _LocationModel implements LocationModel { + const factory _LocationModel( + {required final List locations, + @JsonKey(name: 'response_body') required final String responseBody}) = + _$LocationModelImpl; + + factory _LocationModel.fromJson(Map json) = + _$LocationModelImpl.fromJson; + + @override + List get locations; + @override + @JsonKey(name: 'response_body') + String get responseBody; + @override + @JsonKey(ignore: true) + _$$LocationModelImplCopyWith<_$LocationModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/registration/models/location_model.g.dart b/lib/features/registration/models/location_model.g.dart new file mode 100644 index 0000000..449630a --- /dev/null +++ b/lib/features/registration/models/location_model.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'location_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$LocationModelImpl _$$LocationModelImplFromJson(Map json) => + _$LocationModelImpl( + locations: + (json['locations'] as List).map((e) => e as String).toList(), + responseBody: json['response_body'] as String, + ); + +Map _$$LocationModelImplToJson(_$LocationModelImpl instance) => + { + 'locations': instance.locations, + 'response_body': instance.responseBody, + }; diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart new file mode 100644 index 0000000..cbb2e16 --- /dev/null +++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart @@ -0,0 +1,76 @@ +import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart'; +import 'package:eatvio_app/features/registration/repositories/registration_repository.dart'; +import 'package:go_router/go_router.dart'; + +class RegistrationCubit extends Cubit { + final RegistrationRepository registrationRepository; + + RegistrationCubit({required this.registrationRepository}) + : super( + RegistrationState( + sheet: UserRegistrationSheet( + firstName: '', + lastName: '', + email: '', + password: '', + passwordConfirmation: '', + birthdate: '', + gender: '', + location: '', + responseBody: '', + lang: '', + weight: 0, + height: 0, + chestCircumference: 0, + waistCircumference: 0, + hipCircumference: 0, + bloodPressureUp: 0, + bloodPressureDown: 0, + hasHypo: 0, + hasHyper: 0, + aboutAllergy: '', + aboutTakingPils: '', + aboutSportHobbies: '', + favoriteFoods: '', + unfavoriteFoods: '', + additionalInfo: '', + ), + ), + ); + + updateSheet(UserRegistrationSheet sheet) => emit(RegistrationState(sheet: sheet)); + + Future tryRegistration() async { + try { + final token = await registrationRepository.tryRegister(state.sheet); + await TokenStorage.saveTokenInStorage(token); + AppRouter.navigatorKey.currentContext?.go('/my-profile-screen'); + } catch (e) { + rethrow; + } + } + + Future> getLocationsByQuery(String query) async { + try { + final location = (await registrationRepository.getLocationsListByQuery(query)); + emit(RegistrationState(sheet: state.sheet.copyWith(responseBody: location.responseBody))); + return location.locations; + } catch (e) { + rethrow; + } + } + + Future> getLocationsByCoordinates(String latitude, String longitude) async { + try { + final location = (await registrationRepository.getLocationsListByCoordinates(latitude, longitude)); + emit(RegistrationState(sheet: state.sheet.copyWith(responseBody: location.responseBody))); + return location.locations; + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart new file mode 100644 index 0000000..d1e2090 --- /dev/null +++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.dart @@ -0,0 +1,11 @@ +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'registration_state.freezed.dart'; + +@freezed +class RegistrationState with _$RegistrationState { + const factory RegistrationState({ + required UserRegistrationSheet sheet, + }) = _RegistrationState; +} diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_state.freezed.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.freezed.dart new file mode 100644 index 0000000..dcb4923 --- /dev/null +++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_state.freezed.dart @@ -0,0 +1,147 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'registration_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$RegistrationState { + UserRegistrationSheet get sheet => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $RegistrationStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RegistrationStateCopyWith<$Res> { + factory $RegistrationStateCopyWith( + RegistrationState value, $Res Function(RegistrationState) then) = + _$RegistrationStateCopyWithImpl<$Res, RegistrationState>; + @useResult + $Res call({UserRegistrationSheet sheet}); + + $UserRegistrationSheetCopyWith<$Res> get sheet; +} + +/// @nodoc +class _$RegistrationStateCopyWithImpl<$Res, $Val extends RegistrationState> + implements $RegistrationStateCopyWith<$Res> { + _$RegistrationStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? sheet = null, + }) { + return _then(_value.copyWith( + sheet: null == sheet + ? _value.sheet + : sheet // ignore: cast_nullable_to_non_nullable + as UserRegistrationSheet, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserRegistrationSheetCopyWith<$Res> get sheet { + return $UserRegistrationSheetCopyWith<$Res>(_value.sheet, (value) { + return _then(_value.copyWith(sheet: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$RegistrationStateImplCopyWith<$Res> + implements $RegistrationStateCopyWith<$Res> { + factory _$$RegistrationStateImplCopyWith(_$RegistrationStateImpl value, + $Res Function(_$RegistrationStateImpl) then) = + __$$RegistrationStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({UserRegistrationSheet sheet}); + + @override + $UserRegistrationSheetCopyWith<$Res> get sheet; +} + +/// @nodoc +class __$$RegistrationStateImplCopyWithImpl<$Res> + extends _$RegistrationStateCopyWithImpl<$Res, _$RegistrationStateImpl> + implements _$$RegistrationStateImplCopyWith<$Res> { + __$$RegistrationStateImplCopyWithImpl(_$RegistrationStateImpl _value, + $Res Function(_$RegistrationStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? sheet = null, + }) { + return _then(_$RegistrationStateImpl( + sheet: null == sheet + ? _value.sheet + : sheet // ignore: cast_nullable_to_non_nullable + as UserRegistrationSheet, + )); + } +} + +/// @nodoc + +class _$RegistrationStateImpl implements _RegistrationState { + const _$RegistrationStateImpl({required this.sheet}); + + @override + final UserRegistrationSheet sheet; + + @override + String toString() { + return 'RegistrationState(sheet: $sheet)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RegistrationStateImpl && + (identical(other.sheet, sheet) || other.sheet == sheet)); + } + + @override + int get hashCode => Object.hash(runtimeType, sheet); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RegistrationStateImplCopyWith<_$RegistrationStateImpl> get copyWith => + __$$RegistrationStateImplCopyWithImpl<_$RegistrationStateImpl>( + this, _$identity); +} + +abstract class _RegistrationState implements RegistrationState { + const factory _RegistrationState( + {required final UserRegistrationSheet sheet}) = _$RegistrationStateImpl; + + @override + UserRegistrationSheet get sheet; + @override + @JsonKey(ignore: true) + _$$RegistrationStateImplCopyWith<_$RegistrationStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/registration/presentation/pages/additional_information_screen.dart b/lib/features/registration/presentation/pages/additional_information_screen.dart new file mode 100644 index 0000000..159a599 --- /dev/null +++ b/lib/features/registration/presentation/pages/additional_information_screen.dart @@ -0,0 +1,57 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class AdditionalInformationScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const AdditionalInformationScreen({super.key, required this.sheet}); + + @override + State createState() => _AdditionalInformationScreenState(); +} + +class _AdditionalInformationScreenState extends State { + final editTextController = TextEditingController(); + final editFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + editTextController.text = widget.sheet.additionalInfo; + editFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Дополнительная информация', + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.start, + ), + SizedBox(height: 4), + CustomTextFormField( + controller: editTextController, + hintText: "У меня крепкое здоровье, но последнее время часто утомляюсь, однако, это мне не мешает радоваться жизни", + textInputAction: TextInputAction.done, + maxLines: 8, + focusNode: editFocusNode, + autofocus: true, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(additionalInfo: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/allergies_screen.dart b/lib/features/registration/presentation/pages/allergies_screen.dart new file mode 100644 index 0000000..5a4e4bc --- /dev/null +++ b/lib/features/registration/presentation/pages/allergies_screen.dart @@ -0,0 +1,53 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class AllergiesScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const AllergiesScreen({super.key, required this.sheet}); + + @override + State createState() => _AllergiesScreenState(); +} + +class _AllergiesScreenState extends State { + final enterInformationController = TextEditingController(); + final infoFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + enterInformationController.text = widget.sheet.aboutAllergy; + infoFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("allergies_presence".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: enterInformationController, + hintText: 'Например: орехи, мёд и т.д.', + textInputAction: TextInputAction.done, + focusNode: infoFocusNode, + autofocus: true, + minLines: 2, + maxLines: 8, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(aboutAllergy: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/blood_pressure_screen.dart b/lib/features/registration/presentation/pages/blood_pressure_screen.dart new file mode 100644 index 0000000..d22cf32 --- /dev/null +++ b/lib/features/registration/presentation/pages/blood_pressure_screen.dart @@ -0,0 +1,126 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_drop_down.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class BloodPressureScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const BloodPressureScreen({super.key, required this.sheet}); + + @override + State createState() => _BloodPressureScreenState(); +} + +class _BloodPressureScreenState extends State { + final List selectionPopupList = [ + SelectionPopupModel( + id: 1, + title: "Да", + ), + SelectionPopupModel( + id: 0, + title: "Нет", + ), + ]; + + late SelectionPopupModel selectedPopupHypo; + late SelectionPopupModel selectedPopupHyper; + + final digitsOnly = FilteringTextInputFormatter.digitsOnly; + final upPressureController = TextEditingController(); + final downPressureController = TextEditingController(); + final upFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + selectedPopupHypo = selectionPopupList[1]; + selectedPopupHyper = selectionPopupList[1]; + if (widget.sheet.bloodPressureUp != 0) upPressureController.text = widget.sheet.bloodPressureUp.toString(); + if (widget.sheet.bloodPressureDown != 0) downPressureController.text = widget.sheet.bloodPressureDown.toString(); + widget.sheet.hasHyper == 1 ? selectedPopupHyper = selectionPopupList[0] : selectedPopupHyper = selectionPopupList[1]; + widget.sheet.hasHypo == 1 ? selectedPopupHypo = selectionPopupList[0] : selectedPopupHypo = selectionPopupList[1]; + upFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("up_pressure".tr), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + controller: upPressureController, + autofocus: true, + focusNode: upFocusNode, + hintText: "90".tr, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(bloodPressureUp: int.parse(newValue))); + }, + ), + SizedBox(height: 16), + Text("down_pressure".tr), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + controller: downPressureController, + hintText: "90".tr, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(bloodPressureDown: int.parse(newValue))); + }, + ), + SizedBox(height: 16), + Text("do_you_have_hypotension_tendency".tr), + SizedBox(height: 4), + CustomDropDown( + icon: Container( + margin: EdgeInsets.fromLTRB(30.h, 11.v, 13.h, 11.v), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(1.h)), + child: CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize), + ), + hintText: "Не выбрано".tr, + items: selectionPopupList, + value: selectedPopupHypo, + onChanged: (newPopup) { + setState(() { + selectedPopupHypo = newPopup; + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(hasHypo: selectedPopupHypo.id!)); + }); + }, + ), + SizedBox(height: 16), + Text("do_you_have_hypertension_tendency".tr), + SizedBox(height: 4), + CustomDropDown( + icon: Container( + margin: EdgeInsets.fromLTRB(30.h, 11.v, 13.h, 11.v), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(1.h)), + child: CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize), + ), + hintText: "Не выбрано".tr, + items: selectionPopupList, + value: selectedPopupHyper, + onChanged: (newPopup) { + setState(() { + selectedPopupHyper = newPopup; + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(hasHyper: selectedPopupHyper.id!)); + }); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/body_circumferences_screen.dart b/lib/features/registration/presentation/pages/body_circumferences_screen.dart new file mode 100644 index 0000000..a086da3 --- /dev/null +++ b/lib/features/registration/presentation/pages/body_circumferences_screen.dart @@ -0,0 +1,82 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class BodyCircumferencesScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const BodyCircumferencesScreen({super.key, required this.sheet}); + + @override + State createState() => _BodyCircumferencesScreenState(); +} + +class _BodyCircumferencesScreenState extends State { + final digitsOnly = FilteringTextInputFormatter.digitsOnly; + final chestCircumferenceController = TextEditingController(); + final waistCircumferenceController = TextEditingController(); + final hipCircumferenceController = TextEditingController(); + final chestFocus = FocusNode(); + + @override + void initState() { + super.initState(); + if (widget.sheet.chestCircumference != 0) chestCircumferenceController.text = widget.sheet.chestCircumference.toString(); + if (widget.sheet.waistCircumference != 0) waistCircumferenceController.text = widget.sheet.waistCircumference.toString(); + if (widget.sheet.hipCircumference != 0) hipCircumferenceController.text = widget.sheet.hipCircumference.toString(); + chestFocus.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("chest_circumference".tr), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + autofocus: true, + focusNode: chestFocus, + controller: chestCircumferenceController, + hintText: "90".tr, + onChanged: (value) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(chestCircumference: int.parse(value))); + }, + ), + SizedBox(height: 16), + Text("waist_circumference".tr), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + controller: waistCircumferenceController, + hintText: "60".tr, + onChanged: (value) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(waistCircumference: int.parse(value))); + }, + ), + SizedBox(height: 16), + Text("hip_circumference".tr), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + controller: hipCircumferenceController, + hintText: "90".tr, + textInputAction: TextInputAction.done, + onChanged: (value) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(hipCircumference: int.parse(value))); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/city_of_living_screen.dart b/lib/features/registration/presentation/pages/city_of_living_screen.dart new file mode 100644 index 0000000..b4c8cbe --- /dev/null +++ b/lib/features/registration/presentation/pages/city_of_living_screen.dart @@ -0,0 +1,164 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:location/location.dart'; + +class CityOfLivingScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const CityOfLivingScreen({super.key, required this.sheet}); + + @override + State createState() => _CityOfLivingScreenState(); +} + +class _CityOfLivingScreenState extends State { + final dropdownItemList = [ + SelectionPopupModel(id: 1, title: "Россия", isSelected: true), + ]; + + late SelectionPopupModel selectedItem; + final cityController = TextEditingController(); + final suggestionsController = SuggestionsController(); + bool isLoading = false; + + @override + void initState() { + super.initState(); + if (widget.sheet.location.isNotEmpty) { + cityController.text = widget.sheet.location; + } + } + + Future getLocationData() async { + Location location = new Location(); + + bool _serviceEnabled; + PermissionStatus _permissionGranted; + LocationData _locationData; + + _serviceEnabled = await location.serviceEnabled(); + if (!_serviceEnabled) { + _serviceEnabled = await location.requestService(); + if (!_serviceEnabled) { + return null; + } + } + + _permissionGranted = await location.hasPermission(); + if (_permissionGranted == PermissionStatus.denied) { + _permissionGranted = await location.requestPermission(); + if (_permissionGranted != PermissionStatus.granted) { + return null; + } + } + + _locationData = await location.getLocation(); + + return _locationData; + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, right: 16, left: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Местоположение"), + SizedBox(height: 4), + Row( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width - 80, + child: TypeAheadField( + debounceDuration: Duration(milliseconds: 300), + controller: cityController, + suggestionsController: suggestionsController, + builder: (context, controller, focus) => CustomTextFormField( + controller: cityController, + focusNode: focus, + autofocus: true, + textStyle: TextStyle( + fontSize: 16, + color: Colors.black, + )), + itemBuilder: (BuildContext context, String item) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item, style: theme.textTheme.bodyLarge?.copyWith(color: Colors.black)), + ); + }, + decorationBuilder: (context, child) => Material( + type: MaterialType.card, + elevation: 4, + borderRadius: BorderRadius.circular(8), + child: child, + ), + onSelected: (item) { + setState(() { + cityController.text = item; + }); + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(location: item)); + }, + suggestionsCallback: (query) async { + if (query.length >= 3) { + final registrationCubit = context.read(); + return (await registrationCubit.getLocationsByQuery(query)); + } + return null; + }, + ), + ), + SizedBox(width: 8), + InkWell( + borderRadius: BorderRadius.circular(8), + onTap: !isLoading + ? () async { + setState(() { + isLoading = true; + }); + final LocationData? locationData = await getLocationData(); + if (locationData != null) { + final List locations = await context + .read() + .getLocationsByCoordinates(locationData.latitude.toString(), locationData.longitude.toString()); + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(location: locations.first)); + setState(() { + cityController.text = locations.first; + suggestionsController.suggestions = locations; + }); + } + setState(() { + isLoading = false; + }); + } + : null, + child: Ink( + height: 40, + width: 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Color(0xFFEAF2FD), + ), + child: !isLoading + ? Icon( + Icons.near_me_rounded, + color: appTheme.blueA400, + ) + : CupertinoActivityIndicator(), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/credentials_screen.dart b/lib/features/registration/presentation/pages/credentials_screen.dart new file mode 100644 index 0000000..25b0a2a --- /dev/null +++ b/lib/features/registration/presentation/pages/credentials_screen.dart @@ -0,0 +1,82 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class CredentialsScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const CredentialsScreen({super.key, required this.sheet}); + + @override + State createState() => _CredentialsScreenState(); +} + +class _CredentialsScreenState extends State { + final emailController = TextEditingController(); + + final passwordController = TextEditingController(); + + final passwordConfirmationController = TextEditingController(); + + @override + void initState() { + super.initState(); + emailController.text = widget.sheet.email; + passwordController.text = widget.sheet.password; + passwordConfirmationController.text = widget.sheet.passwordConfirmation; + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16, left: 16, right: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("email".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: emailController, + textInputType: TextInputType.emailAddress, + keyboardType: TextInputType.emailAddress, + hintText: 'Введите email', + textInputAction: TextInputAction.next, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(email: newValue)); + }, + ), + SizedBox(height: 16), + Text("password".tr), + SizedBox(height: 4), + CustomTextFormField( + obscureText: true, + controller: passwordController, + hintText: 'Введите пароль', + textInputAction: TextInputAction.next, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(password: newValue)); + }, + ), + SizedBox(height: 16), + Text("password_confirmation".tr), + SizedBox(height: 4), + CustomTextFormField( + obscureText: true, + controller: passwordConfirmationController, + textInputAction: TextInputAction.done, + hintText: 'Подтвердите пароль', + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(passwordConfirmation: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/date_of_birth_screen.dart b/lib/features/registration/presentation/pages/date_of_birth_screen.dart new file mode 100644 index 0000000..8d510c1 --- /dev/null +++ b/lib/features/registration/presentation/pages/date_of_birth_screen.dart @@ -0,0 +1,101 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class DateOfBirthScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const DateOfBirthScreen({super.key, required this.sheet}); + + @override + State createState() => _DateOfBirthScreenState(); +} + +class _DateOfBirthScreenState extends State { + late DateTime selectedDate; + + @override + void initState() { + super.initState(); + if (widget.sheet.birthdate.isNotEmpty) { + selectedDate = DateFormat('yyyy-mm-dd').parse(widget.sheet.birthdate); + } else { + selectedDate = DateTime.now(); + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(birthdate: DateTime.now().toString())); + } + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16, left: 16, right: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("date_of_birth".tr), + SizedBox(height: 4), + ListTile( + onTap: onTapCalendar(context), + leading: Icon(Icons.calendar_month_rounded, color: appTheme.blueA400), + trailing: Icon(Icons.keyboard_arrow_down_rounded), + title: Text(selectedDate.format('dd MMMM yyyy', 'ru')), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: BorderSide( + color: Colors.grey.shade400, + width: 1, + ), + ), + ), + ], + ), + ); + } + + onTapCalendar(BuildContext context) { + return () { + _showDialog( + CupertinoDatePicker( + initialDateTime: selectedDate, + maximumDate: DateTime.now(), + minimumDate: DateTime(1900), + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (DateTime newDateTime) { + setState(() { + selectedDate = newDateTime; + print(selectedDate); + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(birthdate: selectedDate.toString())); + }); + }, + ), + ); + }; + } + + void _showDialog(Widget child) { + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) => Container( + height: 216, + padding: const EdgeInsets.only(top: 6.0), + // The Bottom margin is provided to align the popup above the system + // navigation bar. + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + // Provide a background color for the popup. + color: CupertinoColors.systemBackground.resolveFrom(context), + // Use a SafeArea widget to avoid system overlaps. + child: SafeArea( + top: false, + child: child, + ), + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/favorite_foods_screen.dart b/lib/features/registration/presentation/pages/favorite_foods_screen.dart new file mode 100644 index 0000000..bab999a --- /dev/null +++ b/lib/features/registration/presentation/pages/favorite_foods_screen.dart @@ -0,0 +1,68 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class FavoriteFoodsScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const FavoriteFoodsScreen({super.key, required this.sheet}); + + @override + State createState() => _FavoriteFoodsScreenState(); +} + +class _FavoriteFoodsScreenState extends State { + final favoriteFoodsController = TextEditingController(); + final unFavoriteFoodsController = TextEditingController(); + final favoriteFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + favoriteFoodsController.text = widget.sheet.favoriteFoods; + unFavoriteFoodsController.text = widget.sheet.unfavoriteFoods; + favoriteFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("favorite_foods".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: favoriteFoodsController, + hintText: "enter_information".tr, + maxLines: 7, + minLines: 2, + focusNode: favoriteFocusNode, + autofocus: true, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(favoriteFoods: newValue)); + }, + ), + SizedBox(height: 16), + Text("unfavorite_foods".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: unFavoriteFoodsController, + hintText: "enter_information".tr, + textInputAction: TextInputAction.done, + maxLines: 7, + minLines: 2, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(unfavoriteFoods: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/favorite_sports_screen.dart b/lib/features/registration/presentation/pages/favorite_sports_screen.dart new file mode 100644 index 0000000..2856ea7 --- /dev/null +++ b/lib/features/registration/presentation/pages/favorite_sports_screen.dart @@ -0,0 +1,52 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class FavoriteSportsScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const FavoriteSportsScreen({super.key, required this.sheet}); + + @override + State createState() => _FavoriteSportsScreenState(); +} + +class _FavoriteSportsScreenState extends State { + final enterInformationController = TextEditingController(); + final infoFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + enterInformationController.text = widget.sheet.aboutSportHobbies; + infoFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("your_favorite_sports".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: enterInformationController, + hintText: "Я занимаюсь плаванием , почти каждый вечер прогулки на свежем воздухе, пару раз в месяц играю в волейбол. Стараюсь не сидеть на месте!", + textInputAction: TextInputAction.done, + focusNode: infoFocusNode, + autofocus: true, + maxLines: 8, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(aboutSportHobbies: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/gender_screen.dart b/lib/features/registration/presentation/pages/gender_screen.dart new file mode 100644 index 0000000..d1bec2f --- /dev/null +++ b/lib/features/registration/presentation/pages/gender_screen.dart @@ -0,0 +1,77 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:flutter/material.dart'; + +class GenderScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const GenderScreen({super.key, required this.sheet}); + + @override + State createState() => _GenderScreenState(); +} + +class _GenderScreenState extends State { + late String currentValue; + + @override + void initState() { + super.initState(); + currentValue = widget.sheet.gender; + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16, left: 16, right: 16), + child: Column( + children: [ + RadioListTile( + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + title: Text('Мужской'), + value: 'male', + groupValue: currentValue, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'male')); + setState(() { + currentValue = 'male'; + }); + }, + secondary: Image.asset( + 'assets/images/img_male.png', + width: 40, + height: 40, + ), + ), + SizedBox(height: 16), + RadioListTile( + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + title: Text('Женский'), + value: 'female', + groupValue: currentValue, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'female')); + setState(() { + currentValue = 'female'; + }); + }, + secondary: Image.asset( + 'assets/images/img_female.png', + width: 40, + height: 40, + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/height_screen.dart b/lib/features/registration/presentation/pages/height_screen.dart new file mode 100644 index 0000000..2aea369 --- /dev/null +++ b/lib/features/registration/presentation/pages/height_screen.dart @@ -0,0 +1,56 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class HeightScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const HeightScreen({super.key, required this.sheet}); + + @override + State createState() => _HeightScreenState(); +} + +class _HeightScreenState extends State { + final heightController = TextEditingController(); + final heightFocus = FocusNode(); + + @override + void initState() { + super.initState(); + if (widget.sheet.height != 0) heightController.text = widget.sheet.height.toString(); + heightFocus.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("your_height".tr), + SizedBox(height: 4), + CustomTextFormField( + textInputAction: TextInputAction.done, + autofocus: true, + focusNode: heightFocus, + hintText: 'см', + controller: heightController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(height: int.parse(newValue))); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/language_select_screen.dart b/lib/features/registration/presentation/pages/language_select_screen.dart new file mode 100644 index 0000000..4d95033 --- /dev/null +++ b/lib/features/registration/presentation/pages/language_select_screen.dart @@ -0,0 +1,60 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_drop_down.dart'; +import 'package:flutter/material.dart'; + +class LanguageSelectScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const LanguageSelectScreen({required this.sheet, super.key}); + + @override + State createState() => _LanguageSelectScreenState(); +} + +class _LanguageSelectScreenState extends State { + final List dropdownItemList = [ + SelectionPopupModel(id: 1, title: "Русский", isSelected: true), + ]; + + late SelectionPopupModel value; + + @override + void initState() { + super.initState(); + if (widget.sheet.lang.isNotEmpty) { + value = dropdownItemList.firstWhere((item) => item.title == widget.sheet.lang); + } else { + value = dropdownItemList.first; + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(lang: value.title)); + } + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, right: 16, left: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "preferred_language".tr, + ), + const SizedBox(height: 4), + CustomDropDown( + value: value, + hintText: "Не выбрано".tr, + items: dropdownItemList, + onChanged: (SelectionPopupModel newValue) => setState(() { + value = newValue; + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(lang: value.title)); + }), + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/medicine_intake_screen.dart b/lib/features/registration/presentation/pages/medicine_intake_screen.dart new file mode 100644 index 0000000..fc09d08 --- /dev/null +++ b/lib/features/registration/presentation/pages/medicine_intake_screen.dart @@ -0,0 +1,53 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class MedicineIntakeScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const MedicineIntakeScreen({super.key, required this.sheet}); + + @override + State createState() => _MedicineIntakeScreenState(); +} + +class _MedicineIntakeScreenState extends State { + final enterInformationController = TextEditingController(); + final infoFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + enterInformationController.text = widget.sheet.aboutTakingPils; + infoFocusNode.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("do_you_take_pills".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: enterInformationController, + hintText: "enter_information".tr, + textInputAction: TextInputAction.done, + focusNode: infoFocusNode, + autofocus: true, + minLines: 2, + maxLines: 8, + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(aboutTakingPils: newValue)); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/name_screen.dart b/lib/features/registration/presentation/pages/name_screen.dart new file mode 100644 index 0000000..ae817ed --- /dev/null +++ b/lib/features/registration/presentation/pages/name_screen.dart @@ -0,0 +1,64 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class NameScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const NameScreen({required this.sheet, super.key}); + + @override + State createState() => _NameScreenState(); +} + +class _NameScreenState extends State { + final firstNameController = TextEditingController(); + final lastNameController = TextEditingController(); + final nameFocus = FocusNode(); + + @override + void initState() { + super.initState(); + firstNameController.text = widget.sheet.firstName; + lastNameController.text = widget.sheet.lastName; + nameFocus.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16, left: 16, right: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("first_name".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: firstNameController, + focusNode: nameFocus, + textInputAction: TextInputAction.next, + hintText: 'Введите имя', + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(firstName: newValue)); + }, + ), + SizedBox(height: 16), + Text("last_name".tr), + SizedBox(height: 4), + CustomTextFormField( + controller: lastNameController, + textInputAction: TextInputAction.done, + hintText: 'Введите фамилию', + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(lastName: newValue)); + }, + ) + ], + ), + ); + } +} diff --git a/lib/features/registration/presentation/pages/registration_screen.dart b/lib/features/registration/presentation/pages/registration_screen.dart new file mode 100644 index 0000000..e95639a --- /dev/null +++ b/lib/features/registration/presentation/pages/registration_screen.dart @@ -0,0 +1,393 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/additional_information_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/allergies_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/blood_pressure_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/body_circumferences_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/city_of_living_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/credentials_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/date_of_birth_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/favorite_foods_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/favorite_sports_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/gender_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/height_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/language_select_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/medicine_intake_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/name_screen.dart'; +import 'package:eatvio_app/features/registration/presentation/pages/weight_screen.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:validators/validators.dart'; + +class RegistrationScreen extends StatefulWidget { + const RegistrationScreen({super.key}); + + @override + State createState() => _RegistrationScreenState(); +} + +class _RegistrationScreenState extends State { + double progressValue = 1 / 15; + int step = 1; + final pageController = PageController(); + final RegistrationCubit registrationCubit = sl(); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (BuildContext context) => registrationCubit, + child: BlocBuilder( + builder: (BuildContext context, RegistrationState state) { + return Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: Row( + children: [ + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.2, + padding: EdgeInsets.only(left: 16, right: 4), + child: FloatingActionButton.extended( + heroTag: 'backButtonRegistration', + highlightElevation: 0, + focusElevation: 0, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: Color(0xFFEAF2FD), + onPressed: () async { + setState(() { + pageController.previousPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + }, + label: Icon( + Icons.arrow_back_ios_new_rounded, + color: appTheme.blueA400, + ), + ), + ), + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.8, + padding: EdgeInsets.only(left: 4, right: 16), + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: appTheme.blueA400, + onPressed: () async { + if (await canGoNext(state)) { + setState(() { + pageController.nextPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + } + }, + label: Text( + 'Продолжить', + style: theme.textTheme.titleSmall, + ), + ), + ), + ], + ), + appBar: AppBar( + automaticallyImplyLeading: false, + leading: Builder( + builder: (context) => IconButton( + icon: Icon(Icons.close_rounded), + onPressed: () => GoRouter.of(context).pop(), + ), + ), + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16), + child: Text('шаг $step из 15'), + ), + ], + bottom: PreferredSize( + preferredSize: Size(MediaQuery.of(context).size.width, 32), + child: Padding( + padding: const EdgeInsets.all(16), + child: TweenAnimationBuilder( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + tween: Tween( + begin: 0, + end: progressValue, + ), + builder: (context, value, _) => LinearProgressIndicator( + value: value, + borderRadius: BorderRadius.circular(16), + minHeight: 8, + backgroundColor: Colors.grey.shade100, + valueColor: AlwaysStoppedAnimation(appTheme.blueA400), + ), + ), + ), + ), + ), + body: PageView( + physics: NeverScrollableScrollPhysics(), + controller: pageController, + onPageChanged: (index) { + setState(() { + step = index + 1; + progressValue = step / 15; + }); + }, + children: [ + LanguageSelectScreen(sheet: state.sheet), + CredentialsScreen(sheet: state.sheet), + NameScreen(sheet: state.sheet), + GenderScreen(sheet: state.sheet), + DateOfBirthScreen(sheet: state.sheet), + CityOfLivingScreen(sheet: state.sheet), + BodyCircumferencesScreen(sheet: state.sheet), + WeightScreen(sheet: state.sheet), + HeightScreen(sheet: state.sheet), + BloodPressureScreen(sheet: state.sheet), + AllergiesScreen(sheet: state.sheet), + MedicineIntakeScreen(sheet: state.sheet), + FavoriteSportsScreen(sheet: state.sheet), + FavoriteFoodsScreen(sheet: state.sheet), + AdditionalInformationScreen(sheet: state.sheet), + ], + ), + ); + }, + ), + ); + } + + Future canGoNext(RegistrationState state) async { + switch (step) { + case 2: + List errors = validateCredentialsFields(state.sheet.email, state.sheet.password, state.sheet.passwordConfirmation); + if (errors.isEmpty) { + return true; + } else { + String errorMessage = ''; + + for (var error in errors) { + errorMessage += error + '\n\n'; + } + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка'), + content: Text(errorMessage), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + return false; + } + case 3: + List errors = validateNameFields( + state.sheet.firstName.toString(), + state.sheet.lastName.toString(), + ); + if (errors.isEmpty) { + return true; + } else { + String errorMessage = ''; + + for (var error in errors) { + errorMessage += error + '\n\n'; + } + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка'), + content: Text(errorMessage), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + return false; + } + case 4: + if (state.sheet.gender.isNotEmpty) + return true; + else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка'), + content: Text('Выберете пол'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + return false; + } + case 6: + if (state.sheet.location.isNotEmpty) + return true; + else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка'), + content: Text('Заполните все поля'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + return false; + } + case 7: + List errors = validateCircumferencesFields( + state.sheet.chestCircumference.toString(), + state.sheet.waistCircumference.toString(), + state.sheet.hipCircumference.toString(), + ); + if (errors.isEmpty) { + return true; + } else { + String errorMessage = ''; + + for (var error in errors) { + errorMessage += error + '\n\n'; + } + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка'), + content: Text(errorMessage), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ), + ); + return false; + } + case 15: + try { + showDialog( + barrierDismissible: false, + useSafeArea: false, + context: context, + builder: (context) => PopScope( + canPop: false, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + await registrationCubit.tryRegistration(); + Navigator.pop(context); + } catch (e) { + Navigator.pop(context); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Ошибка при попытке регистрации'), + ), + ); + } + return false; + default: + return true; + } + } + + List validateCircumferencesFields( + String chestCircumference, + String waistCircumference, + String hipCircumference, + ) { + List errors = []; + + if (chestCircumference.isEmpty | waistCircumference.isEmpty | hipCircumference.isEmpty) { + errors.add('circumference_empty'.tr); + } + + if (![chestCircumference, waistCircumference, hipCircumference].every((circumference) => int.tryParse(circumference) != null)) { + errors.add('circumference_is_not_a_number'.tr); + } + + return errors; + } + + List validateCredentialsFields(String email, String password, String passwordConfirmation) { + List errors = []; + + if (!isEmail(email)) { + errors.add('email_invalid'.tr); + } + + if (email.isEmpty) { + errors.add('email_empty'.tr); + } + + if (password.length < 6) { + errors.add('password_short'.tr); + } + + if (password != passwordConfirmation) { + errors.add('password_confirmation_mismatch'.tr); + } + + return errors; + } + + List validateNameFields(String firstName, String lastName) { + List errors = []; + + if (firstName.isEmpty) { + errors.add('First name cannot be empty'); + } + + if (firstName.length < 1) { + errors.add('First name is too short'); + } + + if (lastName.isEmpty) { + errors.add('Last name cannot be empty'); + } + + if (lastName.length < 1) { + errors.add('Last name is too short'); + } + + return errors; + } +} diff --git a/lib/features/registration/presentation/pages/weight_screen.dart b/lib/features/registration/presentation/pages/weight_screen.dart new file mode 100644 index 0000000..300296d --- /dev/null +++ b/lib/features/registration/presentation/pages/weight_screen.dart @@ -0,0 +1,56 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class WeightScreen extends StatefulWidget { + final UserRegistrationSheet sheet; + + const WeightScreen({super.key, required this.sheet}); + + @override + State createState() => _WeightScreenState(); +} + +class _WeightScreenState extends State { + final weightController = TextEditingController(); + final weightFocus = FocusNode(); + + @override + void initState() { + super.initState(); + if (widget.sheet.weight != 0) weightController.text = widget.sheet.weight.toString(); + weightFocus.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, left: 16, right: 16, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("your_weight".tr), + SizedBox(height: 4), + CustomTextFormField( + autofocus: true, + hintText: 'кг', + focusNode: weightFocus, + textInputAction: TextInputAction.done, + controller: weightController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + onChanged: (newValue) { + final registrationCubit = context.read(); + registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(weight: int.parse(newValue))); + }, + ), + ], + ), + ); + } +} diff --git a/lib/features/registration/repositories/registration_repository.dart b/lib/features/registration/repositories/registration_repository.dart new file mode 100644 index 0000000..d609ee1 --- /dev/null +++ b/lib/features/registration/repositories/registration_repository.dart @@ -0,0 +1,33 @@ +import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; +import 'package:eatvio_app/features/registration/models/location_model.dart'; +import 'package:eatvio_app/features/registration/services/registration_service.dart'; + +class RegistrationRepository { + final RegistrationService registrationService; + + RegistrationRepository({required this.registrationService}); + + Future tryRegister(UserRegistrationSheet sheet) async { + try { + return (await registrationService.register(sheet: sheet.toJson()))['token']!; + } catch (e) { + rethrow; + } + } + + Future getLocationsListByQuery(String query) async { + try { + return (await registrationService.getLocationsByAddress(query: query)); + } catch (e) { + rethrow; + } + } + + Future getLocationsListByCoordinates(String latitude, String longitude) async { + try { + return (await registrationService.getLocationsByCoordinate(latitude: latitude, longitude: longitude)); + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/registration/services/registration_service.dart b/lib/features/registration/services/registration_service.dart new file mode 100644 index 0000000..200c2f6 --- /dev/null +++ b/lib/features/registration/services/registration_service.dart @@ -0,0 +1,26 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/registration/models/location_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'registration_service.g.dart'; + +@RestApi() +abstract class RegistrationService { + factory RegistrationService(Dio dio, {String baseUrl}) = _RegistrationService; + + @POST('/api/register') + Future> register({ + @Body() required Map sheet, + }); + + @GET('/api/location_by_address') + Future getLocationsByAddress({ + @Query('user_address') required String query, + }); + + @GET('/api/location_by_coordinate') + Future getLocationsByCoordinate({ + @Query('coordinate[position][latitude]') required String latitude, + @Query('coordinate[position][longitude]') required String longitude, + }); +} diff --git a/lib/features/registration/services/registration_service.g.dart b/lib/features/registration/services/registration_service.g.dart new file mode 100644 index 0000000..9820fd3 --- /dev/null +++ b/lib/features/registration/services/registration_service.g.dart @@ -0,0 +1,139 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'registration_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _RegistrationService implements RegistrationService { + _RegistrationService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future> register( + {required Map sheet}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(sheet); + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/register', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = _result.data!.cast(); + return _value; + } + + @override + Future getLocationsByAddress({required String query}) async { + final _extra = {}; + final queryParameters = {r'user_address': query}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/location_by_address', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = LocationModel.fromJson(_result.data!); + return _value; + } + + @override + Future getLocationsByCoordinate({ + required String latitude, + required String longitude, + }) async { + final _extra = {}; + final queryParameters = { + r'coordinate[position][latitude]': latitude, + r'coordinate[position][longitude]': longitude, + }; + final _headers = {}; + const Map? _data = null; + final _result = await _dio + .fetch>(_setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/location_by_coordinate', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = LocationModel.fromJson(_result.data!); + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/localization/app_localization.dart b/lib/localization/app_localization.dart index 2fc106d..b477c9a 100644 --- a/lib/localization/app_localization.dart +++ b/lib/localization/app_localization.dart @@ -1,9 +1,9 @@ import 'package:eatvio_app/app_router.dart'; - -import 'ru/ru_translations.dart'; +import 'package:flutter/cupertino.dart'; //import 'en_us/en_us_translations.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/cupertino.dart'; + +import 'ru/ru_translations.dart'; class AppLocalization { AppLocalization(this.locale); @@ -13,6 +13,7 @@ class AppLocalization { static final Map> _localizedValues = { 'ru': ru, }; + /*static final Map> __localizedValues = { 'en': enUs };*/ @@ -23,24 +24,25 @@ class AppLocalization { return Localizations.of(context, AppLocalization)!; } else { // Обработка ситуации, когда context равен null - return AppLocalization(Locale( - 'ru', - '', - )); // Возвращаем дефолтное значение или обработку ошибки + return AppLocalization( + Locale( + 'ru', + '', + ), + ); // Возвращаем дефолтное значение или обработку ошибки } } static List languages() => _localizedValues.keys.toList(); - String getString(String text) => - _localizedValues[locale.languageCode]![text] ?? text; + + String getString(String text) => _localizedValues[locale.languageCode]![text] ?? text; } class AppLocalizationDelegate extends LocalizationsDelegate { const AppLocalizationDelegate(); @override - bool isSupported(Locale locale) => - AppLocalization.languages().contains(locale.languageCode); + bool isSupported(Locale locale) => AppLocalization.languages().contains(locale.languageCode); //Returning a SynchronousFuture here because an async "load" operation //cause an async "load" operation diff --git a/lib/localization/en_us/en_us_translations.dart b/lib/localization/en_us/en_us_translations.dart index 282c4c7..c68f131 100644 --- a/lib/localization/en_us/en_us_translations.dart +++ b/lib/localization/en_us/en_us_translations.dart @@ -27,8 +27,7 @@ final Map enUs = { // blood_pressure Screen "no": "No", - "do_you_have_hypertension_tendency": - "Do you have a tendency for hypertension?", + "do_you_have_hypertension_tendency": "Do you have a tendency for hypertension?", "your_blood_pressure": "Your blood pressure?", "average_pressure": "Average pressure:", "do_you_have_hypotension_tendency": "Do you have a tendency for hypotension?", @@ -43,17 +42,15 @@ final Map enUs = { // schedule Screen "your_schedule": "Your Daily Schedule?", - "tell_your_schedule": - "Tell us about your daily routine, when you wake up, eat, and go to sleep:", + "tell_your_schedule": "Tell us about your daily routine, when you wake up, eat, and go to sleep:", // additional_information Screen "additional_information": "Additional Information:", - "enter_additional_information": - "Enter any additional information you would like to share:", + "enter_additional_information": "Enter any additional information you would like to share:", // language_select Screen "lbl_english": "English", - "preferred_language": "Preferred Language?", + "preferred_language": "Preferred Language", // Common String "continue": "Continue", "skip": "Skip", diff --git a/lib/localization/ru/ru_translations.dart b/lib/localization/ru/ru_translations.dart index 3d28a23..faf5359 100644 --- a/lib/localization/ru/ru_translations.dart +++ b/lib/localization/ru/ru_translations.dart @@ -57,18 +57,16 @@ final Map ru = { // schedule Screen "your_schedule": "Ваш режим дня?", - "tell_your_schedule": - "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:", + "tell_your_schedule": "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:", // additional_information Screen "additional_information": "Дополнительная информация", - "enter_additional_information": - "Введите любую дополнительную информацию на своё усмотрение:", + "enter_additional_information": "Введите любую дополнительную информацию на своё усмотрение:", // language_select Screen "lbl_english": "English", "finish": "Завершить", - "preferred_language": "Предпочитаемый язык общения?", + "preferred_language": "Предпочитаемый язык общения", // Common String "continue": "Продолжить", "skip": "Пропустить", diff --git a/lib/locator_service.dart b/lib/locator_service.dart index 6823378..2c05df6 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -1,27 +1,78 @@ import 'package:dio/dio.dart'; +import 'package:eatvio_app/core/constants/constants.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; +import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_cubit.dart'; +import 'package:eatvio_app/features/blog_post/repositories/blog_post_repository.dart'; +import 'package:eatvio_app/features/blog_post/services/blog_post_service.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart'; +import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; +import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; +import 'package:eatvio_app/features/diary/services/diary_service.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; +import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; +import 'package:eatvio_app/features/feed/services/feed_service.dart'; +import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; +import 'package:eatvio_app/features/registration/repositories/registration_repository.dart'; +import 'package:eatvio_app/features/registration/services/registration_service.dart'; import 'package:get_it/get_it.dart'; final sl = GetIt.instance; Future init() async { - // BLoC - sl.registerFactory(() => ChatRoomCubit(chatRepository: sl())); + // BLoC / Cubit + sl.registerLazySingleton( + () => InitializationCubit(chatRepository: sl())); + sl.registerLazySingleton(() => NewMessagesCubit()); + sl.registerLazySingleton(() => NotificationsCubit()); + + sl.registerFactory( + () => RegistrationCubit(registrationRepository: sl())); + sl.registerFactory( + () => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl())); + sl.registerFactory(() => FeedCubit(feedRepository: sl())); + sl.registerFactory(() => RecipesCubit(feedRepository: sl())); + sl.registerFactory( + () => BlogPostCubit(blogPostRepository: sl())); + sl.registerFactory(() => DiaryBloc(diaryRepository: sl())); + sl.registerFactory( + () => CalendarCubit(calendarRepository: sl())); // Repository - sl.registerLazySingleton(() => ChatRepository(chatService: sl())); + sl.registerLazySingleton( + () => ChatRepository(chatService: sl())); + sl.registerLazySingleton( + () => FeedRepository(feedService: sl())); + sl.registerLazySingleton( + () => BlogPostRepository(blogPostService: sl())); + sl.registerLazySingleton( + () => RegistrationRepository(registrationService: sl())); + sl.registerLazySingleton( + () => DiaryRepository(diaryService: sl())); + sl.registerLazySingleton( + () => CalendarRepository(calendarService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); + sl.registerLazySingleton(() => FeedService(sl())); + sl.registerLazySingleton(() => BlogPostService(sl())); + sl.registerLazySingleton( + () => RegistrationService(sl())); + sl.registerLazySingleton(() => DiaryService(sl())); + sl.registerLazySingleton(() => CalendarService(sl())); // External sl.registerLazySingleton( () => Dio( BaseOptions( - baseUrl: dotenv.env['SERVER_ROOT']!, + baseUrl: baseUrl, ), ), ); diff --git a/lib/main.dart b/lib/main.dart index 8e0c1b9..fdc96e6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,27 @@ import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; +import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/models/diary_edit_model.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/bloc/feed_bloc.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/models/feed_model.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; +import 'package:eatvio_app/locator_service.dart' as di; +import 'package:eatvio_app/locator_service.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'core/app_export.dart'; import 'package:hive_flutter/hive_flutter.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; -import 'package:eatvio_app/locator_service.dart' as di; +import 'package:path_provider/path_provider.dart'; + +import 'core/app_export.dart'; var globalMessengerKey = GlobalKey(); @@ -24,7 +30,6 @@ void main() async { await di.init(); final appDocumentDir = await getApplicationDocumentsDirectory(); final path = appDocumentDir.path; - await dotenv.load(fileName: ".env"); await Hive.initFlutter(path); SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, @@ -32,7 +37,7 @@ void main() async { DeviceOrientation.portraitUp, ]); await PrefUtils().init(); - runApp(MyApp()); + initializeDateFormatting().then((_) => runApp(MyApp())); } class MyApp extends StatelessWidget { @@ -40,64 +45,49 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider( - create: (context) => ThemeBloc( - ThemeState(themeType: PrefUtils().getThemeData()), - ), - ), - BlocProvider( - create: (context) => MyProfileBloc( - MyProfileState( - myProfileModelObj: MyProfileModel(), - ), - )..add(MyProfileInitialEvent()), - ), - BlocProvider( - create: (context) => FeedBloc(FeedState(myProfileModelObj: FeedModel())) - ..add( - FeedInitialEvent(), - ), - ), - BlocProvider( - create: (context) => DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel())) - ..add( - DiaryEditInitialEvent(), - ), - ), + BlocProvider(create: (context) => sl()), + BlocProvider(create: (context) => sl()), + BlocProvider(create: (context) => sl()), + BlocProvider(create: (context) => ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))), + BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), + BlocProvider(create: (context) => sl()..loadRecipesList()), + BlocProvider(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())), + BlocProvider(create: (context) => sl()..add(LoadDiary())), BlocProvider( - create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel())) - ..add( - ChatSelectInitialEvent(), - ), + create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), ), + BlocProvider(create: (context) => sl()..loadCalendarList()), ], - child: BlocBuilder( - builder: (context, state) { - return KeyboardDismisser( - gestures: [ - GestureType.onTap, - GestureType.onPanUpdateDownDirection, - ], - child: MaterialApp.router( - theme: theme, - title: 'Eatvio', - routerConfig: AppRouter.appRouter, - debugShowCheckedModeBanner: false, - localizationsDelegates: [ - AppLocalizationDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, + child: BlocListener( + listener: (BuildContext context, InitializationState state) {}, + child: BlocBuilder( + builder: (context, state) { + return KeyboardDismisser( + gestures: [ + GestureType.onTap, + GestureType.onPanUpdateDownDirection, ], - supportedLocales: [ - Locale( - 'ru', - '', - ), - ], - ), - ); - }, + child: MaterialApp.router( + theme: theme, + title: 'Eatvio', + routerConfig: AppRouter.appRouter, + debugShowCheckedModeBanner: false, + localizationsDelegates: [ + AppLocalizationDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: [ + Locale( + 'ru', + '', + ), + ], + ), + ); + }, + ), ), ); } diff --git a/lib/presentation/auth/auth_screen/auth_screen.dart b/lib/presentation/auth/auth_screen/auth_screen.dart index 9694a2c..5f11a97 100644 --- a/lib/presentation/auth/auth_screen/auth_screen.dart +++ b/lib/presentation/auth/auth_screen/auth_screen.dart @@ -1,21 +1,20 @@ +import 'dart:convert'; + +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; +import 'package:url_launcher/url_launcher.dart'; +import 'package:validators/validators.dart'; import 'bloc/auth_bloc.dart'; import 'models/auth_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:validators/validators.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; -class AuthScreen extends StatelessWidget { +class AuthScreen extends StatefulWidget { static Widget builder(BuildContext context) { return BlocProvider( create: (context) => AuthBloc( @@ -29,66 +28,124 @@ class AuthScreen extends StatelessWidget { ); } + @override + State createState() => _AuthScreenState(); +} + +class _AuthScreenState extends State { + bool checkboxState = false; + @override Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 36.v), - Text("user_authorization".tr, style: theme.textTheme.headlineSmall), - SizedBox(height: 60.v), - Text("email".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.emailController, - builder: (context, emailController) { - return CustomTextFormField(controller: emailController, textInputAction: TextInputAction.done); - }), - SizedBox(height: 22.v), - Text("password".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 5.v), - BlocSelector( - selector: (state) => state.passwordController, - builder: (context, passwordController) { - return CustomTextFormField( - obscureText: true, - controller: passwordController, - ); - }), - SizedBox(height: 50.v), - NextStepButton( - text: "no_account".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapNoAccount(context), + appBar: AppBar( + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio), + ), + body: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("email".tr), + SizedBox(height: 4), + BlocSelector( + selector: (state) => state.emailController, + builder: (context, emailController) { + return CustomTextFormField( + controller: emailController, + textInputAction: TextInputAction.next, + keyboardType: TextInputType.emailAddress, + textInputType: TextInputType.emailAddress, + hintText: 'Введите email', + ); + }, + ), + SizedBox(height: 16), + Text("password".tr), + SizedBox(height: 4), + BlocSelector( + selector: (state) => state.passwordController, + builder: (context, passwordController) { + return CustomTextFormField( + obscureText: true, + controller: passwordController, + hintText: 'Введите пароль', + ); + }, + ), + SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Нет аккаунта? '), + GestureDetector( + onTap: () => GoRouter.of(context).goNamed('registrationScreen'), + child: Text( + 'Зарегистрироваться', + style: TextStyle( + color: appTheme.blueA400, + decorationColor: appTheme.blueA400, + decoration: TextDecoration.underline, + ), ), - /*NextStepButton( - text: "Тест дневника".toUpperCase(), - margin: - EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapDiaryTest(context)), - NextStepButton( - text: "authentificate".tr.toUpperCase(), - margin: - EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapProfileTest(context)),*/ - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "authentificate".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapAuth(state, context)); - }), - ])))); + ), + ], + ), + Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Нажимая "Войти", Вы соглашаетесь с ', + style: TextStyle( + fontSize: 12, + ), + ), + GestureDetector( + onTap: () async { + await launchUrl(Uri.parse(baseUrl + '/oferta_bs.pdf')); + }, + child: Text( + 'Публичной офертой', + style: TextStyle( + fontSize: 12, + color: appTheme.blueA400, + decorationColor: appTheme.blueA400, + decoration: TextDecoration.underline, + ), + ), + ), + ], + ), + SizedBox(height: 16), + BlocBuilder( + builder: (context, state) { + return Container( + height: 48, + width: MediaQuery.of(context).size.width - 32, + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: appTheme.blueA400, + onPressed: onTapAuth(state, context), + label: Text( + 'Войти', + style: theme.textTheme.titleSmall, + ), + ), + ); + }, + ), + ], + ), + ), + ); } onTapAuth(AuthState state, BuildContext context) { @@ -99,15 +156,19 @@ class AuthScreen extends StatelessWidget { 'email': state.emailController!.text, 'password': state.passwordController!.text, }; - final response = await http.post(Uri.parse(dotenv.env['SERVER_ROOT']! + '/login'), - headers: {'Content-Type': 'application/json'}, body: json.encode(credentials), encoding: utf8); + final response = await http.post( + Uri.parse(baseUrl + '/api/login'), + headers: {'Content-Type': 'application/json'}, + body: json.encode(credentials), + encoding: utf8, + ); print(response.statusCode); if (response.statusCode == 200) { var res = await jsonDecode(response.body); final box = await Hive.openBox('token'); final token = res['token']; box.put('token', token); - TokenStorage.saveTokenInStorage(token); + await TokenStorage.saveTokenInStorage(token); GoRouter.of(context).go('/my-profile-screen'); } else { showDialog( @@ -117,7 +178,7 @@ class AuthScreen extends StatelessWidget { content: Text('wrong_credentials'.tr), actions: [ TextButton( - onPressed: onTapOk(context), + onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], @@ -138,7 +199,7 @@ class AuthScreen extends StatelessWidget { content: Text(errorMessage), actions: [ TextButton( - onPressed: onTapOk(context), + onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], @@ -148,41 +209,6 @@ class AuthScreen extends StatelessWidget { }; } - onTapOk(BuildContext context) { - return () { - GoRouter.of(context).pop(context); - }; - } - - onTapDiaryTest(BuildContext context) { - return () { - GoRouter.of(context).goNamed('diaryScreen'); - }; - } - - onTapProfileTest(BuildContext context) { - return () { - GoRouter.of(context).goNamed('mySettingsScreen'); - }; - } - - onTapNoAccount(BuildContext context) { - return () { - GoRouter.of(context).goNamed('languageSelectScreen'); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - centerTitle: true, - title: AppbarTitleImage( - imagePath: ImageConstant.imgLogoEatvio, - ), - ); - } - List validateFields(String email, String password) { List errors = []; diff --git a/lib/presentation/auth/auth_screen/bloc/auth_bloc.dart b/lib/presentation/auth/auth_screen/bloc/auth_bloc.dart index 6622981..0d8f67a 100644 --- a/lib/presentation/auth/auth_screen/bloc/auth_bloc.dart +++ b/lib/presentation/auth/auth_screen/bloc/auth_bloc.dart @@ -1,10 +1,10 @@ +import 'package:eatvio_app/presentation/auth/auth_screen/models/auth_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/auth/auth_screen/models/auth_model.dart'; part 'auth_event.dart'; - part 'auth_state.dart'; /// A bloc that manages the state of a Auth according to the event that is dispatched to it. diff --git a/lib/presentation/auth/auth_screen/bloc/auth_state.dart b/lib/presentation/auth/auth_screen/bloc/auth_state.dart index 504180f..86e8e3b 100644 --- a/lib/presentation/auth/auth_screen/bloc/auth_state.dart +++ b/lib/presentation/auth/auth_screen/bloc/auth_state.dart @@ -22,6 +22,7 @@ class AuthState extends Equatable { passwordController, authModelObj, ]; + AuthState copyWith({ TextEditingController? emailController, TextEditingController? passwordController, diff --git a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart deleted file mode 100644 index 4474110..0000000 --- a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart +++ /dev/null @@ -1,971 +0,0 @@ -import 'dart:async'; -import 'package:intl/intl.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/models/diary_edit_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; - -part 'diary_edit_event.dart'; -part 'diary_edit_state.dart'; - -/// A bloc that manages the state of a DiaryEdit according to the event that is dispatched to it. -class DiaryEditBloc extends Bloc { - DiaryEditBloc(DiaryEditState initialState) : super(initialState) { - on(_onInitialize); - on(_changeSatiety); // пользователь нажимает на шкалу сытости - on(_changeMood); // пользователь нажимает на шкалу настроения - on(_changeMealTime); // пользовательяет времяа пиши - on(_changeMeal); - on(_changePortion); - on(_changeWakeup); // пользователь выбирает время пробуждения - on(_changeRetire); // пользователь выбирает время отхода ко сну - on(_toggleMood); - on(_toggleWakeup); - on(_addPortion); //пользователь нажимает "Добавить продукт" - on(_removePortion); - on( - _removeImage); // пользователь нажимает на крестик около продукта - on(_uploadImages); //пользователь нажимает "Добавить фото" - on(_addComment); //пользователь нажимает "Добавить комментарий" - on( - _inputProduct); //пользователь нажимает "Добавить комментарий" - on(_finishDay); //пользователь нажимает "Добавить комментарий" - on(_sendModeration); - on( - reloadScreen); //пользователь нажимает "Добавить комментарий" - on(_clearInput); - } - - Future _onInitialize( - DiaryEditInitialEvent event, - Emitter emit, - ) async { - try { - // final token = - // "9|laravel_sanctum_KFXbccDcWEvTPfJmV99EQv1neAggmpR2TidVGDPN34fa201a"; - final box = await Hive.openBox('token'); - final token = box.get('token'); - //print(await fetchDiaryId(token)); - final int diaryId = await fetchDiaryId(token, emit); - try { - print("Diary ID fetched"); - final diary = await fetchDiaryData(token, diaryId); - print("Screen load success"); - if (diary is Map) { - final String diaryDate = diary['date'] ?? DateTime.now().toString(); - final chartValues = await fetchChartValues(token, diaryId, emit); - if (state is DiaryEditLoadedState) { - // Если текущее состояние уже загружено, обновляем его - var currentState = state as DiaryEditLoadedState; - emit((currentState).copyWith( - currentMeal: currentState.currentMeal, - wakeupExpanded: currentState.wakeupExpanded, - moodExpanded: currentState.moodExpanded, - moderationExpanded: currentState.moderationExpanded, - token: currentState.token, - meals: currentState.meals, - portions: currentState.portions, - photos: currentState.photos, - wakeupController: currentState.wakeupController, - retireController: currentState.retireController, - commentController: currentState.commentController, - mealTimeController: currentState.mealTimeController, - productNameController: currentState.productNameController, - caloriesController: currentState.caloriesController, - proteinsController: currentState.proteinsController, - fatsController: currentState.fatsController, - carbsController: currentState.carbsController, - selectedSatiety: currentState.selectedSatiety, - selectedMood: currentState.selectedMood, - diaryDate: currentState.diaryDate, - diaryId: currentState.diaryId, - productQuantityController: - currentState.productQuantityController, - recommendedChartValues: currentState.recommendedChartValues, - consumedChartValues: currentState.consumedChartValues, - autocompleteList: currentState.autocompleteList, - diaryEditModelObj: currentState.diaryEditModelObj)); - } else { - // Если текущее состояние - начальное, создаем новое загруженное состояние - final List meals = - fillMealList(diary['meals']); - emit(DiaryEditLoadedState( - currentMeal: meals[0], - portionController: SelectionPopupModel( - id: 0, title: "порций", isSelected: true), - wakeupExpanded: true, - moodExpanded: true, - moderationExpanded: false, - token: token, - recommendedChartValues: chartValues[0], - consumedChartValues: chartValues[1], - meals: diary['meals'], - portions: diary['meals'][0]['portions'], - photos: diary['meals'][0]['photos'], - wakeupController: toTime(diary['wakeup'] ?? "09:00"), - retireController: toTime(diary['retire'] ?? "23:00"), - mealTimeController: - toTime(diary['meals'][0]['time'] ?? "10:00"), - selectedSatiety: diary['meals'][0]['satiety'], - selectedMood: diary['meals'][0]['mood'], - commentController: - TextEditingController(text: diary['comment']), - productNameController: TextEditingController(), - productQuantityController: TextEditingController(), - caloriesController: TextEditingController(), - proteinsController: TextEditingController(), - fatsController: TextEditingController(), - carbsController: TextEditingController(), - diaryId: diaryId, - diaryDate: diaryDate, - autocompleteList: [], - diaryEditModelObj: state.diaryEditModelObj - ?.copyWith(mealList: meals, portionList: fillPortions()))); - } - } - } catch (e) { - // Ошибка при получении данных дневника - emit(DiaryEditErrorState('Ошибка при получении данных дневника: $e')); - } - } catch (e) { - // Ошибка при получении данных дневника - emit(DiaryEditErrorState('Ошибка при получении данных о дневнике: $e')); - } - } - - fetchDiaryId(String token, Emitter emit) async { - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/index'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - if (data is Map && data.containsKey('id')) { - final int diaryId = data['id']; - return diaryId; - } else { - emit(DiaryEditErrorState('Некоторые необходимые данные отсутствуют.')); - print('fail'); - return -1; - } - } else { - emit(DiaryEditErrorState('Ошибка сервера: ${response.statusCode}')); - print('fail'); - return -1; - } - } - - fetchDiaryData(String token, int diaryId) async { - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/$diaryId/show/'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - final diary = jsonDecode(response.body)['diary']; - - return diary; - } - - fetchChartValues( - String token, int diaryID, Emitter emit) async { - final responseChart = await http.get( - Uri.parse( - dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/dailyNutritionData/'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - if (responseChart.statusCode == 200) { - final recommendedChartValues = - jsonDecode(responseChart.body)['dailyNutritionRecommendation'] - .values - .map((value) => value as int) - .toList(); - final consumedChartValues = - jsonDecode(responseChart.body)['dailyNutritionIntake'] - .values - .map((value) => value as int) - .toList(); - return [recommendedChartValues, consumedChartValues]; - } else { - emit(DiaryEditErrorState('Ошибка при декодировании данных КБЖУ')); - print('fail'); - return -1; - } - } - - refreshScreen( - int mealID, - DiaryEditEvent event, - Emitter emit, - ) async { - await reloadScreen(event, emit); - } - - reloadScreen( - DiaryEditEvent event, - Emitter emit, - ) async { - print("Reloading..."); - try { - //final token = - // "9|laravel_sanctum_KFXbccDcWEvTPfJmV99EQv1neAggmpR2TidVGDPN34fa201a"; final box = await Hive.openBox('token'); - final box = await Hive.openBox('token'); - final token = box.get('token'); - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/index'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - if (data is Map && data.containsKey('id')) { - final int diaryId = data['id']; - - final diaryResponse = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/$diaryId/show/'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - - final diary = jsonDecode(diaryResponse.body)['diary']; - - if (diary is Map) { - final String diaryDate = diary['date'] ?? DateTime.now().toString(); - final responseChart = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + - '/diary/$diaryId/dailyNutritionData/'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - if (responseChart.statusCode == 200) { - final recommendedChartValues = jsonDecode( - responseChart.body)['dailyNutritionRecommendation']; - final consumedChartValues = - jsonDecode(responseChart.body)['dailyNutritionIntake']; - final List meals = - fillMealList(diary['meals']); - try { - await Future(() => emit(DiaryEditLoadedState( - diaryEditModelObj: state.diaryEditModelObj?.copyWith( - mealList: meals, portionList: fillPortions()), - currentMeal: meals[0], - portionController: SelectionPopupModel( - id: 0, title: "порций", isSelected: true), - wakeupExpanded: true, - moodExpanded: true, - moderationExpanded: false, - token: token, - recommendedChartValues: recommendedChartValues.values - .map((value) => value as int) - .toList(), - consumedChartValues: consumedChartValues.values - .map((value) => value as int) - .toList(), - meals: diary['meals'], - portions: diary['meals'][0]['portions'], - photos: diary['meals'][0]['photos'], - wakeupController: toTime(diary['wakeup'] ?? "09:00"), - retireController: toTime(diary['retire'] ?? "23:00"), - mealTimeController: - toTime(diary['meals'][0]['time'] ?? "10:00"), - selectedSatiety: diary['meals'][0]['satiety'], - selectedMood: diary['meals'][0]['mood'], - commentController: - TextEditingController(text: diary['comment']), - productNameController: TextEditingController(), - productQuantityController: TextEditingController(), - caloriesController: TextEditingController(), - proteinsController: TextEditingController(), - fatsController: TextEditingController(), - carbsController: TextEditingController(), - diaryId: diaryId, - diaryDate: diaryDate, - isLoading: false, - autocompleteList: [], - ))); - - print("Updated"); - } catch (e) { - print("Ошибка при создании нового состояния $e"); - } - } else { - emit(DiaryEditErrorState('Ошибка при декодировании данных КБЖУ')); - } - } else { - emit(DiaryEditErrorState( - 'Ошибка при декодировании данных дневника')); - } - } else { - emit( - DiaryEditErrorState('Некоторые необходимые данные отсутствуют.')); - } - } else { - emit(DiaryEditErrorState('Ошибка сервера: ${response.statusCode}')); - } - } catch (e) { - emit(DiaryEditErrorState('Ошибка при получении данных дневника: $e')); - } - } - - Future _changeSatiety( - ChangeSatiety event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var updatedState = - currentState.copyWith(selectedSatiety: event.selectedElement); - - // Отправляем данные по HTTP маршруту и ждем ответ - var response = await sendSatietyData( - currentState.token, - event.selectedElement, - currentState.currentMeal?.id, - currentState.diaryId); - - if (response.statusCode == 200) { - updatedState.selectedSatiety = event.selectedElement; - emit(updatedState); // Передаем обновленное состояние в emit - } - } - } - - Future sendSatietyData( - String? token, - int selectedSatiety, - int? mealID, - int diaryID, - ) async { - String url = dotenv.env['SERVER_ROOT']! + - '/diary/$diaryID/meal/$mealID/satiety/fill'; - final Map credentials = { - 'satiety': selectedSatiety, - }; - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - return response; - } - - Future _changeMood( - ChangeMood event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var updatedState = - currentState.copyWith(selectedMood: event.selectedElement); - - // Отправляем данные по HTTP маршруту и ждем ответ - var response = await sendMoodData( - currentState.token, - event.selectedElement, - currentState.currentMeal?.id, - currentState.diaryId); - - if (response.statusCode == 200) { - print( - 'Mood change success! meal_id: ${currentState.currentMeal?.id}, mood: ${event.selectedElement}'); - updatedState.selectedMood = event.selectedElement; - emit(updatedState); // Передаем обновленное состояние в emit - } - } - } - - Future sendMoodData( - String? token, - int selectedMood, - int? mealID, - int diaryID, - ) async { - String url = - dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/meal/$mealID/mood/fill'; - final Map credentials = { - 'mood': selectedMood, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } - - FutureOr _changeWakeup( - WakeupEvent event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var response = await sendWakeupData( - currentState.token, event.selectedTime, currentState.diaryId); - if (response.statusCode == 200) { - await reloadScreen(event, emit); - var updatedState = - currentState.copyWith(wakeupController: event.selectedTime); - print("Wakeup time changed to ${event.selectedTime}"); - emit(updatedState); // Передаем обновленное состояние в emit - } else - print("Wakeup time change error"); - } - } - - FutureOr _changeRetire( - RetireEvent event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var response = await sendRetireData( - currentState.token, event.selectedTime, currentState.diaryId); - if (response.statusCode == 200) { - await reloadScreen(event, emit); - var updatedState = - currentState.copyWith(retireController: event.selectedTime); - print("Retire time changed to ${event.selectedTime}"); - emit(updatedState); // Передаем обновленное состояние в emit - } else - print("Retire time change error"); - } - } - - Future sendWakeupData( - String? token, - TimeOfDay wakeup, - int diaryID, - ) async { - String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/wakeUp/fill'; - final formatter = DateFormat('HH:mm'); - final wakeupString = - formatter.format(DateTime(2022, 1, 1, wakeup.hour, wakeup.minute)); - final Map credentials = { - 'wakeUp': wakeupString, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } - - Future sendRetireData( - String? token, TimeOfDay retire, int diaryID) async { - String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/retire/fill'; - final formatter = DateFormat('HH:mm'); - final retireString = - formatter.format(DateTime(2022, 1, 1, retire.hour, retire.minute)); - final Map credentials = { - 'retire': retireString, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } - - FutureOr _changeMealTime( - ChangeMealTime event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var updatedState = currentState.copyWith(mealTimeController: event.time); - - emit(updatedState); - } - } - - Future sendMealTimeData( - String? token, - TimeOfDay mealTime, - int? mealID, - int diaryID, - ) async { - String url = dotenv.env['SERVER_ROOT']! + '/diary/???'; - final Map credentials = { - 'time': mealTime, - 'meal_id': mealID, - 'diary_id': diaryID, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } - - FutureOr _changeMeal( - ChangeMeal event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - final meal = currentState.meals?.firstWhere( - (meal) => meal['id'] == event.value.id, - orElse: () => null); - int? id = event.value.id; - print(meal['photos']); - DiaryEditLoadedState updatedState = currentState.copyWith( - currentMeal: event.value, - portions: meal['portions'], - photos: meal['photos'], - mealTimeController: toTime(meal['time'] ?? "1$id:00"), - selectedMood: meal['mood'], - selectedSatiety: meal['satiety']); - print(updatedState.photos); - emit(updatedState); - } - } - - - FutureOr _clearInput( - ClearInput event, Emitter emit) { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - DiaryEditLoadedState updatedState = currentState.copyWith( - ); - emit(updatedState); - } - } - - FutureOr _changePortion( - ChangePortion event, Emitter emit) { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - DiaryEditLoadedState updatedState = currentState.copyWith( - portionController: event.value, - ); - emit(updatedState); - } - } - - FutureOr _toggleMood( - ToggleMoodExpandedEvent event, Emitter emit) { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - emit(currentState.copyWith(moodExpanded: !currentState.moodExpanded)); - currentState.moodExpanded = !currentState.moodExpanded; - } - } - - FutureOr _toggleWakeup( - ToggleWakeupExpandedEvent event, Emitter emit) { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - emit(currentState.copyWith(wakeupExpanded: !currentState.wakeupExpanded)); - currentState.wakeupExpanded = !currentState.wakeupExpanded; - } - } - - FutureOr _addPortion( - AddPortionEvent event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - var response = await sendPortionData( - currentState.token, - currentState.productNameController?.text, - currentState.portionController?.id == 0 ? 'pcs' : 'gr', - int.parse(currentState.productQuantityController!.text), - currentState.currentMeal!.id, - currentState.diaryId, - ); - - if (response.statusCode == 200) { - emit(currentState.copyWith(isAdded: true)); - await reloadScreen(event, emit); - } else { - print( - 'Failed to add portion. Status Code: ${response.statusCode} ${response.body}'); - } - } - } - - FutureOr sendPortionData(String? token, String? name, - String portion, int? quantity, int? mealID, int diaryID) async { - String url = - '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/create'; - - final Map credentials = { - 'product_name': name, - 'portion': portion, - 'quantity': quantity, - }; - - var response = await http.post( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8, - ); - - return response; - } - - Future _inputProduct( - ProductInput event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - String? token = currentState.token; - - final Map credentials = {'name': event.input}; - final uri = Uri.parse( - '${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/filter?${Uri(queryParameters: credentials).query}'); - - final response = await http.get( - uri, - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - - final productNutritionalValues = - jsonDecode(response.body)['product_nutritional_value']; - - if (productNutritionalValues is List) { - // Create a new controller with the input text and update the autocomplete list - var updatedState = currentState.copyWith( - productNameController: TextEditingController(text: event.input), - autocompleteList: productNutritionalValues - .map((product) => product['name']) - .toList(), - ); - if (event.input.length > 3) { - updatedState = updatedState.copyWith(moderationExpanded: true); - } else { - updatedState = updatedState.copyWith(moderationExpanded: false); - } - - emit(updatedState); // Emit the updated state - } - } - } - - Future _removePortion( - RemovePortionEvent event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - int? mealId = - currentState.currentMeal?.id; // Rename id to mealId for clarity - - var response = await sendRemovePortion( - currentState.token, - event.portionId, - mealId, - currentState.diaryId, - ); - - if (response.statusCode == 204) { - await reloadScreen(event, emit); - } else { - print( - 'Failed to add portion. Status Code: ${response.statusCode} ${response.body}'); - } - } - } - - Future sendRemovePortion( - String? token, int? portionID, int? mealID, int diaryID) async { - String url = - '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/$portionID/delete'; - - var response = await http.delete( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - encoding: utf8, - ); - - return response; - } - - FutureOr _removeImage( - RemoveImageEvent event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - var response = await sendRemovePhoto( - currentState.token, - event.path, - event.photoID, - currentState.currentMeal?.id, - currentState.diaryId, - ); - print(response.statusCode); - if (response.statusCode == 204) { - await reloadScreen(event, emit); - } else { - print( - 'Failed to remove photo. Status Code: ${response.statusCode} ${response.body}'); - } - } - } - - Future sendRemovePhoto(String? token, String? path, - String? photoID, int? mealID, int diaryID) async { - String url = - '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/photo/delete'; - final Map credentials = { - 'id': photoID, - 'path': path, - }; - var response = await http.delete( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8, - ); - - return response; - } - - Future _finishDay(FinishDay event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - var response = await sendFinishDay( - currentState.token, - currentState.diaryId, - currentState.wakeupController, - currentState.retireController, - currentState.commentController?.text, - ); - - if (response.statusCode == 200) { - await reloadScreen(event, emit); - } - } - } - - Future sendFinishDay(String? token, int diaryID, - TimeOfDay? wakeup, TimeOfDay? retire, String? comment) async { - final formatter = DateFormat('HH:mm'); - final wakeupString = - formatter.format(DateTime(2022, 1, 1, wakeup!.hour, wakeup.minute)); - final retireString = - formatter.format(DateTime(2022, 1, 1, retire!.hour, retire.minute)); - - final Map credentials = { - 'wakeup': wakeupString, - 'retire': retireString, - 'comment': comment ?? " ", - }; - - String url = '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/finishDay'; - - var response = await http.post( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8, - ); - - return response; - } - - Future _uploadImages( - UploadImages event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - - emit(currentState.copyWith(isLoading: true)); - await uploadImageToServer(event.image.path, currentState.diaryId, - currentState.currentMeal!.id!, currentState.token); - await reloadScreen(event, emit); - } - } - - Future uploadImageToServer( - String imagePath, int diaryID, int mealId, String? token) async { - String url = - '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealId/photo/upload'; - - var request = http.MultipartRequest('POST', Uri.parse(url)); - request.headers['Authorization'] = 'Bearer $token'; - - request.files.add(await http.MultipartFile.fromPath('photo', imagePath)); - - var client = http.Client(); - var streamedResponse = await client.send(request); - - if (streamedResponse.statusCode == 200) { - var response = await http.Response.fromStream(streamedResponse); - var imageUrl = response.body; - print('Image successfully uploaded'); - return imageUrl; - } else { - throw Exception( - 'Failed to upload image. Status code: ${streamedResponse.statusCode}}'); - } - } - - FutureOr _sendModeration( - SendModeration event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - final response = await _sendModerationData( - event.name, - event.energyOn100gr, - event.proteinsOn100gr, - event.fatsOn100gr, - event.carbohydratesOn100gr, - currentState.token, - ); - - if (response.statusCode == 200) - print("Moderation success"); - else - print("Moderation error"); - } - } - - Future _sendModerationData( - String name, - String energy_on_100gr, - String proteins_on_100gr, - String fats_on_100gr, - String carbohydrates_on_100gr, - String? token) async { - final Uri url = Uri.parse( - '${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/sendToModeration'); - final Uri serverURL = Uri.parse('${dotenv.env['SERVER_ROOT']!}'); - String host = serverURL.host; - final Map credentials = { - 'name': name, - 'energy_on_100gr': energy_on_100gr, - 'proteins_on_100gr': proteins_on_100gr, - 'fats_on_100gr': fats_on_100gr, - 'carbohydrates_on_100gr': carbohydrates_on_100gr, - }; - - var headers = { - //'Content-Length': bodyBytes, - 'Authorization': 'Bearer $token', - 'Host': host, - }; - - var response = await http.post( - url, - headers: headers, - body: credentials, - encoding: utf8, - ); - - if (response.statusCode == 200) { - return response; - } else { - throw Exception( - 'Failed to send a product for moderation ${response.statusCode}'); - } - } - - FutureOr _addComment( - AddComment event, Emitter emit) async { - if (state is DiaryEditLoadedState) { - var currentState = state as DiaryEditLoadedState; - var updatedState = currentState.copyWith( - commentController: TextEditingController(text: event.comment), - ); - - // Отправляем данные по HTTP маршруту и ждем ответ - var response = await sendCommentData( - currentState.token, event.comment, currentState.diaryId); - - if (response.statusCode == 200) { - emit(updatedState); // Передаем обновленное состояние в emit - } - } - } - - Future sendCommentData( - String? token, String comment, int diaryID) async { - String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/retire/fill'; - final Map credentials = { - 'comment': comment, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } - - TimeOfDay toTime(String timeStr) { - List timeParts = timeStr.split(":"); - int hour = int.parse(timeParts[0]); - int minute = int.parse(timeParts[1]); - - TimeOfDay timeOfDay = TimeOfDay(hour: hour, minute: minute); - return timeOfDay; - } - - List fillMealList(List meals) { - meals.sort(compareTypes); - return meals.map((meal) { - String title = "Прием пищи ${meal['type']}"; - return SelectionPopupModel(id: meal['id'], title: title); - }).toList(); - } - - int compareTypes(a, b) { - return a['type'].compareTo(b['type']); - } - - List fillPortions() { - return [ - SelectionPopupModel(id: 0, title: "порций", isSelected: true), - SelectionPopupModel(id: 1, title: "грамм"), - ]; - } -} diff --git a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart index 61762f0..352daf7 100644 --- a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart +++ b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart @@ -1,6 +1,6 @@ // ignore_for_file: must_be_immutable -part of 'diary_edit_bloc.dart'; +/*part of '../../../../features/diary/presentation/bloc/diary_bloc.dart'; class DiaryEditState extends Equatable { const DiaryEditState({this.diaryEditModelObj}); @@ -12,43 +12,42 @@ class DiaryEditState extends Equatable { } class DiaryEditInitialState extends DiaryEditState { - DiaryEditInitialState({required DiaryEditModel diaryEditModelObj}) - : super(diaryEditModelObj: diaryEditModelObj); + DiaryEditInitialState({required DiaryEditModel diaryEditModelObj}) : super(diaryEditModelObj: diaryEditModelObj); } /// Represents the state of DiaryEdit in the application. class DiaryEditLoadedState extends DiaryEditState { - DiaryEditLoadedState( - {this.diaryEditModelObj, - this.diaryDate, - this.token, - this.meals, - this.portions, - this.photos, - this.autocompleteList, - this.wakeupController, - this.retireController, - this.commentController, - this.mealTimeController, - this.portionController, - this.productNameController, - this.productQuantityController, - this.selectedMood, - this.currentMeal, - this.caloriesController, - this.fatsController, - this.proteinsController, - this.carbsController, - this.isLoading = false, - this.isAdded = false, - required this.recommendedChartValues, - required this.consumedChartValues, - required this.diaryId, - required this.selectedSatiety, - required this.moderationExpanded, - required this.wakeupExpanded, - required this.moodExpanded}) - : super(diaryEditModelObj: null); + DiaryEditLoadedState({ + this.diaryEditModelObj, + this.diaryDate, + this.token, + this.meals, + this.portions, + this.photos, + this.autocompleteList, + this.wakeupController, + this.retireController, + this.commentController, + this.mealTimeController, + this.portionController, + this.productNameController, + this.productQuantityController, + this.selectedMood, + this.currentMeal, + this.caloriesController, + this.fatsController, + this.proteinsController, + this.carbsController, + this.isLoading = false, + this.isAdded = false, + required this.recommendedChartValues, + required this.consumedChartValues, + required this.diaryId, + required this.selectedSatiety, + required this.moderationExpanded, + required this.wakeupExpanded, + required this.moodExpanded, + }) : super(diaryEditModelObj: null); DiaryEditModel? diaryEditModelObj; String? diaryDate; @@ -109,7 +108,7 @@ class DiaryEditLoadedState extends DiaryEditState { moderationExpanded, isLoading, isAdded, - currentMeal + currentMeal, ]; DiaryEditLoadedState copyWith({ DiaryEditModel? diaryEditModelObj, @@ -143,38 +142,36 @@ class DiaryEditLoadedState extends DiaryEditState { bool? isAdded, }) { return DiaryEditLoadedState( - diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj, - diaryDate: diaryDate ?? this.diaryDate, - token: token ?? this.token, - meals: meals ?? this.meals, - photos: photos ?? this.photos, - autocompleteList: autocompleteList ?? this.autocompleteList, - portions: portions ?? this.portions, - recommendedChartValues: - recommendedChartValues ?? this.recommendedChartValues, - consumedChartValues: consumedChartValues ?? this.consumedChartValues, - wakeupController: wakeupController ?? this.wakeupController, - retireController: retireController ?? this.retireController, - mealTimeController: mealTimeController ?? this.mealTimeController, - commentController: commentController ?? this.commentController, - portionController: portionController ?? this.portionController, - productNameController: - productNameController ?? this.productNameController, - productQuantityController: - productQuantityController ?? this.productQuantityController, - selectedMood: selectedMood ?? this.selectedMood, - selectedSatiety: selectedSatiety ?? this.selectedSatiety, - diaryId: diaryId ?? this.diaryId, - currentMeal: currentMeal ?? this.currentMeal, - caloriesController: caloriesController ?? this.caloriesController, - fatsController: fatsController ?? this.fatsController, - proteinsController: proteinsController ?? this.proteinsController, - carbsController: carbsController ?? this.carbsController, - wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded, - moderationExpanded: moderationExpanded ?? this.moderationExpanded, - moodExpanded: moodExpanded ?? this.moodExpanded, - isAdded: isAdded ?? this.isAdded, - isLoading: isLoading ?? this.isLoading); + diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj, + diaryDate: diaryDate ?? this.diaryDate, + token: token ?? this.token, + meals: meals ?? this.meals, + photos: photos ?? this.photos, + autocompleteList: autocompleteList ?? this.autocompleteList, + portions: portions ?? this.portions, + recommendedChartValues: recommendedChartValues ?? this.recommendedChartValues, + consumedChartValues: consumedChartValues ?? this.consumedChartValues, + wakeupController: wakeupController ?? this.wakeupController, + retireController: retireController ?? this.retireController, + mealTimeController: mealTimeController ?? this.mealTimeController, + commentController: commentController ?? this.commentController, + portionController: portionController ?? this.portionController, + productNameController: productNameController ?? this.productNameController, + productQuantityController: productQuantityController ?? this.productQuantityController, + selectedMood: selectedMood ?? this.selectedMood, + selectedSatiety: selectedSatiety ?? this.selectedSatiety, + diaryId: diaryId ?? this.diaryId, + currentMeal: currentMeal ?? this.currentMeal, + caloriesController: caloriesController ?? this.caloriesController, + fatsController: fatsController ?? this.fatsController, + proteinsController: proteinsController ?? this.proteinsController, + carbsController: carbsController ?? this.carbsController, + wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded, + moderationExpanded: moderationExpanded ?? this.moderationExpanded, + moodExpanded: moodExpanded ?? this.moodExpanded, + isAdded: isAdded ?? this.isAdded, + isLoading: isLoading ?? this.isLoading, + ); } } @@ -185,4 +182,4 @@ class DiaryEditErrorState extends DiaryEditState { @override List get props => [errorMessage]; -} +}*/ \ No newline at end of file diff --git a/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart b/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart index e2be948..1ccb56c 100644 --- a/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart +++ b/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart @@ -1,6 +1,6 @@ // ignore_for_file: unused_local_variable -import 'bloc/diary_edit_bloc.dart'; +/*import '../../../features/diary/presentation/bloc/diary_bloc.dart'; import 'models/diary_edit_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -21,7 +21,9 @@ class DiaryEditScreen extends StatelessWidget { static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel()))..add(DiaryEditInitialEvent()), child: DiaryEditScreen()); + create: (context) => DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel()))..add(DiaryEditInitialEvent()), + child: DiaryEditScreen(), + ); } Widget build(BuildContext context) { @@ -221,7 +223,7 @@ class DiaryEditScreen extends StatelessWidget { Icon( Icons.photo_library, color: appTheme.blueGray300, - ) + ), ], ), ), @@ -264,237 +266,241 @@ class DiaryEditScreen extends StatelessWidget { //print(_options); FocusNode focusNodeName = FocusNode(); return Container( - margin: EdgeInsets.symmetric(horizontal: 16.h), - padding: EdgeInsets.symmetric( - horizontal: 24.h, - vertical: 12.v, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Время приема пищи", - style: CustomTextStyles.bodyMediumBlack900, - ), - Expanded( - // Adding Expanded widget - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width - 260, - ), - child: GestureDetector( - onTap: () => _selectMealTime(context, state), - child: AbsorbPointer( - child: CustomTextFormField( - hintText: state.mealTimeController?.format(context).toString(), - autofocus: false, - ), + margin: EdgeInsets.symmetric(horizontal: 16.h), + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Время приема пищи", + style: CustomTextStyles.bodyMediumBlack900, + ), + Expanded( + // Adding Expanded widget + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width - 260, + ), + child: GestureDetector( + onTap: () => _selectMealTime(context, state), + child: AbsorbPointer( + child: CustomTextFormField( + hintText: state.mealTimeController?.format(context).toString(), + autofocus: false, ), ), ), ), ), + ), + ], + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: BlocSelector( + selector: (state) => state.diaryEditModelObj, + builder: (context, diaryEditModelObj) { + return CustomDropDown( + hintText: "Прием пищи", + items: diaryEditModelObj?.mealList, + contentPadding: EdgeInsets.symmetric( + horizontal: 10.h, + vertical: 9.v, + ), + defaultValue: diaryEditModelObj?.mealList[0], + onChanged: changeMeal(context, state), + ); + }, + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: RawAutocomplete( + optionsBuilder: buildOptions(_options), + fieldViewBuilder: ( + BuildContext context, + TextEditingController productEditingController, + FocusNode focusNodeName, + VoidCallback onFieldSubmitted, + ) { + if (state.isAdded) { + print("Clear"); + } + return CustomTextFormField( + hintText: "Введите название продукта", + controller: productEditingController, + focusNode: focusNodeName, + onChanged: getAutocomplete(context, focusNodeName), + ); + }, + optionsViewBuilder: ( + BuildContext context, + AutocompleteOnSelected onSelected, + Iterable options, + ) { + return Align( + alignment: Alignment.topLeft, + child: Material( + elevation: 4.0, + child: SizedBox( + height: 200.0, + child: ListView.builder( + padding: const EdgeInsets.all(8.0), + itemCount: options.length, + itemBuilder: (BuildContext context, int index) { + final String option = options.elementAt(index); + return GestureDetector( + onTap: selectProduct(onSelected, option, state), + child: ListTile( + title: Text(option), + ), + ); + }, + ), + ), + ), + ); + }, + ), + ), + SizedBox(height: 20.v), + if (state.moderationExpanded) + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: GestureDetector( + onTap: () => openCaloriesDialog(context, state), + child: Text("Отправить на модерацию"), + ), + ), + SizedBox(height: 20.v), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CustomTextFormField( + width: 150.h, + hintText: "Кол-во", + textInputAction: TextInputAction.done, + // focusNode: focusNodeQuantity, + controller: state.productQuantityController, + keyboardType: TextInputType.number, + inputFormatters: [digitsOnly], + ), + Padding( + padding: EdgeInsets.only(left: 30.h), + child: BlocSelector( + selector: (state) => state.diaryEditModelObj, + builder: (context, diaryEditModelObj) { + return CustomDropDown( + items: diaryEditModelObj?.portionList, + defaultValue: diaryEditModelObj?.portionList?[0], + onChanged: changePortion(context, state), + ); + }, + ), + ), ], ), ), - SizedBox(height: 20.v), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: BlocSelector( - selector: (state) => state.diaryEditModelObj, - builder: (context, diaryEditModelObj) { - return CustomDropDown( - hintText: "Прием пищи", - items: diaryEditModelObj?.mealList, - contentPadding: EdgeInsets.symmetric( - horizontal: 10.h, - vertical: 9.v, - ), - defaultValue: diaryEditModelObj?.mealList[0], - onChanged: changeMeal(context, state), - ); - })), - SizedBox(height: 20.v), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: RawAutocomplete( - optionsBuilder: buildOptions(_options), - fieldViewBuilder: ( - BuildContext context, - TextEditingController productEditingController, - FocusNode focusNodeName, - VoidCallback onFieldSubmitted, - ) { - if (state.isAdded) { - print("Clear"); - } - return CustomTextFormField( - hintText: "Введите название продукта", - controller: productEditingController, - focusNode: focusNodeName, - onChanged: getAutocomplete(context, focusNodeName), - ); - }, - optionsViewBuilder: ( - BuildContext context, - AutocompleteOnSelected onSelected, - Iterable options, - ) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: SizedBox( - height: 200.0, - child: ListView.builder( - padding: const EdgeInsets.all(8.0), - itemCount: options.length, - itemBuilder: (BuildContext context, int index) { - final String option = options.elementAt(index); - return GestureDetector( - onTap: selectProduct(onSelected, option, state), - child: ListTile( - title: Text(option), - ), - ); - }, - ), - ), - ), - ); - }), - ), - SizedBox(height: 20.v), - if (state.moderationExpanded) - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: GestureDetector( - onTap: () => openCaloriesDialog(context, state), - child: Text("Отправить на модерацию"), - ), - ), - SizedBox(height: 20.v), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomTextFormField( - width: 150.h, - hintText: "Кол-во", - textInputAction: TextInputAction.done, - // focusNode: focusNodeQuantity, - controller: state.productQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [digitsOnly], - ), - Padding( - padding: EdgeInsets.only(left: 30.h), - child: BlocSelector( - selector: (state) => state.diaryEditModelObj, - builder: (context, diaryEditModelObj) { - return CustomDropDown( - items: diaryEditModelObj?.portionList, - defaultValue: diaryEditModelObj?.portionList?[0], - onChanged: changePortion(context, state), - ); - }, - ), - ), - ], - ), - ), - ), - SizedBox(height: 30.v), - _buildAddProduct(context, state), - SizedBox(height: 30.v), - ...state.portions!.map((portion) => _buildProduct(context, portion)).toList(), - SizedBox(height: 30.v), - /*...state.photos != null + ), + SizedBox(height: 30.v), + _buildAddProduct(context, state), + SizedBox(height: 30.v), + ...state.portions!.map((portion) => _buildProduct(context, portion)).toList(), + SizedBox(height: 30.v), + /*...state.photos != null ? state.photos!.isEmpty ? [Text('Фото пока нет')] : state.photos! .map((photo) => _buildPhoto(context, photo)) .toList() : [Text('Фото нет')],*/ - _buildCarousel(context, state), - SizedBox(height: 20.v), - _buildAddPhoto(context, state), - SizedBox(height: 30.v), - Text( - "Ваша сытость после приёма пищи", - style: CustomTextStyles.bodyMediumBlack900, - ), - SizedBox(height: 15.v), - BlocBuilder( - builder: (context, state) { - if (state is DiaryEditLoadedState) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("😭"), - ScaleElement( - color: Colors.red, - isSelected: state.selectedSatiety == 0, - onTap: changeSatiety(context, 0), - ), - ScaleElement( - color: Colors.orange, - isSelected: state.selectedSatiety == 1, - onTap: changeSatiety(context, 1), - ), - ScaleElement( - color: Colors.yellow, - isSelected: state.selectedSatiety == 2, - onTap: changeSatiety(context, 2), - ), - ScaleElement( - color: Colors.lime, - isSelected: state.selectedSatiety == 3, - onTap: changeSatiety(context, 3), - ), - ScaleElement( - color: Colors.lightGreen, - isSelected: state.selectedSatiety == 4, - onTap: changeSatiety(context, 4), - ), - ScaleElement( - color: Colors.green, - isSelected: state.selectedSatiety == 5, - onTap: changeSatiety(context, 5), - ), - Text("😊"), - // Остальные элементы шкалы - ], - ); - } else { - return Container(); // Возвращаем пустой контейнер, если состояние не является DiaryEditLoadedState - } - }, - ) - ], - )); + _buildCarousel(context, state), + SizedBox(height: 20.v), + _buildAddPhoto(context, state), + SizedBox(height: 30.v), + Text( + "Ваша сытость после приёма пищи", + style: CustomTextStyles.bodyMediumBlack900, + ), + SizedBox(height: 15.v), + BlocBuilder( + builder: (context, state) { + if (state is DiaryEditLoadedState) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("😭"), + ScaleElement( + color: Colors.red, + isSelected: state.selectedSatiety == 0, + onTap: changeSatiety(context, 0), + ), + ScaleElement( + color: Colors.orange, + isSelected: state.selectedSatiety == 1, + onTap: changeSatiety(context, 1), + ), + ScaleElement( + color: Colors.yellow, + isSelected: state.selectedSatiety == 2, + onTap: changeSatiety(context, 2), + ), + ScaleElement( + color: Colors.lime, + isSelected: state.selectedSatiety == 3, + onTap: changeSatiety(context, 3), + ), + ScaleElement( + color: Colors.lightGreen, + isSelected: state.selectedSatiety == 4, + onTap: changeSatiety(context, 4), + ), + ScaleElement( + color: Colors.green, + isSelected: state.selectedSatiety == 5, + onTap: changeSatiety(context, 5), + ), + Text("😊"), + // Остальные элементы шкалы + ], + ); + } else { + return Container(); // Возвращаем пустой контейнер, если состояние не является DiaryEditLoadedState + } + }, + ), + ], + ), + ); } openCaloriesDialog(BuildContext context, DiaryEditLoadedState state) { @@ -542,8 +548,15 @@ class DiaryEditScreen extends StatelessWidget { child: Text('Отмена'), ), TextButton( - onPressed: triggerModeration(context, state.productNameController!.text, state.caloriesController!.text, state.proteinsController!.text, - state.fatsController!.text, state.carbsController!.text, dialogContext), + onPressed: triggerModeration( + context, + state.productNameController!.text, + state.caloriesController!.text, + state.proteinsController!.text, + state.fatsController!.text, + state.carbsController!.text, + dialogContext, + ), child: Text('Отправить'), ), ], @@ -552,12 +565,26 @@ class DiaryEditScreen extends StatelessWidget { ); } - triggerModeration(BuildContext context, String name, String energyOn100gr, String proteinsOn100gr, String fatsOn100gr, String carbohydratesOn100gr, - BuildContext dialogContext) { + triggerModeration( + BuildContext context, + String name, + String energyOn100gr, + String proteinsOn100gr, + String fatsOn100gr, + String carbohydratesOn100gr, + BuildContext dialogContext, + ) { return () { // Call function to send moderation with the entered values - context.read().add(SendModeration( - name: name, energyOn100gr: energyOn100gr, proteinsOn100gr: proteinsOn100gr, fatsOn100gr: fatsOn100gr, carbohydratesOn100gr: carbohydratesOn100gr)); + context.read().add( + SendModeration( + name: name, + energyOn100gr: energyOn100gr, + proteinsOn100gr: proteinsOn100gr, + fatsOn100gr: fatsOn100gr, + carbohydratesOn100gr: carbohydratesOn100gr, + ), + ); Navigator.of(dialogContext).pop(); // Dismiss the dialog }; } @@ -640,14 +667,15 @@ class DiaryEditScreen extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: EdgeInsets.only( - left: 7.h, - top: 5.v, - ), - child: Text( - portion['product_name'].length > 8 ? portion['product_name'].substring(0, 8) : portion['product_name'], - style: CustomTextStyles.titleMedium16, - )), + padding: EdgeInsets.only( + left: 7.h, + top: 5.v, + ), + child: Text( + portion['product_name'].length > 8 ? portion['product_name'].substring(0, 8) : portion['product_name'], + style: CustomTextStyles.titleMedium16, + ), + ), Padding( padding: EdgeInsets.only( left: 20.h, @@ -660,14 +688,15 @@ class DiaryEditScreen extends StatelessWidget { ), Spacer(), GestureDetector( - onTap: removePortion(context, portion), - child: Padding( - padding: const EdgeInsets.only(right: 10), - child: Icon( - Icons.close, - color: appTheme.blueGray300, - ), - )), + onTap: removePortion(context, portion), + child: Padding( + padding: const EdgeInsets.only(right: 10), + child: Icon( + Icons.close, + color: appTheme.blueGray300, + ), + ), + ), ], ), ); @@ -779,30 +808,42 @@ class DiaryEditScreen extends StatelessWidget { ), borderData: FlBorderData(show: false), barGroups: [ - BarChartGroupData(x: 0, barRods: [ - BarChartRodData( - toY: consumedValues[0] / recommendedValues[0] * 100, - color: checkConsumedValues([recommendedValues[0]], [consumedValues[1]]) ? Colors.red : Colors.blue, - ) - ]), - BarChartGroupData(x: 1, barRods: [ - BarChartRodData( - toY: consumedValues[1] / recommendedValues[1] * 100, - color: checkConsumedValues([recommendedValues[1]], [consumedValues[1]]) ? Colors.red : Colors.blue, - ) - ]), - BarChartGroupData(x: 2, barRods: [ - BarChartRodData( - toY: consumedValues[2] / recommendedValues[2] * 100, - color: checkConsumedValues([recommendedValues[2]], [consumedValues[2]]) ? Colors.red : Colors.blue, - ) - ]), - BarChartGroupData(x: 3, barRods: [ - BarChartRodData( - toY: consumedValues[3] / recommendedValues[3] * 100, - color: checkConsumedValues([recommendedValues[3]], [consumedValues[3]]) ? Colors.red : Colors.blue, - ) - ]), + BarChartGroupData( + x: 0, + barRods: [ + BarChartRodData( + toY: consumedValues[0] / recommendedValues[0] * 100, + color: checkConsumedValues([recommendedValues[0]], [consumedValues[1]]) ? Colors.red : Colors.blue, + ), + ], + ), + BarChartGroupData( + x: 1, + barRods: [ + BarChartRodData( + toY: consumedValues[1] / recommendedValues[1] * 100, + color: checkConsumedValues([recommendedValues[1]], [consumedValues[1]]) ? Colors.red : Colors.blue, + ), + ], + ), + BarChartGroupData( + x: 2, + barRods: [ + BarChartRodData( + toY: consumedValues[2] / recommendedValues[2] * 100, + color: checkConsumedValues([recommendedValues[2]], [consumedValues[2]]) ? Colors.red : Colors.blue, + ), + ], + ), + BarChartGroupData( + x: 3, + barRods: [ + BarChartRodData( + toY: consumedValues[3] / recommendedValues[3] * 100, + color: checkConsumedValues([recommendedValues[3]], [consumedValues[3]]) ? Colors.red : Colors.blue, + ), + ], + ), ], ), ), @@ -909,7 +950,7 @@ class DiaryEditScreen extends StatelessWidget { Text( "*Превышенная суточная норма", style: theme.textTheme.labelLarge, - ) + ), ], ), ); @@ -1077,24 +1118,25 @@ class DiaryEditScreen extends StatelessWidget { _buildMood(BuildContext context, DiaryEditLoadedState state) { return Container( - margin: EdgeInsets.symmetric(horizontal: 16.h), - padding: EdgeInsets.symmetric( - horizontal: 24.h, - vertical: 12.v, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(children: [ + margin: EdgeInsets.symmetric(horizontal: 16.h), + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + children: [ GestureDetector( onTap: toggleMood(context), child: Row( @@ -1147,7 +1189,9 @@ class DiaryEditScreen extends StatelessWidget { // Остальные элементы шкалы ], ), - ])); + ], + ), + ); } changeMood(BuildContext context, int satiety) { @@ -1206,3 +1250,4 @@ bool checkConsumedValues(List recommendedValues, List consumedValues) // Если ни одно потребленное значение не превышает рекомендованное с соответствующим индексом return false; // Возвращаем true } +*/ \ No newline at end of file diff --git a/lib/presentation/diary/diary_edit_screen/models/diary_edit_model.dart b/lib/presentation/diary/diary_edit_screen/models/diary_edit_model.dart index 6f68bc2..d37abbf 100644 --- a/lib/presentation/diary/diary_edit_screen/models/diary_edit_model.dart +++ b/lib/presentation/diary/diary_edit_screen/models/diary_edit_model.dart @@ -1,7 +1,7 @@ // ignore_for_file: must_be_immutable -import 'package:equatable/equatable.dart'; import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; +import 'package:equatable/equatable.dart'; /// This class defines the variables used in the [k0_page], /// and is typically used to hold data that is passed between different parts of the application. diff --git a/lib/presentation/diets/diet_create_screen/bloc/diet_create_bloc.dart b/lib/presentation/diets/diet_create_screen/bloc/diet_create_bloc.dart index e4e0cbc..65ea65b 100644 --- a/lib/presentation/diets/diet_create_screen/bloc/diet_create_bloc.dart +++ b/lib/presentation/diets/diet_create_screen/bloc/diet_create_bloc.dart @@ -1,15 +1,15 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/diets/diet_create_screen/models/diet_create_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/diets/diet_create_screen/models/diet_create_model.dart'; part 'diet_create_event.dart'; part 'diet_create_state.dart'; @@ -32,21 +32,27 @@ class DietCreateBloc extends Bloc { } if (state is DietCreateLoadedState) { var currentState = state as DietCreateLoadedState; - emit(currentState.copyWith( - dietModelObj: currentState.dietModelObj, - name: currentState.name, - details: currentState.details, - )); + emit( + currentState.copyWith( + dietModelObj: currentState.dietModelObj, + name: currentState.name, + details: currentState.details, + ), + ); } else { - emit(DietCreateLoadedState( - name: TextEditingController(), - details: TextEditingController(), - )); + emit( + DietCreateLoadedState( + name: TextEditingController(), + details: TextEditingController(), + ), + ); } } FutureOr _createDiet( - CreateDiet event, Emitter emit) async { + CreateDiet event, + Emitter emit, + ) async { if (state is DietCreateLoadedState) { var currentState = state as DietCreateLoadedState; @@ -59,7 +65,8 @@ class DietCreateBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('dietSelectScreen'); } else { print( - 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}'); + 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}', + ); } } } @@ -68,7 +75,7 @@ class DietCreateBloc extends Bloc { String? name, String? details, ) async { - String url = '${dotenv.env['SERVER_ROOT']!}/diets/create'; + String url = '${baseUrl}/api/diets/create'; final Map credentials = { 'name': name, @@ -77,7 +84,7 @@ class DietCreateBloc extends Bloc { 'state': 'active', 'type': '{"meat": true}', 'daily_schedule': - '{"1": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 494}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 12}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 432}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 195}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 710}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 119}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 287}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 445}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 500}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 764}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 735}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 127}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 89}]}, "2": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 436}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 700}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 766}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 194}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 426}], "snacks": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 58}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 152}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 925}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 224}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 918}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 81}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 308}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 579}]}, "3": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 266}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 790}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 26}], "snacks": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 549}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 446}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 92}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 403}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 894}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 457}]}, "4": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 698}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 43}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 994}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 965}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 42}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 948}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 28}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 54}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 112}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 891}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 538}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 635}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 586}]}, "5": {"lunch": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 900}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 242}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 375}], "snacks": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 604}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 510}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 887}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 554}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 731}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 574}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 274}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 276}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 80}]}, "6": {"lunch": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 359}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 358}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 639}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 861}], "dinner": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 122}], "snacks": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 980}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 837}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 444}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 577}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 706}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 839}]}, "7": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 118}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 664}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 665}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 986}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 296}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 807}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 493}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 227}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 385}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 448}], "breakfast": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 784}]}, "8": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 433}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 871}], "dinner": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 332}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 41}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 388}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 649}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 114}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 968}], "breakfast": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 180}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 269}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 998}]}, "9": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 68}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 505}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 554}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 579}], "snacks": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 751}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 144}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 677}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 263}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 304}], "breakfast": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 963}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 258}]}, "10": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 167}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 306}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 243}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 79}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 560}], "snacks": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 294}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 145}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 639}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 108}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 924}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 894}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 280}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 336}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 338}]}, "11": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 817}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 968}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 525}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 864}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 457}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 548}], "snacks": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 658}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 239}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 358}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 416}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 220}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 323}]}, "12": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 377}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 138}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 654}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 237}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 902}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 76}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 723}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 481}], "breakfast": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 571}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 515}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 188}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 411}]}, "13": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 379}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 231}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 147}], "dinner": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 871}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 679}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 359}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 561}], "snacks": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 414}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 827}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 649}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 161}], "breakfast": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 185}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 464}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 387}]}, "14": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 248}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 5}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 693}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 655}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 709}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 881}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 588}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 36}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 453}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 692}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 186}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 721}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 740}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 731}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 842}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 850}]}, "15": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 380}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 689}], "dinner": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 326}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 629}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 201}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 129}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 749}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 315}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 444}]}, "16": {"lunch": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 953}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 101}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 684}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 506}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 333}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 416}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 796}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 756}], "supper": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 858}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 619}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 800}], "breakfast": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 539}]}, "17": {"lunch": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 134}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 977}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 209}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 227}], "breakfast": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 195}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 917}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 706}]}, "18": {"lunch": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 239}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 798}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 155}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 959}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 958}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 984}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 134}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 432}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 242}]}, "19": {"lunch": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 906}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 152}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 610}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 605}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 498}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 616}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 512}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 146}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 200}], "supper": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 764}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 353}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 181}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 783}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 506}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 887}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 130}]}, "20": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 48}], "dinner": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 266}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 143}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 55}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 174}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 855}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 6}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 878}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}], "breakfast": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 442}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "milliliters", "quantity": 558}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 885}]}, "21": {"lunch": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 504}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 652}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 996}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 200}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 641}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 87}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 689}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 143}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 475}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 924}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 98}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 438}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 383}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 462}]}}' + '{"1": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 494}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 12}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 432}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 195}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 710}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 119}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 287}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 445}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 500}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 764}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 735}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 127}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 89}]}, "2": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 436}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 700}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 766}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 194}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 426}], "snacks": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 58}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 152}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 925}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 224}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 918}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 81}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 308}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 579}]}, "3": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 266}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 790}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 26}], "snacks": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 549}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 446}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 92}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 403}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 894}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 457}]}, "4": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 698}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 43}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 994}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 965}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 42}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 948}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 28}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 54}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 112}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 891}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 538}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 635}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 586}]}, "5": {"lunch": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 900}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 242}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 375}], "snacks": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 604}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 510}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 887}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 554}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 731}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 574}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 274}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 276}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 80}]}, "6": {"lunch": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 359}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 358}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 639}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 861}], "dinner": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 122}], "snacks": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 980}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 837}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 444}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 577}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 706}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 839}]}, "7": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 118}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 664}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 665}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 986}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 296}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 807}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 493}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 227}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 385}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 448}], "breakfast": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 784}]}, "8": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 433}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 871}], "dinner": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 332}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 41}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 388}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 649}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 114}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 968}], "breakfast": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 180}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 269}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 998}]}, "9": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 68}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 505}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 554}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 579}], "snacks": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 751}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 144}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 677}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 263}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 304}], "breakfast": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 963}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 258}]}, "10": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 167}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 306}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 243}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 79}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 560}], "snacks": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 294}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 145}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 639}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 108}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 924}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 894}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 280}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 336}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 338}]}, "11": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 817}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 968}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 525}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 864}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 457}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 548}], "snacks": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 658}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 239}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 358}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 416}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 220}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 323}]}, "12": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 377}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 138}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 654}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 237}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 902}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 76}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 723}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 481}], "breakfast": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 571}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 515}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 188}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 411}]}, "13": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 379}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 231}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 147}], "dinner": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 871}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 679}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 359}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 561}], "snacks": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 414}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 827}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 649}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 161}], "breakfast": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 185}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 464}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 387}]}, "14": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 248}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 5}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 693}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 655}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 709}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 881}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 588}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 36}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 453}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 692}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 186}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 721}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 740}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 731}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 842}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 850}]}, "15": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 380}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 689}], "dinner": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 326}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 629}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 201}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 129}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 749}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 315}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 444}]}, "16": {"lunch": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 953}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 101}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 684}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 506}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 333}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 416}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 796}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 756}], "supper": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 858}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 619}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 800}], "breakfast": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 539}]}, "17": {"lunch": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 134}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 977}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 209}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 227}], "breakfast": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 195}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 917}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 706}]}, "18": {"lunch": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 239}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 798}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 155}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 959}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 958}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 984}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 134}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 432}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 242}]}, "19": {"lunch": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 906}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 152}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 610}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 605}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 498}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 616}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 512}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 146}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 200}], "supper": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 764}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 353}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 181}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 783}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 506}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 887}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 130}]}, "20": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 48}], "dinner": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 266}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 143}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 55}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 174}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 855}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 6}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 878}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}], "breakfast": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 442}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "milliliters", "quantity": 558}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 885}]}, "21": {"lunch": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 504}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 652}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 996}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 200}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 641}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 87}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 689}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 143}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 475}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 924}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 98}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 438}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 383}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 462}]}}', }; var response = await http.post( diff --git a/lib/presentation/diets/diet_create_screen/bloc/diet_create_state.dart b/lib/presentation/diets/diet_create_screen/bloc/diet_create_state.dart index be825ab..e063a43 100644 --- a/lib/presentation/diets/diet_create_screen/bloc/diet_create_state.dart +++ b/lib/presentation/diets/diet_create_screen/bloc/diet_create_state.dart @@ -14,6 +14,7 @@ class DietCreateState extends Equatable { @override List get props => [dietModelObj]; + DietCreateState copyWith({DietCreateModel? dietModelObj}) { return DietCreateState( dietModelObj: dietModelObj ?? this.dietModelObj, @@ -31,12 +32,14 @@ class DietCreateLoadedState extends DietCreateState { DietCreateModel? dietModelObj; TextEditingController? name; TextEditingController? details; + @override List get props => [ dietModelObj, name, details, ]; + DietCreateLoadedState copyWith({ DietCreateModel? dietModelObj, TextEditingController? name, @@ -60,6 +63,5 @@ class DietCreateErrorState extends DietCreateState { } class DietCreateInitialState extends DietCreateState { - DietCreateInitialState({required DietCreateModel dietModelObj}) - : super(dietModelObj: dietModelObj); + DietCreateInitialState({required DietCreateModel dietModelObj}) : super(dietModelObj: dietModelObj); } diff --git a/lib/presentation/diets/diet_create_screen/diet_create_screen.dart b/lib/presentation/diets/diet_create_screen/diet_create_screen.dart index 516a931..2ade3f8 100644 --- a/lib/presentation/diets/diet_create_screen/diet_create_screen.dart +++ b/lib/presentation/diets/diet_create_screen/diet_create_screen.dart @@ -1,16 +1,18 @@ -import 'bloc/diet_create_bloc.dart'; -import 'models/diet_create_model.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; +import 'bloc/diet_create_bloc.dart'; +import 'models/diet_create_model.dart'; + class DietCreateScreen extends StatelessWidget { const DietCreateScreen({Key? key}) : super(key: key); static Widget builder(BuildContext context) { final dietID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => DietCreateBloc(DietCreateState(dietModelObj: DietCreateModel(dietID: dietID.toString())))..add(DietCreateInitialEvent()), - child: DietCreateScreen()); + create: (context) => DietCreateBloc(DietCreateState(dietModelObj: DietCreateModel(dietID: dietID.toString())))..add(DietCreateInitialEvent()), + child: DietCreateScreen(), + ); } Widget build(BuildContext context) { @@ -43,47 +45,52 @@ class DietCreateScreen extends StatelessWidget { body: Container( width: double.maxFinite, decoration: AppDecoration.fillGray, - child: ListView(children: [ - SizedBox(height: 30.v), - Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - TextFormField( - controller: state.name, - decoration: InputDecoration(labelText: 'Заголовок'), + child: ListView( + children: [ + SizedBox(height: 30.v), + Container( + margin: EdgeInsets.only( + left: 16.h, + right: 20.h, + bottom: 10.h, ), - SizedBox(height: 16.0), - TextFormField( - controller: state.details, - decoration: InputDecoration(labelText: 'Описание'), + padding: EdgeInsets.all(12.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], ), - SizedBox(height: 16.0), - // Здесь нужно добавить виджет для загрузки картинки - ElevatedButton( - onPressed: () => context.read().add(CreateDiet()), - child: Text('Создать'), - ) - ]), - ) - ]), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 16.0), + TextFormField( + controller: state.name, + decoration: InputDecoration(labelText: 'Заголовок'), + ), + SizedBox(height: 16.0), + TextFormField( + controller: state.details, + decoration: InputDecoration(labelText: 'Описание'), + ), + SizedBox(height: 16.0), + // Здесь нужно добавить виджет для загрузки картинки + ElevatedButton( + onPressed: () => context.read().add(CreateDiet()), + child: Text('Создать'), + ), + ], + ), + ), + ], + ), ), ), ); diff --git a/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_bloc.dart b/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_bloc.dart index e69101c..81e034a 100644 --- a/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_bloc.dart +++ b/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/diets/diet_edit_screen/models/diet_edit_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/diets/diet_edit_screen/models/diet_edit_model.dart'; part 'diet_edit_event.dart'; - part 'diet_edit_state.dart'; /// A bloc that manages the state of a DietEdit according to the event that is dispatched to it. @@ -34,7 +33,7 @@ class DietEditBloc extends Bloc { } final String? dietID = state.dietModelObj?.dietID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diets/show/$dietID'), + Uri.parse(baseUrl + '/api/diets/show/$dietID'), headers: { 'Authorization': 'Bearer $token', }, @@ -44,18 +43,24 @@ class DietEditBloc extends Bloc { if (data is Map) { if (state is DietEditLoadedState) { var currentState = state as DietEditLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( dietModelObj: currentState.dietModelObj, diet: currentState.diet, name: currentState.name, duration: currentState.duration, - details: currentState.details)); + details: currentState.details, + ), + ); } else { - emit(DietEditLoadedState( + emit( + DietEditLoadedState( diet: data, name: TextEditingController(text: data['name']), details: TextEditingController(text: data['details']), - duration: TextEditingController(text: data['duration']))); + duration: TextEditingController(text: data['duration']), + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку @@ -96,7 +101,7 @@ class DietEditBloc extends Bloc { String? duration, ) async { int id = diet?['id']; - String url = '${dotenv.env['SERVER_ROOT']!}/diets/update/$id'; + String url = '${baseUrl}/api/diets/update/$id'; final Map credentials = { 'id': id, diff --git a/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_state.dart b/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_state.dart index 1c10a40..ab0d2ee 100644 --- a/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_state.dart +++ b/lib/presentation/diets/diet_edit_screen/bloc/diet_edit_state.dart @@ -22,8 +22,13 @@ class DietEditState extends Equatable { } class DietEditLoadedState extends DietEditState { - DietEditLoadedState( - {this.dietModelObj, this.diet, this.name, this.details, this.duration}); + DietEditLoadedState({ + this.dietModelObj, + this.diet, + this.name, + this.details, + this.duration, + }); DietEditModel? dietModelObj; Map? diet; @@ -59,6 +64,5 @@ class DietEditErrorState extends DietEditState { } class DietEditInitialState extends DietEditState { - DietEditInitialState({required DietEditModel dietModelObj}) - : super(dietModelObj: dietModelObj); + DietEditInitialState({required DietEditModel dietModelObj}) : super(dietModelObj: dietModelObj); } diff --git a/lib/presentation/diets/diet_edit_screen/diet_edit_screen.dart b/lib/presentation/diets/diet_edit_screen/diet_edit_screen.dart index a0f988d..d76d79d 100644 --- a/lib/presentation/diets/diet_edit_screen/diet_edit_screen.dart +++ b/lib/presentation/diets/diet_edit_screen/diet_edit_screen.dart @@ -1,9 +1,9 @@ -import 'bloc/diet_edit_bloc.dart'; -import 'models/diet_edit_model.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import 'bloc/diet_edit_bloc.dart'; +import 'models/diet_edit_model.dart'; class DietEditScreen extends StatelessWidget { const DietEditScreen({Key? key}) : super(key: key); @@ -11,8 +11,9 @@ class DietEditScreen extends StatelessWidget { static Widget builder(BuildContext context) { final dietID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => DietEditBloc(DietEditState(dietModelObj: DietEditModel(dietID: dietID.toString())))..add(DietEditInitialEvent()), - child: DietEditScreen()); + create: (context) => DietEditBloc(DietEditState(dietModelObj: DietEditModel(dietID: dietID.toString())))..add(DietEditInitialEvent()), + child: DietEditScreen(), + ); } Widget build(BuildContext context) { @@ -71,7 +72,7 @@ class DietEditScreen extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.diet?['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.diet?['image'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -98,10 +99,10 @@ class DietEditScreen extends StatelessWidget { ElevatedButton( onPressed: () => context.read().add(EditDiet()), child: Text('Сохранить'), - ) + ), ], ), - ) + ), ], ), ), diff --git a/lib/presentation/diets/diet_select_screen/bloc/diet_select_bloc.dart b/lib/presentation/diets/diet_select_screen/bloc/diet_select_bloc.dart index dbc622f..56dabcf 100644 --- a/lib/presentation/diets/diet_select_screen/bloc/diet_select_bloc.dart +++ b/lib/presentation/diets/diet_select_screen/bloc/diet_select_bloc.dart @@ -1,17 +1,17 @@ //import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/diets/diet_select_screen/models/diet_select_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/diets/diet_select_screen/models/diet_select_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; + +import '/core/app_export.dart'; part 'diet_select_event.dart'; part 'diet_select_state.dart'; @@ -33,7 +33,7 @@ class DietSelectBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diets/index'), + Uri.parse(baseUrl + '/api/diets/index'), headers: { 'Authorization': 'Bearer $token', }, @@ -47,15 +47,19 @@ class DietSelectBloc extends Bloc { if (state is DietSelectLoadedState) { print('Got loaded'); var currentState = state as DietSelectLoadedState; - emit((currentState).copyWith( - posts: data, - myProfileModelObj: currentState.myProfileModelObj, - )); + emit( + (currentState).copyWith( + posts: data, + myProfileModelObj: currentState.myProfileModelObj, + ), + ); } else { print('Got unloaded'); - emit(DietSelectLoadedState( - posts: data, - )); + emit( + DietSelectLoadedState( + posts: data, + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку diff --git a/lib/presentation/diets/diet_select_screen/bloc/diet_select_event.dart b/lib/presentation/diets/diet_select_screen/bloc/diet_select_event.dart index 9137295..75a889b 100644 --- a/lib/presentation/diets/diet_select_screen/bloc/diet_select_event.dart +++ b/lib/presentation/diets/diet_select_screen/bloc/diet_select_event.dart @@ -17,7 +17,9 @@ class DietSelectInitialEvent extends DietSelectEvent { class UploadAvatar extends DietSelectEvent { UploadAvatar(this.image); + final XFile image; + @override List get props => [image]; } diff --git a/lib/presentation/diets/diet_select_screen/bloc/diet_select_state.dart b/lib/presentation/diets/diet_select_screen/bloc/diet_select_state.dart index e7b709d..6401481 100644 --- a/lib/presentation/diets/diet_select_screen/bloc/diet_select_state.dart +++ b/lib/presentation/diets/diet_select_screen/bloc/diet_select_state.dart @@ -12,22 +12,22 @@ class DietSelectState extends Equatable { } class DietSelectInitialState extends DietSelectState { - DietSelectInitialState({required DietSelectModel myProfileModelObj}) - : super(myProfileModelObj: myProfileModelObj); + DietSelectInitialState({required DietSelectModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj); } /// Represents the state of DietSelect in the application. class DietSelectLoadedState extends DietSelectState { - DietSelectLoadedState({this.myProfileModelObj, this.posts}) - : super(myProfileModelObj: null); + DietSelectLoadedState({this.myProfileModelObj, this.posts}) : super(myProfileModelObj: null); DietSelectModel? myProfileModelObj; List? posts; + @override List get props => [ myProfileModelObj, posts, ]; + DietSelectLoadedState copyWith({ DietSelectModel? myProfileModelObj, List? posts, diff --git a/lib/presentation/diets/diet_select_screen/diet_select_screen.dart b/lib/presentation/diets/diet_select_screen/diet_select_screen.dart index 68834d0..3f4a8ce 100644 --- a/lib/presentation/diets/diet_select_screen/diet_select_screen.dart +++ b/lib/presentation/diets/diet_select_screen/diet_select_screen.dart @@ -1,19 +1,20 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/diet_select_bloc.dart'; import 'models/diet_select_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; class DietSelectScreen extends StatelessWidget { static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => DietSelectBloc(DietSelectState(myProfileModelObj: DietSelectModel()))..add(DietSelectInitialEvent()), child: DietSelectScreen()); + create: (context) => DietSelectBloc(DietSelectState(myProfileModelObj: DietSelectModel()))..add(DietSelectInitialEvent()), + child: DietSelectScreen(), + ); } Widget build(BuildContext context) { @@ -95,14 +96,14 @@ class DietSelectScreen extends StatelessWidget { onTap: () => GoRouter.of(context).goNamed('dietCreateScreen'), child: Icon(Icons.create_outlined), ), - ) + ), ], ), ), ), ), SizedBox(height: 20), - _buildDietList(context, state) + _buildDietList(context, state), ], ), ), @@ -118,50 +119,51 @@ class DietSelectScreen extends StatelessWidget { itemBuilder: (context, index) { final post = state.posts?[index]; return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], + margin: EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: ListTile( + leading: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + post['image'], + imageBuilder: (context, imageProvider) => CircleAvatar( + backgroundImage: imageProvider, + radius: 25, + ), + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => CircleAvatar( + child: Icon(Icons.person), + backgroundColor: Colors.white, + radius: 25, + ), ), - child: ListTile( - leading: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + post['image'], - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, - ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, - ), - ), - title: Text( - post?['name'] ?? '', - style: CustomTextStyles.titleMediumSemiBold, - ), - subtitle: Text(post?['details'] ?? ''), + title: Text( + post?['name'] ?? '', + style: CustomTextStyles.titleMediumSemiBold, + ), + subtitle: Text(post?['details'] ?? ''), + onTap: () => GoRouter.of(context).goNamed( + 'dietScreen', + extra: post?['id'].toString(), + ), + trailing: GestureDetector( onTap: () => GoRouter.of(context).goNamed( - 'dietScreen', + 'dietEditScreen', extra: post?['id'].toString(), ), - trailing: GestureDetector( - onTap: () => GoRouter.of(context).goNamed( - 'dietEditScreen', - extra: post?['id'].toString(), - ), - child: Icon(Icons.edit), - ), - )); + child: Icon(Icons.edit), + ), + ), + ); }, ); } diff --git a/lib/presentation/diets/diet_show_screen/bloc/diet_show_bloc.dart b/lib/presentation/diets/diet_show_screen/bloc/diet_show_bloc.dart index 5fcd3a1..3d0551a 100644 --- a/lib/presentation/diets/diet_show_screen/bloc/diet_show_bloc.dart +++ b/lib/presentation/diets/diet_show_screen/bloc/diet_show_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/diets/diet_show_screen/models/diet_show_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/diets/diet_show_screen/models/diet_show_model.dart'; -import 'package:go_router/go_router.dart'; part 'diet_show_event.dart'; - part 'diet_show_state.dart'; /// A bloc that manages the state of a Diet according to the event that is dispatched to it. @@ -34,7 +33,7 @@ class DietBloc extends Bloc { } final String? dietID = state.dietModelObj?.dietID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diets/show/$dietID'), + Uri.parse(baseUrl + '/api/diets/show/$dietID'), headers: { 'Authorization': 'Bearer $token', }, @@ -70,7 +69,7 @@ class DietBloc extends Bloc { } final int id = event.id; final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/diets/delete/$id'), + Uri.parse(baseUrl + '/api/diets/delete/$id'), headers: { 'Authorization': 'Bearer $token', }, diff --git a/lib/presentation/diets/diet_show_screen/bloc/diet_show_event.dart b/lib/presentation/diets/diet_show_screen/bloc/diet_show_event.dart index 6a131d5..c79eaf3 100644 --- a/lib/presentation/diets/diet_show_screen/bloc/diet_show_event.dart +++ b/lib/presentation/diets/diet_show_screen/bloc/diet_show_event.dart @@ -17,7 +17,9 @@ class DietInitialEvent extends DietEvent { class DeleteEntry extends DietEvent { DeleteEntry(this.id); + final int id; + @override List get props => [id]; } diff --git a/lib/presentation/diets/diet_show_screen/bloc/diet_show_state.dart b/lib/presentation/diets/diet_show_screen/bloc/diet_show_state.dart index 49913f7..32070c1 100644 --- a/lib/presentation/diets/diet_show_screen/bloc/diet_show_state.dart +++ b/lib/presentation/diets/diet_show_screen/bloc/diet_show_state.dart @@ -14,6 +14,7 @@ class DietState extends Equatable { @override List get props => [dietModelObj]; + DietState copyWith({DietModel? dietModelObj}) { return DietState( dietModelObj: dietModelObj ?? this.dietModelObj, @@ -26,10 +27,11 @@ class DietLoadedState extends DietState { DietModel? dietModelObj; Map? diet; + @override List get props => [dietModelObj, diet]; - DietLoadedState copyWith( - {DietModel? dietModelObj, Map? diet}) { + + DietLoadedState copyWith({DietModel? dietModelObj, Map? diet}) { return DietLoadedState( dietModelObj: dietModelObj ?? this.dietModelObj, diet: diet ?? this.diet, @@ -47,6 +49,5 @@ class DietErrorState extends DietState { } class DietInitialState extends DietState { - DietInitialState({required DietModel dietModelObj}) - : super(dietModelObj: dietModelObj); + DietInitialState({required DietModel dietModelObj}) : super(dietModelObj: dietModelObj); } diff --git a/lib/presentation/diets/diet_show_screen/diet_show_screen.dart b/lib/presentation/diets/diet_show_screen/diet_show_screen.dart index 0c06f5d..9fae1ef 100644 --- a/lib/presentation/diets/diet_show_screen/diet_show_screen.dart +++ b/lib/presentation/diets/diet_show_screen/diet_show_screen.dart @@ -1,11 +1,10 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/diet_show_bloc.dart'; import 'models/diet_show_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; class DietScreen extends StatelessWidget { const DietScreen({Key? key}) : super(key: key); @@ -13,7 +12,9 @@ class DietScreen extends StatelessWidget { static Widget builder(BuildContext context) { final dietID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => DietBloc(DietState(dietModelObj: DietModel(dietID: dietID.toString())))..add(DietInitialEvent()), child: DietScreen()); + create: (context) => DietBloc(DietState(dietModelObj: DietModel(dietID: dietID.toString())))..add(DietInitialEvent()), + child: DietScreen(), + ); } Widget build(BuildContext context) { @@ -68,45 +69,48 @@ class DietScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.diet?['image'] ?? ''), - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (state.diet?['image'] ?? ''), + imageBuilder: (context, imageProvider) => CircleAvatar( + backgroundImage: imageProvider, + radius: 25, + ), + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => CircleAvatar( + child: Icon(Icons.person), + backgroundColor: Colors.white, + radius: 25, + ), ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, + SizedBox(height: 16.0), + Text(state.diet?['name'], style: CustomTextStyles.titleMediumBlack), + SizedBox(height: 8.0), + Text( + state.diet?['details'], ), - ), - SizedBox(height: 16.0), - Text(state.diet?['name'], style: CustomTextStyles.titleMediumBlack), - SizedBox(height: 8.0), - Text( - state.diet?['details'], - ), - SizedBox(height: 16.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - ElevatedButton( - onPressed: () => GoRouter.of(context).goNamed( - 'dietEditScreen', - extra: state.diet?['id'].toString(), + SizedBox(height: 16.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + onPressed: () => GoRouter.of(context).goNamed( + 'dietEditScreen', + extra: state.diet?['id'].toString(), + ), + child: Text('Редактировать'), ), - child: Text('Редактировать'), - ), - ElevatedButton( - onPressed: () => context.read().add(DeleteEntry(state.diet?['id'])), - child: Text('Удалить'), - ), - ], - ) - ]), - ) + ElevatedButton( + onPressed: () => context.read().add(DeleteEntry(state.diet?['id'])), + child: Text('Удалить'), + ), + ], + ), + ], + ), + ), ], ), ), diff --git a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart index 77f0f1a..798b771 100644 --- a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart +++ b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart @@ -1,24 +1,26 @@ import 'dart:async'; +import 'package:dio/dio.dart'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:eatvio_app/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:image_picker/image_picker.dart'; + +import '/core/app_export.dart'; + part 'blog_post_create_event.dart'; part 'blog_post_create_state.dart'; /// A bloc that manages the state of a BlogPostCreate according to the event that is dispatched to it. -class BlogPostCreateBloc - extends Bloc { +class BlogPostCreateBloc extends Bloc { BlogPostCreateBloc(BlogPostCreateState initialState) : super(initialState) { on(_onInitialize); on(_createBlogPost); + on(_uploadImages); } _onInitialize( @@ -32,66 +34,72 @@ class BlogPostCreateBloc } if (state is BlogPostCreateLoadedState) { var currentState = state as BlogPostCreateLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( blog_postModelObj: currentState.blog_postModelObj, title: currentState.title, description: currentState.description, - youtube_url: currentState.youtube_url, - token: currentState.token)); + youtubeURL: currentState.youtubeURL, + token: currentState.token, + ), + ); } else { - emit(BlogPostCreateLoadedState( + emit( + BlogPostCreateLoadedState( token: token, title: TextEditingController(), description: TextEditingController(), - youtube_url: TextEditingController())); + youtubeURL: TextEditingController(), + ), + ); } } FutureOr _createBlogPost( - CreateBlogPost event, Emitter emit) async { + CreateBlogPost event, + Emitter emit, + ) async { if (state is BlogPostCreateLoadedState) { var currentState = state as BlogPostCreateLoadedState; var response = await sendBlogPost( currentState.title?.text, - currentState.youtube_url?.text, + currentState.youtubeURL?.text, currentState.description?.text, + currentState.image, ); - if (response.statusCode == 200) { + if (response.statusCode == 200 || response.statusCode == 201) { AppRouter.navigatorKey.currentContext?.goNamed('feedScreen'); } else { - print( - 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}'); + print('Failed to create blog post. Status Code: ${response.statusCode} ${response.data}'); } } } - FutureOr sendBlogPost( - String? title, - String? youtube_url, - String? description, - ) async { - String url = '${dotenv.env['SERVER_ROOT']!}/feed/create'; - final box = await Hive.openBox('token'); - final token = box.get('token'); - final Map credentials = { + Future sendBlogPost(String? title, String? youtubeURL, String? description, XFile? image) async { + String url = baseUrl + '/api/blogPosts/create'; + + FormData formData = FormData.fromMap({ 'title': title, 'description': description, - 'youtube_url': youtube_url, - 'status': 'active', - }; + 'youtube_url': youtubeURL, + 'state': 'active', + 'image': await MultipartFile.fromFile(image!.path, filename: image.name), + }); - var response = await http.post( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8, + final response = await sl().post( + url, + data: formData, ); return response; } + + FutureOr _uploadImages(UploadImages event, Emitter emit) { + if (state is BlogPostCreateLoadedState) { + var currentState = state as BlogPostCreateLoadedState; + emit(currentState.copyWith(image: event.image)); + } + } } diff --git a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_event.dart b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_event.dart index 7631fac..6ce10ca 100644 --- a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_event.dart +++ b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_event.dart @@ -19,3 +19,12 @@ class CreateBlogPost extends BlogPostCreateEvent { @override List get props => []; } + +class UploadImages extends BlogPostCreateEvent { + UploadImages(this.image); + + final XFile image; + + @override + List get props => [image]; +} diff --git a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_state.dart b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_state.dart index de3bab4..8e0c8e8 100644 --- a/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_state.dart +++ b/lib/presentation/feed/blog_post_create_screen/bloc/blog_post_create_state.dart @@ -14,6 +14,7 @@ class BlogPostCreateState extends Equatable { @override List get props => [blog_postModelObj]; + BlogPostCreateState copyWith({BlogPostCreateModel? blog_postModelObj}) { return BlogPostCreateState( blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, @@ -22,33 +23,52 @@ class BlogPostCreateState extends Equatable { } class BlogPostCreateLoadedState extends BlogPostCreateState { - BlogPostCreateLoadedState( - {this.token, - this.blog_postModelObj, - this.title, - this.description, - this.youtube_url}); + BlogPostCreateLoadedState({ + this.token, + this.blog_postModelObj, + this.title, + this.description, + this.youtubeURL, + this.image, + this.isLoading = false, + }); BlogPostCreateModel? blog_postModelObj; TextEditingController? title; TextEditingController? description; - TextEditingController? youtube_url; + TextEditingController? youtubeURL; String? token; + bool isLoading; + XFile? image; + @override - List get props => - [blog_postModelObj, title, description, youtube_url]; - BlogPostCreateLoadedState copyWith( - {BlogPostCreateModel? blog_postModelObj, - TextEditingController? title, - TextEditingController? description, - TextEditingController? youtube_url, - String? token}) { + List get props => [ + blog_postModelObj, + title, + description, + youtubeURL, + token, + image, + isLoading, + ]; + + BlogPostCreateLoadedState copyWith({ + BlogPostCreateModel? blog_postModelObj, + TextEditingController? title, + TextEditingController? description, + TextEditingController? youtubeURL, + String? token, + XFile? image, + bool isLoading = false, + }) { return BlogPostCreateLoadedState( blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, title: title ?? this.title, description: description ?? this.description, - youtube_url: youtube_url ?? this.youtube_url, + youtubeURL: youtubeURL ?? this.youtubeURL, token: token ?? this.token, + image: image ?? this.image, + isLoading: this.isLoading, ); } } @@ -63,6 +83,5 @@ class BlogPostCreateErrorState extends BlogPostCreateState { } class BlogPostCreateInitialState extends BlogPostCreateState { - BlogPostCreateInitialState({required BlogPostCreateModel blog_postModelObj}) - : super(blog_postModelObj: blog_postModelObj); + BlogPostCreateInitialState({required BlogPostCreateModel blog_postModelObj}) : super(blog_postModelObj: blog_postModelObj); } diff --git a/lib/presentation/feed/blog_post_create_screen/blog_post_create_screen.dart b/lib/presentation/feed/blog_post_create_screen/blog_post_create_screen.dart deleted file mode 100644 index be78f7e..0000000 --- a/lib/presentation/feed/blog_post_create_screen/blog_post_create_screen.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'bloc/blog_post_create_bloc.dart'; -import 'models/blog_post_create_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; - -class BlogPostCreateScreen extends StatelessWidget { - const BlogPostCreateScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context) { - final blog_postID = ModalRoute.of(context)!.settings.arguments; - return BlocProvider( - create: (context) => BlogPostCreateBloc(BlogPostCreateState(blog_postModelObj: BlogPostCreateModel(blog_postID: blog_postID.toString()))) - ..add(BlogPostCreateInitialEvent()), - child: BlogPostCreateScreen()); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is BlogPostCreateInitialState) { - // Это начальное состояние, данные ещё не загружены. - return Container( - color: Colors.white, - ); - } else if (state is BlogPostCreateLoadedState) { - // Данные загружены, можно строить экран. - return _buildBlogPostCreate(context, state); - } else if (state is BlogPostCreateErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }, - ); - } - - _buildBlogPostCreate(BuildContext context, BlogPostCreateLoadedState state) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView( - children: [ - SizedBox(height: 30.v), - Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Column( - children: [ - Text("Заголовок новости", style: theme.textTheme.bodyLarge), - CustomTextFormField( - controller: state.title, - validator: _validateTitle, - ), - SizedBox(height: 8.0), - Text("Ссылка на YouTube", style: theme.textTheme.bodyLarge), - CustomTextFormField( - controller: state.youtube_url, - validator: _validateYouTubeLink, - ), - SizedBox(height: 8.0), - Text("Описание", style: theme.textTheme.bodyLarge), - CustomTextFormField( - controller: state.description, - validator: _validateDescription, - maxLines: 6, - ), - SizedBox(height: 16.0), - // Add widget for image upload here - CustomOutlinedButton( - onPressed: () => _submitForm(context, state.title!.text, state.description!.text, state.youtube_url!.text), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - text: 'Создать', - ), - ], - ), - ], - ), - ) - ], - ), - ), - ); - } -} - -_submitForm(BuildContext context, String title, String description, String youtubeURL) { - String? titleError = _validateTitle(title); - String? descriptionError = _validateDescription(description); - String? youtubeURLError = _validateYouTubeLink(youtubeURL); - - if (titleError != null || descriptionError != null || youtubeURLError != null) { - // Display error messages or handle invalid input as needed - // For example, show a snackbar with the error message - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(titleError ?? descriptionError ?? youtubeURLError!)), - ); - } else { - // Proceed with form submission - context.read().add(CreateBlogPost()); - } -} - -String? _validateTitle(value) { - if (value!.isEmpty) { - return 'Пожалуйста, введите заголовок'; - } - return null; -} - -String? _validateDescription(value) { - if (value!.isEmpty) { - return 'Пожалуйста, введите описание'; - } - return null; -} - -String? _validateYouTubeLink(value) { - if (value!.isEmpty) { - return 'Пожалуйста, введите ссылку'; - } else if (!_isValidUrl(value)) { - return 'Пожалуйста, введите корректную ссылку'; - } - return null; -} - -bool _isValidUrl(String url) { - final RegExp urlRegExp = new RegExp(r"^(http|https):\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$"); - return urlRegExp.hasMatch(url); -} diff --git a/lib/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart b/lib/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart index 46b21c4..b571cef 100644 --- a/lib/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart +++ b/lib/presentation/feed/blog_post_create_screen/models/blog_post_create_model.dart @@ -8,8 +8,7 @@ import 'package:equatable/equatable.dart'; class BlogPostCreateModel extends Equatable { final String blog_postID; - BlogPostCreateModel({required String blog_postID}) - : blog_postID = blog_postID; + BlogPostCreateModel({required String blog_postID}) : blog_postID = blog_postID; BlogPostCreateModel copyWith(String blog_postID) { return BlogPostCreateModel(blog_postID: blog_postID); diff --git a/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_bloc.dart b/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_bloc.dart index b3a3027..c9c6bf9 100644 --- a/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_bloc.dart +++ b/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/feed/blog_post_edit_screen/models/blog_post_edit_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_edit_screen/models/blog_post_edit_model.dart'; -import 'package:go_router/go_router.dart'; part 'blog_post_edit_event.dart'; - part 'blog_post_edit_state.dart'; /// A bloc that manages the state of a BlogPostEdit according to the event that is dispatched to it. @@ -34,7 +33,7 @@ class BlogPostEditBloc extends Bloc { } final String? blog_postID = state.blog_postModelObj?.blog_postID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/show/$blog_postID'), + Uri.parse(baseUrl + '/api/blogPosts/show/$blog_postID'), headers: { 'Authorization': 'Bearer $token', }, @@ -44,18 +43,24 @@ class BlogPostEditBloc extends Bloc { if (data is Map) { if (state is BlogPostEditLoadedState) { var currentState = state as BlogPostEditLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( blog_postModelObj: currentState.blog_postModelObj, blog_post: currentState.blog_post, title: currentState.title, description: currentState.description, - youtube_url: currentState.youtube_url)); + youtubeURL: currentState.youtubeURL, + ), + ); } else { - emit(BlogPostEditLoadedState( + emit( + BlogPostEditLoadedState( blog_post: data, title: TextEditingController(text: data['title']), description: TextEditingController(text: data['description']), - youtube_url: TextEditingController(text: data['youtube_url']))); + youtubeURL: TextEditingController(text: data['youtubeURL']), + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку @@ -78,7 +83,7 @@ class BlogPostEditBloc extends Bloc { var response = await sendBlogPost( currentState.blog_post, currentState.title?.text, - currentState.youtube_url?.text, + currentState.youtubeURL?.text, currentState.description?.text, ); @@ -93,17 +98,17 @@ class BlogPostEditBloc extends Bloc { FutureOr sendBlogPost( Map? blog_post, String? title, - String? youtube_url, + String? youtubeURL, String? description, ) async { int id = blog_post?['id']; - String url = '${dotenv.env['SERVER_ROOT']!}/feed/update/$id'; + String url = '${baseUrl}/api/feed/update/$id'; final Map credentials = { 'id': id, 'title': title, 'description': description, - 'youtube_url': youtube_url, + 'youtubeURL': youtubeURL, }; var response = await http.post( diff --git a/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_state.dart b/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_state.dart index 321448e..3fa6f7b 100644 --- a/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_state.dart +++ b/lib/presentation/feed/blog_post_edit_screen/bloc/blog_post_edit_state.dart @@ -14,6 +14,7 @@ class BlogPostEditState extends Equatable { @override List get props => [blog_postModelObj]; + BlogPostEditState copyWith({BlogPostEditModel? blog_postModelObj}) { return BlogPostEditState( blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, @@ -22,34 +23,36 @@ class BlogPostEditState extends Equatable { } class BlogPostEditLoadedState extends BlogPostEditState { - BlogPostEditLoadedState( - {this.blog_postModelObj, - this.blog_post, - this.title, - this.description, - this.youtube_url}); + BlogPostEditLoadedState({ + this.blog_postModelObj, + this.blog_post, + this.title, + this.description, + this.youtubeURL, + }); BlogPostEditModel? blog_postModelObj; Map? blog_post; TextEditingController? title; TextEditingController? description; - TextEditingController? youtube_url; + TextEditingController? youtubeURL; + @override - List get props => - [blog_postModelObj, blog_post, title, description, youtube_url]; + List get props => [blog_postModelObj, blog_post, title, description, youtubeURL]; + BlogPostEditLoadedState copyWith({ BlogPostEditModel? blog_postModelObj, Map? blog_post, TextEditingController? title, TextEditingController? description, - TextEditingController? youtube_url, + TextEditingController? youtubeURL, }) { return BlogPostEditLoadedState( blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, blog_post: blog_post ?? this.blog_post, title: title ?? this.title, description: description ?? this.description, - youtube_url: youtube_url ?? this.youtube_url, + youtubeURL: youtubeURL ?? this.youtubeURL, ); } } @@ -64,6 +67,5 @@ class BlogPostEditErrorState extends BlogPostEditState { } class BlogPostEditInitialState extends BlogPostEditState { - BlogPostEditInitialState({required BlogPostEditModel blog_postModelObj}) - : super(blog_postModelObj: blog_postModelObj); + BlogPostEditInitialState({required BlogPostEditModel blog_postModelObj}) : super(blog_postModelObj: blog_postModelObj); } diff --git a/lib/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart b/lib/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart index 5c38ffb..ba69137 100644 --- a/lib/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart +++ b/lib/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart @@ -1,18 +1,19 @@ -import 'bloc/blog_post_edit_bloc.dart'; -import 'models/blog_post_edit_model.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import 'bloc/blog_post_edit_bloc.dart'; +import 'models/blog_post_edit_model.dart'; class BlogPostEditScreen extends StatelessWidget { const BlogPostEditScreen({Key? key}) : super(key: key); static Widget builder(BuildContext context, blog_postID) { return BlocProvider( - create: (context) => - BlogPostEditBloc(BlogPostEditState(blog_postModelObj: BlogPostEditModel(blog_postID: blog_postID.toString())))..add(BlogPostEditInitialEvent()), - child: BlogPostEditScreen()); + create: (context) => + BlogPostEditBloc(BlogPostEditState(blog_postModelObj: BlogPostEditModel(blog_postID: blog_postID.toString())))..add(BlogPostEditInitialEvent()), + child: BlogPostEditScreen(), + ); } Widget build(BuildContext context) { @@ -74,7 +75,7 @@ class BlogPostEditScreen extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.blog_post?['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.blog_post?['image'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -98,7 +99,7 @@ class BlogPostEditScreen extends StatelessWidget { ), SizedBox(height: 16.0), TextFormField( - controller: state.youtube_url, + controller: state.youtubeURL, decoration: InputDecoration(labelText: 'Ссылка'), ), SizedBox(height: 16.0), @@ -106,10 +107,10 @@ class BlogPostEditScreen extends StatelessWidget { ElevatedButton( onPressed: () => context.read().add(EditBlogPost()), child: Text('Сохранить'), - ) + ), ], ), - ) + ), ], ), ), diff --git a/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart b/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart deleted file mode 100644 index 9f5f11f..0000000 --- a/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart +++ /dev/null @@ -1,184 +0,0 @@ -import 'dart:async'; - -import 'package:eatvio_app/app_router.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; -import 'dart:convert'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_screen/models/blog_post_model.dart'; -import 'package:go_router/go_router.dart'; -part 'blog_post_event.dart'; -part 'blog_post_state.dart'; - -/// A bloc that manages the state of a BlogPost according to the event that is dispatched to it. -class BlogPostBloc extends Bloc { - BlogPostBloc(BlogPostState initialState) : super(initialState) { - on(_onInitialize); - on(_deleteEntry); - on(_createComment); - } - - _onInitialize( - BlogPostInitialEvent event, - Emitter emit, - ) async { - try { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - final String? blog_postID = state.blog_postModelObj?.blog_postID; - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/show/$blog_postID'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - if (data is Map) { - if (state is BlogPostLoadedState) { - var currentState = state as BlogPostLoadedState; - emit(currentState.copyWith( - blog_postModelObj: currentState.blog_postModelObj, - blog_post: currentState.blog_post, - author: currentState.author, - comments: currentState.comments, - token: currentState.token)); - } else { - emit(BlogPostLoadedState( - blog_post: data, - token: token, - commentController: TextEditingController(), - author: await _fetchAuthor(data['id']), - comments: fillCommentList(await _fetchComments(data['id'])))); - } - } else { - // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку - emit(BlogPostErrorState('Некоторые необходимые данные отсутствуют.')); - } - } else { - // Статус ответа не равен 200, обрабатываем ошибку - emit(BlogPostErrorState('Ошибка сервера: ${response.statusCode}')); - } - } catch (e) { - // Ошибка при декодировании JSON или другая ошибка выполнения - emit(BlogPostErrorState('Ошибка при получении данных о чатах: $e')); - } - } - - FutureOr _createComment( - CreateComment event, Emitter emit) async { - if (state is BlogPostLoadedState) { - var currentState = state as BlogPostLoadedState; - // Отправляем данные по HTTP маршруту и ждем ответ - var response = await _sendCommentData( - currentState.token, event.body, currentState.blog_post?['id']); - if (response.statusCode == 200) { - var updatedComments = fillCommentList( - await _fetchComments(currentState.blog_post?['id'])); - var updatedState = currentState.copyWith( - comments: updatedComments, - commentController: - TextEditingController(), // Clear the comment input field - ); - emit(updatedState); // Emit the updated state to trigger a screen update - } - } - } - - FutureOr _deleteEntry( - DeleteEntry event, Emitter emit) async { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - final int id = event.id; - final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/delete/$id'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - if (response.statusCode == 200) { - AppRouter.navigatorKey.currentContext?.goNamed('feedScreen'); - } else { - // Статус ответа не равен 200, обрабатываем ошибку - emit(BlogPostErrorState('Ошибка: ${response.statusCode}')); - } - } - - _fetchAuthor(int id) async { - final box = await Hive.openBox('token'); - final token = box.get('token'); - - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/getAuthor/$id'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - final data = jsonDecode(response.body); - return data; - } - - Future _fetchComments(int id) async { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/getComments/$id'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - final data = jsonDecode(response.body); - return data; - } - - List fillCommentList(List comments) { - List list = []; - for (int i = 0; i < comments.length; i++) { - list.add(CommentModel( - id: comments[i]['id'].toString(), - userImage: comments[i]['profile_photo_path'], - username: comments[i]['name'], - dateText: DateFormat('dd.MM') - .format(DateTime.parse(comments[i]['updated_at'])), - greetingText: comments[i]['body'])); - } - return list; - } - - Future _sendCommentData( - String? token, String body, int id) async { - String url = dotenv.env['SERVER_ROOT']! + '/feed/createComment/$id'; - final Map credentials = { - 'id': id, - 'body': body, - }; - - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); - - return response; - } -} diff --git a/lib/presentation/feed/blog_post_screen/bloc/blog_post_event.dart b/lib/presentation/feed/blog_post_screen/bloc/blog_post_event.dart deleted file mode 100644 index e143511..0000000 --- a/lib/presentation/feed/blog_post_screen/bloc/blog_post_event.dart +++ /dev/null @@ -1,44 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'blog_post_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///BlogPost widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class BlogPostEvent extends Equatable {} - -/// Event that is dispatched when the BlogPost widget is first created. -class BlogPostInitialEvent extends BlogPostEvent { - @override - List get props => []; -} - -class DeleteEntry extends BlogPostEvent { - DeleteEntry(this.id); - final int id; - @override - List get props => [id]; -} - -class FetchAuthor extends BlogPostEvent { - FetchAuthor(this.id); - final int id; - @override - List get props => [id]; -} - -class FetchComments extends BlogPostEvent { - FetchComments(this.id); - final int id; - @override - List get props => [id]; -} - -class CreateComment extends BlogPostEvent { - CreateComment(this.body); - final String body; - @override - List get props => [body]; -} diff --git a/lib/presentation/feed/blog_post_screen/bloc/blog_post_state.dart b/lib/presentation/feed/blog_post_screen/bloc/blog_post_state.dart deleted file mode 100644 index 7622602..0000000 --- a/lib/presentation/feed/blog_post_screen/bloc/blog_post_state.dart +++ /dev/null @@ -1,70 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'blog_post_bloc.dart'; - -/// Represents the state of BlogPost in the application. -/// - -class BlogPostState extends Equatable { - BlogPostState({ - this.blog_postModelObj, - }); - - BlogPostModel? blog_postModelObj; - - @override - List get props => [blog_postModelObj]; - BlogPostState copyWith({BlogPostModel? blog_postModelObj}) { - return BlogPostState( - blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, - ); - } -} - -class BlogPostLoadedState extends BlogPostState { - BlogPostLoadedState( - {this.blog_postModelObj, - this.blog_post, - this.author, - this.comments, - this.token, - this.commentController}); - - BlogPostModel? blog_postModelObj; - Map? blog_post; - Map? author; - List? comments; - TextEditingController? commentController; - String? token; - @override - List get props => [blog_postModelObj, blog_post, author, comments]; - BlogPostLoadedState copyWith( - {BlogPostModel? blog_postModelObj, - Map? blog_post, - Map? author, - TextEditingController? commentController, - String? token, - List? comments}) { - return BlogPostLoadedState( - blog_postModelObj: blog_postModelObj ?? this.blog_postModelObj, - blog_post: blog_post ?? this.blog_post, - author: author ?? this.author, - comments: comments ?? this.comments, - token: token ?? this.token, - commentController: commentController ?? this.commentController); - } -} - -class BlogPostErrorState extends BlogPostState { - final String errorMessage; - - BlogPostErrorState(this.errorMessage); - - @override - List get props => [errorMessage]; -} - -class BlogPostInitialState extends BlogPostState { - BlogPostInitialState({required BlogPostModel blog_postModelObj}) - : super(blog_postModelObj: blog_postModelObj); -} diff --git a/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart b/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart index 67cbe66..106b3b5 100644 --- a/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart +++ b/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart @@ -1,11 +1,13 @@ // ignore_for_file: must_be_immutable -import 'package:equatable/equatable.dart'; import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; +import 'package:equatable/equatable.dart'; class BlogPostModel extends Equatable { final String blog_postID; + BlogPostModel({required this.blog_postID, this.comments = const []}); + List comments; BlogPostModel copyWith({String? blog_postID, List? comments}) { diff --git a/lib/presentation/feed/blog_post_screen/models/comment_model.dart b/lib/presentation/feed/blog_post_screen/models/comment_model.dart index 3c8c593..2b9c713 100644 --- a/lib/presentation/feed/blog_post_screen/models/comment_model.dart +++ b/lib/presentation/feed/blog_post_screen/models/comment_model.dart @@ -4,12 +4,13 @@ import 'package:eatvio_app/core/app_export.dart'; // ignore_for_file: must_be_immutable class CommentModel { - CommentModel( - {this.userImage, - this.username, - this.dateText, - this.greetingText, - required this.id}) { + CommentModel({ + this.userImage, + this.username, + this.dateText, + this.greetingText, + required this.id, + }) { userImage = userImage ?? ImageConstant.imageNotFound; username = username; dateText = dateText; diff --git a/lib/presentation/feed/blog_post_screen/widgets/comment_widget.dart b/lib/presentation/feed/blog_post_screen/widgets/comment_widget.dart index c224966..ed2e075 100644 --- a/lib/presentation/feed/blog_post_screen/widgets/comment_widget.dart +++ b/lib/presentation/feed/blog_post_screen/widgets/comment_widget.dart @@ -1,10 +1,9 @@ // ignore_for_file: must_be_immutable -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; -import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; class CommentWidget extends StatelessWidget { CommentWidget(this.commentModelObj, {Key? key}) @@ -36,13 +35,11 @@ class CommentWidget extends StatelessWidget { ], ), child: Row( - mainAxisAlignment: MainAxisAlignment - .spaceBetween, // Move the main axis alignment to space between - crossAxisAlignment: - CrossAxisAlignment.center, // Center the items vertically + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Move the main axis alignment to space between + crossAxisAlignment: CrossAxisAlignment.center, // Center the items vertically children: [ CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + commentModelObj.userImage!, + imageUrl: baseUrl + '/storage/' + commentModelObj.userImage!, imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -69,10 +66,7 @@ class CommentWidget extends StatelessWidget { child: Row( children: [ Text( - commentModelObj.username!.length <= 15 - ? commentModelObj.username! - : commentModelObj.username!.substring(0, 15) + - '...', + commentModelObj.username!.length <= 15 ? commentModelObj.username! : commentModelObj.username!.substring(0, 15) + '...', style: theme.textTheme.titleMedium, ), Spacer(), @@ -82,7 +76,7 @@ class CommentWidget extends StatelessWidget { commentModelObj.dateText!, style: theme.textTheme.bodyMedium, ), - ) + ), ], ), ), @@ -96,10 +90,11 @@ class CommentWidget extends StatelessWidget { ), ), CustomImageView( - imagePath: ImageConstant.imgSend, - height: 30.v, - width: 30.h, - margin: EdgeInsets.only(left: 5)), + imagePath: ImageConstant.imgSend, + height: 30.v, + width: 30.h, + margin: EdgeInsets.only(left: 5), + ), ], ), ); diff --git a/lib/presentation/feed/feed_screen/bloc/feed_event.dart b/lib/presentation/feed/feed_screen/bloc/feed_event.dart deleted file mode 100644 index cbb510f..0000000 --- a/lib/presentation/feed/feed_screen/bloc/feed_event.dart +++ /dev/null @@ -1,23 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'feed_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Feed widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class FeedEvent extends Equatable {} - -/// Event that is dispatched when the Feed widget is first created. -class FeedInitialEvent extends FeedEvent { - @override - List get props => []; -} - -class UploadAvatar extends FeedEvent { - UploadAvatar(this.image); - final XFile image; - @override - List get props => [image]; -} diff --git a/lib/presentation/feed/feed_screen/bloc/feed_state.dart b/lib/presentation/feed/feed_screen/bloc/feed_state.dart deleted file mode 100644 index dbc57ac..0000000 --- a/lib/presentation/feed/feed_screen/bloc/feed_state.dart +++ /dev/null @@ -1,49 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'feed_bloc.dart'; - -class FeedState extends Equatable { - const FeedState({this.myProfileModelObj}); - - final FeedModel? myProfileModelObj; - - @override - List get props => [myProfileModelObj]; -} - -class FeedInitialState extends FeedState { - FeedInitialState({required FeedModel myProfileModelObj}) - : super(myProfileModelObj: myProfileModelObj); -} - -/// Represents the state of Feed in the application. -class FeedLoadedState extends FeedState { - FeedLoadedState({this.myProfileModelObj, this.posts}) - : super(myProfileModelObj: null); - - FeedModel? myProfileModelObj; - List? posts; - @override - List get props => [ - myProfileModelObj, - posts, - ]; - FeedLoadedState copyWith({ - FeedModel? myProfileModelObj, - List? posts, - }) { - return FeedLoadedState( - myProfileModelObj: myProfileModelObj ?? this.myProfileModelObj, - posts: posts ?? this.posts, - ); - } -} - -class FeedErrorState extends FeedState { - final String errorMessage; - - const FeedErrorState(this.errorMessage); - - @override - List get props => [errorMessage]; -} diff --git a/lib/presentation/feed/feed_screen/feed_screen.dart b/lib/presentation/feed/feed_screen/feed_screen.dart deleted file mode 100644 index 1af8a84..0000000 --- a/lib/presentation/feed/feed_screen/feed_screen.dart +++ /dev/null @@ -1,303 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/feed_bloc.dart'; -import 'models/feed_model.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/widgets/feed_search_view.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/widgets/feed_scroll_item.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -class FeedScreen extends StatelessWidget { - static Widget builder(BuildContext context) { - return BlocProvider(create: (context) => FeedBloc(FeedState(myProfileModelObj: FeedModel()))..add(FeedInitialEvent()), child: FeedScreen()); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is FeedInitialState) { - // Это начальное состояние, данные ещё не загружены. - return CircularProgressIndicator( - color: Colors.white, - backgroundColor: Colors.white, - ); - } else if (state is FeedLoadedState) { - // Данные загружены, можно строить экран. - return _buildFeedScreen(context, state); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }, - ); - } - - _buildFeedScreen(BuildContext context, FeedLoadedState state) { - mediaQueryData = MediaQuery.of(context); - return SafeArea( - child: Scaffold( - backgroundColor: Colors.grey[200], - resizeToAvoidBottomInset: true, - body: SingleChildScrollView( - child: Container( - width: double.maxFinite, - decoration: BoxDecoration(color: Colors.grey[200]), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox(height: 20), - _buildSearch(context), - SizedBox(height: 20), - _buildMenu(context, state), - SizedBox(height: 20), - _buildBlogPostList(context, state) - ], - ), - ), - ), - ), - ), - ); - } - - _buildSearch(BuildContext context) { - return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - children: [ - CustomSearchView( - hintText: "Поиск записей", - ), - SizedBox(height: 10), - Row( - children: [ - Flexible( - flex: 5, - child: CustomOutlinedButton( - text: "Найти запись", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - SizedBox(width: 8), // Add some spacing between the buttons - Flexible( - flex: 1, - child: CustomOutlinedButton( - text: "+", - onPressed: () => GoRouter.of(context).goNamed('blogPostCreateScreen'), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - ], - ) - ], - ), - ), - ); - } - - _buildBlogPostList(BuildContext context, FeedLoadedState state) { - List postWidgets = []; - - if (state.posts != null) { - for (var post in state.posts!) { - postWidgets.add(_buildFeedEntry(post, context)); - } - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: postWidgets, - ); - } - - _buildFeedEntry(post, BuildContext context) { - return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column(children: [ - ListTile( - leading: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (post["author"]['profile_photo_path'] ?? ''), - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, - ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, - ), - ), - title: Text( - post?['author']['name'] ?? '', - style: CustomTextStyles.titleMediumSemiBold, - ), - subtitle: Text( - DateFormat('dd.MM.yyyy').format(DateTime.parse(post?['post']['updated_at'])), - style: theme.textTheme.bodyMedium, - ), - onTap: () => GoRouter.of(context).goNamed( - 'blogPostScreen', - extra: post?['post']['id'].toString(), - ), - trailing: PopupMenuButton( - onSelected: (value) => print("tap"), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'edit', - child: Text('Редактировать'), - ), - PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Spacer(), - Align( - alignment: Alignment.center, - child: Text( - post?['post']['title'], - style: CustomTextStyles.titleMediumBlack, - ), - ), - Spacer(), - ], - ), - SizedBox(height: 8.0), - Text( - post?['post']['description'], - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 16.0), - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (post?['post']['image'] ?? ''), - imageBuilder: (context, imageProvider) => Stack( - children: [ - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - child: Image( - image: imageProvider, - ), - ), - ], - ), - placeholder: (context, url) => CircularProgressIndicator(), - ), - SizedBox(height: 16.0), - Row(children: [ - Padding( - padding: EdgeInsets.only(left: 4), - child: Row(children: [ - Padding( - padding: EdgeInsets.only(right: 4), - child: Icon(Icons.comment_outlined), - ), - Text( - "Комментировать", - ) - ]), - ), - Spacer(), - Row(children: [ - Padding( - padding: const EdgeInsets.only(right: 4), - child: Icon(Icons.favorite_outline), - ), - Text( - "Нравится", - ) - ]), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 4), - child: Icon(Icons.share_outlined), - ), - ]), - ], - ), - ), - ])); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - _buildMenu(BuildContext context, FeedLoadedState state) { - return Container( - padding: EdgeInsets.all(12), - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - ScrollItem(title: 'Все'), - ScrollItem(title: 'Рецепты'), - ScrollItem(title: 'Диеты'), - ScrollItem(title: 'Планы'), - ScrollItem(title: 'Записи'), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/feed/feed_screen/widgets/feed_scroll_item.dart b/lib/presentation/feed/feed_screen/widgets/feed_scroll_item.dart index 2c40739..bc3b161 100644 --- a/lib/presentation/feed/feed_screen/widgets/feed_scroll_item.dart +++ b/lib/presentation/feed/feed_screen/widgets/feed_scroll_item.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class ScrollItem extends StatelessWidget { final String title; diff --git a/lib/presentation/feed/feed_screen/widgets/feed_search_view.dart b/lib/presentation/feed/feed_screen/widgets/feed_search_view.dart index 20cce2e..bbfff40 100644 --- a/lib/presentation/feed/feed_screen/widgets/feed_search_view.dart +++ b/lib/presentation/feed/feed_screen/widgets/feed_search_view.dart @@ -1,31 +1,31 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class CustomSearchView extends StatelessWidget { - CustomSearchView( - {Key? key, - this.alignment, - this.width, - this.scrollPadding, - this.controller, - this.focusNode, - this.autofocus = false, - this.textStyle, - this.textInputType = TextInputType.text, - this.maxLines, - this.hintText, - this.hintStyle, - this.prefix, - this.prefixConstraints, - this.suffix, - this.suffixConstraints, - this.contentPadding, - this.borderDecoration, - this.fillColor, - this.filled = true, - this.validator, - this.onChanged}) - : super( + CustomSearchView({ + Key? key, + this.alignment, + this.width, + this.scrollPadding, + this.controller, + this.focusNode, + this.autofocus = false, + this.textStyle, + this.textInputType = TextInputType.text, + this.maxLines, + this.hintText, + this.hintStyle, + this.prefix, + this.prefixConstraints, + this.suffix, + this.suffixConstraints, + this.contentPadding, + this.borderDecoration, + this.fillColor, + this.filled = true, + this.validator, + this.onChanged, + }) : super( key: key, ); @@ -76,15 +76,15 @@ class CustomSearchView extends StatelessWidget { return alignment != null ? Align( alignment: alignment ?? Alignment.center, - child: searchViewWidget(context)) + child: searchViewWidget(context), + ) : searchViewWidget(context); } searchViewWidget(BuildContext context) => SizedBox( width: width ?? double.maxFinite, child: TextFormField( - scrollPadding: - EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + scrollPadding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), controller: controller, focusNode: focusNode, onTapOutside: (event) => onTapOutside(), @@ -112,8 +112,9 @@ class CustomSearchView extends StatelessWidget { prefixIcon: prefix ?? SizedBox( child: Padding( - padding: EdgeInsets.only(left: 10), - child: Icon(Icons.search)), + padding: EdgeInsets.only(left: 10), + child: Icon(Icons.search), + ), ), prefixIconConstraints: prefixConstraints ?? BoxConstraints( diff --git a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_bloc.dart b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_bloc.dart index 5f63f29..3bae9e8 100644 --- a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_bloc.dart +++ b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_bloc.dart @@ -1,15 +1,16 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/glossary/glossary_screen/models/glossary_screen_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/glossary/glossary_screen/models/glossary_screen_model.dart'; -import 'package:go_router/go_router.dart'; + part 'glossary_screen_event.dart'; part 'glossary_screen_state.dart'; @@ -31,7 +32,7 @@ class GlossaryBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final responseProductGroups = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/glossary/getProductGroups'), + Uri.parse(baseUrl + '/api/glossaries/group/index'), headers: { 'Authorization': 'Bearer $token', }, @@ -41,18 +42,23 @@ class GlossaryBloc extends Bloc { if (dataProductGroups is List) { if (state is GlossaryLoadedState) { var currentState = state as GlossaryLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( glossaryModelObj: currentState.glossaryModelObj, token: currentState.token, productGroups: currentState.productGroups, - productList: currentState.productList)); + productList: currentState.productList, + ), + ); } else { - List productGroupsModel = - _fillProductGroups(dataProductGroups); - emit(GlossaryLoadedState( + List productGroupsModel = _fillProductGroups(dataProductGroups); + emit( + GlossaryLoadedState( token: token, productGroups: productGroupsModel, - productList: [])); + productList: [], + ), + ); await _getProductListById(token, emit, productGroupsModel[0].id); } } else { @@ -61,8 +67,11 @@ class GlossaryBloc extends Bloc { } } else { // Статус ответа не равен 200, обрабатываем ошибку - emit(GlossaryErrorState( - 'Ошибка сервера: ${responseProductGroups.statusCode}')); + emit( + GlossaryErrorState( + 'Ошибка сервера: ${responseProductGroups.statusCode}', + ), + ); } } catch (e) { // Ошибка при декодировании JSON или другая ошибка выполнения @@ -71,7 +80,9 @@ class GlossaryBloc extends Bloc { } void _changeProductGroup( - ChangeProductGroup event, Emitter emit) async { + ChangeProductGroup event, + Emitter emit, + ) async { if (state is GlossaryLoadedState) { var currentState = state as GlossaryLoadedState; await _getProductListById(currentState.token, emit, event.id); @@ -79,9 +90,12 @@ class GlossaryBloc extends Bloc { } Future _getProductListById( - token, Emitter emit, int? productGroupID) async { + token, + Emitter emit, + int? productGroupID, + ) async { final responseProductList = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/glossary/index/$productGroupID'), + Uri.parse(baseUrl + '/api/glossary/index/$productGroupID'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', @@ -90,10 +104,13 @@ class GlossaryBloc extends Bloc { final dataProductList = jsonDecode(responseProductList.body); if (dataProductList is List) { var currentState = state as GlossaryLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( glossaryModelObj: currentState.glossaryModelObj, productGroups: currentState.productGroups, - productList: dataProductList)); + productList: dataProductList, + ), + ); } else { emit(GlossaryErrorState('Список продуктов некорректного формата')); } diff --git a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_event.dart b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_event.dart index f3fb4dd..29cabd5 100644 --- a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_event.dart +++ b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_event.dart @@ -17,14 +17,18 @@ class GlossaryInitialEvent extends GlossaryEvent { class DeleteEntry extends GlossaryEvent { DeleteEntry(this.id); + final int id; + @override List get props => [id]; } class ChangeProductGroup extends GlossaryEvent { ChangeProductGroup(this.id); + final int id; + @override List get props => [id]; } diff --git a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_state.dart b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_state.dart index 7536386..a3d819f 100644 --- a/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_state.dart +++ b/lib/presentation/glossary/glossary_screen/bloc/glossary_screen_state.dart @@ -14,6 +14,7 @@ class GlossaryState extends Equatable { @override List get props => [glossaryModelObj]; + GlossaryState copyWith({GlossaryModel? glossaryModelObj}) { return GlossaryState( glossaryModelObj: glossaryModelObj ?? this.glossaryModelObj, @@ -22,24 +23,27 @@ class GlossaryState extends Equatable { } class GlossaryLoadedState extends GlossaryState { - GlossaryLoadedState( - {this.glossaryModelObj, - this.productGroups, - this.productList, - this.token}); + GlossaryLoadedState({ + this.glossaryModelObj, + this.productGroups, + this.productList, + this.token, + }); GlossaryModel? glossaryModelObj; String? token; List? productGroups; List? productList; + @override - List get props => - [glossaryModelObj, productGroups, productList, token]; - GlossaryLoadedState copyWith( - {GlossaryModel? glossaryModelObj, - String? token, - List? productGroups, - List? productList}) { + List get props => [glossaryModelObj, productGroups, productList, token]; + + GlossaryLoadedState copyWith({ + GlossaryModel? glossaryModelObj, + String? token, + List? productGroups, + List? productList, + }) { return GlossaryLoadedState( glossaryModelObj: glossaryModelObj ?? this.glossaryModelObj, productGroups: productGroups ?? this.productGroups, @@ -59,6 +63,5 @@ class GlossaryErrorState extends GlossaryState { } class GlossaryInitialState extends GlossaryState { - GlossaryInitialState({required GlossaryModel glossaryModelObj}) - : super(glossaryModelObj: glossaryModelObj); + GlossaryInitialState({required GlossaryModel glossaryModelObj}) : super(glossaryModelObj: glossaryModelObj); } diff --git a/lib/presentation/glossary/glossary_screen/glossary_screen.dart b/lib/presentation/glossary/glossary_screen/glossary_screen.dart index ada1e86..e845318 100644 --- a/lib/presentation/glossary/glossary_screen/glossary_screen.dart +++ b/lib/presentation/glossary/glossary_screen/glossary_screen.dart @@ -1,20 +1,22 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart'; +import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart'; +import 'package:eatvio_app/widgets/custom_drop_down.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:flutter/material.dart'; + import 'bloc/glossary_screen_bloc.dart'; import 'models/glossary_screen_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; -import 'package:eatvio_app/widgets/custom_drop_down.dart'; -import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart'; -import 'package:eatvio_app/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart'; class GlossaryScreen extends StatelessWidget { const GlossaryScreen({Key? key}) : super(key: key); static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => GlossaryBloc(GlossaryState(glossaryModelObj: GlossaryModel()))..add(GlossaryInitialEvent()), child: GlossaryScreen()); + create: (context) => GlossaryBloc(GlossaryState(glossaryModelObj: GlossaryModel()))..add(GlossaryInitialEvent()), + child: GlossaryScreen(), + ); } Widget build(BuildContext context) { @@ -67,7 +69,7 @@ class GlossaryScreen extends StatelessWidget { SizedBox(height: 20), _buildMenu(context), SizedBox(height: 20), - _buildProducts(context, state) + _buildProducts(context, state), ], ), ), @@ -125,24 +127,26 @@ class GlossaryScreen extends StatelessWidget { ), ], ), - child: Column(children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - "Поиск по алфавиту", - style: CustomTextStyles.titleMediumSemiBold, + child: Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "Поиск по алфавиту", + style: CustomTextStyles.titleMediumSemiBold, + ), ), - ), - SizedBox( - height: 8, - ), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: List.generate(33, _fillAlphabet), + SizedBox( + height: 8, ), - ), - ]), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: List.generate(33, _fillAlphabet), + ), + ), + ], + ), ); } @@ -162,42 +166,44 @@ class GlossaryScreen extends StatelessWidget { ), ], ), - child: Column(children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - "Группа продуктов", - style: CustomTextStyles.titleMediumSemiBold, + child: Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "Группа продуктов", + style: CustomTextStyles.titleMediumSemiBold, + ), ), - ), - SizedBox( - height: 8, - ), - CustomDropDown( - items: state.productGroups, - defaultValue: state.productGroups?[0], - fillColor: Colors.grey[200]!, - hintText: 'Выберите категорию', - borderDecoration: OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(8)), - borderSide: BorderSide(color: Colors.grey[200]!, width: 1), + SizedBox( + height: 8, ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 9, + CustomDropDown( + items: state.productGroups, + value: state.productGroups?[0], + fillColor: Colors.grey[200]!, + hintText: 'Выберите категорию', + borderDecoration: OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + borderSide: BorderSide(color: Colors.grey[200]!, width: 1), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 9, + ), + onChanged: _changeProductGroup(context, state), + width: MediaQuery.of(context).size.width, // Set a percentage value as per your layout ), - onChanged: _changeProductGroup(context, state), - width: MediaQuery.of(context).size.width, // Set a percentage value as per your layout - ), - SizedBox( - height: 8, - ), - Align(alignment: Alignment.centerLeft, child: Text("*КБЖУ указано за 100гр")), - SizedBox( - height: 8, - ), - _buildProductList(context, state) - ]), + SizedBox( + height: 8, + ), + Align(alignment: Alignment.centerLeft, child: Text("*КБЖУ указано за 100гр")), + SizedBox( + height: 8, + ), + _buildProductList(context, state), + ], + ), ); } @@ -218,23 +224,24 @@ class GlossaryScreen extends StatelessWidget { _buildProductEntry(product, BuildContext context) { return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 3, - offset: Offset(0, 3), - ), - ], - ), - child: Column(children: [ + margin: EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 3, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + children: [ ListTile( trailing: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (product['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (product['image'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -255,26 +262,34 @@ class GlossaryScreen extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: Column( children: [ - Row(children: [ - Column(children: [ - Text("Ккал - ${product['energy_on_100gr'].toString()}"), - SizedBox(height: 8), - Text("Белки - ${product['proteins_on_100gr'].toString()}") - ]), - Spacer(), - Padding( - padding: const EdgeInsets.only(right: 24.0), - child: Column(children: [ - Text("Жиры - ${product['fats_on_100gr'].toString()}"), - SizedBox(height: 8), - Text("Углеводы - ${product['carbohydrates_on_100gr'].toString()}") - ]), - ) - ]) + Row( + children: [ + Column( + children: [ + Text("Ккал - ${product['energy_on_100gr'].toString()}"), + SizedBox(height: 8), + Text("Белки - ${product['proteins_on_100gr'].toString()}"), + ], + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 24.0), + child: Column( + children: [ + Text("Жиры - ${product['fats_on_100gr'].toString()}"), + SizedBox(height: 8), + Text("Углеводы - ${product['carbohydrates_on_100gr'].toString()}"), + ], + ), + ), + ], + ), ], ), ), - ])); + ], + ), + ); } Widget _fillAlphabet(int index) { diff --git a/lib/presentation/glossary/glossary_screen/models/glossary_screen_model.dart b/lib/presentation/glossary/glossary_screen/models/glossary_screen_model.dart index d19bbb5..1077bd6 100644 --- a/lib/presentation/glossary/glossary_screen/models/glossary_screen_model.dart +++ b/lib/presentation/glossary/glossary_screen/models/glossary_screen_model.dart @@ -7,6 +7,7 @@ import 'package:equatable/equatable.dart'; class GlossaryModel extends Equatable { GlossaryModel(); + GlossaryModel copyWith() { return GlossaryModel(); } diff --git a/lib/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart b/lib/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart index 2c40739..bc3b161 100644 --- a/lib/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart +++ b/lib/presentation/glossary/glossary_screen/widgets/glossary_scroll_item.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class ScrollItem extends StatelessWidget { final String title; diff --git a/lib/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart b/lib/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart index 20cce2e..bbfff40 100644 --- a/lib/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart +++ b/lib/presentation/glossary/glossary_screen/widgets/glossary_search_widget.dart @@ -1,31 +1,31 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class CustomSearchView extends StatelessWidget { - CustomSearchView( - {Key? key, - this.alignment, - this.width, - this.scrollPadding, - this.controller, - this.focusNode, - this.autofocus = false, - this.textStyle, - this.textInputType = TextInputType.text, - this.maxLines, - this.hintText, - this.hintStyle, - this.prefix, - this.prefixConstraints, - this.suffix, - this.suffixConstraints, - this.contentPadding, - this.borderDecoration, - this.fillColor, - this.filled = true, - this.validator, - this.onChanged}) - : super( + CustomSearchView({ + Key? key, + this.alignment, + this.width, + this.scrollPadding, + this.controller, + this.focusNode, + this.autofocus = false, + this.textStyle, + this.textInputType = TextInputType.text, + this.maxLines, + this.hintText, + this.hintStyle, + this.prefix, + this.prefixConstraints, + this.suffix, + this.suffixConstraints, + this.contentPadding, + this.borderDecoration, + this.fillColor, + this.filled = true, + this.validator, + this.onChanged, + }) : super( key: key, ); @@ -76,15 +76,15 @@ class CustomSearchView extends StatelessWidget { return alignment != null ? Align( alignment: alignment ?? Alignment.center, - child: searchViewWidget(context)) + child: searchViewWidget(context), + ) : searchViewWidget(context); } searchViewWidget(BuildContext context) => SizedBox( width: width ?? double.maxFinite, child: TextFormField( - scrollPadding: - EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + scrollPadding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), controller: controller, focusNode: focusNode, onTapOutside: (event) => onTapOutside(), @@ -112,8 +112,9 @@ class CustomSearchView extends StatelessWidget { prefixIcon: prefix ?? SizedBox( child: Padding( - padding: EdgeInsets.only(left: 10), - child: Icon(Icons.search)), + padding: EdgeInsets.only(left: 10), + child: Icon(Icons.search), + ), ), prefixIconConstraints: prefixConstraints ?? BoxConstraints( diff --git a/lib/presentation/plans/plan_create_screen/bloc/plan_create_bloc.dart b/lib/presentation/plans/plan_create_screen/bloc/plan_create_bloc.dart index 51e08b9..3cab0f6 100644 --- a/lib/presentation/plans/plan_create_screen/bloc/plan_create_bloc.dart +++ b/lib/presentation/plans/plan_create_screen/bloc/plan_create_bloc.dart @@ -1,15 +1,16 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/plans/plan_create_screen/models/plan_create_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/plans/plan_create_screen/models/plan_create_model.dart'; -import 'package:go_router/go_router.dart'; + part 'plan_create_event.dart'; part 'plan_create_state.dart'; @@ -31,21 +32,27 @@ class PlanCreateBloc extends Bloc { } if (state is PlanCreateLoadedState) { var currentState = state as PlanCreateLoadedState; - emit(currentState.copyWith( - planModelObj: currentState.planModelObj, - name: currentState.name, - details: currentState.details, - )); + emit( + currentState.copyWith( + planModelObj: currentState.planModelObj, + name: currentState.name, + details: currentState.details, + ), + ); } else { - emit(PlanCreateLoadedState( - name: TextEditingController(), - details: TextEditingController(), - )); + emit( + PlanCreateLoadedState( + name: TextEditingController(), + details: TextEditingController(), + ), + ); } } FutureOr _createPlan( - CreatePlan event, Emitter emit) async { + CreatePlan event, + Emitter emit, + ) async { if (state is PlanCreateLoadedState) { var currentState = state as PlanCreateLoadedState; @@ -58,7 +65,8 @@ class PlanCreateBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('planSelectScreen'); } else { print( - 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}'); + 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}', + ); } } } @@ -67,7 +75,7 @@ class PlanCreateBloc extends Bloc { String? name, String? details, ) async { - String url = '${dotenv.env['SERVER_ROOT']!}/plans/create'; + String url = '${baseUrl}/api/plans/create'; final Map credentials = { 'name': name, @@ -76,7 +84,7 @@ class PlanCreateBloc extends Bloc { 'state': 'active', 'type': '{"meat": true}', 'daily_schedule': - '{"1": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 494}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 12}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 432}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 195}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 710}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 119}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 287}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 445}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 500}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 764}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 735}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 127}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 89}]}, "2": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 436}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 700}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 766}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 194}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 426}], "snacks": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 58}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 152}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 925}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 224}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 918}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 81}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 308}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 579}]}, "3": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 266}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 790}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 26}], "snacks": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 549}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 446}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 92}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 403}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 894}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 457}]}, "4": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 698}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 43}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 994}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 965}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 42}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 948}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 28}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 54}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 112}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 891}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 538}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 635}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 586}]}, "5": {"lunch": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 900}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 242}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 375}], "snacks": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 604}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 510}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 887}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 554}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 731}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 574}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 274}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 276}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 80}]}, "6": {"lunch": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 359}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 358}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 639}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 861}], "dinner": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 122}], "snacks": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 980}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 837}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 444}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 577}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 706}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 839}]}, "7": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 118}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 664}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 665}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 986}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 296}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 807}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 493}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 227}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 385}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 448}], "breakfast": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 784}]}, "8": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 433}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 871}], "dinner": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 332}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 41}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 388}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 649}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 114}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 968}], "breakfast": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 180}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 269}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 998}]}, "9": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 68}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 505}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 554}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 579}], "snacks": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 751}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 144}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 677}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 263}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 304}], "breakfast": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 963}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 258}]}, "10": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 167}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 306}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 243}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 79}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 560}], "snacks": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 294}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 145}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 639}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 108}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 924}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 894}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 280}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 336}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 338}]}, "11": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 817}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 968}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 525}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 864}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 457}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 548}], "snacks": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 658}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 239}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 358}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 416}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 220}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 323}]}, "12": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 377}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 138}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 654}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 237}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 902}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 76}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 723}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 481}], "breakfast": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 571}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 515}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 188}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 411}]}, "13": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 379}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 231}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 147}], "dinner": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 871}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 679}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 359}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 561}], "snacks": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 414}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 827}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 649}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 161}], "breakfast": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 185}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 464}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 387}]}, "14": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 248}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 5}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 693}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 655}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 709}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 881}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 588}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 36}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 453}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 692}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 186}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 721}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 740}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 731}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 842}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 850}]}, "15": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 380}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 689}], "dinner": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 326}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 629}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 201}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 129}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 749}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 315}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 444}]}, "16": {"lunch": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 953}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 101}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 684}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 506}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 333}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 416}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 796}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 756}], "supper": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 858}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 619}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 800}], "breakfast": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 539}]}, "17": {"lunch": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 134}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 977}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 209}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 227}], "breakfast": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 195}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 917}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 706}]}, "18": {"lunch": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 239}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 798}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 155}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 959}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 958}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 984}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 134}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 432}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 242}]}, "19": {"lunch": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 906}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 152}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 610}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 605}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 498}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 616}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 512}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 146}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 200}], "supper": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 764}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 353}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 181}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 783}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 506}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 887}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 130}]}, "20": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 48}], "dinner": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 266}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 143}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 55}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 174}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 855}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 6}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 878}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}], "breakfast": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 442}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "milliliters", "quantity": 558}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 885}]}, "21": {"lunch": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 504}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 652}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 996}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 200}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 641}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 87}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 689}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 143}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 475}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 924}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 98}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 438}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 383}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 462}]}}' + '{"1": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 494}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 12}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 432}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 195}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 710}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 119}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 287}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 445}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 500}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 764}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 735}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 127}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 89}]}, "2": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 436}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 700}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 766}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 194}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 426}], "snacks": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 58}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 152}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 925}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 224}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 918}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 81}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 308}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 579}]}, "3": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 266}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 790}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 26}], "snacks": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 549}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 446}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 92}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 403}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 894}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 457}]}, "4": {"lunch": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 698}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 43}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 994}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 965}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 42}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 948}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 28}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 54}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 112}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 891}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 538}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 635}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 586}]}, "5": {"lunch": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 900}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 242}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 375}], "snacks": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 604}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 510}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 887}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 554}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 731}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 574}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 274}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 276}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 80}]}, "6": {"lunch": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 359}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 358}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 639}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 861}], "dinner": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 122}], "snacks": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 980}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 837}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 444}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 577}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 706}], "breakfast": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 839}]}, "7": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 118}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 664}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 665}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 986}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 296}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 807}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 493}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 227}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 385}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 448}], "breakfast": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 784}]}, "8": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 433}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 871}], "dinner": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 332}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 41}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 388}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 649}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 114}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "milliliters", "quantity": 968}], "breakfast": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 180}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 269}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 998}]}, "9": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 68}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 505}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 554}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 579}], "snacks": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 751}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 144}], "supper": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 677}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 263}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 304}], "breakfast": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 963}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 258}]}, "10": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 167}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 306}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 243}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 79}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 560}], "snacks": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 294}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 145}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 639}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 108}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 924}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 894}], "breakfast": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 280}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 336}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 338}]}, "11": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 817}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 968}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 525}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 864}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "pcs", "quantity": 457}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 548}], "snacks": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 658}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 239}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 358}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 406}], "supper": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "grams", "quantity": 416}], "breakfast": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 220}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 323}]}, "12": {"lunch": [{"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 377}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 138}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 654}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 237}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 902}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 76}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 723}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 481}], "breakfast": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 571}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 515}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 188}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 411}]}, "13": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 379}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "grams", "quantity": 231}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 147}], "dinner": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 871}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 679}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 359}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 561}], "snacks": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 414}], "supper": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 827}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 649}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 161}], "breakfast": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 185}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 464}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 387}]}, "14": {"lunch": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 248}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 5}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 693}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 655}], "dinner": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 709}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 881}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 588}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 36}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "pcs", "quantity": 453}], "supper": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 692}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 186}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 721}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 740}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 731}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 842}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 850}]}, "15": {"lunch": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "grams", "quantity": 124}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 380}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 689}], "dinner": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 326}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 629}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 201}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 129}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 749}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "milliliters", "quantity": 315}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 444}]}, "16": {"lunch": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 953}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 101}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 684}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "pcs", "quantity": 506}], "dinner": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 333}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 416}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "milliliters", "quantity": 796}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 799}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "pcs", "quantity": 756}], "supper": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 858}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 619}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 800}], "breakfast": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "pcs", "quantity": 363}, {"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "grams", "quantity": 539}]}, "17": {"lunch": [{"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 134}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 977}], "snacks": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "pcs", "quantity": 211}], "supper": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 209}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "grams", "quantity": 227}], "breakfast": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 195}, {"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "pcs", "quantity": 917}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 706}]}, "18": {"lunch": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 239}, {"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 798}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 155}], "dinner": [{"name": "Little Hamburger", "uniq": "Little Hamburger-1709115623", "portion": "grams", "quantity": 959}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 958}], "snacks": [{"name": "Pasta", "uniq": "Pasta-1709115623", "portion": "milliliters", "quantity": 984}], "supper": [{"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 134}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 432}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "milliliters", "quantity": 242}]}, "19": {"lunch": [{"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 906}, {"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 152}], "dinner": [{"name": "Cheeseburger", "uniq": "Cheeseburger-1709115623", "portion": "milliliters", "quantity": 610}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 605}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "grams", "quantity": 498}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 616}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 512}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 146}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 200}], "supper": [{"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 764}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 353}, {"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 181}], "breakfast": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 783}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 506}, {"name": "Bacon Cheeseburger", "uniq": "Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 887}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 130}]}, "20": {"lunch": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 48}], "dinner": [{"name": "Bacon Dog", "uniq": "Bacon Dog-1709115623", "portion": "milliliters", "quantity": 266}, {"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 143}], "snacks": [{"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "grams", "quantity": 55}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "grams", "quantity": 174}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 855}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "milliliters", "quantity": 6}], "supper": [{"name": "Grilled Cheese", "uniq": "Grilled Cheese-1709115623", "portion": "pcs", "quantity": 296}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 878}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "pcs", "quantity": 376}], "breakfast": [{"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "milliliters", "quantity": 442}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "milliliters", "quantity": 558}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 885}]}, "21": {"lunch": [{"name": "Little Bacon Burger", "uniq": "Little Bacon Burger-1709115623", "portion": "grams", "quantity": 504}, {"name": "Little Bacon Cheeseburger", "uniq": "Little Bacon Cheeseburger-1709115623", "portion": "milliliters", "quantity": 652}, {"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 996}], "dinner": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "milliliters", "quantity": 200}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "pcs", "quantity": 641}, {"name": "Cheese Veggie Sandwich", "uniq": "Cheese Veggie Sandwich-1709115623", "portion": "milliliters", "quantity": 87}, {"name": "Cheese Dog", "uniq": "Cheese Dog-1709115623", "portion": "pcs", "quantity": 689}], "snacks": [{"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 143}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "pcs", "quantity": 528}, {"name": "Veggie Sandwich", "uniq": "Veggie Sandwich-1709115623", "portion": "grams", "quantity": 475}], "supper": [{"name": "Little Cheeseburger", "uniq": "Little Cheeseburger-1709115623", "portion": "grams", "quantity": 924}, {"name": "Hamburger", "uniq": "Hamburger-1709115623", "portion": "grams", "quantity": 98}], "breakfast": [{"name": "Bacon Cheese Dog", "uniq": "Bacon Cheese Dog-1709115623", "portion": "grams", "quantity": 438}, {"name": "Cheese Pizza", "uniq": "Cheese Pizza-1709115623", "portion": "milliliters", "quantity": 383}, {"name": "Bacon Burger", "uniq": "Bacon Burger-1709115623", "portion": "grams", "quantity": 462}]}}', }; var response = await http.post( diff --git a/lib/presentation/plans/plan_create_screen/bloc/plan_create_state.dart b/lib/presentation/plans/plan_create_screen/bloc/plan_create_state.dart index 93e4aaf..f248565 100644 --- a/lib/presentation/plans/plan_create_screen/bloc/plan_create_state.dart +++ b/lib/presentation/plans/plan_create_screen/bloc/plan_create_state.dart @@ -14,6 +14,7 @@ class PlanCreateState extends Equatable { @override List get props => [planModelObj]; + PlanCreateState copyWith({PlanCreateModel? planModelObj}) { return PlanCreateState( planModelObj: planModelObj ?? this.planModelObj, @@ -31,12 +32,14 @@ class PlanCreateLoadedState extends PlanCreateState { PlanCreateModel? planModelObj; TextEditingController? name; TextEditingController? details; + @override List get props => [ planModelObj, name, details, ]; + PlanCreateLoadedState copyWith({ PlanCreateModel? planModelObj, TextEditingController? name, @@ -60,6 +63,5 @@ class PlanCreateErrorState extends PlanCreateState { } class PlanCreateInitialState extends PlanCreateState { - PlanCreateInitialState({required PlanCreateModel planModelObj}) - : super(planModelObj: planModelObj); + PlanCreateInitialState({required PlanCreateModel planModelObj}) : super(planModelObj: planModelObj); } diff --git a/lib/presentation/plans/plan_create_screen/plan_create_screen.dart b/lib/presentation/plans/plan_create_screen/plan_create_screen.dart index bd354af..165be86 100644 --- a/lib/presentation/plans/plan_create_screen/plan_create_screen.dart +++ b/lib/presentation/plans/plan_create_screen/plan_create_screen.dart @@ -1,16 +1,18 @@ -import 'bloc/plan_create_bloc.dart'; -import 'models/plan_create_model.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; +import 'bloc/plan_create_bloc.dart'; +import 'models/plan_create_model.dart'; + class PlanCreateScreen extends StatelessWidget { const PlanCreateScreen({Key? key}) : super(key: key); static Widget builder(BuildContext context) { final planID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => PlanCreateBloc(PlanCreateState(planModelObj: PlanCreateModel(planID: planID.toString())))..add(PlanCreateInitialEvent()), - child: PlanCreateScreen()); + create: (context) => PlanCreateBloc(PlanCreateState(planModelObj: PlanCreateModel(planID: planID.toString())))..add(PlanCreateInitialEvent()), + child: PlanCreateScreen(), + ); } Widget build(BuildContext context) { @@ -65,25 +67,28 @@ class PlanCreateScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - TextFormField( - controller: state.name, - decoration: InputDecoration(labelText: 'Заголовок'), - ), - SizedBox(height: 16.0), - TextFormField( - controller: state.details, - decoration: InputDecoration(labelText: 'Описание'), - ), - SizedBox(height: 16.0), - // Здесь нужно добавить виджет для загрузки картинки - ElevatedButton( - onPressed: () => context.read().add(CreatePlan()), - child: Text('Создать'), - ) - ]), - ) + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 16.0), + TextFormField( + controller: state.name, + decoration: InputDecoration(labelText: 'Заголовок'), + ), + SizedBox(height: 16.0), + TextFormField( + controller: state.details, + decoration: InputDecoration(labelText: 'Описание'), + ), + SizedBox(height: 16.0), + // Здесь нужно добавить виджет для загрузки картинки + ElevatedButton( + onPressed: () => context.read().add(CreatePlan()), + child: Text('Создать'), + ), + ], + ), + ), ], ), ), diff --git a/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_bloc.dart b/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_bloc.dart index 1e7e4f2..5987b6b 100644 --- a/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_bloc.dart +++ b/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/plans/plan_edit_screen/models/plan_edit_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/plans/plan_edit_screen/models/plan_edit_model.dart'; -import 'package:go_router/go_router.dart'; part 'plan_edit_event.dart'; - part 'plan_edit_state.dart'; /// A bloc that manages the state of a PlanEdit according to the event that is dispatched to it. @@ -34,7 +33,7 @@ class PlanEditBloc extends Bloc { } final String? planID = state.planModelObj?.planID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/plans/show/$planID'), + Uri.parse(baseUrl + '/api/plans/show/$planID'), headers: { 'Authorization': 'Bearer $token', }, @@ -44,18 +43,24 @@ class PlanEditBloc extends Bloc { if (data is Map) { if (state is PlanEditLoadedState) { var currentState = state as PlanEditLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( planModelObj: currentState.planModelObj, plan: currentState.plan, name: currentState.name, duration: currentState.duration, - details: currentState.details)); + details: currentState.details, + ), + ); } else { - emit(PlanEditLoadedState( + emit( + PlanEditLoadedState( plan: data, name: TextEditingController(text: data['name']), details: TextEditingController(text: data['details']), - duration: TextEditingController(text: data['duration'].toString()))); + duration: TextEditingController(text: data['duration'].toString()), + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку @@ -96,7 +101,7 @@ class PlanEditBloc extends Bloc { String? duration, ) async { int id = plan?['id']; - String url = '${dotenv.env['SERVER_ROOT']!}/plans/update/$id'; + String url = '${baseUrl}/api/plans/update/$id'; final Map credentials = { 'id': id, diff --git a/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_state.dart b/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_state.dart index 427bf0d..57e0a3a 100644 --- a/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_state.dart +++ b/lib/presentation/plans/plan_edit_screen/bloc/plan_edit_state.dart @@ -14,6 +14,7 @@ class PlanEditState extends Equatable { @override List get props => [planModelObj]; + PlanEditState copyWith({PlanEditModel? planModelObj}) { return PlanEditState( planModelObj: planModelObj ?? this.planModelObj, @@ -22,16 +23,23 @@ class PlanEditState extends Equatable { } class PlanEditLoadedState extends PlanEditState { - PlanEditLoadedState( - {this.planModelObj, this.plan, this.name, this.details, this.duration}); + PlanEditLoadedState({ + this.planModelObj, + this.plan, + this.name, + this.details, + this.duration, + }); PlanEditModel? planModelObj; Map? plan; TextEditingController? name; TextEditingController? details; TextEditingController? duration; + @override List get props => [planModelObj, plan, name, details, duration]; + PlanEditLoadedState copyWith({ PlanEditModel? planModelObj, Map? plan, @@ -59,6 +67,5 @@ class PlanEditErrorState extends PlanEditState { } class PlanEditInitialState extends PlanEditState { - PlanEditInitialState({required PlanEditModel planModelObj}) - : super(planModelObj: planModelObj); + PlanEditInitialState({required PlanEditModel planModelObj}) : super(planModelObj: planModelObj); } diff --git a/lib/presentation/plans/plan_edit_screen/plan_edit_screen.dart b/lib/presentation/plans/plan_edit_screen/plan_edit_screen.dart index 7baa33d..c700574 100644 --- a/lib/presentation/plans/plan_edit_screen/plan_edit_screen.dart +++ b/lib/presentation/plans/plan_edit_screen/plan_edit_screen.dart @@ -1,9 +1,9 @@ -import 'bloc/plan_edit_bloc.dart'; -import 'models/plan_edit_model.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import 'bloc/plan_edit_bloc.dart'; +import 'models/plan_edit_model.dart'; class PlanEditScreen extends StatelessWidget { const PlanEditScreen({Key? key}) : super(key: key); @@ -11,8 +11,9 @@ class PlanEditScreen extends StatelessWidget { static Widget builder(BuildContext context) { final planID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => PlanEditBloc(PlanEditState(planModelObj: PlanEditModel(planID: planID.toString())))..add(PlanEditInitialEvent()), - child: PlanEditScreen()); + create: (context) => PlanEditBloc(PlanEditState(planModelObj: PlanEditModel(planID: planID.toString())))..add(PlanEditInitialEvent()), + child: PlanEditScreen(), + ); } Widget build(BuildContext context) { @@ -71,7 +72,7 @@ class PlanEditScreen extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.plan?['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.plan?['image'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -98,10 +99,10 @@ class PlanEditScreen extends StatelessWidget { ElevatedButton( onPressed: () => context.read().add(EditPlan()), child: Text('Сохранить'), - ) + ), ], ), - ) + ), ], ), ), diff --git a/lib/presentation/plans/plan_select_screen/bloc/plan_select_bloc.dart b/lib/presentation/plans/plan_select_screen/bloc/plan_select_bloc.dart index b74c0ed..dcf6070 100644 --- a/lib/presentation/plans/plan_select_screen/bloc/plan_select_bloc.dart +++ b/lib/presentation/plans/plan_select_screen/bloc/plan_select_bloc.dart @@ -1,17 +1,17 @@ //import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/plans/plan_select_screen/models/plan_select_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/plans/plan_select_screen/models/plan_select_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; + +import '/core/app_export.dart'; part 'plan_select_event.dart'; part 'plan_select_state.dart'; @@ -33,7 +33,7 @@ class PlanSelectBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/plans/index'), + Uri.parse(baseUrl + '/api/plans/index'), ); print('Got response'); if (response.statusCode == 200) { @@ -44,15 +44,19 @@ class PlanSelectBloc extends Bloc { if (state is PlanSelectLoadedState) { print('Got loaded'); var currentState = state as PlanSelectLoadedState; - emit((currentState).copyWith( - posts: data, - myProfileModelObj: currentState.myProfileModelObj, - )); + emit( + (currentState).copyWith( + posts: data, + myProfileModelObj: currentState.myProfileModelObj, + ), + ); } else { print('Got unloaded'); - emit(PlanSelectLoadedState( - posts: data, - )); + emit( + PlanSelectLoadedState( + posts: data, + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку diff --git a/lib/presentation/plans/plan_select_screen/bloc/plan_select_event.dart b/lib/presentation/plans/plan_select_screen/bloc/plan_select_event.dart index 5cb4b41..1cae632 100644 --- a/lib/presentation/plans/plan_select_screen/bloc/plan_select_event.dart +++ b/lib/presentation/plans/plan_select_screen/bloc/plan_select_event.dart @@ -17,7 +17,9 @@ class PlanSelectInitialEvent extends PlanSelectEvent { class UploadAvatar extends PlanSelectEvent { UploadAvatar(this.image); + final XFile image; + @override List get props => [image]; } diff --git a/lib/presentation/plans/plan_select_screen/bloc/plan_select_state.dart b/lib/presentation/plans/plan_select_screen/bloc/plan_select_state.dart index 5ab68c2..b5245be 100644 --- a/lib/presentation/plans/plan_select_screen/bloc/plan_select_state.dart +++ b/lib/presentation/plans/plan_select_screen/bloc/plan_select_state.dart @@ -12,22 +12,22 @@ class PlanSelectState extends Equatable { } class PlanSelectInitialState extends PlanSelectState { - PlanSelectInitialState({required PlanSelectModel myProfileModelObj}) - : super(myProfileModelObj: myProfileModelObj); + PlanSelectInitialState({required PlanSelectModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj); } /// Represents the state of PlanSelect in the application. class PlanSelectLoadedState extends PlanSelectState { - PlanSelectLoadedState({this.myProfileModelObj, this.posts}) - : super(myProfileModelObj: null); + PlanSelectLoadedState({this.myProfileModelObj, this.posts}) : super(myProfileModelObj: null); PlanSelectModel? myProfileModelObj; List? posts; + @override List get props => [ myProfileModelObj, posts, ]; + PlanSelectLoadedState copyWith({ PlanSelectModel? myProfileModelObj, List? posts, diff --git a/lib/presentation/plans/plan_select_screen/plan_select_screen.dart b/lib/presentation/plans/plan_select_screen/plan_select_screen.dart index 810bd3a..1508c75 100644 --- a/lib/presentation/plans/plan_select_screen/plan_select_screen.dart +++ b/lib/presentation/plans/plan_select_screen/plan_select_screen.dart @@ -1,19 +1,20 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/plan_select_bloc.dart'; import 'models/plan_select_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; class PlanSelectScreen extends StatelessWidget { static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => PlanSelectBloc(PlanSelectState(myProfileModelObj: PlanSelectModel()))..add(PlanSelectInitialEvent()), child: PlanSelectScreen()); + create: (context) => PlanSelectBloc(PlanSelectState(myProfileModelObj: PlanSelectModel()))..add(PlanSelectInitialEvent()), + child: PlanSelectScreen(), + ); } Widget build(BuildContext context) { @@ -95,14 +96,14 @@ class PlanSelectScreen extends StatelessWidget { onTap: () => GoRouter.of(context).goNamed('planCreateScreen'), child: Icon(Icons.create_outlined), ), - ) + ), ], ), ), ), ), SizedBox(height: 20), - _buildPlanList(context, state) + _buildPlanList(context, state), ], ), ), @@ -133,7 +134,7 @@ class PlanSelectScreen extends StatelessWidget { ), child: ListTile( leading: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + post['image'], + imageUrl: baseUrl + '/storage/' + post['image'], imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, diff --git a/lib/presentation/plans/plan_show_screen/bloc/plan_show_bloc.dart b/lib/presentation/plans/plan_show_screen/bloc/plan_show_bloc.dart index e920db8..ad9a7a4 100644 --- a/lib/presentation/plans/plan_show_screen/bloc/plan_show_bloc.dart +++ b/lib/presentation/plans/plan_show_screen/bloc/plan_show_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/plans/plan_show_screen/models/plan_show_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/plans/plan_show_screen/models/plan_show_model.dart'; -import 'package:go_router/go_router.dart'; part 'plan_show_event.dart'; - part 'plan_show_state.dart'; /// A bloc that manages the state of a Plan according to the event that is dispatched to it. @@ -34,7 +33,7 @@ class PlanBloc extends Bloc { } final String? planID = state.planModelObj?.planID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/plans/show/$planID'), + Uri.parse(baseUrl + '/api/plans/show/$planID'), headers: { 'Authorization': 'Bearer $token', }, @@ -70,7 +69,7 @@ class PlanBloc extends Bloc { } final int id = event.id; final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/plans/delete/$id'), + Uri.parse(baseUrl + '/api/plans/delete/$id'), headers: { 'Authorization': 'Bearer $token', }, diff --git a/lib/presentation/plans/plan_show_screen/bloc/plan_show_event.dart b/lib/presentation/plans/plan_show_screen/bloc/plan_show_event.dart index fc83e02..6572e25 100644 --- a/lib/presentation/plans/plan_show_screen/bloc/plan_show_event.dart +++ b/lib/presentation/plans/plan_show_screen/bloc/plan_show_event.dart @@ -17,7 +17,9 @@ class PlanInitialEvent extends PlanEvent { class DeleteEntry extends PlanEvent { DeleteEntry(this.id); + final int id; + @override List get props => [id]; } diff --git a/lib/presentation/plans/plan_show_screen/bloc/plan_show_state.dart b/lib/presentation/plans/plan_show_screen/bloc/plan_show_state.dart index cefb6cf..127be04 100644 --- a/lib/presentation/plans/plan_show_screen/bloc/plan_show_state.dart +++ b/lib/presentation/plans/plan_show_screen/bloc/plan_show_state.dart @@ -14,6 +14,7 @@ class PlanState extends Equatable { @override List get props => [planModelObj]; + PlanState copyWith({PlanModel? planModelObj}) { return PlanState( planModelObj: planModelObj ?? this.planModelObj, @@ -26,10 +27,11 @@ class PlanLoadedState extends PlanState { PlanModel? planModelObj; Map? plan; + @override List get props => [planModelObj, plan]; - PlanLoadedState copyWith( - {PlanModel? planModelObj, Map? plan}) { + + PlanLoadedState copyWith({PlanModel? planModelObj, Map? plan}) { return PlanLoadedState( planModelObj: planModelObj ?? this.planModelObj, plan: plan ?? this.plan, @@ -47,6 +49,5 @@ class PlanErrorState extends PlanState { } class PlanInitialState extends PlanState { - PlanInitialState({required PlanModel planModelObj}) - : super(planModelObj: planModelObj); + PlanInitialState({required PlanModel planModelObj}) : super(planModelObj: planModelObj); } diff --git a/lib/presentation/plans/plan_show_screen/plan_show_screen.dart b/lib/presentation/plans/plan_show_screen/plan_show_screen.dart index a19f6da..bf61868 100644 --- a/lib/presentation/plans/plan_show_screen/plan_show_screen.dart +++ b/lib/presentation/plans/plan_show_screen/plan_show_screen.dart @@ -1,12 +1,10 @@ - +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/plan_show_bloc.dart'; import 'models/plan_show_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; class PlanScreen extends StatelessWidget { const PlanScreen({Key? key}) : super(key: key); @@ -14,7 +12,9 @@ class PlanScreen extends StatelessWidget { static Widget builder(BuildContext context) { final planID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => PlanBloc(PlanState(planModelObj: PlanModel(planID: planID.toString())))..add(PlanInitialEvent()), child: PlanScreen()); + create: (context) => PlanBloc(PlanState(planModelObj: PlanModel(planID: planID.toString())))..add(PlanInitialEvent()), + child: PlanScreen(), + ); } Widget build(BuildContext context) { @@ -69,44 +69,47 @@ class PlanScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.plan?['image'] ?? ''), - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, - ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, - ), - ), - SizedBox(height: 16.0), - Text(state.plan?['name'], style: CustomTextStyles.titleMediumBlack), - SizedBox(height: 8.0), - Text( - state.plan?['details'], - ), - SizedBox(height: 16.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - ElevatedButton( - onPressed: () { - // Действие для редактирования - }, - child: Text('Редактировать'), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (state.plan?['image'] ?? ''), + imageBuilder: (context, imageProvider) => CircleAvatar( + backgroundImage: imageProvider, + radius: 25, ), - ElevatedButton( - onPressed: () => context.read().add(DeleteEntry(state.plan?['id'])), - child: Text('Удалить'), + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => CircleAvatar( + child: Icon(Icons.person), + backgroundColor: Colors.white, + radius: 25, ), - ], - ) - ]), - ) + ), + SizedBox(height: 16.0), + Text(state.plan?['name'], style: CustomTextStyles.titleMediumBlack), + SizedBox(height: 8.0), + Text( + state.plan?['details'], + ), + SizedBox(height: 16.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + onPressed: () { + // Действие для редактирования + }, + child: Text('Редактировать'), + ), + ElevatedButton( + onPressed: () => context.read().add(DeleteEntry(state.plan?['id'])), + child: Text('Удалить'), + ), + ], + ), + ], + ), + ), ], ), ), diff --git a/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart b/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart index db799d2..8b01f61 100644 --- a/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart +++ b/lib/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart @@ -1,17 +1,17 @@ //import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; + +import '/core/app_export.dart'; part 'my_profile_event.dart'; part 'my_profile_state.dart'; @@ -36,7 +36,7 @@ class MyProfileBloc extends Bloc { //final token = // "9|laravel_sanctum_KFXbccDcWEvTPfJmV99EQv1ne AggmpR2TidVGDPN34fa201a"; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/index'), + Uri.parse(baseUrl + '/api/profile/index'), headers: { 'Authorization': 'Bearer $token', }, @@ -48,10 +48,10 @@ class MyProfileBloc extends Bloc { data.containsKey('userDetails') && data.containsKey('chartPoints') && data.containsKey('circumferences')) { - final avatarBox = await Hive.openBox('avatar'); - final avatar = data['user']['profile_photo_path']; - print(avatar); - avatarBox.put('avatar', avatar); + final avatarBox = await Hive.openBox('avatar'); + final avatar = data['user']['profile_photo_path']; + print(avatar); + avatarBox.put('avatar', avatar); if (state is MyProfileLoadedState) { var currentState = state as MyProfileLoadedState; var plans = [] @@ -61,46 +61,44 @@ class MyProfileBloc extends Bloc { ..addAll(data["paidPlan"]) ..addAll(data["requestedPlan"]) ..addAll(data["initedPlan"]); - emit((currentState).copyWith( - chartPoints: currentState.chartPoints, - chartDates: currentState.chartDates, - circumferences: currentState.circumferences, - user: data['user'], - userDetails: data['userDetails'], - plans: plans, - token: token, - chestCircumferenceController: TextEditingController(), - waistCircumferenceController: TextEditingController(), - hipCircumferenceController: TextEditingController(), - weightController: TextEditingController(), - chestCircumferenceFormController: - currentState.chestCircumferenceFormController, - waistCircumferenceFormController: - currentState.waistCircumferenceFormController, - hipCircumferenceFormController: - currentState.hipCircumferenceFormController, - firstNameFormController: currentState.firstNameFormController, - lastNameFormController: currentState.lastNameFormController, - countryFormController: currentState.countryFormController, - cityFormController: currentState.cityFormController, - heightFormController: currentState.heightFormController, - upPressureFormController: currentState.upPressureFormController, - downPressureFormController: - currentState.downPressureFormController, - allergiesFormController: currentState.allergiesFormController, - pillsFormController: currentState.pillsFormController, - favoriteFormController: currentState.favoriteFormController, - unfavoriteFormController: currentState.unfavoriteFormController, - additionalFormController: currentState.additionalFormController, - sportsFormController: currentState.sportsFormController, - dateFormController: currentState.dateFormController, - hypoFormController: currentState.hypoFormController, - hyperFormController: currentState.hyperFormController, - selectedCity: currentState.selectedCity, - selectedCountry: currentState.selectedCountry, - selectedActivity: currentState.selectedActivity, - myProfileModelObj: currentState.myProfileModelObj, - )); + emit( + (currentState).copyWith( + chartPoints: currentState.chartPoints, + chartDates: currentState.chartDates, + circumferences: currentState.circumferences, + user: data['user'], + userDetails: data['userDetails'], + plans: plans, + token: token, + chestCircumferenceController: TextEditingController(), + waistCircumferenceController: TextEditingController(), + hipCircumferenceController: TextEditingController(), + weightController: TextEditingController(), + chestCircumferenceFormController: currentState.chestCircumferenceFormController, + waistCircumferenceFormController: currentState.waistCircumferenceFormController, + hipCircumferenceFormController: currentState.hipCircumferenceFormController, + firstNameFormController: currentState.firstNameFormController, + lastNameFormController: currentState.lastNameFormController, + countryFormController: currentState.countryFormController, + cityFormController: currentState.cityFormController, + heightFormController: currentState.heightFormController, + upPressureFormController: currentState.upPressureFormController, + downPressureFormController: currentState.downPressureFormController, + allergiesFormController: currentState.allergiesFormController, + pillsFormController: currentState.pillsFormController, + favoriteFormController: currentState.favoriteFormController, + unfavoriteFormController: currentState.unfavoriteFormController, + additionalFormController: currentState.additionalFormController, + sportsFormController: currentState.sportsFormController, + dateFormController: currentState.dateFormController, + hypoFormController: currentState.hypoFormController, + hyperFormController: currentState.hyperFormController, + selectedCity: currentState.selectedCity, + selectedCountry: currentState.selectedCountry, + selectedActivity: currentState.selectedActivity, + myProfileModelObj: currentState.myProfileModelObj, + ), + ); } else { var plans = [] ..addAll(data["finishedPlans"]) @@ -135,7 +133,7 @@ class MyProfileBloc extends Bloc { "0000-00-00 00:00:00", "0000-00-00 00:00:00", "0000-00-00 00:00:00", - "0000-00-00 00:00:00" + "0000-00-00 00:00:00", ]; for (int i = 0; i < data["circumferences"].length; i++) { dates[i] = data["circumferences"]['$i']["created_at"]; @@ -147,7 +145,7 @@ class MyProfileBloc extends Bloc { "user_id": 0, "weight": 0, "created_at": "0000-00-00 00:00:00", - "updated_at": "0000-00-00 00:00:00" + "updated_at": "0000-00-00 00:00:00", }; } } @@ -161,72 +159,87 @@ class MyProfileBloc extends Bloc { "waist_circumference": 0, "hip_circumference": 0, "created_at": "0000-00-00 00:00:00", - "updated_at": "0000-00-00 00:00:00" + "updated_at": "0000-00-00 00:00:00", }; } } - emit(MyProfileLoadedState( - chartPoints: chartPoints, - chartDates: dates, - circumferences: circumferences, - user: data['user'], - userDetails: data['userDetails'], - plans: plans, - token: token, - chestCircumferenceController: TextEditingController(), - waistCircumferenceController: TextEditingController(), - hipCircumferenceController: TextEditingController(), - hypoFormController: data['userDetails']['has_hypo'].toString(), - hyperFormController: data['userDetails']['has_hyper'].toString(), - chestCircumferenceFormController: TextEditingController( - text: data['userDetails']['chest_circumference']?.toString()), - waistCircumferenceFormController: TextEditingController( - text: data['userDetails']['waist_circumference']?.toString()), - hipCircumferenceFormController: TextEditingController( - text: data['userDetails']['hip_circumference']?.toString()), - weightController: TextEditingController( - text: data['userDetails']['weight']?.toString()), - weightFormController: TextEditingController( - text: data['userDetails']['weight']?.toString()), - firstNameFormController: TextEditingController( - text: data['userDetails']['first_name']), - lastNameFormController: - TextEditingController(text: data['userDetails']['last_name']), - countryFormController: - TextEditingController(text: data['userDetails']['country']), - cityFormController: - TextEditingController(text: data['userDetails']['city']), - heightFormController: TextEditingController( - text: data['userDetails']['height']?.toString()), - upPressureFormController: TextEditingController( - text: data['userDetails']['blood_pressure_up']?.toString()), - downPressureFormController: TextEditingController( - text: data['userDetails']['blood_pressure_down']?.toString()), - allergiesFormController: TextEditingController( - text: data['userDetails']['about_alergy']), - pillsFormController: TextEditingController( - text: data['userDetails']['about_taking_pils']), - sportsFormController: TextEditingController( - text: data['userDetails']['about_sport_hobbies']), - favoriteFormController: TextEditingController( - text: data['userDetails']['favorite_foods']), - unfavoriteFormController: TextEditingController( - text: data['userDetails']['unfavorite_foods']), - additionalFormController: TextEditingController( - text: data['userDetails']['additional_info']), - dateFormController: - TextEditingController(text: data['userDetails']['birthdate']), - selectedCity: data['userDetails']['city'], - selectedCountry: data['userDetails']['country'], - selectedActivity: determineActivityLevel( - data['userDetails']['activity_coefficient']), - )); + emit( + MyProfileLoadedState( + chartPoints: chartPoints, + chartDates: dates, + circumferences: circumferences, + user: data['user'], + userDetails: data['userDetails'], + plans: plans, + token: token, + chestCircumferenceController: TextEditingController(), + waistCircumferenceController: TextEditingController(), + hipCircumferenceController: TextEditingController(), + hypoFormController: data['userDetails']['has_hypo'].toString(), + hyperFormController: data['userDetails']['has_hyper'].toString(), + chestCircumferenceFormController: TextEditingController( + text: data['userDetails']['chest_circumference']?.toString(), + ), + waistCircumferenceFormController: TextEditingController( + text: data['userDetails']['waist_circumference']?.toString(), + ), + hipCircumferenceFormController: TextEditingController( + text: data['userDetails']['hip_circumference']?.toString(), + ), + weightController: TextEditingController( + text: data['userDetails']['weight']?.toString(), + ), + weightFormController: TextEditingController( + text: data['userDetails']['weight']?.toString(), + ), + firstNameFormController: TextEditingController( + text: data['userDetails']['first_name'], + ), + lastNameFormController: TextEditingController(text: data['userDetails']['last_name']), + countryFormController: TextEditingController(text: data['userDetails']['country']), + cityFormController: TextEditingController(text: data['userDetails']['city']), + heightFormController: TextEditingController( + text: data['userDetails']['height']?.toString(), + ), + upPressureFormController: TextEditingController( + text: data['userDetails']['blood_pressure_up']?.toString(), + ), + downPressureFormController: TextEditingController( + text: data['userDetails']['blood_pressure_down']?.toString(), + ), + allergiesFormController: TextEditingController( + text: data['userDetails']['about_alergy'], + ), + pillsFormController: TextEditingController( + text: data['userDetails']['about_taking_pils'], + ), + sportsFormController: TextEditingController( + text: data['userDetails']['about_sport_hobbies'], + ), + favoriteFormController: TextEditingController( + text: data['userDetails']['favorite_foods'], + ), + unfavoriteFormController: TextEditingController( + text: data['userDetails']['unfavorite_foods'], + ), + additionalFormController: TextEditingController( + text: data['userDetails']['additional_info'], + ), + dateFormController: TextEditingController(text: data['userDetails']['birthdate']), + selectedCity: data['userDetails']['city'], + selectedCountry: data['userDetails']['country'], + selectedActivity: determineActivityLevel( + data['userDetails']['activity_coefficient'], + ), + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку emit( - MyProfileErrorState('Некоторые необходимые данные отсутствуют.')); + MyProfileErrorState('Некоторые необходимые данные отсутствуют.'), + ); } } else { // Статус ответа не равен 200, обрабатываем ошибку @@ -253,16 +266,19 @@ class MyProfileBloc extends Bloc { } // колхоз, но свитчкейсы в дарте странно ведут себя при сравнении double Future _uploadAvatar( - UploadAvatar event, Emitter emit) async { + UploadAvatar event, + Emitter emit, + ) async { if (state is MyProfileLoadedState) { var currentState = state as MyProfileLoadedState; await uploadImageToServer(event.image.path, currentState.token); + this.add(MyProfileInitialEvent()); } } Future uploadImageToServer(String imagePath, String? token) async { - String url = '${dotenv.env['SERVER_ROOT']!}/profile/photo/upload'; + String url = '${baseUrl}/api/profile/photo/upload'; print(url); var request = http.MultipartRequest('POST', Uri.parse(url)); request.headers['Authorization'] = 'Bearer $token'; @@ -279,7 +295,8 @@ class MyProfileBloc extends Bloc { return imageUrl; } else { throw Exception( - 'Failed to upload image. Status code: ${streamedResponse.statusCode} ${streamedResponse}}'); + 'Failed to upload image. Status code: ${streamedResponse.statusCode} ${streamedResponse}}', + ); } } } diff --git a/lib/presentation/profile/my_profile_screen/bloc/my_profile_event.dart b/lib/presentation/profile/my_profile_screen/bloc/my_profile_event.dart index ca76f24..e682252 100644 --- a/lib/presentation/profile/my_profile_screen/bloc/my_profile_event.dart +++ b/lib/presentation/profile/my_profile_screen/bloc/my_profile_event.dart @@ -17,7 +17,9 @@ class MyProfileInitialEvent extends MyProfileEvent { class UploadAvatar extends MyProfileEvent { UploadAvatar(this.image); + final XFile image; + @override List get props => [image]; } diff --git a/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart b/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart index acf4823..002d6f0 100644 --- a/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart +++ b/lib/presentation/profile/my_profile_screen/bloc/my_profile_state.dart @@ -12,49 +12,48 @@ class MyProfileState extends Equatable { } class MyProfileInitialState extends MyProfileState { - MyProfileInitialState({required MyProfileModel myProfileModelObj}) - : super(myProfileModelObj: myProfileModelObj); + MyProfileInitialState({required MyProfileModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj); } /// Represents the state of MyProfile in the application. class MyProfileLoadedState extends MyProfileState { - MyProfileLoadedState( - {this.chestCircumferenceController, - this.waistCircumferenceController, - this.hipCircumferenceController, - this.myProfileModelObj, - this.weightController, - this.user, - this.userDetails, - this.chartPoints, - this.chartDates, - this.plans, - this.token, - this.selectedCountry, - this.selectedCity, - this.selectedActivity, - this.chestCircumferenceFormController, - this.waistCircumferenceFormController, - this.hipCircumferenceFormController, - this.firstNameFormController, - this.lastNameFormController, - this.countryFormController, - this.dateFormController, - this.cityFormController, - this.heightFormController, - this.weightFormController, - this.upPressureFormController, - this.downPressureFormController, - this.allergiesFormController, - this.pillsFormController, - this.sportsFormController, - this.favoriteFormController, - this.unfavoriteFormController, - this.additionalFormController, - this.hypoFormController, - this.hyperFormController, - this.circumferences}) - : super(myProfileModelObj: null); + MyProfileLoadedState({ + this.chestCircumferenceController, + this.waistCircumferenceController, + this.hipCircumferenceController, + this.myProfileModelObj, + this.weightController, + this.user, + this.userDetails, + this.chartPoints, + this.chartDates, + this.plans, + this.token, + this.selectedCountry, + this.selectedCity, + this.selectedActivity, + this.chestCircumferenceFormController, + this.waistCircumferenceFormController, + this.hipCircumferenceFormController, + this.firstNameFormController, + this.lastNameFormController, + this.countryFormController, + this.dateFormController, + this.cityFormController, + this.heightFormController, + this.weightFormController, + this.upPressureFormController, + this.downPressureFormController, + this.allergiesFormController, + this.pillsFormController, + this.sportsFormController, + this.favoriteFormController, + this.unfavoriteFormController, + this.additionalFormController, + this.hypoFormController, + this.hyperFormController, + this.circumferences, + }) : super(myProfileModelObj: null); MyProfileModel? myProfileModelObj; Map? user; @@ -91,6 +90,7 @@ class MyProfileLoadedState extends MyProfileState { String? selectedActivity; String? hypoFormController; String? hyperFormController; + @override List get props => [ myProfileModelObj, @@ -128,6 +128,7 @@ class MyProfileLoadedState extends MyProfileState { hypoFormController, hyperFormController, ]; + MyProfileLoadedState copyWith({ MyProfileModel? myProfileModelObj, Map? user, @@ -174,42 +175,27 @@ class MyProfileLoadedState extends MyProfileState { chartPoints: chartPoints ?? this.chartPoints, chartDates: chartDates ?? this.chartDates, weightController: weightController ?? this.weightController, - chestCircumferenceController: - chestCircumferenceController ?? this.chestCircumferenceController, - waistCircumferenceController: - waistCircumferenceController ?? this.waistCircumferenceController, - hipCircumferenceController: - hipCircumferenceController ?? this.hipCircumferenceController, - chestCircumferenceFormController: chestCircumferenceFormController ?? - this.chestCircumferenceFormController, - waistCircumferenceFormController: waistCircumferenceFormController ?? - this.waistCircumferenceFormController, - hipCircumferenceFormController: - hipCircumferenceFormController ?? this.hipCircumferenceFormController, - firstNameFormController: - firstNameFormController ?? this.firstNameFormController, - lastNameFormController: - lastNameFormController ?? this.lastNameFormController, - countryFormController: - countryFormController ?? this.countryFormController, + chestCircumferenceController: chestCircumferenceController ?? this.chestCircumferenceController, + waistCircumferenceController: waistCircumferenceController ?? this.waistCircumferenceController, + hipCircumferenceController: hipCircumferenceController ?? this.hipCircumferenceController, + chestCircumferenceFormController: chestCircumferenceFormController ?? this.chestCircumferenceFormController, + waistCircumferenceFormController: waistCircumferenceFormController ?? this.waistCircumferenceFormController, + hipCircumferenceFormController: hipCircumferenceFormController ?? this.hipCircumferenceFormController, + firstNameFormController: firstNameFormController ?? this.firstNameFormController, + lastNameFormController: lastNameFormController ?? this.lastNameFormController, + countryFormController: countryFormController ?? this.countryFormController, dateFormController: dateFormController ?? this.dateFormController, cityFormController: cityFormController ?? this.cityFormController, heightFormController: heightFormController ?? this.heightFormController, weightFormController: weightFormController ?? this.weightFormController, - upPressureFormController: - upPressureFormController ?? this.upPressureFormController, - downPressureFormController: - downPressureFormController ?? this.downPressureFormController, - allergiesFormController: - allergiesFormController ?? this.allergiesFormController, + upPressureFormController: upPressureFormController ?? this.upPressureFormController, + downPressureFormController: downPressureFormController ?? this.downPressureFormController, + allergiesFormController: allergiesFormController ?? this.allergiesFormController, pillsFormController: pillsFormController ?? this.pillsFormController, sportsFormController: sportsFormController ?? this.sportsFormController, - favoriteFormController: - favoriteFormController ?? this.favoriteFormController, - unfavoriteFormController: - unfavoriteFormController ?? this.unfavoriteFormController, - additionalFormController: - additionalFormController ?? this.additionalFormController, + favoriteFormController: favoriteFormController ?? this.favoriteFormController, + unfavoriteFormController: unfavoriteFormController ?? this.unfavoriteFormController, + additionalFormController: additionalFormController ?? this.additionalFormController, token: token ?? this.token, selectedCountry: selectedCountry ?? this.selectedCountry, selectedCity: selectedCity ?? this.selectedCity, diff --git a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart index e6f9706..d10b70a 100644 --- a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart +++ b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart @@ -1,21 +1,21 @@ -import 'package:go_router/go_router.dart'; +import 'dart:convert'; +import 'dart:math'; -import 'bloc/my_profile_bloc.dart'; -import 'models/my_profile_model.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:carousel_slider_plus/carousel_slider_plus.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:carousel_slider/carousel_slider.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/services.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:http/http.dart' as http; import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; -import 'dart:math'; -import 'dart:convert'; + +import 'bloc/my_profile_bloc.dart'; +import 'models/my_profile_model.dart'; class MyProfileScreen extends StatelessWidget { static Widget builder(BuildContext context) { @@ -96,6 +96,27 @@ class MyProfileScreen extends StatelessWidget { ), SizedBox(height: 15.v), Container( + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: _buildCarousel(context, state), + ), + SizedBox(height: 15.v), + if (!state.plans!.isEmpty) + Container( padding: EdgeInsets.symmetric( horizontal: 24.h, vertical: 12.v, @@ -112,32 +133,13 @@ class MyProfileScreen extends StatelessWidget { ), ], ), - child: _buildCarousel(context, state)), - SizedBox(height: 15.v), - if (!state.plans!.isEmpty) - Container( - padding: EdgeInsets.symmetric( - horizontal: 24.h, - vertical: 12.v, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: _buildPlans( - context, - state.plans?.map((plan) => plan['name']).toList(), - state.plans?.map((plan) => plan['image']).toList(), - state.plans?.map((plan) => plan['state']).toList(), - )), + child: _buildPlans( + context, + state.plans?.map((plan) => plan['name']).toList(), + state.plans?.map((plan) => plan['image']).toList(), + state.plans?.map((plan) => plan['state']).toList(), + ), + ), SizedBox(height: 5.v), ], ), @@ -154,7 +156,7 @@ class MyProfileScreen extends StatelessWidget { GestureDetector( onTap: () => addImage(context), child: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.user?['profile_photo_path'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.user?['profile_photo_path'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 60, @@ -175,13 +177,11 @@ class MyProfileScreen extends StatelessWidget { } addImage(BuildContext context) async { - final picker = ImagePicker(); - List? images = await picker.pickMultiImage(); - if (images.isNotEmpty) { - for (var image in images) { - context.read().add(UploadAvatar(image)); - } - } + final picker = ImagePicker(); + XFile? image = await picker.pickImage(source: ImageSource.gallery); + if (image != null) { + context.read().add(UploadAvatar(image)); + } } onTapSettings(BuildContext context) { @@ -192,15 +192,16 @@ class MyProfileScreen extends StatelessWidget { _buildCarousel(BuildContext contex, MyProfileLoadedState state) { return CarouselSlider( - options: CarouselOptions(height: 320.0), + options: CarouselOptions(height: 340), items: [1, 2, 3].map((chartType) { return Builder( builder: (BuildContext context) { switch (chartType) { case 1: // График веса return GestureDetector( - onTap: () => _editWeight(context, state), - child: Column(children: [ + onTap: () => _editWeight(context, state), + child: Column( + children: [ Text( "weight_chart".tr, style: CustomTextStyles.titleMediumBlack.copyWith( @@ -212,27 +213,35 @@ class MyProfileScreen extends StatelessWidget { context, state.chartPoints?.values.map((e) => e['weight']).toList().map((i) => i.toDouble()).toList() ?? [0.0, 0.0, 0.0, 0.0], state.chartDates, - ) - ])); - case 2: // График ИМТ - return Column(children: [ - Text( - "bodymass_chart".tr, - style: CustomTextStyles.titleMediumBlack.copyWith( - color: appTheme.black900, - ), + ), + ], ), - SizedBox(height: 50.v), - _buildChart( + ); + case 2: // График ИМТ + return Column( + children: [ + Text( + "bodymass_chart".tr, + style: CustomTextStyles.titleMediumBlack.copyWith( + color: appTheme.black900, + ), + ), + SizedBox(height: 50.v), + _buildChart( context, - _bodyMassIndex(state.chartPoints?.values.map((e) => e['weight']).toList().map((i) => i.toDouble()).toList() ?? [0.0, 0.0, 0.0, 0.0], - state.userDetails?['height'].toInt() ?? 160), - state.chartDates), - ]); + _bodyMassIndex( + state.chartPoints?.values.map((e) => e['weight']).toList().map((i) => i.toDouble()).toList() ?? [0.0, 0.0, 0.0, 0.0], + state.userDetails?['height'].toInt() ?? 160, + ), + state.chartDates, + ), + ], + ); case 3: //График обхватов return GestureDetector( - onTap: () => _editCircumference(context, state), - child: Column(children: [ + onTap: () => _editCircumference(context, state), + child: Column( + children: [ Text( "circumferences_chart".tr, style: CustomTextStyles.titleMediumBlack.copyWith( @@ -241,8 +250,10 @@ class MyProfileScreen extends StatelessWidget { ), SizedBox(height: 30.v), _buildCircumferenceChart(context, state.circumferences, state.chartDates), - _buildChartLegend() - ])); + _buildChartLegend(), + ], + ), + ); default: return Text('text', style: TextStyle(fontSize: 16.0)); } @@ -342,7 +353,7 @@ class MyProfileScreen extends StatelessWidget { lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( maxContentWidth: 100, - tooltipBgColor: Colors.black, + // tooltipBgColor: Colors.black, getTooltipItems: mapSpots(), ), handleBuiltInTouches: true, @@ -519,7 +530,7 @@ class MyProfileScreen extends StatelessWidget { lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( maxContentWidth: 100, - tooltipBgColor: Colors.black, + // tooltipBgColor: Colors.black, getTooltipItems: mapTouchedSpots(), ), handleBuiltInTouches: true, @@ -636,79 +647,108 @@ class MyProfileScreen extends StatelessWidget { /// Section Widget _buildPlans(BuildContext context, List? plans, List? imagePaths, List? states) { return Padding( - padding: EdgeInsets.only(left: 7.h), - child: Column(children: [ + padding: EdgeInsets.only(left: 7.h), + child: Column( + children: [ Padding( - padding: EdgeInsets.only(left: 15.h), - child: Text("plans_complete".tr, style: CustomTextStyles.titleMediumBlack.copyWith(color: appTheme.black900))), + padding: EdgeInsets.only(left: 15.h), + child: Text("plans_complete".tr, style: CustomTextStyles.titleMediumBlack.copyWith(color: appTheme.black900)), + ), SizedBox(height: 5.v), Container( - decoration: AppDecoration.outlineBlueGray.copyWith(borderRadius: BorderRadiusStyle.roundedBorder5), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + decoration: AppDecoration.outlineBlueGray.copyWith(borderRadius: BorderRadiusStyle.roundedBorder5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ SizedBox( - height: 105.v, - width: 343.h, - child: Stack(alignment: Alignment.bottomCenter, children: [ + height: 105.v, + width: 343.h, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ Align( - alignment: Alignment.topCenter, - child: ListView.builder( - itemCount: plans?.length ?? 0, - itemBuilder: (context, i) { - String state = states?[i]; - var boxColor = appTheme.greenA700; - switch (states?[i]) { - case 'active': - boxColor = appTheme.greenA700; - break; - case 'archived': // График ИМТ - boxColor = appTheme.gray400; - break; - case 'draft': - boxColor = appTheme.deepOrange900; - break; - case 'in_progress': //График обхватов - boxColor = appTheme.lightGreen300; - break; - } - return SizedBox( - height: 40.v, - width: 343.h, - child: Stack(alignment: Alignment.bottomRight, children: [ - Align( - alignment: Alignment.topCenter, - child: Container( - margin: EdgeInsets.only(bottom: 11.v), - padding: EdgeInsets.symmetric(horizontal: 6.h, vertical: 4.v), - decoration: AppDecoration.fillGray.copyWith(borderRadius: BorderRadiusStyle.roundedBorder5), - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: EdgeInsets.only(bottom: 1.v), - child: Text(plans![i], style: CustomTextStyles.titleSmallBluegray800Bold)), - Container( - height: 19.v, - width: 100.h, - decoration: BoxDecoration(color: boxColor, borderRadius: BorderRadius.circular(5.h))) - ]))), - Align( - alignment: Alignment.center, - child: Container( - margin: EdgeInsets.only(bottom: 12.h), - child: Image.network( - dotenv.env['STORAGE_URL']! + imagePaths?[i], - height: 25.adaptSize, - width: 25.adaptSize, - ))), - Align( - alignment: Alignment.bottomRight, - child: Container( - width: 70.h, - margin: EdgeInsets.only(bottom: 14.h, right: 22.h), - child: Text("$state".tr, maxLines: 3, overflow: TextOverflow.ellipsis, style: theme.textTheme.titleSmall))) - ])); - })), - ])) - ])) - ])); + alignment: Alignment.topCenter, + child: ListView.builder( + itemCount: plans?.length ?? 0, + itemBuilder: (context, i) { + String state = states?[i]; + var boxColor = appTheme.greenA700; + switch (states?[i]) { + case 'active': + boxColor = appTheme.greenA700; + break; + case 'archived': // График ИМТ + boxColor = appTheme.gray400; + break; + case 'draft': + boxColor = appTheme.deepOrange900; + break; + case 'in_progress': //График обхватов + boxColor = appTheme.lightGreen300; + break; + } + return SizedBox( + height: 40.v, + width: 343.h, + child: Stack( + alignment: Alignment.bottomRight, + children: [ + Align( + alignment: Alignment.topCenter, + child: Container( + margin: EdgeInsets.only(bottom: 11.v), + padding: EdgeInsets.symmetric(horizontal: 6.h, vertical: 4.v), + decoration: AppDecoration.fillGray.copyWith(borderRadius: BorderRadiusStyle.roundedBorder5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 1.v), + child: Text(plans![i], style: CustomTextStyles.titleSmallBluegray800Bold), + ), + Container( + height: 19.v, + width: 100.h, + decoration: BoxDecoration(color: boxColor, borderRadius: BorderRadius.circular(5.h)), + ), + ], + ), + ), + ), + Align( + alignment: Alignment.center, + child: Container( + margin: EdgeInsets.only(bottom: 12.h), + child: Image.network( + baseUrl + '/storage/' + imagePaths?[i], + height: 25.adaptSize, + width: 25.adaptSize, + ), + ), + ), + Align( + alignment: Alignment.bottomRight, + child: Container( + width: 70.h, + margin: EdgeInsets.only(bottom: 14.h, right: 22.h), + child: Text("$state".tr, maxLines: 3, overflow: TextOverflow.ellipsis, style: theme.textTheme.titleSmall), + ), + ), + ], + ), + ); + }, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); } List _bodyMassIndex(List weightPoints, int height) { @@ -729,48 +769,49 @@ class MyProfileScreen extends StatelessWidget { title: Center(child: Text("Добавить замер")), content: SizedBox( - width: 200, // Ширина диалогового окна - height: 300, // Высота диалогового окна - child: ListView( - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 5.v), - child: Text("chest_circumference".tr, style: theme.textTheme.bodyLarge), - ), - SizedBox(height: 5.v), - CustomTextFormField( - controller: state.chestCircumferenceController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами - ], - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 15.v), - child: Text("waist_circumference".tr, style: theme.textTheme.bodyLarge), - ), - SizedBox(height: 5.v), - CustomTextFormField( - controller: state.waistCircumferenceController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами - ], - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 15.v), - child: Text("hip_circumference".tr, style: theme.textTheme.bodyLarge), - ), - SizedBox(height: 5.v), - CustomTextFormField( - controller: state.hipCircumferenceController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами - ], - ), - ], - )), + width: 200, // Ширина диалогового окна + height: 300, // Высота диалогового окна + child: ListView( + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 5.v), + child: Text("chest_circumference".tr, style: theme.textTheme.bodyLarge), + ), + SizedBox(height: 5.v), + CustomTextFormField( + controller: state.chestCircumferenceController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами + ], + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 15.v), + child: Text("waist_circumference".tr, style: theme.textTheme.bodyLarge), + ), + SizedBox(height: 5.v), + CustomTextFormField( + controller: state.waistCircumferenceController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами + ], + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 15.v), + child: Text("hip_circumference".tr, style: theme.textTheme.bodyLarge), + ), + SizedBox(height: 5.v), + CustomTextFormField( + controller: state.hipCircumferenceController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, // Ограничение ввода только цифрами + ], + ), + ], + ), + ), actions: [ TextButton( onPressed: onTapOk(context), @@ -778,10 +819,12 @@ class MyProfileScreen extends StatelessWidget { ), TextButton( onPressed: sendEditData(state, context), - child: Text("Изменить", - style: CustomTextStyles.titleMediumBlack.copyWith( - color: Colors.blue, - )), + child: Text( + "Изменить", + style: CustomTextStyles.titleMediumBlack.copyWith( + color: Colors.blue, + ), + ), ), ], backgroundColor: Colors.white, @@ -806,7 +849,7 @@ class MyProfileScreen extends StatelessWidget { try { final token = state.token; final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/addCircumference'), + Uri.parse(baseUrl + '/api/profile/addCircumference'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', @@ -824,6 +867,7 @@ class MyProfileScreen extends StatelessWidget { // Обработка ошибок при отправке запроса print("Ошибка при отправке запроса: $e"); } + Navigator.pop(context); }; } @@ -859,10 +903,12 @@ class MyProfileScreen extends StatelessWidget { ), TextButton( onPressed: () => saveWeight(state, context), - child: Text("Изменить", - style: CustomTextStyles.titleMediumBlack.copyWith( - color: Colors.blue, - )), + child: Text( + "Изменить", + style: CustomTextStyles.titleMediumBlack.copyWith( + color: Colors.blue, + ), + ), ), ], backgroundColor: Colors.white, @@ -895,7 +941,7 @@ class MyProfileScreen extends StatelessWidget { try { final token = state.token; final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/addWeight'), + Uri.parse(baseUrl + '/api/profile/addWeight'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', diff --git a/lib/presentation/profile/my_profile_screen/my_settings_screen.dart b/lib/presentation/profile/my_profile_screen/my_settings_screen.dart index a5be7c0..4cd47b1 100644 --- a/lib/presentation/profile/my_profile_screen/my_settings_screen.dart +++ b/lib/presentation/profile/my_profile_screen/my_settings_screen.dart @@ -1,22 +1,24 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_about_list.dart'; +import 'package:eatvio_app/widgets/custom_expandable_list.dart'; +import 'package:eatvio_app/widgets/custom_language_drop_down.dart'; +import 'package:eatvio_app/widgets/custom_notification_screen.dart'; +import 'package:eatvio_app/widgets/custom_section_title.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/my_profile_bloc.dart'; import 'models/my_profile_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/custom_about_list.dart'; -import 'package:eatvio_app/widgets/custom_expandable_list.dart'; -import 'package:eatvio_app/widgets/custom_notification_screen.dart'; -import 'package:eatvio_app/widgets/custom_section_title.dart'; -import 'package:eatvio_app/widgets/custom_language_drop_down.dart'; -import 'package:flutter/material.dart'; class MySettingsScreen extends StatelessWidget { static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent()), child: MySettingsScreen()); + create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent()), + child: MySettingsScreen(), + ); } Widget build(BuildContext context) { @@ -45,7 +47,6 @@ class MySettingsScreen extends StatelessWidget { } _buildSetingsScreen(BuildContext context, MyProfileLoadedState state) { - return Scaffold( appBar: AppBar( toolbarHeight: 0, @@ -64,30 +65,32 @@ class MySettingsScreen extends StatelessWidget { children: [ SizedBox(height: 30), Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: CustomAppBar( - height: 54.v, - leadingWidth: 28.h, - leading: AppbarLeadingImage( - imagePath: ImageConstant.imgArrowLeft, - margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), - onTap: () => GoRouter.of(context).pop(), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), ), - title: Padding( - padding: EdgeInsets.only(left: 20.h), - child: Row(children: [AppbarSubtitle(text: state.user?['name'], margin: EdgeInsets.only(left: 80.h, top: 12.v, bottom: 9.v))])), - )), + ], + ), + child: CustomAppBar( + height: 54.v, + leadingWidth: 28.h, + leading: AppbarLeadingImage( + imagePath: ImageConstant.imgArrowLeft, + margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), + onTap: () => GoRouter.of(context).pop(), + ), + title: Padding( + padding: EdgeInsets.only(left: 20.h), + child: Row(children: [AppbarSubtitle(text: state.user?['name'], margin: EdgeInsets.only(left: 80.h, top: 12.v, bottom: 9.v))]), + ), + ), + ), SizedBox(height: 20), Container( padding: EdgeInsets.symmetric( diff --git a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_bloc.dart b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_bloc.dart index 881e14a..c0b0e2e 100644 --- a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_bloc.dart +++ b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_bloc.dart @@ -1,15 +1,16 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/recipe/recipe_create_screen/models/recipe_create_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/recipe/recipe_create_screen/models/recipe_create_model.dart'; -import 'package:go_router/go_router.dart'; + part 'recipe_create_event.dart'; part 'recipe_create_state.dart'; @@ -34,7 +35,8 @@ class RecipeCreateBloc extends Bloc { } if (state is RecipeCreateLoadedState) { var currentState = state as RecipeCreateLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( recipeModelObj: currentState.recipeModelObj, title: currentState.title, token: currentState.token, @@ -42,62 +44,79 @@ class RecipeCreateBloc extends Bloc { video_url: currentState.video_url, steps: currentState.steps, stepDescriptions: currentState.stepDescriptions, - tags: currentState.tags)); + tags: currentState.tags, + ), + ); } else { final Map step = { 'description': '', 'image': '', }; - emit(RecipeCreateLoadedState( + emit( + RecipeCreateLoadedState( token: token, title: TextEditingController(), description: TextEditingController(), video_url: TextEditingController(), tags: TextEditingController(), stepDescriptions: [TextEditingController()], - steps: [step])); + steps: [step], + ), + ); } } FutureOr _addStep( - AddStep event, Emitter emit) async { + AddStep event, + Emitter emit, + ) async { if (state is RecipeCreateLoadedState) { var currentState = state as RecipeCreateLoadedState; List? updatedSteps = currentState.steps; - List? updatedStepDescriptions = - currentState.stepDescriptions; + List? updatedStepDescriptions = currentState.stepDescriptions; updatedSteps!.add({ 'description': '', 'image': '', }); updatedStepDescriptions!.add(TextEditingController()); - emit(currentState.copyWith( - steps: updatedSteps, stepDescriptions: updatedStepDescriptions)); + emit( + currentState.copyWith( + steps: updatedSteps, + stepDescriptions: updatedStepDescriptions, + ), + ); await _reloadScreen(event, emit); } } FutureOr _removeStep( - RemoveStep event, Emitter emit) async { + RemoveStep event, + Emitter emit, + ) async { if (state is RecipeCreateLoadedState) { var currentState = state as RecipeCreateLoadedState; List? updatedSteps = currentState.steps; - List? updatedStepDescriptions = - currentState.stepDescriptions; + List? updatedStepDescriptions = currentState.stepDescriptions; updatedSteps!.removeAt(event.id); updatedStepDescriptions!.removeAt(event.id); - emit(currentState.copyWith( - steps: updatedSteps, stepDescriptions: updatedStepDescriptions)); + emit( + currentState.copyWith( + steps: updatedSteps, + stepDescriptions: updatedStepDescriptions, + ), + ); await _reloadScreen(event, emit); } } FutureOr _createRecipe( - CreateRecipe event, Emitter emit) async { + CreateRecipe event, + Emitter emit, + ) async { if (state is RecipeCreateLoadedState) { var currentState = state as RecipeCreateLoadedState; @@ -112,14 +131,19 @@ class RecipeCreateBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('recipeSelectScreen'); } else { print( - 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}'); + 'Failed to create blog post. Status Code: ${response.statusCode} ${response.body}', + ); } } } - FutureOr sendRecipe(String? title, String? video_url, - String? description, List? steps) async { - String url = '${dotenv.env['SERVER_ROOT']!}/recipe/create'; + FutureOr sendRecipe( + String? title, + String? video_url, + String? description, + List? steps, + ) async { + String url = '${baseUrl}/api/recipe/create'; final Map credentials = { 'title': title, 'description': description, @@ -141,7 +165,9 @@ class RecipeCreateBloc extends Bloc { } FutureOr _reloadScreen( - RecipeCreateEvent? event, Emitter emit) async { + RecipeCreateEvent? event, + Emitter emit, + ) async { print('Reloading..'); final box = await Hive.openBox('token'); final token = box.get('token'); @@ -150,7 +176,8 @@ class RecipeCreateBloc extends Bloc { } if (state is RecipeCreateLoadedState) { var currentState = state as RecipeCreateLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( recipeModelObj: currentState.recipeModelObj, title: currentState.title, token: currentState.token, @@ -158,7 +185,9 @@ class RecipeCreateBloc extends Bloc { video_url: currentState.video_url, steps: currentState.steps, stepDescriptions: currentState.stepDescriptions, - tags: currentState.tags)); + tags: currentState.tags, + ), + ); } } } diff --git a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_event.dart b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_event.dart index 085045d..85d8ee4 100644 --- a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_event.dart +++ b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_event.dart @@ -22,19 +22,23 @@ class CreateRecipe extends RecipeCreateEvent { class AddStep extends RecipeCreateEvent { AddStep(); + @override List get props => []; } class RemoveStep extends RecipeCreateEvent { RemoveStep(this.id); + final int id; + @override List get props => [id]; } class ReloadScreen extends RecipeCreateEvent { ReloadScreen(); + @override List get props => []; } diff --git a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_state.dart b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_state.dart index 8545b83..d2e1b2b 100644 --- a/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_state.dart +++ b/lib/presentation/recipe/recipe_create_screen/bloc/recipe_create_state.dart @@ -14,6 +14,7 @@ class RecipeCreateState extends Equatable { @override List get props => [recipeModelObj]; + RecipeCreateState copyWith({RecipeCreateModel? recipeModelObj}) { return RecipeCreateState( recipeModelObj: recipeModelObj ?? this.recipeModelObj, @@ -22,15 +23,16 @@ class RecipeCreateState extends Equatable { } class RecipeCreateLoadedState extends RecipeCreateState { - RecipeCreateLoadedState( - {this.recipeModelObj, - this.token, - this.title, - this.description, - this.video_url, - this.tags, - this.stepDescriptions, - this.steps}); + RecipeCreateLoadedState({ + this.recipeModelObj, + this.token, + this.title, + this.description, + this.video_url, + this.tags, + this.stepDescriptions, + this.steps, + }); RecipeCreateModel? recipeModelObj; String? token; @@ -40,6 +42,7 @@ class RecipeCreateLoadedState extends RecipeCreateState { TextEditingController? tags; List? steps; List? stepDescriptions; + @override List get props => [ recipeModelObj, @@ -49,8 +52,9 @@ class RecipeCreateLoadedState extends RecipeCreateState { video_url, steps, tags, - stepDescriptions + stepDescriptions, ]; + RecipeCreateLoadedState copyWith({ RecipeCreateModel? recipeModelObj, String? token, @@ -62,14 +66,15 @@ class RecipeCreateLoadedState extends RecipeCreateState { List? stepDescriptions, }) { return RecipeCreateLoadedState( - recipeModelObj: recipeModelObj ?? this.recipeModelObj, - title: title ?? this.title, - description: description ?? this.description, - video_url: video_url ?? this.video_url, - token: token ?? this.token, - steps: steps ?? this.steps, - tags: tags ?? this.tags, - stepDescriptions: stepDescriptions ?? this.stepDescriptions); + recipeModelObj: recipeModelObj ?? this.recipeModelObj, + title: title ?? this.title, + description: description ?? this.description, + video_url: video_url ?? this.video_url, + token: token ?? this.token, + steps: steps ?? this.steps, + tags: tags ?? this.tags, + stepDescriptions: stepDescriptions ?? this.stepDescriptions, + ); } } @@ -83,6 +88,5 @@ class RecipeCreateErrorState extends RecipeCreateState { } class RecipeCreateInitialState extends RecipeCreateState { - RecipeCreateInitialState({required RecipeCreateModel recipeModelObj}) - : super(recipeModelObj: recipeModelObj); + RecipeCreateInitialState({required RecipeCreateModel recipeModelObj}) : super(recipeModelObj: recipeModelObj); } diff --git a/lib/presentation/recipe/recipe_create_screen/recipe_create_screen.dart b/lib/presentation/recipe/recipe_create_screen/recipe_create_screen.dart index 3a81754..0f8f3f5 100644 --- a/lib/presentation/recipe/recipe_create_screen/recipe_create_screen.dart +++ b/lib/presentation/recipe/recipe_create_screen/recipe_create_screen.dart @@ -1,14 +1,14 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/recipe_create_bloc.dart'; import 'models/recipe_create_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; class RecipeCreateScreen extends StatelessWidget { const RecipeCreateScreen({Key? key}) : super(key: key); @@ -16,9 +16,10 @@ class RecipeCreateScreen extends StatelessWidget { static Widget builder(BuildContext context) { final recipeID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => - RecipeCreateBloc(RecipeCreateState(recipeModelObj: RecipeCreateModel(recipeID: recipeID.toString())))..add(RecipeCreateInitialEvent()), - child: RecipeCreateScreen()); + create: (context) => + RecipeCreateBloc(RecipeCreateState(recipeModelObj: RecipeCreateModel(recipeID: recipeID.toString())))..add(RecipeCreateInitialEvent()), + child: RecipeCreateScreen(), + ); } Widget build(BuildContext context) { @@ -53,29 +54,33 @@ class RecipeCreateScreen extends StatelessWidget { } return RefreshIndicator( - onRefresh: refreshPage(context), - child: Scaffold( - appBar: AppBar( - toolbarHeight: 0, - automaticallyImplyLeading: false, - ), - resizeToAvoidBottomInset: false, - body: Container( - width: double.maxFinite, - decoration: BoxDecoration(color: Colors.grey[200]), - child: ListView(children: [ - _buldAppBar(context), - SizedBox(height: 20.v), - _buildRecipeInfo(state, context), - SizedBox(height: 20.v), - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: steps, - ), - SizedBox(height: 20.v), - _buildAdditional(context, state) - ]), - ))); + onRefresh: refreshPage(context), + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + resizeToAvoidBottomInset: false, + body: Container( + width: double.maxFinite, + decoration: BoxDecoration(color: Colors.grey[200]), + child: ListView( + children: [ + _buldAppBar(context), + SizedBox(height: 20.v), + _buildRecipeInfo(state, context), + SizedBox(height: 20.v), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: steps, + ), + SizedBox(height: 20.v), + _buildAdditional(context, state), + ], + ), + ), + ), + ); } _buldAppBar(BuildContext context) { @@ -102,10 +107,11 @@ class RecipeCreateScreen extends StatelessWidget { onTap: onTapBack(context), ), title: Align( - alignment: Alignment.center, - child: AppbarSubtitle( - text: "Добавление рецепта", - )), + alignment: Alignment.center, + child: AppbarSubtitle( + text: "Добавление рецепта", + ), + ), ), ); } @@ -130,41 +136,44 @@ class RecipeCreateScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Изображение")), - _buildAddPhoto(context, state), - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Название рецепта")), - CustomTextFormField( - controller: state.title, - hintText: "Введите название рецепта", - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Изображение")), + _buildAddPhoto(context, state), + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Название рецепта")), + CustomTextFormField( + controller: state.title, + hintText: "Введите название рецепта", + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Описание")), - CustomTextFormField( - controller: state.description, - hintText: "Введите описание рецепта", - maxLines: 4, - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Описание")), + CustomTextFormField( + controller: state.description, + hintText: "Введите описание рецепта", + maxLines: 4, + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - ]), + SizedBox(height: 16.0), + ], + ), ); } @@ -206,7 +215,7 @@ class RecipeCreateScreen extends StatelessWidget { Icon( Icons.photo_library, color: appTheme.blueGray300, - ) + ), ], ), ), @@ -254,71 +263,74 @@ class RecipeCreateScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - "Шаг ${i + 1}", - style: CustomTextStyles.titleMediumSemiBold, - ), - ), - SizedBox(height: 8.0), - CustomTextFormField( - controller: state.stepDescriptions?[i], - hintText: "Введите описание шага", - maxLines: 4, - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "Шаг ${i + 1}", + style: CustomTextStyles.titleMediumSemiBold, ), ), - ), - SizedBox(height: 16.0), - _buildAddPhoto(context, state), - SizedBox(height: 16.0), - if (isFirstStep && isLastStep) - CustomOutlinedButton( - onPressed: () => context.read().add(AddStep()), - text: "Добавить шаг", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - if (isLastStep && !isFirstStep) // Добавляем кнопку "Добавить шаг" только для последнего шага - Column( - children: [ - SizedBox(height: 16.0), - Row( - children: [ - Flexible( - flex: 5, - child: CustomOutlinedButton( - onPressed: () => context.read().add(AddStep()), - text: "Добавить шаг", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - SizedBox(width: 8), // Add some spacing between the buttons - Flexible( - flex: 1, - child: CustomOutlinedButton( - text: "х", - onPressed: () => context.read().add(RemoveStep(i)), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - ], + SizedBox(height: 8.0), + CustomTextFormField( + controller: state.stepDescriptions?[i], + hintText: "Введите описание шага", + maxLines: 4, + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, ), - ], + ), ), - if (!isLastStep && !isFirstStep) - CustomOutlinedButton( - onPressed: () => context.read().add(RemoveStep(i)), - text: "x", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ]), + SizedBox(height: 16.0), + _buildAddPhoto(context, state), + SizedBox(height: 16.0), + if (isFirstStep && isLastStep) + CustomOutlinedButton( + onPressed: () => context.read().add(AddStep()), + text: "Добавить шаг", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + if (isLastStep && !isFirstStep) // Добавляем кнопку "Добавить шаг" только для последнего шага + Column( + children: [ + SizedBox(height: 16.0), + Row( + children: [ + Flexible( + flex: 5, + child: CustomOutlinedButton( + onPressed: () => context.read().add(AddStep()), + text: "Добавить шаг", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + SizedBox(width: 8), // Add some spacing between the buttons + Flexible( + flex: 1, + child: CustomOutlinedButton( + text: "х", + onPressed: () => context.read().add(RemoveStep(i)), + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + ], + ), + ], + ), + if (!isLastStep && !isFirstStep) + CustomOutlinedButton( + onPressed: () => context.read().add(RemoveStep(i)), + text: "x", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ], + ), ); } @@ -342,40 +354,43 @@ class RecipeCreateScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Align(alignment: Alignment.centerLeft, child: Text("Теги")), - CustomTextFormField( - controller: state.tags, - hintText: "Введите теги, через запятую", - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align(alignment: Alignment.centerLeft, child: Text("Теги")), + CustomTextFormField( + controller: state.tags, + hintText: "Введите теги, через запятую", + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 8.0), - Align(alignment: Alignment.centerLeft, child: Text("Ссылка на видео (необязательно)")), - CustomTextFormField( - controller: state.video_url, - hintText: "YouTube", - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + SizedBox(height: 8.0), + Align(alignment: Alignment.centerLeft, child: Text("Ссылка на видео (необязательно)")), + CustomTextFormField( + controller: state.video_url, + hintText: "YouTube", + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - CustomOutlinedButton( - text: "Добавить рецепт", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ]), + SizedBox(height: 16.0), + CustomOutlinedButton( + text: "Добавить рецепт", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ], + ), ); } diff --git a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_bloc.dart b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_bloc.dart index 9c982dd..560c75e 100644 --- a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_bloc.dart +++ b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_bloc.dart @@ -1,18 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/recipe/recipe_edit_screen/models/recipe_edit_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/recipe/recipe_edit_screen/models/recipe_edit_model.dart'; -import 'package:go_router/go_router.dart'; part 'recipe_edit_event.dart'; - part 'recipe_edit_state.dart'; /// A bloc that manages the state of a RecipeEdit according to the event that is dispatched to it. @@ -37,7 +36,7 @@ class RecipeEditBloc extends Bloc { } final String? recipeID = state.recipeModelObj?.recipeID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/show/$recipeID'), + Uri.parse(baseUrl + '/api/recipes/show/$recipeID'), headers: { 'Authorization': 'Bearer $token', }, @@ -47,7 +46,8 @@ class RecipeEditBloc extends Bloc { if (data is Map) { if (state is RecipeEditLoadedState) { var currentState = state as RecipeEditLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( recipeModelObj: currentState.recipeModelObj, title: currentState.title, token: currentState.token, @@ -56,7 +56,9 @@ class RecipeEditBloc extends Bloc { video_url: currentState.video_url, steps: currentState.steps, stepDescriptions: currentState.stepDescriptions, - tags: currentState.tags)); + tags: currentState.tags, + ), + ); } else { final Map defaultStep = { 'description': '', @@ -75,17 +77,19 @@ class RecipeEditBloc extends Bloc { } } - emit(RecipeEditLoadedState( - token: token, - recipe: data, - title: TextEditingController(text: data['title']), - description: TextEditingController(text: data['description']), - video_url: TextEditingController(text: data['video_url']), - tagsController: TextEditingController(), - tags: await _fetchTags(data['id']), - stepDescriptions: stepDescriptions, - steps: steps, - )); + emit( + RecipeEditLoadedState( + token: token, + recipe: data, + title: TextEditingController(text: data['title']), + description: TextEditingController(text: data['description']), + video_url: TextEditingController(text: data['video_url']), + tagsController: TextEditingController(), + tags: await _fetchTags(data['id']), + stepDescriptions: stepDescriptions, + steps: steps, + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку @@ -161,7 +165,7 @@ class RecipeEditBloc extends Bloc { String? description, ) async { int id = recipe?['id']; - String url = '${dotenv.env['SERVER_ROOT']!}/recipe/update/$id'; + String url = '${baseUrl}/api/recipe/update/$id'; final Map credentials = { 'id': id, @@ -171,7 +175,7 @@ class RecipeEditBloc extends Bloc { 'steps': '[{"image": "steps/bT91V52zY2hIkjZezUxO4jW4njfhDfCe2PcMxciZ.jpg", "description": "Excepturi fuga sed quaerat impedit facere recusandae. Nihil exercitationem architecto accusantium ut. Qui consequuntur rerum quam asperiores repellendus molestias."}, {"image": "steps/7vaLlotrw65NXbqaD0dK4OTLVyxMgmB9wL3xBzg3.jpg", "description": "Sit hic sint ullam qui. Odit nihil possimus quo id itaque nisi non."}, {"image": "steps/et7cKUsnQkegcRAE72TS0mfAf2jLJXW93QDAGfjz.jpg", "description": "Ab dolores qui voluptatem sed quasi vero. Culpa minus optio in voluptatibus aut corrupti. Dolor expedita minus aut nesciunt quos quibusdam rerum."}, {"image": "steps/260401J6r71r9kuUt694VcsuMMQKTlQMrlIwfaKo.jpg", "description": "Eos dolores corrupti cupiditate aut. Nam nesciunt eveniet eos nam vitae ut. Quibusdam ab commodi ut natus. Nisi earum porro quidem et eligendi iste doloribus."}, {"image": "steps/Ol10BkOFeZ9EG4BAShgB1wnVwtCimoUMcSNDh2EB.jpg", "description": "Consectetur optio porro nobis voluptas quibusdam. Consequatur dolor dolorem laboriosam magnam iste atque."}, {"image": "steps/8PanRq2aWWdXG1xCYkRyJ0M3Z39y6jMPfnHCqlVi.jpg", "description": "A optio porro eligendi ullam. Sed numquam ullam quasi aperiam inventore corrupti enim. Alias id et consequatur perferendis. Ullam consequatur incidunt nesciunt ut et aut."}, {"image": "steps/19U2sYSGDkprS3L8SIFT3xz59OwQJ5xs0A8etZjr.jpg", "description": "In doloribus vel voluptas dolorum. Temporibus iusto est repellat quo sed. Perspiciatis enim sit beatae in dolor ut. Quis ad qui eligendi nisi. Est suscipit dolore ratione dolores suscipit molestiae."}, {"image": "steps/CRxJtjgQw84kG3teJVtl9GqwWUQ1WKpvOeBbwf9a.jpg", "description": "Aut quia maiores et aut. Quidem ab voluptates blanditiis. Est quam quia repellat exercitationem rerum et iste mollitia. Et sed dolores tempore nam et similique qui."}, {"image": "steps/NoG9rHtvHNLrYI2LujURT3DMQCmEe68UbpiXco2y.jpg", "description": "Nam et dolorum delectus. Labore fuga asperiores nam cumque sit. Eum hic officiis ea asperiores qui. Soluta totam enim quasi explicabo sed aut."}]', 'ingredients': - '[{"name": "Cheeseburger", "unit": "pcs", "portion": 336}, {"name": "Little Cheeseburger", "unit": "gr", "portion": 623}, {"name": "Bacon Burger", "unit": "ml", "portion": 713}, {"name": "Little Bacon Burger", "unit": "pcs", "portion": 160}, {"name": "Hamburger", "unit": "tablespoon", "portion": 390}, {"name": "Bacon Cheese Dog", "unit": "teespons", "portion": 295}, {"name": "Hamburger", "unit": "pcs", "portion": 813}, {"name": "Cheeseburger", "unit": "gr", "portion": 951}]' + '[{"name": "Cheeseburger", "unit": "pcs", "portion": 336}, {"name": "Little Cheeseburger", "unit": "gr", "portion": 623}, {"name": "Bacon Burger", "unit": "ml", "portion": 713}, {"name": "Little Bacon Burger", "unit": "pcs", "portion": 160}, {"name": "Hamburger", "unit": "tablespoon", "portion": 390}, {"name": "Bacon Cheese Dog", "unit": "teespons", "portion": 295}, {"name": "Hamburger", "unit": "pcs", "portion": 813}, {"name": "Cheeseburger", "unit": "gr", "portion": 951}]', }; var response = await http.post( @@ -195,7 +199,7 @@ class RecipeEditBloc extends Bloc { } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/getTags/$id'), + Uri.parse(baseUrl + '/api/recipes/getTags/$id'), headers: { 'Authorization': 'Bearer $token', }, @@ -213,7 +217,8 @@ class RecipeEditBloc extends Bloc { } if (state is RecipeEditLoadedState) { var currentState = state as RecipeEditLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( recipeModelObj: currentState.recipeModelObj, recipe: currentState.recipe, title: currentState.title, @@ -222,7 +227,9 @@ class RecipeEditBloc extends Bloc { video_url: currentState.video_url, steps: currentState.steps, stepDescriptions: currentState.stepDescriptions, - tags: currentState.tags)); + tags: currentState.tags, + ), + ); } } } diff --git a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_event.dart b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_event.dart index c6d49d3..b4bdd5f 100644 --- a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_event.dart +++ b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_event.dart @@ -22,19 +22,23 @@ class EditRecipe extends RecipeEditEvent { class AddStep extends RecipeEditEvent { AddStep(); + @override List get props => []; } class RemoveStep extends RecipeEditEvent { RemoveStep(this.id); + final int id; + @override List get props => [id]; } class ReloadScreen extends RecipeEditEvent { ReloadScreen(); + @override List get props => []; } diff --git a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_state.dart b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_state.dart index af03fcf..c01ffc4 100644 --- a/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_state.dart +++ b/lib/presentation/recipe/recipe_edit_screen/bloc/recipe_edit_state.dart @@ -14,6 +14,7 @@ class RecipeEditState extends Equatable { @override List get props => [recipeModelObj]; + RecipeEditState copyWith({RecipeEditModel? recipeModelObj}) { return RecipeEditState( recipeModelObj: recipeModelObj ?? this.recipeModelObj, @@ -22,17 +23,18 @@ class RecipeEditState extends Equatable { } class RecipeEditLoadedState extends RecipeEditState { - RecipeEditLoadedState( - {this.recipeModelObj, - this.token, - this.recipe, - this.title, - this.description, - this.video_url, - this.tagsController, - this.stepDescriptions, - this.tags, - this.steps}); + RecipeEditLoadedState({ + this.recipeModelObj, + this.token, + this.recipe, + this.title, + this.description, + this.video_url, + this.tagsController, + this.stepDescriptions, + this.tags, + this.steps, + }); RecipeEditModel? recipeModelObj; Map? recipe; @@ -44,9 +46,10 @@ class RecipeEditLoadedState extends RecipeEditState { List? steps; List? tags; List? stepDescriptions; + @override - List get props => - [recipeModelObj, recipe, title, description, video_url]; + List get props => [recipeModelObj, recipe, title, description, video_url]; + RecipeEditLoadedState copyWith({ RecipeEditModel? recipeModelObj, Map? recipe, @@ -84,6 +87,5 @@ class RecipeEditErrorState extends RecipeEditState { } class RecipeEditInitialState extends RecipeEditState { - RecipeEditInitialState({required RecipeEditModel recipeModelObj}) - : super(recipeModelObj: recipeModelObj); + RecipeEditInitialState({required RecipeEditModel recipeModelObj}) : super(recipeModelObj: recipeModelObj); } diff --git a/lib/presentation/recipe/recipe_edit_screen/recipe_edit_screen.dart b/lib/presentation/recipe/recipe_edit_screen/recipe_edit_screen.dart index c9ce266..e3dbcbe 100644 --- a/lib/presentation/recipe/recipe_edit_screen/recipe_edit_screen.dart +++ b/lib/presentation/recipe/recipe_edit_screen/recipe_edit_screen.dart @@ -1,16 +1,15 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/recipe_edit_bloc.dart'; import 'models/recipe_edit_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; class RecipeEditScreen extends StatelessWidget { const RecipeEditScreen({Key? key}) : super(key: key); @@ -18,8 +17,9 @@ class RecipeEditScreen extends StatelessWidget { static Widget builder(BuildContext context) { final recipeID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => RecipeEditBloc(RecipeEditState(recipeModelObj: RecipeEditModel(recipeID: recipeID.toString())))..add(RecipeEditInitialEvent()), - child: RecipeEditScreen()); + create: (context) => RecipeEditBloc(RecipeEditState(recipeModelObj: RecipeEditModel(recipeID: recipeID.toString())))..add(RecipeEditInitialEvent()), + child: RecipeEditScreen(), + ); } Widget build(BuildContext context) { @@ -76,7 +76,7 @@ class RecipeEditScreen extends StatelessWidget { children: steps, ), SizedBox(height: 20.v), - _buildAdditional(context, state) + _buildAdditional(context, state), ], ), ), @@ -109,10 +109,11 @@ class RecipeEditScreen extends StatelessWidget { onTap: onTapBack(context), ), title: Align( - alignment: Alignment.center, - child: AppbarSubtitle( - text: "Редактирование рецепта", - )), + alignment: Alignment.center, + child: AppbarSubtitle( + text: "Редактирование рецепта", + ), + ), ), ); } @@ -137,52 +138,55 @@ class RecipeEditScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Изображение")), - if (state.recipe?['image'] != null) - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.recipe?['image']), - width: double.infinity, - // Установите ширину равной ширине родительского элемента - height: 200.0, - fit: BoxFit.cover, - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(Icons.error), - ) - else - _buildAddPhoto(context, state), - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Название рецепта")), - CustomTextFormField( - controller: state.title, - hintText: "Введите название рецепта", - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Изображение")), + if (state.recipe?['image'] != null) + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (state.recipe?['image']), + width: double.infinity, + // Установите ширину равной ширине родительского элемента + height: 200.0, + fit: BoxFit.cover, + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => Icon(Icons.error), + ) + else + _buildAddPhoto(context, state), + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Название рецепта")), + CustomTextFormField( + controller: state.title, + hintText: "Введите название рецепта", + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - Align(alignment: Alignment.centerLeft, child: Text("Описание")), - CustomTextFormField( - controller: state.description, - hintText: "Введите описание рецепта", - maxLines: 4, - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + SizedBox(height: 16.0), + Align(alignment: Alignment.centerLeft, child: Text("Описание")), + CustomTextFormField( + controller: state.description, + hintText: "Введите описание рецепта", + maxLines: 4, + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - ]), + SizedBox(height: 16.0), + ], + ), ); } @@ -224,7 +228,7 @@ class RecipeEditScreen extends StatelessWidget { Icon( Icons.photo_library, color: appTheme.blueGray300, - ) + ), ], ), ), @@ -272,83 +276,86 @@ class RecipeEditScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - "Шаг ${i + 1}", - style: CustomTextStyles.titleMediumSemiBold, - ), - ), - SizedBox(height: 8.0), - CustomTextFormField( - controller: state.stepDescriptions?[i], - hintText: "Введите описание шага", - maxLines: 4, - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "Шаг ${i + 1}", + style: CustomTextStyles.titleMediumSemiBold, ), ), - ), - SizedBox(height: 16.0), - if (state.steps?[i]['image'] != null) - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.steps?[i]['image']), - width: double.infinity, - // Установите ширину равной ширине родительского элемента - height: 200.0, - // Задайте постоянную высоту элемента - fit: BoxFit.cover, - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(Icons.error), - ) - else - _buildAddPhoto(context, state), - SizedBox(height: 16.0), - if (isFirstStep && isLastStep) - CustomOutlinedButton( - onPressed: () => context.read().add(AddStep()), - text: "Добавить шаг", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - if (isLastStep && !isFirstStep) // Добавляем кнопку "Добавить шаг" только для последнего шага - Column( - children: [ - SizedBox(height: 16.0), - Row( - children: [ - Flexible( - flex: 5, - child: CustomOutlinedButton( - onPressed: () => context.read().add(AddStep()), - text: "Добавить шаг", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - SizedBox(width: 8), // Add some spacing between the buttons - Flexible( - flex: 1, - child: CustomOutlinedButton( - text: "х", - onPressed: () => context.read().add(RemoveStep(i)), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ), - ], + SizedBox(height: 8.0), + CustomTextFormField( + controller: state.stepDescriptions?[i], + hintText: "Введите описание шага", + maxLines: 4, + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, ), - ], + ), ), - if (!isLastStep && !isFirstStep) - CustomOutlinedButton( - onPressed: () => context.read().add(RemoveStep(i)), - text: "x", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ]), + SizedBox(height: 16.0), + if (state.steps?[i]['image'] != null) + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (state.steps?[i]['image']), + width: double.infinity, + // Установите ширину равной ширине родительского элемента + height: 200.0, + // Задайте постоянную высоту элемента + fit: BoxFit.cover, + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => Icon(Icons.error), + ) + else + _buildAddPhoto(context, state), + SizedBox(height: 16.0), + if (isFirstStep && isLastStep) + CustomOutlinedButton( + onPressed: () => context.read().add(AddStep()), + text: "Добавить шаг", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + if (isLastStep && !isFirstStep) // Добавляем кнопку "Добавить шаг" только для последнего шага + Column( + children: [ + SizedBox(height: 16.0), + Row( + children: [ + Flexible( + flex: 5, + child: CustomOutlinedButton( + onPressed: () => context.read().add(AddStep()), + text: "Добавить шаг", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + SizedBox(width: 8), // Add some spacing between the buttons + Flexible( + flex: 1, + child: CustomOutlinedButton( + text: "х", + onPressed: () => context.read().add(RemoveStep(i)), + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + ], + ), + ], + ), + if (!isLastStep && !isFirstStep) + CustomOutlinedButton( + onPressed: () => context.read().add(RemoveStep(i)), + text: "x", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ], + ), ); } @@ -372,29 +379,32 @@ class RecipeEditScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Align(alignment: Alignment.centerLeft, child: Text("Теги")), - _buildEditableTags(state.tags), - SizedBox(height: 8.0), - Align(alignment: Alignment.centerLeft, child: Text("Ссылка на видео (необязательно)")), - CustomTextFormField( - controller: state.video_url, - hintText: "YouTube", - fillColor: appTheme.gray50, - borderDecoration: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.h), - borderSide: BorderSide( - color: appTheme.gray50, - width: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align(alignment: Alignment.centerLeft, child: Text("Теги")), + _buildEditableTags(state.tags), + SizedBox(height: 8.0), + Align(alignment: Alignment.centerLeft, child: Text("Ссылка на видео (необязательно)")), + CustomTextFormField( + controller: state.video_url, + hintText: "YouTube", + fillColor: appTheme.gray50, + borderDecoration: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.h), + borderSide: BorderSide( + color: appTheme.gray50, + width: 1, + ), ), ), - ), - SizedBox(height: 16.0), - CustomOutlinedButton( - text: "Добавить рецепт", - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - ), - ]), + SizedBox(height: 16.0), + CustomOutlinedButton( + text: "Добавить рецепт", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ], + ), ); } diff --git a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_bloc.dart b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_bloc.dart index a7b0d37..399e20f 100644 --- a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_bloc.dart +++ b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_bloc.dart @@ -1,16 +1,16 @@ import 'dart:async'; +import 'package:dio/dio.dart'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:eatvio_app/presentation/recipe/recipe_select_screen/models/recipe_select_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/recipe/recipe_select_screen/models/recipe_select_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:image_picker/image_picker.dart'; + +import '/core/app_export.dart'; part 'recipe_select_event.dart'; part 'recipe_select_state.dart'; @@ -31,27 +31,29 @@ class RecipeSelectBloc extends Bloc { if (token == null) { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/index'), - ); + final response = await sl().get(baseUrl + '/api/recipes/index'); print('Got response'); if (response.statusCode == 200) { print('Got 200'); - final data = jsonDecode(response.body); + final data = response.data['data']; if (data is List) { print('Got List'); if (state is RecipeSelectLoadedState) { print('Got loaded'); var currentState = state as RecipeSelectLoadedState; - emit((currentState).copyWith( - posts: data, - myProfileModelObj: currentState.myProfileModelObj, - )); + emit( + (currentState).copyWith( + posts: data, + myProfileModelObj: currentState.myProfileModelObj, + ), + ); } else { print('Got unloaded'); - emit(RecipeSelectLoadedState( - posts: data, - )); + emit( + RecipeSelectLoadedState( + posts: data, + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку diff --git a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_event.dart b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_event.dart index 460c79c..416e1f2 100644 --- a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_event.dart +++ b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_event.dart @@ -17,7 +17,9 @@ class RecipeSelectInitialEvent extends RecipeSelectEvent { class UploadAvatar extends RecipeSelectEvent { UploadAvatar(this.image); + final XFile image; + @override List get props => [image]; } diff --git a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_state.dart b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_state.dart index feb87b2..02b6a79 100644 --- a/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_state.dart +++ b/lib/presentation/recipe/recipe_select_screen/bloc/recipe_select_state.dart @@ -12,22 +12,22 @@ class RecipeSelectState extends Equatable { } class RecipeSelectInitialState extends RecipeSelectState { - RecipeSelectInitialState({required RecipeSelectModel myProfileModelObj}) - : super(myProfileModelObj: myProfileModelObj); + RecipeSelectInitialState({required RecipeSelectModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj); } /// Represents the state of RecipeSelect in the application. class RecipeSelectLoadedState extends RecipeSelectState { - RecipeSelectLoadedState({this.myProfileModelObj, this.posts}) - : super(myProfileModelObj: null); + RecipeSelectLoadedState({this.myProfileModelObj, this.posts}) : super(myProfileModelObj: null); RecipeSelectModel? myProfileModelObj; List? posts; + @override List get props => [ myProfileModelObj, posts, ]; + RecipeSelectLoadedState copyWith({ RecipeSelectModel? myProfileModelObj, List? posts, diff --git a/lib/presentation/recipe/recipe_select_screen/recipe_select_screen.dart b/lib/presentation/recipe/recipe_select_screen/recipe_select_screen.dart index 2a3a108..29e47b3 100644 --- a/lib/presentation/recipe/recipe_select_screen/recipe_select_screen.dart +++ b/lib/presentation/recipe/recipe_select_screen/recipe_select_screen.dart @@ -1,20 +1,20 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'bloc/recipe_select_bloc.dart'; import 'models/recipe_select_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; class RecipeSelectScreen extends StatelessWidget { static Widget builder(BuildContext context) { return BlocProvider( - create: (context) => RecipeSelectBloc(RecipeSelectState(myProfileModelObj: RecipeSelectModel()))..add(RecipeSelectInitialEvent()), - child: RecipeSelectScreen()); + create: (context) => RecipeSelectBloc(RecipeSelectState(myProfileModelObj: RecipeSelectModel()))..add(RecipeSelectInitialEvent()), + child: RecipeSelectScreen(), + ); } Widget build(BuildContext context) { @@ -94,7 +94,7 @@ class RecipeSelectScreen extends StatelessWidget { onTap: () => GoRouter.of(context).goNamed('recipeCreateScreen'), child: Icon(Icons.create_outlined), ), - ) + ), ], ), ), @@ -112,55 +112,57 @@ class RecipeSelectScreen extends StatelessWidget { _buildRecipeList(BuildContext context, RecipeSelectLoadedState state) { return ListView.builder( + physics: NeverScrollableScrollPhysics(), shrinkWrap: true, // Add this line itemCount: state.posts?.length ?? 0, itemBuilder: (context, index) { final post = state.posts?[index]; return Container( - margin: EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], + margin: EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: ListTile( + leading: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + post['image'], + imageBuilder: (context, imageProvider) => CircleAvatar( + backgroundImage: imageProvider, + radius: 25, + ), + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => CircleAvatar( + child: Icon(Icons.person), + backgroundColor: Colors.white, + radius: 25, + ), ), - child: ListTile( - leading: CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + post['image'], - imageBuilder: (context, imageProvider) => CircleAvatar( - backgroundImage: imageProvider, - radius: 25, - ), - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => CircleAvatar( - child: Icon(Icons.person), - backgroundColor: Colors.white, - radius: 25, - ), - ), - title: Text( - post?['title'] ?? '', - style: CustomTextStyles.titleMediumSemiBold, - ), - subtitle: Text(post?['description'] ?? ''), + title: Text( + post?['title'] ?? '', + style: CustomTextStyles.titleMediumSemiBold, + ), + subtitle: Text(post?['description'] ?? ''), + onTap: () => GoRouter.of(context).goNamed( + 'recipeScreen', + extra: post?['id'].toString(), + ), + trailing: GestureDetector( onTap: () => GoRouter.of(context).goNamed( - 'recipeScreen', + 'recipeEditScreen', extra: post?['id'].toString(), ), - trailing: GestureDetector( - onTap: () => GoRouter.of(context).goNamed( - 'recipeEditScreen', - extra: post?['id'].toString(), - ), - child: Icon(Icons.edit), - ), - )); + child: Icon(Icons.edit), + ), + ), + ); }, ); } diff --git a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_bloc.dart b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_bloc.dart index a8b5e19..ac2d9a9 100644 --- a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_bloc.dart +++ b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_bloc.dart @@ -1,20 +1,19 @@ import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; +import 'package:eatvio_app/presentation/recipe/recipe_show_screen/models/recipe_show_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; -import 'dart:convert'; + import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/recipe/recipe_show_screen/models/recipe_show_model.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; -import 'package:go_router/go_router.dart'; part 'recipe_show_event.dart'; - part 'recipe_show_state.dart'; /// A bloc that manages the state of a Recipe according to the event that is dispatched to it. @@ -37,7 +36,7 @@ class RecipeBloc extends Bloc { } final String? recipeID = state.recipeModelObj?.recipeID; final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/show/$recipeID'), + Uri.parse(baseUrl + '/api/recipes/show/$recipeID'), headers: { 'Authorization': 'Bearer $token', }, @@ -47,23 +46,29 @@ class RecipeBloc extends Bloc { if (data is Map) { if (state is RecipeLoadedState) { var currentState = state as RecipeLoadedState; - emit(currentState.copyWith( + emit( + currentState.copyWith( recipeModelObj: currentState.recipeModelObj, recipe: currentState.recipe, token: currentState.token, commentController: currentState.commentController, comments: currentState.comments, steps: currentState.steps, - author: currentState.author)); + author: currentState.author, + ), + ); } else { - emit(RecipeLoadedState( + emit( + RecipeLoadedState( token: token, recipe: data, steps: data['steps'], author: await _fetchAuthor(data['id']), comments: fillCommentList(await _fetchComments(data['id'])), tags: await _fetchTags(data['id']), - commentController: TextEditingController())); + commentController: TextEditingController(), + ), + ); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку @@ -87,7 +92,7 @@ class RecipeBloc extends Bloc { } final int id = event.id; final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/delete/$id'), + Uri.parse(baseUrl + '/api/recipes/delete/$id'), headers: { 'Authorization': 'Bearer $token', }, @@ -125,7 +130,7 @@ class RecipeBloc extends Bloc { } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/getAuthor/$id'), + Uri.parse(baseUrl + '/api/recipes/getAuthor/$id'), headers: { 'Authorization': 'Bearer $token', }, @@ -141,7 +146,7 @@ class RecipeBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/getComments/$id'), + Uri.parse(baseUrl + '/api/recipes/getComments/$id'), headers: { 'Authorization': 'Bearer $token', }, @@ -159,7 +164,7 @@ class RecipeBloc extends Bloc { } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/recipe/getTags/$id'), + Uri.parse(baseUrl + '/api/recipes/getTags/$id'), headers: { 'Authorization': 'Bearer $token', }, @@ -171,30 +176,35 @@ class RecipeBloc extends Bloc { List fillCommentList(List comments) { List list = []; for (int i = 0; i < comments.length; i++) { - list.add(CommentModel( + list.add( + CommentModel( id: comments[i]['id'].toString(), userImage: comments[i]['profile_photo_path'], username: comments[i]['name'], dateText: DateFormat('dd.MM').format(DateTime.parse(comments[i]['updated_at'])), - greetingText: comments[i]['body'])); + greetingText: comments[i]['body'], + ), + ); } return list; } Future _sendCommentData(String? token, String body, int id) async { - String url = dotenv.env['SERVER_ROOT']! + '/recipe/createComment/$id'; + String url = baseUrl + '/api/recipes/createComment/$id'; final Map credentials = { 'id': id, 'body': body, }; - var response = await http.post(Uri.parse(url), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - body: json.encode(credentials), - encoding: utf8); + var response = await http.post( + Uri.parse(url), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(credentials), + encoding: utf8, + ); return response; } diff --git a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_event.dart b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_event.dart index 7510c3a..f2e71b7 100644 --- a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_event.dart +++ b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_event.dart @@ -17,14 +17,18 @@ class RecipeInitialEvent extends RecipeEvent { class DeleteEntry extends RecipeEvent { DeleteEntry(this.id); + final int id; + @override List get props => [id]; } class CreateComment extends RecipeEvent { CreateComment(this.body); + final String body; + @override List get props => [body]; } diff --git a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_state.dart b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_state.dart index fc3a9f4..0b7b2e8 100644 --- a/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_state.dart +++ b/lib/presentation/recipe/recipe_show_screen/bloc/recipe_show_state.dart @@ -14,6 +14,7 @@ class RecipeState extends Equatable { @override List get props => [recipeModelObj]; + RecipeState copyWith({RecipeModel? recipeModelObj}) { return RecipeState( recipeModelObj: recipeModelObj ?? this.recipeModelObj, @@ -22,15 +23,16 @@ class RecipeState extends Equatable { } class RecipeLoadedState extends RecipeState { - RecipeLoadedState( - {this.recipeModelObj, - this.recipe, - this.author, - this.comments, - this.token, - this.commentController, - this.tags, - this.steps}); + RecipeLoadedState({ + this.recipeModelObj, + this.recipe, + this.author, + this.comments, + this.token, + this.commentController, + this.tags, + this.steps, + }); RecipeModel? recipeModelObj; Map? recipe; @@ -40,6 +42,7 @@ class RecipeLoadedState extends RecipeState { List? steps; List? tags; String? token; + @override List get props => [ recipeModelObj, @@ -48,17 +51,19 @@ class RecipeLoadedState extends RecipeState { comments, token, commentController, - steps + steps, ]; - RecipeLoadedState copyWith( - {RecipeModel? recipeModelObj, - Map? recipe, - Map? author, - TextEditingController? commentController, - String? token, - List? tags, - List? steps, - List? comments}) { + + RecipeLoadedState copyWith({ + RecipeModel? recipeModelObj, + Map? recipe, + Map? author, + TextEditingController? commentController, + String? token, + List? tags, + List? steps, + List? comments, + }) { return RecipeLoadedState( recipeModelObj: recipeModelObj ?? this.recipeModelObj, recipe: recipe ?? this.recipe, @@ -82,6 +87,5 @@ class RecipeErrorState extends RecipeState { } class RecipeInitialState extends RecipeState { - RecipeInitialState({required RecipeModel recipeModelObj}) - : super(recipeModelObj: recipeModelObj); + RecipeInitialState({required RecipeModel recipeModelObj}) : super(recipeModelObj: recipeModelObj); } diff --git a/lib/presentation/recipe/recipe_show_screen/recipe_show_screen.dart b/lib/presentation/recipe/recipe_show_screen/recipe_show_screen.dart index f1835f8..c42813d 100644 --- a/lib/presentation/recipe/recipe_show_screen/recipe_show_screen.dart +++ b/lib/presentation/recipe/recipe_show_screen/recipe_show_screen.dart @@ -1,15 +1,14 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/presentation/feed/blog_post_screen/widgets/comment_widget.dart'; +import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; import 'bloc/recipe_show_bloc.dart'; import 'models/recipe_show_model.dart'; -import 'package:eatvio_app/presentation/feed/blog_post_screen/widgets/comment_widget.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; class RecipeScreen extends StatelessWidget { const RecipeScreen({Key? key}) : super(key: key); @@ -17,8 +16,9 @@ class RecipeScreen extends StatelessWidget { static Widget builder(BuildContext context) { final recipeID = ModalRoute.of(context)!.settings.arguments; return BlocProvider( - create: (context) => RecipeBloc(RecipeState(recipeModelObj: RecipeModel(recipeID: recipeID.toString())))..add(RecipeInitialEvent()), - child: RecipeScreen()); + create: (context) => RecipeBloc(RecipeState(recipeModelObj: RecipeModel(recipeID: recipeID.toString())))..add(RecipeInitialEvent()), + child: RecipeScreen(), + ); } Widget build(BuildContext context) { @@ -52,32 +52,33 @@ class RecipeScreen extends StatelessWidget { } } return Scaffold( - appBar: AppBar( - toolbarHeight: 0, - automaticallyImplyLeading: false, + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + resizeToAvoidBottomInset: false, + body: Container( + width: double.maxFinite, + decoration: AppDecoration.fillGray, + child: ListView( + children: [ + SizedBox(height: 15.v), + _buildHeaderRow(context, state), + SizedBox(height: 15.v), + _buildRecipeData(context, state), + SizedBox(height: 15.v), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: steps, + ), + SizedBox(height: 15.v), + _buildTextField(context, state), + SizedBox(height: 15.v), + _buildCommentSection(context, state), + ], ), - resizeToAvoidBottomInset: false, - body: Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView( - children: [ - SizedBox(height: 15.v), - _buildHeaderRow(context, state), - SizedBox(height: 15.v), - _buildRecipeData(context, state), - SizedBox(height: 15.v), - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: steps, - ), - SizedBox(height: 15.v), - _buildTextField(context, state), - SizedBox(height: 15.v), - _buildCommentSection(context, state), - ], - ), - )); + ), + ); } _buildHeaderRow(BuildContext context, RecipeLoadedState state) { @@ -119,7 +120,7 @@ class RecipeScreen extends StatelessWidget { ), ), CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.author?['profile_photo_path'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.author?['profile_photo_path'] ?? ''), imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -159,75 +160,86 @@ class RecipeScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Row( - children: [ - Text( - state.recipe?['title'], - style: CustomTextStyles.titleMediumBlack, - ), - Spacer(), - PopupMenuButton( - onSelected: (value) => tapMenu(value, context, state), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'edit', - child: Text('Редактировать'), - ), - PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), - ], - ), - ], - ), - SizedBox(height: 8.0), - _buildImage(state), - SizedBox(height: 16.0), - Text( - state.recipe?['description'], - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 16.0), - Align( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Text( + state.recipe?['title'], + style: CustomTextStyles.titleMediumBlack, + ), + Spacer(), + PopupMenuButton( + onSelected: (value) => tapMenu(value, context, state), + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: 'edit', + child: Text('Редактировать'), + ), + PopupMenuItem( + value: 'delete', + child: Text('Удалить'), + ), + ], + ), + ], + ), + SizedBox(height: 8.0), + _buildImage(state), + SizedBox(height: 16.0), + Text( + state.recipe?['description'], + style: CustomTextStyles.bodyMediumBluegray800, + ), + SizedBox(height: 16.0), + Align( alignment: Alignment.topLeft, child: Text( DateFormat('dd.MM.yyyy').format(DateTime.parse(state.recipe?['updated_at'])), style: theme.textTheme.bodyMedium, - )), - SizedBox(height: 16.0), - _buildTags(state.tags), - SizedBox(height: 16.0), - Row(children: [ - Padding( - padding: EdgeInsets.only(left: 24), - child: Row(children: [ - Padding( - padding: EdgeInsets.only(right: 8), - child: Icon(Icons.favorite_outline), - ), - Text( - "Нравится", - style: CustomTextStyles.titleMediumSemiBold, - ) - ]), + ), ), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 24), - child: Row(children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon(Icons.share_outlined), + SizedBox(height: 16.0), + _buildTags(state.tags), + SizedBox(height: 16.0), + Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 24), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 8), + child: Icon(Icons.favorite_outline), + ), + Text( + "Нравится", + style: CustomTextStyles.titleMediumSemiBold, + ), + ], ), - Text( - "Поделиться", - style: CustomTextStyles.titleMediumSemiBold, - ) - ])) - ]), - ]), + ), + Spacer(), + Padding( + padding: EdgeInsets.only(right: 24), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: Icon(Icons.share_outlined), + ), + Text( + "Поделиться", + style: CustomTextStyles.titleMediumSemiBold, + ), + ], + ), + ), + ], + ), + ], + ), ); } @@ -245,7 +257,7 @@ class RecipeScreen extends StatelessWidget { _buildImage(RecipeLoadedState state) { return CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.recipe?['image'] ?? ''), + imageUrl: baseUrl + '/storage/' + (state.recipe?['image'] ?? ''), imageBuilder: (context, imageProvider) => Stack( children: [ ClipRRect( @@ -368,7 +380,7 @@ class RecipeScreen extends StatelessWidget { ), onPressed: () => context.read().add(CreateComment(state.commentController!.text)), // Установите прозрачный фон - ) + ), ], ), ], @@ -400,7 +412,7 @@ class RecipeScreen extends StatelessWidget { ), SizedBox( height: 20, - ) + ), ], ); } @@ -431,28 +443,31 @@ class RecipeScreen extends StatelessWidget { ), ], ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - "Шаг ${i + 1}", - style: CustomTextStyles.titleMediumSemiBold, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "Шаг ${i + 1}", + style: CustomTextStyles.titleMediumSemiBold, + ), ), - ), - SizedBox(height: 16.0), - CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + (state.steps?[i]['image']), - width: double.infinity, - // Установите ширину равной ширине родительского элемента - height: 200.0, - // Задайте постоянную высоту элемента - fit: BoxFit.cover, - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(Icons.error), - ), - SizedBox(height: 16.0), - Text(state.steps?[i]['description']) - ]), + SizedBox(height: 16.0), + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (state.steps?[i]['image']), + width: double.infinity, + // Установите ширину равной ширине родительского элемента + height: 200.0, + // Задайте постоянную высоту элемента + fit: BoxFit.cover, + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => Icon(Icons.error), + ), + SizedBox(height: 16.0), + Text(state.steps?[i]['description']), + ], + ), ); } } diff --git a/lib/presentation/recipe/recipe_show_screen/widgets/comment_widget.dart b/lib/presentation/recipe/recipe_show_screen/widgets/comment_widget.dart index c224966..ed2e075 100644 --- a/lib/presentation/recipe/recipe_show_screen/widgets/comment_widget.dart +++ b/lib/presentation/recipe/recipe_show_screen/widgets/comment_widget.dart @@ -1,10 +1,9 @@ // ignore_for_file: must_be_immutable -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart'; -import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; class CommentWidget extends StatelessWidget { CommentWidget(this.commentModelObj, {Key? key}) @@ -36,13 +35,11 @@ class CommentWidget extends StatelessWidget { ], ), child: Row( - mainAxisAlignment: MainAxisAlignment - .spaceBetween, // Move the main axis alignment to space between - crossAxisAlignment: - CrossAxisAlignment.center, // Center the items vertically + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Move the main axis alignment to space between + crossAxisAlignment: CrossAxisAlignment.center, // Center the items vertically children: [ CachedNetworkImage( - imageUrl: dotenv.env['STORAGE_URL']! + commentModelObj.userImage!, + imageUrl: baseUrl + '/storage/' + commentModelObj.userImage!, imageBuilder: (context, imageProvider) => CircleAvatar( backgroundImage: imageProvider, radius: 25, @@ -69,10 +66,7 @@ class CommentWidget extends StatelessWidget { child: Row( children: [ Text( - commentModelObj.username!.length <= 15 - ? commentModelObj.username! - : commentModelObj.username!.substring(0, 15) + - '...', + commentModelObj.username!.length <= 15 ? commentModelObj.username! : commentModelObj.username!.substring(0, 15) + '...', style: theme.textTheme.titleMedium, ), Spacer(), @@ -82,7 +76,7 @@ class CommentWidget extends StatelessWidget { commentModelObj.dateText!, style: theme.textTheme.bodyMedium, ), - ) + ), ], ), ), @@ -96,10 +90,11 @@ class CommentWidget extends StatelessWidget { ), ), CustomImageView( - imagePath: ImageConstant.imgSend, - height: 30.v, - width: 30.h, - margin: EdgeInsets.only(left: 5)), + imagePath: ImageConstant.imgSend, + height: 30.v, + width: 30.h, + margin: EdgeInsets.only(left: 5), + ), ], ), ); diff --git a/lib/presentation/registration/additional_information_screen/additional_information_screen.dart b/lib/presentation/registration/additional_information_screen/additional_information_screen.dart deleted file mode 100644 index c855fb4..0000000 --- a/lib/presentation/registration/additional_information_screen/additional_information_screen.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/additional_information_bloc.dart'; -import 'models/additional_information_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter/material.dart'; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; - -class AdditionalInformationScreen extends StatelessWidget { - const AdditionalInformationScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => - AdditionalInformationBloc(AdditionalInformationState(additionalInformationModelObj: AdditionalInformationModel(userRegistrationSheet: sheet))) - ..add(AdditionalInformationInitialEvent()), - child: AdditionalInformationScreen()); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 1, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 20.v), - SizedBox(height: 73.v), - _buildTextFormField(context), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "finish".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapFinish(state, context)); - }), - ]))); - } - - onTapFinish(AdditionalInformationState state, BuildContext context) { - return () async { - UserRegistrationSheet sheet = state.additionalInformationModelObj!.userRegistrationSheet; - sheet.additionalInfo = state.editTextController!.text; - - final response = await http.post(Uri.parse(dotenv.env['SERVER_ROOT']! + '/register'), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, body: jsonEncode(sheet.toJson()), encoding: utf8); - - var res = await jsonDecode(response.body); - if (response.statusCode == 200) { - final box = await Hive.openBox('token'); - final token = res['token']; - box.put('token', token); - GoRouter.of(context).goNamed('myProfileScreen'); - } else { - showErrorMessage(context, res['message']); - } - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 31.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 18.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildTextFormField(BuildContext context) { - return SizedBox( - height: 315.v, - width: 343.h, - child: Stack(alignment: Alignment.center, children: [ - Align( - alignment: Alignment.center, - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Container( - width: 294.h, - margin: EdgeInsets.only(left: 24.h, right: 23.h), - child: Text("enter_additional_information".tr, - maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: CustomTextStyles.titleMediumSegoeUI)), - SizedBox(height: 10.v), - BlocSelector( - selector: (state) => state.editTextController, - builder: (context, editTextController) { - return CustomTextFormField( - controller: editTextController, - hintText: "У меня крепкое здоровье, но последнее время часто утомляюсь, однако, это мне не мешает радоваться жизни", - textInputAction: TextInputAction.done, - maxLines: 8); - }) - ])) - ])); - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - /// Displays an alert dialog when the action is triggered. - /// The dialog box contains a title and a message with the `Теперь вы можете пользоваться полным функционалом приложения` - showErrorMessage(BuildContext context, String text) { - showDialog( - context: context, - builder: (_) => AlertDialog( - title: const Text('Ошибка'), - content: Text(text), - actions: [TextButton(onPressed: onTapOk(context), child: const Text('Ok'))], - )); - } - - onTapOk(BuildContext context) { - return () { - Navigator.pop(context); - }; - } -} diff --git a/lib/presentation/registration/additional_information_screen/bloc/additional_information_bloc.dart b/lib/presentation/registration/additional_information_screen/bloc/additional_information_bloc.dart deleted file mode 100644 index b2405c5..0000000 --- a/lib/presentation/registration/additional_information_screen/bloc/additional_information_bloc.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/additional_information_screen/models/additional_information_model.dart'; -part 'additional_information_event.dart'; -part 'additional_information_state.dart'; - -/// A bloc that manages the state of a AdditionalInformation according to the event that is dispatched to it. -class AdditionalInformationBloc - extends Bloc { - AdditionalInformationBloc(AdditionalInformationState initialState) - : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - AdditionalInformationInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith(editTextController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/additional_information_screen/bloc/additional_information_event.dart b/lib/presentation/registration/additional_information_screen/bloc/additional_information_event.dart deleted file mode 100644 index 71494f8..0000000 --- a/lib/presentation/registration/additional_information_screen/bloc/additional_information_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'additional_information_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///AdditionalInformation widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class AdditionalInformationEvent extends Equatable {} - -/// Event that is dispatched when the AdditionalInformation widget is first created. -class AdditionalInformationInitialEvent extends AdditionalInformationEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/additional_information_screen/bloc/additional_information_state.dart b/lib/presentation/registration/additional_information_screen/bloc/additional_information_state.dart deleted file mode 100644 index 08dd10c..0000000 --- a/lib/presentation/registration/additional_information_screen/bloc/additional_information_state.dart +++ /dev/null @@ -1,31 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'additional_information_bloc.dart'; - -/// Represents the state of AdditionalInformation in the application. -class AdditionalInformationState extends Equatable { - AdditionalInformationState({ - this.editTextController, - this.additionalInformationModelObj, - }); - - TextEditingController? editTextController; - - AdditionalInformationModel? additionalInformationModelObj; - - @override - List get props => [ - editTextController, - additionalInformationModelObj, - ]; - AdditionalInformationState copyWith({ - TextEditingController? editTextController, - AdditionalInformationModel? additionalInformationModelObj, - }) { - return AdditionalInformationState( - editTextController: editTextController ?? this.editTextController, - additionalInformationModelObj: - additionalInformationModelObj ?? this.additionalInformationModelObj, - ); - } -} diff --git a/lib/presentation/registration/additional_information_screen/models/additional_information_model.dart b/lib/presentation/registration/additional_information_screen/models/additional_information_model.dart deleted file mode 100644 index ff001d9..0000000 --- a/lib/presentation/registration/additional_information_screen/models/additional_information_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [additional_information_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class AdditionalInformationModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - AdditionalInformationModel({required this.userRegistrationSheet}); - - AdditionalInformationModel copyWith() { - return AdditionalInformationModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/allergies_screen/allergies_screen.dart b/lib/presentation/registration/allergies_screen/allergies_screen.dart deleted file mode 100644 index 50d056b..0000000 --- a/lib/presentation/registration/allergies_screen/allergies_screen.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/allergies_bloc.dart'; -import 'models/allergies_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class AllergiesScreen extends StatefulWidget { - const AllergiesScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => AllergiesBloc(AllergiesState(allergiesModelObj: AllergiesModel(userRegistrationSheet: sheet)))..add(AllergiesInitialEvent()), - child: AllergiesScreen()); - } - - @override - State createState() => _AllergiesScreenState(); -} - -class _AllergiesScreenState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.76, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 22.v), - Text("allergies_presence".tr, style: theme.textTheme.headlineSmall), - Spacer(flex: 36), - _buildTextFormField(context), - Spacer(flex: 54), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - BlocBuilder(builder: (context, state) { - return GestureDetector( - onTap: onTapSkip(state, context), - child: Text("skip".tr, style: theme.textTheme.bodyLarge), - ); - }), - ]))); - } - - onTapSkip(AllergiesState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.allergiesModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('medicineIntakeScreen', extra: sheet); - }; - } - - onTapContinue(AllergiesState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.allergiesModelObj!.userRegistrationSheet; - sheet.aboutAllergy = state.enterInformationController!.text; - GoRouter.of(context).goNamed('medicineIntakeScreen', extra: sheet); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 31.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 18.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildTextFormField(BuildContext context) { - return Column(children: [ - Text("fill_in_information".tr, style: CustomTextStyles.titleMediumSegoeUI), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.enterInformationController, - builder: (context, enterInformationController) { - return CustomTextFormField( - controller: enterInformationController, hintText: "enter_information".tr, textInputAction: TextInputAction.done, maxLines: 8); - }) - ]); - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/registration/allergies_screen/bloc/allergies_bloc.dart b/lib/presentation/registration/allergies_screen/bloc/allergies_bloc.dart deleted file mode 100644 index f4cf7a2..0000000 --- a/lib/presentation/registration/allergies_screen/bloc/allergies_bloc.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/allergies_screen/models/allergies_model.dart'; -part 'allergies_event.dart'; -part 'allergies_state.dart'; - -/// A bloc that manages the state of a Allergies according to the event that is dispatched to it. -class AllergiesBloc extends Bloc { - AllergiesBloc(AllergiesState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - AllergiesInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith(enterInformationController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/allergies_screen/bloc/allergies_event.dart b/lib/presentation/registration/allergies_screen/bloc/allergies_event.dart deleted file mode 100644 index 8892cc3..0000000 --- a/lib/presentation/registration/allergies_screen/bloc/allergies_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'allergies_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Allergies widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class AllergiesEvent extends Equatable {} - -/// Event that is dispatched when the Allergies widget is first created. -class AllergiesInitialEvent extends AllergiesEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/allergies_screen/bloc/allergies_state.dart b/lib/presentation/registration/allergies_screen/bloc/allergies_state.dart deleted file mode 100644 index a63c52d..0000000 --- a/lib/presentation/registration/allergies_screen/bloc/allergies_state.dart +++ /dev/null @@ -1,31 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'allergies_bloc.dart'; - -/// Represents the state of Allergies in the application. -class AllergiesState extends Equatable { - AllergiesState({ - this.enterInformationController, - this.allergiesModelObj, - }); - - TextEditingController? enterInformationController; - - AllergiesModel? allergiesModelObj; - - @override - List get props => [ - enterInformationController, - allergiesModelObj, - ]; - AllergiesState copyWith({ - TextEditingController? enterInformationController, - AllergiesModel? allergiesModelObj, - }) { - return AllergiesState( - enterInformationController: - enterInformationController ?? this.enterInformationController, - allergiesModelObj: allergiesModelObj ?? this.allergiesModelObj, - ); - } -} diff --git a/lib/presentation/registration/allergies_screen/models/allergies_model.dart b/lib/presentation/registration/allergies_screen/models/allergies_model.dart deleted file mode 100644 index ebd2006..0000000 --- a/lib/presentation/registration/allergies_screen/models/allergies_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [allergies_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class AllergiesModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - AllergiesModel({required this.userRegistrationSheet}); - - AllergiesModel copyWith() { - return AllergiesModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/app_navigation_screen/app_navigation_screen.dart b/lib/presentation/registration/app_navigation_screen/app_navigation_screen.dart deleted file mode 100644 index 781552e..0000000 --- a/lib/presentation/registration/app_navigation_screen/app_navigation_screen.dart +++ /dev/null @@ -1,236 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/app_navigation_bloc.dart'; -import 'models/app_navigation_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; - -class AppNavigationScreen extends StatefulWidget { - const AppNavigationScreen({Key? key}) - : super( - key: key, - ); - - static Widget builder(BuildContext context) { - return BlocProvider( - create: (context) => AppNavigationBloc(AppNavigationState( - appNavigationModelObj: AppNavigationModel(), - )) - ..add(AppNavigationInitialEvent()), - child: AppNavigationScreen(), - ); - } - - @override - State createState() => _AppNavigationScreenState(); -} - -class _AppNavigationScreenState extends State { - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - - return BlocBuilder( - builder: (context, state) { - return SafeArea( - child: Scaffold( - backgroundColor: Color(0XFFFFFFFF), - body: SizedBox( - width: double.maxFinite, - child: Column( - children: [ - _buildAppNavigation(context), - Expanded( - child: SingleChildScrollView( - child: Container( - decoration: BoxDecoration( - color: Color(0XFFFFFFFF), - ), - child: Column( - children: [ - _buildScreenTitle( - context, - screenTitle: "date_of_birth".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('dateOfBirthScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "city_of_living".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('cityOfLivingScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "body_circumferences".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('bodyCircumferencesScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "weight".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('weightScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "allergies".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('allergiesScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "medicine_intake".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('medicineIntakeScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "splash_screen".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('splashScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "gender".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('genderScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "blood_pressure".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('bloodPressureScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "favorite_sports".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('favoriteSportsScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "favorite_foods".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('favoriteFoodsScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "schedule".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('scheduleScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "additional_information".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('additionalInformationScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "language_select".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('languageSelectScreen'), - ), - _buildScreenTitle( - context, - screenTitle: "auth".tr, - onTapScreenTitle: () => GoRouter.of(context).goNamed('authScreen'), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ); - }, - ); - } - - /// Section Widget - _buildAppNavigation(BuildContext context) { - return Container( - decoration: BoxDecoration( - color: Color(0XFFFFFFFF), - ), - child: Column( - children: [ - SizedBox(height: 10.v), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 20.h), - child: Text( - "App Navigation".tr, - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0XFF000000), - fontSize: 20.fSize, - fontFamily: 'Roboto', - fontWeight: FontWeight.w400, - ), - ), - ), - ), - SizedBox(height: 10.v), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: EdgeInsets.only(left: 20.h), - child: Text( - "Check your app's UI from the below demo screens of your app.".tr, - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0XFF888888), - fontSize: 16.fSize, - fontFamily: 'Roboto', - fontWeight: FontWeight.w400, - ), - ), - ), - ), - SizedBox(height: 5.v), - Divider( - height: 1.v, - thickness: 1.v, - color: Color(0XFF000000), - ), - ], - ), - ); - } - - /// Common widget - _buildScreenTitle( - BuildContext context, { - required String screenTitle, - Function? onTapScreenTitle, - }) { - return GestureDetector( - onTap: onTapScreenTitle!.call(), - child: Container( - decoration: BoxDecoration( - color: Color(0XFFFFFFFF), - ), - child: Column( - children: [ - SizedBox(height: 10.v), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 20.h), - child: Text( - screenTitle, - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0XFF000000), - fontSize: 20.fSize, - fontFamily: 'Roboto', - fontWeight: FontWeight.w400, - ), - ), - ), - ), - SizedBox(height: 10.v), - SizedBox(height: 5.v), - Divider( - height: 1.v, - thickness: 1.v, - color: Color(0XFF888888), - ), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_bloc.dart b/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_bloc.dart deleted file mode 100644 index adb5110..0000000 --- a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_bloc.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/app_navigation_screen/models/app_navigation_model.dart'; -part 'app_navigation_event.dart'; -part 'app_navigation_state.dart'; - -/// A bloc that manages the state of a AppNavigation according to the event that is dispatched to it. -class AppNavigationBloc extends Bloc { - AppNavigationBloc(AppNavigationState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - AppNavigationInitialEvent event, - Emitter emit, - ) async {} -} diff --git a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_event.dart b/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_event.dart deleted file mode 100644 index 649738e..0000000 --- a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'app_navigation_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///AppNavigation widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class AppNavigationEvent extends Equatable {} - -/// Event that is dispatched when the AppNavigation widget is first created. -class AppNavigationInitialEvent extends AppNavigationEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_state.dart b/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_state.dart deleted file mode 100644 index 2ee3346..0000000 --- a/lib/presentation/registration/app_navigation_screen/bloc/app_navigation_state.dart +++ /dev/null @@ -1,21 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'app_navigation_bloc.dart'; - -/// Represents the state of AppNavigation in the application. -class AppNavigationState extends Equatable { - AppNavigationState({this.appNavigationModelObj}); - - AppNavigationModel? appNavigationModelObj; - - @override - List get props => [ - appNavigationModelObj, - ]; - AppNavigationState copyWith({AppNavigationModel? appNavigationModelObj}) { - return AppNavigationState( - appNavigationModelObj: - appNavigationModelObj ?? this.appNavigationModelObj, - ); - } -} diff --git a/lib/presentation/registration/app_navigation_screen/models/app_navigation_model.dart b/lib/presentation/registration/app_navigation_screen/models/app_navigation_model.dart deleted file mode 100644 index 73fd71d..0000000 --- a/lib/presentation/registration/app_navigation_screen/models/app_navigation_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; - -/// This class defines the variables used in the [app_navigation_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class AppNavigationModel extends Equatable { - AppNavigationModel(); - - AppNavigationModel copyWith() { - return AppNavigationModel(); - } - - @override - List get props => []; -} diff --git a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_bloc.dart b/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_bloc.dart deleted file mode 100644 index e5a0c6a..0000000 --- a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_bloc.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/blood_pressure_screen/models/blood_pressure_model.dart'; -part 'blood_pressure_event.dart'; -part 'blood_pressure_state.dart'; - -/// A bloc that manages the state of a BloodPressure according to the event that is dispatched to it. -class BloodPressureBloc extends Bloc { - BloodPressureBloc(BloodPressureState initialState) : super(initialState) { - on(_onInitialize); - on(_changeHypoDropDown); - on(_changeHyperDropDown); - } - - _changeHyperDropDown( - ChangeHyperDropDownEvent event, - Emitter emit, - ) { - if (event.value.id == 1) { - state.bloodPressureModelObj!.userRegistrationSheet.hasHyper = '1'; - } else { - state.bloodPressureModelObj!.userRegistrationSheet.hasHyper = '0'; - } - emit(state.copyWith(selectedHyperValue: event.value)); - } - - _changeHypoDropDown( - ChangeHypoDownEvent event, - Emitter emit, - ) { - if (event.value.id == 1) { - state.bloodPressureModelObj!.userRegistrationSheet.hasHypo = '1'; - } else { - state.bloodPressureModelObj!.userRegistrationSheet.hasHypo = '0'; - } - emit(state.copyWith(selectedHypoValue: event.value)); - } - - List fillDropdownItemList() { - return [ - SelectionPopupModel( - id: 1, - title: "Да", - ), - SelectionPopupModel(id: 2, title: "Нет", isSelected: true), - ]; - } - - _onInitialize( - BloodPressureInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - upPressureController: TextEditingController(), - downPressureController: TextEditingController())); - emit(state.copyWith( - bloodPressureModelObj: state.bloodPressureModelObj - ?.copyWith(dropdownItemList: fillDropdownItemList()))); - } -} diff --git a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_event.dart b/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_event.dart deleted file mode 100644 index 677d243..0000000 --- a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_event.dart +++ /dev/null @@ -1,39 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'blood_pressure_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///BloodPressure widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class BloodPressureEvent extends Equatable {} - -/// Event that is dispatched when the BloodPressure widget is first created. -class BloodPressureInitialEvent extends BloodPressureEvent { - @override - List get props => []; -} - -///event for dropdown selection -class ChangeHyperDropDownEvent extends BloodPressureEvent { - ChangeHyperDropDownEvent({required this.value}); - - SelectionPopupModel value; - - @override - List get props => [ - value, - ]; -} - -class ChangeHypoDownEvent extends BloodPressureEvent { - ChangeHypoDownEvent({required this.value}); - - SelectionPopupModel value; - - @override - List get props => [ - value, - ]; -} diff --git a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_state.dart b/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_state.dart deleted file mode 100644 index d1db1c4..0000000 --- a/lib/presentation/registration/blood_pressure_screen/bloc/blood_pressure_state.dart +++ /dev/null @@ -1,50 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'blood_pressure_bloc.dart'; - -/// Represents the state of BloodPressure in the application. -class BloodPressureState extends Equatable { - BloodPressureState({ - this.upPressureController, - this.downPressureController, - this.selectedHyperValue, - this.selectedHypoValue, - this.bloodPressureModelObj, - }); - - TextEditingController? upPressureController; - - TextEditingController? downPressureController; - - SelectionPopupModel? selectedHypoValue; - - SelectionPopupModel? selectedHyperValue; - - BloodPressureModel? bloodPressureModelObj; - - @override - List get props => [ - upPressureController, - downPressureController, - selectedHyperValue, - selectedHypoValue, - bloodPressureModelObj, - ]; - BloodPressureState copyWith({ - TextEditingController? upPressureController, - TextEditingController? downPressureController, - SelectionPopupModel? selectedHyperValue, - SelectionPopupModel? selectedHypoValue, - BloodPressureModel? bloodPressureModelObj, - }) { - return BloodPressureState( - upPressureController: upPressureController ?? this.upPressureController, - downPressureController: - downPressureController ?? this.downPressureController, - selectedHyperValue: selectedHyperValue ?? this.selectedHyperValue, - selectedHypoValue: selectedHypoValue ?? this.selectedHypoValue, - bloodPressureModelObj: - bloodPressureModelObj ?? this.bloodPressureModelObj, - ); - } -} diff --git a/lib/presentation/registration/blood_pressure_screen/blood_pressure_screen.dart b/lib/presentation/registration/blood_pressure_screen/blood_pressure_screen.dart deleted file mode 100644 index 5d4d8cc..0000000 --- a/lib/presentation/registration/blood_pressure_screen/blood_pressure_screen.dart +++ /dev/null @@ -1,241 +0,0 @@ -import 'package:eatvio_app/app_router.dart'; -import 'package:go_router/go_router.dart'; - -import 'bloc/blood_pressure_bloc.dart'; -import 'package:flutter/services.dart'; -import 'models/blood_pressure_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/custom_drop_down.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class BloodPressureScreen extends StatefulWidget { - const BloodPressureScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => - BloodPressureBloc(BloodPressureState(bloodPressureModelObj: BloodPressureModel(userRegistrationSheet: sheet)))..add(BloodPressureInitialEvent()), - child: BloodPressureScreen()); - } - - @override - State createState() => _BloodPressureScreenState(); -} - -class _BloodPressureScreenState extends State { - @override - Widget build(BuildContext context) { - final digitsOnly = FilteringTextInputFormatter.digitsOnly; - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - padding: EdgeInsets.symmetric(horizontal: 4.h), - // Apply padding directly to the Container - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all( - color: theme.colorScheme.primary, - width: 1.h, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.62, - backgroundColor: theme.colorScheme.onPrimary, - valueColor: AlwaysStoppedAnimation(appTheme.blueA400), - ), - ), - ), - SizedBox(height: 21.v), - SizedBox( - width: 224.h, - child: Text("your_blood_pressure".tr, - maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: theme.textTheme.headlineSmall)), - SizedBox(height: 21.v), - Container( - margin: EdgeInsets.only(right: 1.h), - padding: EdgeInsets.symmetric(horizontal: 3.h), - child: Column(children: [ - Text("up_pressure".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.upPressureController, - builder: (context, upPressureController) { - return CustomTextFormField(inputFormatters: [digitsOnly], controller: upPressureController, hintText: "90".tr); - }) - ])), - SizedBox(height: 21.v), - Container( - margin: EdgeInsets.only(right: 1.h), - padding: EdgeInsets.symmetric(horizontal: 3.h), - child: Column(children: [ - Text("down_pressure".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.downPressureController, - builder: (context, downPressureController) { - return CustomTextFormField(inputFormatters: [digitsOnly], controller: downPressureController, hintText: "90".tr); - }) - ])), - SizedBox(height: 22.v), - Text("do_you_have_hypotension_tendency".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - Padding( - padding: EdgeInsets.symmetric(horizontal: 4.h), - child: BlocSelector( - selector: (state) => state.bloodPressureModelObj, - builder: (context, bloodPressureModelObj) { - return CustomDropDown( - icon: Container( - margin: EdgeInsets.fromLTRB(30.h, 11.v, 13.h, 11.v), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(1.h)), - child: CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize)), - hintText: "Не выбрано".tr, - items: bloodPressureModelObj?.dropdownItemList ?? [], - onChanged: onChangeHyper(context)); - })), - SizedBox(height: 22.v), - Text("do_you_have_hypertension_tendency".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - Padding( - padding: EdgeInsets.symmetric(horizontal: 4.h), - child: BlocSelector( - selector: (state) => state.bloodPressureModelObj, - builder: (context, bloodPressureModelObj) { - return CustomDropDown( - icon: Container( - margin: EdgeInsets.fromLTRB(30.h, 11.v, 13.h, 11.v), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(1.h)), - child: CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize)), - hintText: "Не выбрано".tr, - items: bloodPressureModelObj?.dropdownItemList ?? [], - onChanged: onChangeHypo(context)); - })), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - BlocBuilder(builder: (context, state) { - return GestureDetector( - onTap: onTapSkip(state, context), - child: Text("skip".tr, style: theme.textTheme.bodyLarge), - ); - }), - ]))); - } - - onTapSkip(BloodPressureState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.bloodPressureModelObj!.userRegistrationSheet; - AppRouter.navigatorKey.currentContext?.goNamed('allergiesScreen', extra: sheet); - }; - } - - onTapContinue(BloodPressureState state, BuildContext context) { - return () { - List errors = validateFields(state.upPressureController!.text, state.downPressureController!.text); - if (errors.isEmpty) { - UserRegistrationSheet sheet = state.bloodPressureModelObj!.userRegistrationSheet; - sheet.bloodPressureUp = state.upPressureController!.text; - sheet.bloodPressureDown = state.downPressureController!.text; - AppRouter.navigatorKey.currentContext?.goNamed('favoriteSportsScreen', extra: sheet); - } else { - String errorMessage = ''; - - for (var error in errors) { - errorMessage += error + '\n\n'; - } - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Ошибка'), - content: Text(errorMessage), - actions: [ - TextButton( - onPressed: onTapOK(context), - child: Text('OK'), - ), - ], - ), - ); - } - }; - } - - onTapOK(BuildContext context) { - return () { - Navigator.pop(context); - }; - } - - onChangeHypo(BuildContext context) { - return (value) { - context.read().add(ChangeHyperDropDownEvent(value: value)); - }; - } - - onChangeHyper(BuildContext context) { - return (value) { - context.read().add(ChangeHypoDownEvent(value: value)); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - List validateFields( - String bloodPressureUp, - String bloodPressureDown, - ) { - List errors = []; - - if (bloodPressureUp.isEmpty | bloodPressureDown.isEmpty) { - errors.add('pressure_empty'.tr); - } - - if (![bloodPressureUp, bloodPressureDown].every((pressure) => int.tryParse(pressure) != null)) { - errors.add('pressure_is_not_a_number'.tr); - } - - return errors; - } -} diff --git a/lib/presentation/registration/blood_pressure_screen/models/blood_pressure_model.dart b/lib/presentation/registration/blood_pressure_screen/models/blood_pressure_model.dart deleted file mode 100644 index 328d1c5..0000000 --- a/lib/presentation/registration/blood_pressure_screen/models/blood_pressure_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [blood_pressure_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class BloodPressureModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - BloodPressureModel( - {required this.userRegistrationSheet, this.dropdownItemList = const []}); - - List dropdownItemList; - - BloodPressureModel copyWith({List? dropdownItemList}) { - return BloodPressureModel( - userRegistrationSheet: userRegistrationSheet, - dropdownItemList: dropdownItemList ?? this.dropdownItemList, - ); - } - - @override - List get props => [dropdownItemList, userRegistrationSheet]; -} diff --git a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_bloc.dart b/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_bloc.dart deleted file mode 100644 index 13f1a27..0000000 --- a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_bloc.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/body_circumferences_screen/models/body_circumferences_model.dart'; -part 'body_circumferences_event.dart'; -part 'body_circumferences_state.dart'; - -/// A bloc that manages the state of a BodyCircumferences according to the event that is dispatched to it. -class BodyCircumferencesBloc - extends Bloc { - BodyCircumferencesBloc(BodyCircumferencesState initialState) - : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - BodyCircumferencesInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - chestCircumferenceController: TextEditingController(), - waistCircumferenceController: TextEditingController(), - hipCircumferenceController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_event.dart b/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_event.dart deleted file mode 100644 index d164270..0000000 --- a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'body_circumferences_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///BodyCircumferences widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class BodyCircumferencesEvent extends Equatable {} - -/// Event that is dispatched when the BodyCircumferences widget is first created. -class BodyCircumferencesInitialEvent extends BodyCircumferencesEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_state.dart b/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_state.dart deleted file mode 100644 index df28755..0000000 --- a/lib/presentation/registration/body_circumferences_screen/bloc/body_circumferences_state.dart +++ /dev/null @@ -1,46 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'body_circumferences_bloc.dart'; - -/// Represents the state of BodyCircumferences in the application. -class BodyCircumferencesState extends Equatable { - BodyCircumferencesState({ - this.chestCircumferenceController, - this.waistCircumferenceController, - this.hipCircumferenceController, - this.bodyCircumferencesModelObj, - }); - - TextEditingController? chestCircumferenceController; - - TextEditingController? waistCircumferenceController; - - TextEditingController? hipCircumferenceController; - - BodyCircumferencesModel? bodyCircumferencesModelObj; - - @override - List get props => [ - chestCircumferenceController, - waistCircumferenceController, - hipCircumferenceController, - bodyCircumferencesModelObj, - ]; - BodyCircumferencesState copyWith({ - TextEditingController? chestCircumferenceController, - TextEditingController? waistCircumferenceController, - TextEditingController? hipCircumferenceController, - BodyCircumferencesModel? bodyCircumferencesModelObj, - }) { - return BodyCircumferencesState( - chestCircumferenceController: - chestCircumferenceController ?? this.chestCircumferenceController, - waistCircumferenceController: - waistCircumferenceController ?? this.waistCircumferenceController, - hipCircumferenceController: - hipCircumferenceController ?? this.hipCircumferenceController, - bodyCircumferencesModelObj: - bodyCircumferencesModelObj ?? this.bodyCircumferencesModelObj, - ); - } -} diff --git a/lib/presentation/registration/body_circumferences_screen/body_circumferences_screen.dart b/lib/presentation/registration/body_circumferences_screen/body_circumferences_screen.dart deleted file mode 100644 index 3610697..0000000 --- a/lib/presentation/registration/body_circumferences_screen/body_circumferences_screen.dart +++ /dev/null @@ -1,170 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/body_circumferences_bloc.dart'; -import 'package:flutter/services.dart'; -import 'models/body_circumferences_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class BodyCircumferencesScreen extends StatelessWidget { - const BodyCircumferencesScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => BodyCircumferencesBloc(BodyCircumferencesState(bodyCircumferencesModelObj: BodyCircumferencesModel(userRegistrationSheet: sheet))) - ..add(BodyCircumferencesInitialEvent()), - child: BodyCircumferencesScreen(), - ); - } - - @override - Widget build(BuildContext context) { - final digitsOnly = FilteringTextInputFormatter.digitsOnly; - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.40, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 39.v), - Text("initial_measurements".tr, style: theme.textTheme.headlineSmall), - SizedBox(height: 93.v), - Column(children: [ - Text("chest_circumference".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.chestCircumferenceController, - builder: (context, chestCircumferenceController) { - return CustomTextFormField(inputFormatters: [digitsOnly], controller: chestCircumferenceController, hintText: "90".tr); - }) - ]), - SizedBox(height: 19.v), - Text("waist_circumference".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 5.v), - BlocSelector( - selector: (state) => state.waistCircumferenceController, - builder: (context, waistCircumferenceController) { - return CustomTextFormField(inputFormatters: [digitsOnly], controller: waistCircumferenceController, hintText: "60".tr); - }), - SizedBox(height: 21.v), - Text("hip_circumference".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.hipCircumferenceController, - builder: (context, hipCircumferenceController) { - return CustomTextFormField( - inputFormatters: [digitsOnly], controller: hipCircumferenceController, hintText: "90".tr, textInputAction: TextInputAction.done); - }), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - ]))); - } - - onTapContinue(BodyCircumferencesState state, BuildContext context) { - return () { - List errors = - validateFields(state.chestCircumferenceController!.text, state.waistCircumferenceController!.text, state.hipCircumferenceController!.text); - if (errors.isEmpty) { - UserRegistrationSheet sheet = state.bodyCircumferencesModelObj!.userRegistrationSheet; - sheet.chestCircumference = state.chestCircumferenceController!.text; - sheet.waistCircumference = state.waistCircumferenceController!.text; - sheet.hipCircumference = state.hipCircumferenceController!.text; - GoRouter.of(context).goNamed('weightScreen', extra: sheet); - } else { - String errorMessage = ''; - - for (var error in errors) { - errorMessage += error + '\n\n'; - } - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Ошибка'), - content: Text(errorMessage), - actions: [ - TextButton( - onPressed: onTapOk(context), - child: Text('OK'), - ), - ], - ), - ); - } - }; - } - - onTapOk(BuildContext context) { - return () { - Navigator.pop(context); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - /// Navigates to the weightScreen when the action is triggered. - navigateToWeight(BuildContext context) => GoRouter.of(context).goNamed('weightScreen'); - - List validateFields( - String chestCircumference, - String waistCircumference, - String hipCircumference, - ) { - List errors = []; - - if (chestCircumference.isEmpty | waistCircumference.isEmpty | hipCircumference.isEmpty) { - errors.add('circumference_empty'.tr); - } - - if (![chestCircumference, waistCircumference, hipCircumference].every((circumference) => int.tryParse(circumference) != null)) { - errors.add('circumference_is_not_a_number'.tr); - } - - return errors; - } -} diff --git a/lib/presentation/registration/body_circumferences_screen/models/body_circumferences_model.dart b/lib/presentation/registration/body_circumferences_screen/models/body_circumferences_model.dart deleted file mode 100644 index 2af76f9..0000000 --- a/lib/presentation/registration/body_circumferences_screen/models/body_circumferences_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [body_circumferences_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class BodyCircumferencesModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - BodyCircumferencesModel({required this.userRegistrationSheet}); - - BodyCircumferencesModel copyWith() { - return BodyCircumferencesModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_bloc.dart b/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_bloc.dart deleted file mode 100644 index ce4073f..0000000 --- a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_bloc.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/city_of_living_screen/models/city_of_living_model.dart'; -part 'city_of_living_event.dart'; -part 'city_of_living_state.dart'; - -/// A bloc that manages the state of a CityOfLiving according to the event that is dispatched to it. -class CityOfLivingBloc extends Bloc { - CityOfLivingBloc(CityOfLivingState initialState) : super(initialState) { - on(_onInitialize); - on(_changeDropDown); - } - - _onInitialize( - CityOfLivingInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - cityOfLivingModelObj: state.cityOfLivingModelObj?.copyWith( - dropdownItemList: fillDropdownItemList(), - ))); - } - - _changeDropDown( - ChangeDropDownEvent event, - Emitter emit, - ) { - emit(state.copyWith(selectedDropDownValue: event.value)); - state.cityOfLivingModelObj?.userRegistrationSheet.country = - event.value.title; - } - - List fillDropdownItemList() { - return [SelectionPopupModel(id: 1, title: "Россия", isSelected: true)]; - } -} diff --git a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_event.dart b/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_event.dart deleted file mode 100644 index d841812..0000000 --- a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_event.dart +++ /dev/null @@ -1,28 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'city_of_living_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///CityOfLiving widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class CityOfLivingEvent extends Equatable {} - -/// Event that is dispatched when the CityOfLiving widget is first created. -class CityOfLivingInitialEvent extends CityOfLivingEvent { - @override - List get props => []; -} - -///event for dropdown selection -class ChangeDropDownEvent extends CityOfLivingEvent { - ChangeDropDownEvent({required this.value}); - - SelectionPopupModel value; - - @override - List get props => [ - value, - ]; -} diff --git a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_state.dart b/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_state.dart deleted file mode 100644 index 5179b21..0000000 --- a/lib/presentation/registration/city_of_living_screen/bloc/city_of_living_state.dart +++ /dev/null @@ -1,37 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'city_of_living_bloc.dart'; - -/// Represents the state of CityOfLiving in the application. -class CityOfLivingState extends Equatable { - CityOfLivingState({ - this.selectedDropDownValue, - this.cityController, - this.cityOfLivingModelObj, - }); - - SelectionPopupModel? selectedDropDownValue; - - TextEditingController? cityController; - - CityOfLivingModel? cityOfLivingModelObj; - - @override - List get props => [ - selectedDropDownValue, - cityController, - cityOfLivingModelObj, - ]; - CityOfLivingState copyWith({ - SelectionPopupModel? selectedDropDownValue, - SelectionPopupModel? selectedDropDownValue1, - CityOfLivingModel? cityOfLivingModelObj, - }) { - return CityOfLivingState( - selectedDropDownValue: - selectedDropDownValue ?? this.selectedDropDownValue, - cityController: cityController ?? this.cityController, - cityOfLivingModelObj: cityOfLivingModelObj ?? this.cityOfLivingModelObj, - ); - } -} diff --git a/lib/presentation/registration/city_of_living_screen/city_of_living_screen.dart b/lib/presentation/registration/city_of_living_screen/city_of_living_screen.dart deleted file mode 100644 index 5ce9150..0000000 --- a/lib/presentation/registration/city_of_living_screen/city_of_living_screen.dart +++ /dev/null @@ -1,1291 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/city_of_living_bloc.dart'; -import 'models/city_of_living_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/custom_drop_down.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class CityOfLivingScreen extends StatelessWidget { - const CityOfLivingScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => - CityOfLivingBloc(CityOfLivingState(cityOfLivingModelObj: CityOfLivingModel(userRegistrationSheet: sheet)))..add(CityOfLivingInitialEvent()), - child: CityOfLivingScreen(), - ); - } - - @override - Widget build(BuildContext context) { - List _options = [ - "Абаза", - "Абакан", - "Абдулино", - "Абинск", - "Агидель", - "Агрыз", - "Адыгейск", - "Азнакаево", - "Азов", - "Ак-Довурак", - "Аксай", - "Алагир", - "Алапаевск", - "Алатырь", - "Алдан", - "Алейск", - "Александров", - "Александровск", - "Александровск-Сахалинский", - "Алексеевка", - "Алексин", - "Алзамай", - "АлупкаОспаривается", - "АлуштаОспаривается", - "Альметьевск", - "Амурск", - "Анадырь", - "Анапа", - "Ангарск", - "Андреаполь", - "Анжеро-Судженск", - "Анива", - "Апатиты", - "Апрелевка", - "Апшеронск", - "Арамиль", - "Аргун", - "Ардатов", - "Ардон", - "Арзамас", - "Аркадак", - "Армавир", - "АрмянскОспаривается", - "Арсеньев", - "Арск", - "Артём", - "Артёмовск", - "Артёмовский", - "Архангельск", - "Асбест", - "Асино", - "Астрахань", - "Аткарск", - "Ахтубинск", - "Ачинск", - "Аша", - "Бабаево", - "Бабушкин", - "Бавлы", - "Багратионовск", - "Байкальск", - "Баймак", - "Бакал", - "Баксан", - "Балабаново", - "Балаково", - "Балахна", - "Балашиха", - "Балашов", - "Балей", - "Балтийск", - "Барабинск", - "Барнаул", - "Барыш", - "Батайск", - "БахчисарайОспаривается", - "Бежецк", - "Белая Калитва", - "Белая Холуница", - "Белгород", - "Белебей", - "Белёв", - "Белинский", - "Белово", - "Белогорск", - "БелогорскОспаривается", - "Белозерск", - "Белокуриха", - "Беломорск", - "Белоозёрский", - "Белорецк", - "Белореченск", - "Белоусово", - "Белоярский", - "Белый", - "Бердск", - "Березники", - "Берёзовский", - "Берёзовский", - "Беслан", - "Бийск", - "Бикин", - "Билибино", - "Биробиджан", - "Бирск", - "Бирюсинск", - "Бирюч", - "Благовещенск", - "Благовещенск", - "Благодарный", - "Бобров", - "Богданович", - "Богородицк", - "Богородск", - "Боготол", - "Богучар", - "Бодайбо", - "Бокситогорск", - "Болгар", - "Бологое", - "Болотное", - "Болохово", - "Болхов", - "Большой Камень", - "Бор", - "Борзя", - "Борисоглебск", - "Боровичи", - "Боровск", - "Бородино", - "Братск", - "Бронницы", - "Брянск", - "Бугульма", - "Бугуруслан", - "Будённовск", - "Бузулук", - "Буинск", - "Буй", - "Буйнакск", - "Бутурлиновка", - "Валдай", - "Валуйки", - "Велиж", - "Великие Луки", - "Великий Новгород", - "Великий Устюг", - "Вельск", - "Венёв", - "Верещагино", - "Верея", - "Верхнеуральск", - "Верхний Тагил", - "Верхний Уфалей", - "Верхняя Пышма", - "Верхняя Салда", - "Верхняя Тура", - "Верхотурье", - "Верхоянск", - "Весьегонск", - "Ветлуга", - "Видное", - "Вилюйск", - "Вилючинск", - "Вихоревка", - "Вичуга", - "Владивосток", - "Владикавказ", - "Владимир", - "Волгоград", - "Волгодонск", - "Волгореченск", - "Волжск", - "Волжский", - "Вологда", - "Володарск", - "Волоколамск", - "Волосово", - "Волхов", - "Волчанск", - "Вольск", - "Воркута", - "Воронеж", - "Ворсма", - "Воскресенск", - "Воткинск", - "Всеволожск", - "Вуктыл", - "Выборг", - "Выкса", - "Высоковск", - "Высоцк", - "Вытегра", - "Вышний Волочёк", - "Вяземский", - "Вязники", - "Вязьма", - "Вятские Поляны", - "Гаврилов Посад", - "Гаврилов-Ям", - "Гагарин", - "Гаджиево", - "Гай", - "Галич", - "Гатчина", - "Гвардейск", - "Гдов", - "Геленджик", - "Георгиевск", - "Глазов", - "Голицыно", - "Горбатов", - "Горно-Алтайск", - "Горнозаводск", - "Горняк", - "Городец", - "Городище", - "Городовиковск", - "Гороховец", - "Горячий Ключ", - "Грайворон", - "Гремячинск", - "Грозный", - "Грязи", - "Грязовец", - "Губаха", - "Губкин", - "Губкинский", - "Гудермес", - "Гуково", - "Гулькевичи", - "Гурьевск", - "Гурьевск", - "Гусев", - "Гусиноозёрск", - "Гусь-Хрустальный", - "Давлеканово", - "Дагестанские Огни", - "Далматово", - "Дальнегорск", - "Дальнереченск", - "Данилов", - "Данков", - "Дегтярск", - "Дедовск", - "Демидов", - "Дербент", - "Десногорск", - "ДжанкойОспаривается", - "Дзержинск", - "Дзержинский", - "Дивногорск", - "Дигора", - "Димитровград", - "Дмитриев", - "Дмитров", - "Дмитровск", - "Дно", - "Добрянка", - "Долгопрудный", - "Долинск", - "Домодедово", - "Донецк", - "Донской", - "Дорогобуж", - "Дрезна", - "Дубна", - "Дубовка", - "Дудинка", - "Духовщина", - "Дюртюли", - "Дятьково", - "ЕвпаторияОспаривается", - "Егорьевск", - "Ейск", - "Екатеринбург", - "Елабуга", - "Елец", - "Елизово", - "Ельня", - "Еманжелинск", - "Емва", - "Енисейск", - "Ермолино", - "Ершов", - "Ессентуки", - "Ефремов", - "Железноводск", - "Железногорск", - "Железногорск", - "Железногорск-Илимский", - "Жердевка", - "Жигулёвск", - "Жиздра", - "Жирновск", - "Жуков", - "Жуковка", - "Жуковский", - "Завитинск", - "Заводоуковск", - "Заволжск", - "Заволжье", - "Задонск", - "Заинск", - "Закаменск", - "Заозёрный", - "Заозёрск", - "Западная Двина", - "Заполярный", - "Зарайск", - "Заречный", - "Заречный", - "Заринск", - "Звенигово", - "Звенигород", - "Зверево", - "Зеленогорск", - "Зеленоградск", - "Зеленодольск", - "Зеленокумск", - "Зерноград", - "Зея", - "Зима", - "Златоуст", - "Злынка", - "Змеиногорск", - "Знаменск", - "Зубцов", - "Зуевка", - "Ивангород", - "Иваново", - "Ивантеевка", - "Ивдель", - "Игарка", - "Ижевск", - "Избербаш", - "Изобильный", - "Иланский", - "Инза", - "Иннополис", - "Инсар", - "Инта", - "Ипатово", - "Ирбит", - "Иркутск", - "Исилькуль", - "Искитим", - "Истра", - "Ишим", - "Ишимбай", - "Йошкар-Ола", - "Кадников", - "Казань", - "Калач", - "Калач-на-Дону", - "Калачинск", - "Калининград", - "Калининск", - "Калтан", - "Калуга", - "Калязин", - "Камбарка", - "Каменка", - "Каменногорск", - "Каменск-Уральский", - "Каменск-Шахтинский", - "Камень-на-Оби", - "Камешково", - "Камызяк", - "Камышин", - "Камышлов", - "Канаш", - "Кандалакша", - "Канск", - "Карабаново", - "Карабаш", - "Карабулак", - "Карасук", - "Карачаевск", - "Карачев", - "Каргат", - "Каргополь", - "Карпинск", - "Карталы", - "Касимов", - "Касли", - "Каспийск", - "Катав-Ивановск", - "Катайск", - "Качканар", - "Кашин", - "Кашира", - "Кедровый", - "Кемерово", - "Кемь", - "КерчьОспаривается", - "Кизел", - "Кизилюрт", - "Кизляр", - "Кимовск", - "Кимры", - "Кингисепп", - "Кинель", - "Кинешма", - "Киреевск", - "Киренск", - "Киржач", - "Кириллов", - "Кириши", - "Киров", - "Киров", - "Кировград", - "Кирово-Чепецк", - "Кировск", - "Кировск", - "Кирс", - "Кирсанов", - "Киселёвск", - "Кисловодск", - "Клин", - "Клинцы", - "Княгинино", - "Ковдор", - "Ковров", - "Ковылкино", - "Когалым", - "Кодинск", - "Козельск", - "Козловка", - "Козьмодемьянск", - "Кола", - "Кологрив", - "Коломна", - "Колпашево", - "Кольчугино", - "Коммунар", - "Комсомольск", - "Комсомольск-на-Амуре", - "Конаково", - "Кондопога", - "Кондрово", - "Константиновск", - "Копейск", - "Кораблино", - "Кореновск", - "Коркино", - "Королёв", - "Короча", - "Корсаков", - "Коряжма", - "Костерёво", - "Костомукша", - "Кострома", - "Котельники", - "Котельниково", - "Котельнич", - "Котлас", - "Котово", - "Котовск", - "Кохма", - "Красавино", - "Красноармейск", - "Красноармейск", - "Красновишерск", - "Красногорск", - "Краснодар", - "Краснозаводск", - "Краснознаменск", - "Краснознаменск", - "Краснокаменск", - "Краснокамск", - "КрасноперекопскОспаривается", - "Краснослободск", - "Краснослободск", - "Краснотурьинск", - "Красноуральск", - "Красноуфимск", - "Красноярск", - "Красный Кут", - "Красный Сулин", - "Красный Холм", - "Кремёнки", - "Кропоткин", - "Крымск", - "Кстово", - "Кубинка", - "Кувандык", - "Кувшиново", - "Кудрово", - "Кудымкар", - "Кузнецк", - "Куйбышев", - "Кукмор", - "Кулебаки", - "Кумертау", - "Кунгур", - "Купино", - "Курган", - "Курганинск", - "Курильск", - "Курлово", - "Куровское", - "Курск", - "Куртамыш", - "Курчалой", - "Курчатов", - "Куса", - "Кушва", - "Кызыл", - "Кыштым", - "Кяхта", - "Лабинск", - "Лабытнанги", - "Лагань", - "Ладушкин", - "Лаишево", - "Лакинск", - "Лангепас", - "Лахденпохья", - "Лебедянь", - "Лениногорск", - "Ленинск", - "Ленинск-Кузнецкий", - "Ленск", - "Лермонтов", - "Лесной", - "Лесозаводск", - "Лесосибирск", - "Ливны", - "Ликино-Дулёво", - "Липецк", - "Липки", - "Лиски", - "Лихославль", - "Лобня", - "Лодейное Поле", - "Лосино-Петровский", - "Луга", - "Луза", - "Лукоянов", - "Луховицы", - "Лысково", - "Лысьва", - "Лыткарино", - "Льгов", - "Любань", - "Люберцы", - "Любим", - "Людиново", - "Лянтор", - "Магадан", - "Магас", - "Магнитогорск", - "Майкоп", - "Майский", - "Макаров", - "Макарьев", - "Макушино", - "Малая Вишера", - "Малгобек", - "Малмыж", - "Малоархангельск", - "Малоярославец", - "Мамадыш", - "Мамоново", - "Мантурово", - "Мариинск", - "Мариинский Посад", - "Маркс", - "Махачкала", - "Мглин", - "Мегион", - "Медвежьегорск", - "Медногорск", - "Медынь", - "Межгорье", - "Междуреченск", - "Мезень", - "Меленки", - "Мелеуз", - "Менделеевск", - "Мензелинск", - "Мещовск", - "Миасс", - "Микунь", - "Миллерово", - "Минеральные Воды", - "Минусинск", - "Миньяр", - "Мирный", - "Мирный", - "Михайлов", - "Михайловка", - "Михайловск", - "Михайловск", - "Мичуринск", - "Могоча", - "Можайск", - "Можга", - "Моздок", - "Мончегорск", - "Морозовск", - "Моршанск", - "Мосальск", - "Москва", - "Муравленко", - "Мураши", - "Мурино", - "Мурманск", - "Муром", - "Мценск", - "Мыски", - "Мытищи", - "Мышкин", - "Набережные Челны", - "Навашино", - "Наволоки", - "Надым", - "Назарово", - "Назрань", - "Называевск", - "Нальчик", - "Нариманов", - "Наро-Фоминск", - "Нарткала", - "Нарьян-Мар", - "Находка", - "Невель", - "Невельск", - "Невинномысск", - "Невьянск", - "Нелидово", - "Неман", - "Нерехта", - "Нерчинск", - "Нерюнгри", - "Нестеров", - "Нефтегорск", - "Нефтекамск", - "Нефтекумск", - "Нефтеюганск", - "Нея", - "Нижневартовск", - "Нижнекамск", - "Нижнеудинск", - "Нижние Серги", - "Нижний Ломов", - "Нижний Новгород", - "Нижний Тагил", - "Нижняя Салда", - "Нижняя Тура", - "Николаевск", - "Николаевск-на-Амуре", - "Никольск", - "Никольск", - "Никольское", - "Новая Ладога", - "Новая Ляля", - "Новоалександровск", - "Новоалтайск", - "Новоаннинский", - "Нововоронеж", - "Новодвинск", - "Новозыбков", - "Новокубанск", - "Новокузнецк", - "Новокуйбышевск", - "Новомичуринск", - "Новомосковск", - "Новопавловск", - "Новоржев", - "Новороссийск", - "Новосибирск", - "Новосиль", - "Новосокольники", - "Новотроицк", - "Новоузенск", - "Новоульяновск", - "Новоуральск", - "Новохопёрск", - "Новочебоксарск", - "Новочеркасск", - "Новошахтинск", - "Новый Оскол", - "Новый Уренгой", - "Ногинск", - "Нолинск", - "Норильск", - "Ноябрьск", - "Нурлат", - "Нытва", - "Нюрба", - "Нягань", - "Нязепетровск", - "Няндома", - "Облучье", - "Обнинск", - "Обоянь", - "Обь", - "Одинцово", - "Озёрск", - "Озёрск", - "Озёры", - "Октябрьск", - "Октябрьский", - "Окуловка", - "Олёкминск", - "Оленегорск", - "Олонец", - "Омск", - "Омутнинск", - "Онега", - "Опочка", - "Орёл", - "Оренбург", - "Орехово-Зуево", - "Орлов", - "Орск", - "Оса", - "Осинники", - "Осташков", - "Остров", - "Островной", - "Острогожск", - "Отрадное", - "Отрадный", - "Оха", - "Оханск", - "Очёр", - "Павлово", - "Павловск", - "Павловский Посад", - "Палласовка", - "Партизанск", - "Певек", - "Пенза", - "Первомайск", - "Первоуральск", - "Перевоз", - "Пересвет", - "Переславль-Залесский", - "Пермь", - "Пестово", - "Петров Вал", - "Петровск", - "Петровск-Забайкальский", - "Петрозаводск", - "Петропавловск-Камчатский", - "Петухово", - "Петушки", - "Печора", - "Печоры", - "Пикалёво", - "Пионерский", - "Питкяранта", - "Плавск", - "Пласт", - "Плёс", - "Поворино", - "Подольск", - "Подпорожье", - "Покачи", - "Покров", - "Покровск", - "Полевской", - "Полесск", - "Полысаево", - "Полярные Зори", - "Полярный", - "Поронайск", - "Порхов", - "Похвистнево", - "Почеп", - "Починок", - "Пошехонье", - "Правдинск", - "Приволжск", - "Приморск", - "Приморск", - "Приморско-Ахтарск", - "Приозерск", - "Прокопьевск", - "Пролетарск", - "Протвино", - "Прохладный", - "Псков", - "Пугачёв", - "Пудож", - "Пустошка", - "Пучеж", - "Пушкино", - "Пущино", - "Пыталово", - "Пыть-Ях", - "Пятигорск", - "Радужный", - "Радужный", - "Райчихинск", - "Раменское", - "Рассказово", - "Ревда", - "Реж", - "Реутов", - "Ржев", - "Родники", - "Рославль", - "Россошь", - "Ростов-на-Дону", - "Ростов", - "Рошаль", - "Ртищево", - "Рубцовск", - "Рудня", - "Руза", - "Рузаевка", - "Рыбинск", - "Рыбное", - "Рыльск", - "Ряжск", - "Рязань", - "СакиОспаривается", - "Салават", - "Салаир", - "Салехард", - "Сальск", - "Самара", - "Санкт-Петербург", - "Саранск", - "Сарапул", - "Саратов", - "Саров", - "Сасово", - "Сатка", - "Сафоново", - "Саяногорск", - "Саянск", - "Светлогорск", - "Светлоград", - "Светлый", - "Светогорск", - "Свирск", - "Свободный", - "Себеж", - "СевастопольОспаривается", - "Северо-Курильск", - "Северобайкальск", - "Северодвинск", - "Североморск", - "Североуральск", - "Северск", - "Севск", - "Сегежа", - "Сельцо", - "Семёнов", - "Семикаракорск", - "Семилуки", - "Сенгилей", - "Серафимович", - "Сергач", - "Сергиев Посад", - "Сердобск", - "Серов", - "Серпухов", - "Сертолово", - "Сибай", - "Сим", - "СимферопольОспаривается", - "Сковородино", - "Скопин", - "Славгород", - "Славск", - "Славянск-на-Кубани", - "Сланцы", - "Слободской", - "Слюдянка", - "Смоленск", - "Снежинск", - "Снежногорск", - "Собинка", - "Советск", - "Советск", - "Советск", - "Советская Гавань", - "Советский", - "Сокол", - "Солигалич", - "Соликамск", - "Солнечногорск", - "Соль-Илецк", - "Сольвычегодск", - "Сольцы", - "Сорочинск", - "Сорск", - "Сортавала", - "Сосенский", - "Сосновка", - "Сосновоборск", - "Сосновый Бор", - "Сосногорск", - "Сочи", - "Спас-Деменск", - "Спас-Клепики", - "Спасск", - "Спасск-Дальний", - "Спасск-Рязанский", - "Среднеколымск", - "Среднеуральск", - "Сретенск", - "Ставрополь", - "Старая Купавна", - "Старая Русса", - "Старица", - "Стародуб", - "Старый КрымОспаривается", - "Старый Оскол", - "Стерлитамак", - "Стрежевой", - "Строитель", - "Струнино", - "Ступино", - "Суворов", - "СудакОспаривается", - "Суджа", - "Судогда", - "Суздаль", - "Сунжа", - "Суоярви", - "Сураж", - "Сургут", - "Суровикино", - "Сурск", - "Сусуман", - "Сухиничи", - "Сухой Лог", - "Сызрань", - "Сыктывкар", - "Сысерть", - "Сычёвка", - "Сясьстрой", - "Тавда", - "Таганрог", - "Тайга", - "Тайшет", - "Талдом", - "Талица", - "Тамбов", - "Тара", - "Тарко-Сале", - "Таруса", - "Татарск", - "Таштагол", - "Тверь", - "Теберда", - "Тейково", - "Темников", - "Темрюк", - "Терек", - "Тетюши", - "Тимашёвск", - "Тихвин", - "Тихорецк", - "Тобольск", - "Тогучин", - "Тольятти", - "Томари", - "Томмот", - "Томск", - "Топки", - "Торжок", - "Торопец", - "Тосно", - "Тотьма", - "Трёхгорный", - "Троицк", - "Трубчевск", - "Туапсе", - "Туймазы", - "Тула", - "Тулун", - "Туран", - "Туринск", - "Тутаев", - "Тында", - "Тырныауз", - "Тюкалинск", - "Тюмень", - "Уварово", - "Углегорск", - "Углич", - "Удачный", - "Удомля", - "Ужур", - "Узловая", - "Улан-Удэ", - "Ульяновск", - "Унеча", - "Урай", - "Урень", - "Уржум", - "Урус-Мартан", - "Урюпинск", - "Усинск", - "Усмань", - "Усолье-Сибирское", - "Усолье", - "Уссурийск", - "Усть-Джегута", - "Усть-Илимск", - "Усть-Катав", - "Усть-Кут", - "Усть-Лабинск", - "Устюжна", - "Уфа", - "Ухта", - "Учалы", - "Уяр", - "Фатеж", - "ФеодосияОспаривается", - "Фокино", - "Фокино", - "Фролово", - "Фрязино", - "Фурманов", - "Хабаровск", - "Хадыженск", - "Ханты-Мансийск", - "Харабали", - "Харовск", - "Хасавюрт", - "Хвалынск", - "Хилок", - "Химки", - "Холм", - "Холмск", - "Хотьково", - "Цивильск", - "Цимлянск", - "Циолковский", - "Чадан", - "Чайковский", - "Чапаевск", - "Чаплыгин", - "Чебаркуль", - "Чебоксары", - "Чегем", - "Чекалин", - "Челябинск", - "Чердынь", - "Черемхово", - "Черепаново", - "Череповец", - "Черкесск", - "Чёрмоз", - "Черноголовка", - "Черногорск", - "Чернушка", - "Черняховск", - "Чехов", - "Чистополь", - "Чита", - "Чкаловск", - "Чудово", - "Чулым", - "Чусовой", - "Чухлома", - "Шагонар", - "Шадринск", - "Шали", - "Шарыпово", - "Шарья", - "Шатура", - "Шахты", - "Шахунья", - "Шацк", - "Шебекино", - "Шелехов", - "Шенкурск", - "Шилка", - "Шимановск", - "Шиханы", - "Шлиссельбург", - "Шумерля", - "Шумиха", - "Шуя", - "Щёкино", - "ЩёлкиноОспаривается", - "Щёлково", - "Щигры", - "Щучье", - "Электрогорск", - "Электросталь", - "Электроугли", - "Элиста", - "Энгельс", - "Эртиль", - "Югорск", - "Южа", - "Южно-Сахалинск", - "Южно-Сухокумск", - "Южноуральск", - "Юрга", - "Юрьев-Польский", - "Юрьевец", - "Юрюзань", - "Юхнов", - "Ядрин", - "Якутск", - "ЯлтаОспаривается", - "Ялуторовск", - "Янаул", - "Яранск", - "Яровое", - "Ярославль", - "Ярцево", - "Ясногорск", - "Ясный", - "Яхрома" - ]; - return Scaffold( - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.32, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 39.v), - Text("place_of_living".tr, style: theme.textTheme.headlineSmall), - Spacer(flex: 34), - Text("country".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.cityOfLivingModelObj, - builder: (context, cityOfLivingModelObj) { - return CustomDropDown( - icon: Container( - margin: EdgeInsets.fromLTRB(30.h, 11.v, 17.h, 11.v), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(1.h)), - child: CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize)), - hintText: "Не выбрано".tr, - items: cityOfLivingModelObj?.dropdownItemList ?? [], - onChanged: onDropDownChange(context)); - }), - SizedBox(height: 22.v), - Text("Населенный пункт", style: theme.textTheme.bodyLarge), - SizedBox(height: 2.v), - BlocBuilder(builder: (context, state) { - return RawAutocomplete( - optionsBuilder: (TextEditingValue textEditingValue) => _options.where((String option) { - return option.toLowerCase().startsWith(textEditingValue.text.toLowerCase()); - }), - fieldViewBuilder: ( - BuildContext context, - TextEditingController textEditingController, - FocusNode focusNode, - VoidCallback onFieldSubmitted, - ) { - return CustomTextFormField( - controller: textEditingController, - focusNode: focusNode, - onFieldSubmitted: (String value) => onFieldSubmitted(), - ); - }, - optionsViewBuilder: ( - BuildContext context, - AutocompleteOnSelected onSelected, - Iterable options, - ) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: SizedBox( - height: 200.0, - child: ListView.builder( - padding: const EdgeInsets.all(8.0), - itemCount: options.length, - itemBuilder: (BuildContext context, int index) { - final String option = options.elementAt(index); - return GestureDetector( - onTap: () => onSelected(option), - child: ListTile( - title: Text(option), - ), - ); - }, - ), - ), - ), - ); - }, - ); - }), - Spacer(flex: 65), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - ]))); - } - - onTapContinue(CityOfLivingState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.cityOfLivingModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('bodyCircumferencesScreen', extra: sheet); - }; - } - - onDropDownChange(BuildContext context) { - return (value) { - context.read().add(ChangeDropDownEvent(value: value)); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} - -selectProduct(AutocompleteOnSelected onSelected, String option, CityOfLivingState state) { - state.cityController?.text = option; - return () { - onSelected(option); - }; -} - -buildOptions(List _options) { - return (TextEditingValue textEditingValue) { - return _options.where((String option) { - return true; - }); - }; -} diff --git a/lib/presentation/registration/city_of_living_screen/models/city_of_living_model.dart b/lib/presentation/registration/city_of_living_screen/models/city_of_living_model.dart deleted file mode 100644 index 10366f3..0000000 --- a/lib/presentation/registration/city_of_living_screen/models/city_of_living_model.dart +++ /dev/null @@ -1,1153 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [city_of_living_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class CityOfLivingModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - CityOfLivingModel({ - required this.userRegistrationSheet, - this.dropdownItemList = const [], - this.cityList = const [ - "Абаза", - "Абакан", - "Абдулино", - "Абинск", - "Агидель", - "Агрыз", - "Адыгейск", - "Азнакаево", - "Азов", - "Ак-Довурак", - "Аксай", - "Алагир", - "Алапаевск", - "Алатырь", - "Алдан", - "Алейск", - "Александров", - "Александровск", - "Александровск-Сахалинский", - "Алексеевка", - "Алексин", - "Алзамай", - "АлупкаОспаривается", - "АлуштаОспаривается", - "Альметьевск", - "Амурск", - "Анадырь", - "Анапа", - "Ангарск", - "Андреаполь", - "Анжеро-Судженск", - "Анива", - "Апатиты", - "Апрелевка", - "Апшеронск", - "Арамиль", - "Аргун", - "Ардатов", - "Ардон", - "Арзамас", - "Аркадак", - "Армавир", - "АрмянскОспаривается", - "Арсеньев", - "Арск", - "Артём", - "Артёмовск", - "Артёмовский", - "Архангельск", - "Асбест", - "Асино", - "Астрахань", - "Аткарск", - "Ахтубинск", - "Ачинск", - "Аша", - "Бабаево", - "Бабушкин", - "Бавлы", - "Багратионовск", - "Байкальск", - "Баймак", - "Бакал", - "Баксан", - "Балабаново", - "Балаково", - "Балахна", - "Балашиха", - "Балашов", - "Балей", - "Балтийск", - "Барабинск", - "Барнаул", - "Барыш", - "Батайск", - "БахчисарайОспаривается", - "Бежецк", - "Белая Калитва", - "Белая Холуница", - "Белгород", - "Белебей", - "Белёв", - "Белинский", - "Белово", - "Белогорск", - "БелогорскОспаривается", - "Белозерск", - "Белокуриха", - "Беломорск", - "Белоозёрский", - "Белорецк", - "Белореченск", - "Белоусово", - "Белоярский", - "Белый", - "Бердск", - "Березники", - "Берёзовский", - "Берёзовский", - "Беслан", - "Бийск", - "Бикин", - "Билибино", - "Биробиджан", - "Бирск", - "Бирюсинск", - "Бирюч", - "Благовещенск", - "Благовещенск", - "Благодарный", - "Бобров", - "Богданович", - "Богородицк", - "Богородск", - "Боготол", - "Богучар", - "Бодайбо", - "Бокситогорск", - "Болгар", - "Бологое", - "Болотное", - "Болохово", - "Болхов", - "Большой Камень", - "Бор", - "Борзя", - "Борисоглебск", - "Боровичи", - "Боровск", - "Бородино", - "Братск", - "Бронницы", - "Брянск", - "Бугульма", - "Бугуруслан", - "Будённовск", - "Бузулук", - "Буинск", - "Буй", - "Буйнакск", - "Бутурлиновка", - "Валдай", - "Валуйки", - "Велиж", - "Великие Луки", - "Великий Новгород", - "Великий Устюг", - "Вельск", - "Венёв", - "Верещагино", - "Верея", - "Верхнеуральск", - "Верхний Тагил", - "Верхний Уфалей", - "Верхняя Пышма", - "Верхняя Салда", - "Верхняя Тура", - "Верхотурье", - "Верхоянск", - "Весьегонск", - "Ветлуга", - "Видное", - "Вилюйск", - "Вилючинск", - "Вихоревка", - "Вичуга", - "Владивосток", - "Владикавказ", - "Владимир", - "Волгоград", - "Волгодонск", - "Волгореченск", - "Волжск", - "Волжский", - "Вологда", - "Володарск", - "Волоколамск", - "Волосово", - "Волхов", - "Волчанск", - "Вольск", - "Воркута", - "Воронеж", - "Ворсма", - "Воскресенск", - "Воткинск", - "Всеволожск", - "Вуктыл", - "Выборг", - "Выкса", - "Высоковск", - "Высоцк", - "Вытегра", - "Вышний Волочёк", - "Вяземский", - "Вязники", - "Вязьма", - "Вятские Поляны", - "Гаврилов Посад", - "Гаврилов-Ям", - "Гагарин", - "Гаджиево", - "Гай", - "Галич", - "Гатчина", - "Гвардейск", - "Гдов", - "Геленджик", - "Георгиевск", - "Глазов", - "Голицыно", - "Горбатов", - "Горно-Алтайск", - "Горнозаводск", - "Горняк", - "Городец", - "Городище", - "Городовиковск", - "Гороховец", - "Горячий Ключ", - "Грайворон", - "Гремячинск", - "Грозный", - "Грязи", - "Грязовец", - "Губаха", - "Губкин", - "Губкинский", - "Гудермес", - "Гуково", - "Гулькевичи", - "Гурьевск", - "Гурьевск", - "Гусев", - "Гусиноозёрск", - "Гусь-Хрустальный", - "Давлеканово", - "Дагестанские Огни", - "Далматово", - "Дальнегорск", - "Дальнереченск", - "Данилов", - "Данков", - "Дегтярск", - "Дедовск", - "Демидов", - "Дербент", - "Десногорск", - "ДжанкойОспаривается", - "Дзержинск", - "Дзержинский", - "Дивногорск", - "Дигора", - "Димитровград", - "Дмитриев", - "Дмитров", - "Дмитровск", - "Дно", - "Добрянка", - "Долгопрудный", - "Долинск", - "Домодедово", - "Донецк", - "Донской", - "Дорогобуж", - "Дрезна", - "Дубна", - "Дубовка", - "Дудинка", - "Духовщина", - "Дюртюли", - "Дятьково", - "ЕвпаторияОспаривается", - "Егорьевск", - "Ейск", - "Екатеринбург", - "Елабуга", - "Елец", - "Елизово", - "Ельня", - "Еманжелинск", - "Емва", - "Енисейск", - "Ермолино", - "Ершов", - "Ессентуки", - "Ефремов", - "Железноводск", - "Железногорск", - "Железногорск", - "Железногорск-Илимский", - "Жердевка", - "Жигулёвск", - "Жиздра", - "Жирновск", - "Жуков", - "Жуковка", - "Жуковский", - "Завитинск", - "Заводоуковск", - "Заволжск", - "Заволжье", - "Задонск", - "Заинск", - "Закаменск", - "Заозёрный", - "Заозёрск", - "Западная Двина", - "Заполярный", - "Зарайск", - "Заречный", - "Заречный", - "Заринск", - "Звенигово", - "Звенигород", - "Зверево", - "Зеленогорск", - "Зеленоградск", - "Зеленодольск", - "Зеленокумск", - "Зерноград", - "Зея", - "Зима", - "Златоуст", - "Злынка", - "Змеиногорск", - "Знаменск", - "Зубцов", - "Зуевка", - "Ивангород", - "Иваново", - "Ивантеевка", - "Ивдель", - "Игарка", - "Ижевск", - "Избербаш", - "Изобильный", - "Иланский", - "Инза", - "Иннополис", - "Инсар", - "Инта", - "Ипатово", - "Ирбит", - "Иркутск", - "Исилькуль", - "Искитим", - "Истра", - "Ишим", - "Ишимбай", - "Йошкар-Ола", - "Кадников", - "Казань", - "Калач", - "Калач-на-Дону", - "Калачинск", - "Калининград", - "Калининск", - "Калтан", - "Калуга", - "Калязин", - "Камбарка", - "Каменка", - "Каменногорск", - "Каменск-Уральский", - "Каменск-Шахтинский", - "Камень-на-Оби", - "Камешково", - "Камызяк", - "Камышин", - "Камышлов", - "Канаш", - "Кандалакша", - "Канск", - "Карабаново", - "Карабаш", - "Карабулак", - "Карасук", - "Карачаевск", - "Карачев", - "Каргат", - "Каргополь", - "Карпинск", - "Карталы", - "Касимов", - "Касли", - "Каспийск", - "Катав-Ивановск", - "Катайск", - "Качканар", - "Кашин", - "Кашира", - "Кедровый", - "Кемерово", - "Кемь", - "КерчьОспаривается", - "Кизел", - "Кизилюрт", - "Кизляр", - "Кимовск", - "Кимры", - "Кингисепп", - "Кинель", - "Кинешма", - "Киреевск", - "Киренск", - "Киржач", - "Кириллов", - "Кириши", - "Киров", - "Киров", - "Кировград", - "Кирово-Чепецк", - "Кировск", - "Кировск", - "Кирс", - "Кирсанов", - "Киселёвск", - "Кисловодск", - "Клин", - "Клинцы", - "Княгинино", - "Ковдор", - "Ковров", - "Ковылкино", - "Когалым", - "Кодинск", - "Козельск", - "Козловка", - "Козьмодемьянск", - "Кола", - "Кологрив", - "Коломна", - "Колпашево", - "Кольчугино", - "Коммунар", - "Комсомольск", - "Комсомольск-на-Амуре", - "Конаково", - "Кондопога", - "Кондрово", - "Константиновск", - "Копейск", - "Кораблино", - "Кореновск", - "Коркино", - "Королёв", - "Короча", - "Корсаков", - "Коряжма", - "Костерёво", - "Костомукша", - "Кострома", - "Котельники", - "Котельниково", - "Котельнич", - "Котлас", - "Котово", - "Котовск", - "Кохма", - "Красавино", - "Красноармейск", - "Красноармейск", - "Красновишерск", - "Красногорск", - "Краснодар", - "Краснозаводск", - "Краснознаменск", - "Краснознаменск", - "Краснокаменск", - "Краснокамск", - "КрасноперекопскОспаривается", - "Краснослободск", - "Краснослободск", - "Краснотурьинск", - "Красноуральск", - "Красноуфимск", - "Красноярск", - "Красный Кут", - "Красный Сулин", - "Красный Холм", - "Кремёнки", - "Кропоткин", - "Крымск", - "Кстово", - "Кубинка", - "Кувандык", - "Кувшиново", - "Кудрово", - "Кудымкар", - "Кузнецк", - "Куйбышев", - "Кукмор", - "Кулебаки", - "Кумертау", - "Кунгур", - "Купино", - "Курган", - "Курганинск", - "Курильск", - "Курлово", - "Куровское", - "Курск", - "Куртамыш", - "Курчалой", - "Курчатов", - "Куса", - "Кушва", - "Кызыл", - "Кыштым", - "Кяхта", - "Лабинск", - "Лабытнанги", - "Лагань", - "Ладушкин", - "Лаишево", - "Лакинск", - "Лангепас", - "Лахденпохья", - "Лебедянь", - "Лениногорск", - "Ленинск", - "Ленинск-Кузнецкий", - "Ленск", - "Лермонтов", - "Лесной", - "Лесозаводск", - "Лесосибирск", - "Ливны", - "Ликино-Дулёво", - "Липецк", - "Липки", - "Лиски", - "Лихославль", - "Лобня", - "Лодейное Поле", - "Лосино-Петровский", - "Луга", - "Луза", - "Лукоянов", - "Луховицы", - "Лысково", - "Лысьва", - "Лыткарино", - "Льгов", - "Любань", - "Люберцы", - "Любим", - "Людиново", - "Лянтор", - "Магадан", - "Магас", - "Магнитогорск", - "Майкоп", - "Майский", - "Макаров", - "Макарьев", - "Макушино", - "Малая Вишера", - "Малгобек", - "Малмыж", - "Малоархангельск", - "Малоярославец", - "Мамадыш", - "Мамоново", - "Мантурово", - "Мариинск", - "Мариинский Посад", - "Маркс", - "Махачкала", - "Мглин", - "Мегион", - "Медвежьегорск", - "Медногорск", - "Медынь", - "Межгорье", - "Междуреченск", - "Мезень", - "Меленки", - "Мелеуз", - "Менделеевск", - "Мензелинск", - "Мещовск", - "Миасс", - "Микунь", - "Миллерово", - "Минеральные Воды", - "Минусинск", - "Миньяр", - "Мирный", - "Мирный", - "Михайлов", - "Михайловка", - "Михайловск", - "Михайловск", - "Мичуринск", - "Могоча", - "Можайск", - "Можга", - "Моздок", - "Мончегорск", - "Морозовск", - "Моршанск", - "Мосальск", - "Москва", - "Муравленко", - "Мураши", - "Мурино", - "Мурманск", - "Муром", - "Мценск", - "Мыски", - "Мытищи", - "Мышкин", - "Набережные Челны", - "Навашино", - "Наволоки", - "Надым", - "Назарово", - "Назрань", - "Называевск", - "Нальчик", - "Нариманов", - "Наро-Фоминск", - "Нарткала", - "Нарьян-Мар", - "Находка", - "Невель", - "Невельск", - "Невинномысск", - "Невьянск", - "Нелидово", - "Неман", - "Нерехта", - "Нерчинск", - "Нерюнгри", - "Нестеров", - "Нефтегорск", - "Нефтекамск", - "Нефтекумск", - "Нефтеюганск", - "Нея", - "Нижневартовск", - "Нижнекамск", - "Нижнеудинск", - "Нижние Серги", - "Нижний Ломов", - "Нижний Новгород", - "Нижний Тагил", - "Нижняя Салда", - "Нижняя Тура", - "Николаевск", - "Николаевск-на-Амуре", - "Никольск", - "Никольск", - "Никольское", - "Новая Ладога", - "Новая Ляля", - "Новоалександровск", - "Новоалтайск", - "Новоаннинский", - "Нововоронеж", - "Новодвинск", - "Новозыбков", - "Новокубанск", - "Новокузнецк", - "Новокуйбышевск", - "Новомичуринск", - "Новомосковск", - "Новопавловск", - "Новоржев", - "Новороссийск", - "Новосибирск", - "Новосиль", - "Новосокольники", - "Новотроицк", - "Новоузенск", - "Новоульяновск", - "Новоуральск", - "Новохопёрск", - "Новочебоксарск", - "Новочеркасск", - "Новошахтинск", - "Новый Оскол", - "Новый Уренгой", - "Ногинск", - "Нолинск", - "Норильск", - "Ноябрьск", - "Нурлат", - "Нытва", - "Нюрба", - "Нягань", - "Нязепетровск", - "Няндома", - "Облучье", - "Обнинск", - "Обоянь", - "Обь", - "Одинцово", - "Озёрск", - "Озёрск", - "Озёры", - "Октябрьск", - "Октябрьский", - "Окуловка", - "Олёкминск", - "Оленегорск", - "Олонец", - "Омск", - "Омутнинск", - "Онега", - "Опочка", - "Орёл", - "Оренбург", - "Орехово-Зуево", - "Орлов", - "Орск", - "Оса", - "Осинники", - "Осташков", - "Остров", - "Островной", - "Острогожск", - "Отрадное", - "Отрадный", - "Оха", - "Оханск", - "Очёр", - "Павлово", - "Павловск", - "Павловский Посад", - "Палласовка", - "Партизанск", - "Певек", - "Пенза", - "Первомайск", - "Первоуральск", - "Перевоз", - "Пересвет", - "Переславль-Залесский", - "Пермь", - "Пестово", - "Петров Вал", - "Петровск", - "Петровск-Забайкальский", - "Петрозаводск", - "Петропавловск-Камчатский", - "Петухово", - "Петушки", - "Печора", - "Печоры", - "Пикалёво", - "Пионерский", - "Питкяранта", - "Плавск", - "Пласт", - "Плёс", - "Поворино", - "Подольск", - "Подпорожье", - "Покачи", - "Покров", - "Покровск", - "Полевской", - "Полесск", - "Полысаево", - "Полярные Зори", - "Полярный", - "Поронайск", - "Порхов", - "Похвистнево", - "Почеп", - "Починок", - "Пошехонье", - "Правдинск", - "Приволжск", - "Приморск", - "Приморск", - "Приморско-Ахтарск", - "Приозерск", - "Прокопьевск", - "Пролетарск", - "Протвино", - "Прохладный", - "Псков", - "Пугачёв", - "Пудож", - "Пустошка", - "Пучеж", - "Пушкино", - "Пущино", - "Пыталово", - "Пыть-Ях", - "Пятигорск", - "Радужный", - "Радужный", - "Райчихинск", - "Раменское", - "Рассказово", - "Ревда", - "Реж", - "Реутов", - "Ржев", - "Родники", - "Рославль", - "Россошь", - "Ростов-на-Дону", - "Ростов", - "Рошаль", - "Ртищево", - "Рубцовск", - "Рудня", - "Руза", - "Рузаевка", - "Рыбинск", - "Рыбное", - "Рыльск", - "Ряжск", - "Рязань", - "СакиОспаривается", - "Салават", - "Салаир", - "Салехард", - "Сальск", - "Самара", - "Санкт-Петербург", - "Саранск", - "Сарапул", - "Саратов", - "Саров", - "Сасово", - "Сатка", - "Сафоново", - "Саяногорск", - "Саянск", - "Светлогорск", - "Светлоград", - "Светлый", - "Светогорск", - "Свирск", - "Свободный", - "Себеж", - "СевастопольОспаривается", - "Северо-Курильск", - "Северобайкальск", - "Северодвинск", - "Североморск", - "Североуральск", - "Северск", - "Севск", - "Сегежа", - "Сельцо", - "Семёнов", - "Семикаракорск", - "Семилуки", - "Сенгилей", - "Серафимович", - "Сергач", - "Сергиев Посад", - "Сердобск", - "Серов", - "Серпухов", - "Сертолово", - "Сибай", - "Сим", - "СимферопольОспаривается", - "Сковородино", - "Скопин", - "Славгород", - "Славск", - "Славянск-на-Кубани", - "Сланцы", - "Слободской", - "Слюдянка", - "Смоленск", - "Снежинск", - "Снежногорск", - "Собинка", - "Советск", - "Советск", - "Советск", - "Советская Гавань", - "Советский", - "Сокол", - "Солигалич", - "Соликамск", - "Солнечногорск", - "Соль-Илецк", - "Сольвычегодск", - "Сольцы", - "Сорочинск", - "Сорск", - "Сортавала", - "Сосенский", - "Сосновка", - "Сосновоборск", - "Сосновый Бор", - "Сосногорск", - "Сочи", - "Спас-Деменск", - "Спас-Клепики", - "Спасск", - "Спасск-Дальний", - "Спасск-Рязанский", - "Среднеколымск", - "Среднеуральск", - "Сретенск", - "Ставрополь", - "Старая Купавна", - "Старая Русса", - "Старица", - "Стародуб", - "Старый КрымОспаривается", - "Старый Оскол", - "Стерлитамак", - "Стрежевой", - "Строитель", - "Струнино", - "Ступино", - "Суворов", - "СудакОспаривается", - "Суджа", - "Судогда", - "Суздаль", - "Сунжа", - "Суоярви", - "Сураж", - "Сургут", - "Суровикино", - "Сурск", - "Сусуман", - "Сухиничи", - "Сухой Лог", - "Сызрань", - "Сыктывкар", - "Сысерть", - "Сычёвка", - "Сясьстрой", - "Тавда", - "Таганрог", - "Тайга", - "Тайшет", - "Талдом", - "Талица", - "Тамбов", - "Тара", - "Тарко-Сале", - "Таруса", - "Татарск", - "Таштагол", - "Тверь", - "Теберда", - "Тейково", - "Темников", - "Темрюк", - "Терек", - "Тетюши", - "Тимашёвск", - "Тихвин", - "Тихорецк", - "Тобольск", - "Тогучин", - "Тольятти", - "Томари", - "Томмот", - "Томск", - "Топки", - "Торжок", - "Торопец", - "Тосно", - "Тотьма", - "Трёхгорный", - "Троицк", - "Трубчевск", - "Туапсе", - "Туймазы", - "Тула", - "Тулун", - "Туран", - "Туринск", - "Тутаев", - "Тында", - "Тырныауз", - "Тюкалинск", - "Тюмень", - "Уварово", - "Углегорск", - "Углич", - "Удачный", - "Удомля", - "Ужур", - "Узловая", - "Улан-Удэ", - "Ульяновск", - "Унеча", - "Урай", - "Урень", - "Уржум", - "Урус-Мартан", - "Урюпинск", - "Усинск", - "Усмань", - "Усолье-Сибирское", - "Усолье", - "Уссурийск", - "Усть-Джегута", - "Усть-Илимск", - "Усть-Катав", - "Усть-Кут", - "Усть-Лабинск", - "Устюжна", - "Уфа", - "Ухта", - "Учалы", - "Уяр", - "Фатеж", - "ФеодосияОспаривается", - "Фокино", - "Фокино", - "Фролово", - "Фрязино", - "Фурманов", - "Хабаровск", - "Хадыженск", - "Ханты-Мансийск", - "Харабали", - "Харовск", - "Хасавюрт", - "Хвалынск", - "Хилок", - "Химки", - "Холм", - "Холмск", - "Хотьково", - "Цивильск", - "Цимлянск", - "Циолковский", - "Чадан", - "Чайковский", - "Чапаевск", - "Чаплыгин", - "Чебаркуль", - "Чебоксары", - "Чегем", - "Чекалин", - "Челябинск", - "Чердынь", - "Черемхово", - "Черепаново", - "Череповец", - "Черкесск", - "Чёрмоз", - "Черноголовка", - "Черногорск", - "Чернушка", - "Черняховск", - "Чехов", - "Чистополь", - "Чита", - "Чкаловск", - "Чудово", - "Чулым", - "Чусовой", - "Чухлома", - "Шагонар", - "Шадринск", - "Шали", - "Шарыпово", - "Шарья", - "Шатура", - "Шахты", - "Шахунья", - "Шацк", - "Шебекино", - "Шелехов", - "Шенкурск", - "Шилка", - "Шимановск", - "Шиханы", - "Шлиссельбург", - "Шумерля", - "Шумиха", - "Шуя", - "Щёкино", - "ЩёлкиноОспаривается", - "Щёлково", - "Щигры", - "Щучье", - "Электрогорск", - "Электросталь", - "Электроугли", - "Элиста", - "Энгельс", - "Эртиль", - "Югорск", - "Южа", - "Южно-Сахалинск", - "Южно-Сухокумск", - "Южноуральск", - "Юрга", - "Юрьев-Польский", - "Юрьевец", - "Юрюзань", - "Юхнов", - "Ядрин", - "Якутск", - "ЯлтаОспаривается", - "Ялуторовск", - "Янаул", - "Яранск", - "Яровое", - "Ярославль", - "Ярцево", - "Ясногорск", - "Ясный", - "Яхрома" - ], - }); - - List dropdownItemList; - - List cityList; - - CityOfLivingModel copyWith({ - List? dropdownItemList, - List? dropdownItemList1, - }) { - return CityOfLivingModel( - userRegistrationSheet: userRegistrationSheet, - dropdownItemList: dropdownItemList ?? this.dropdownItemList, - cityList: cityList, - ); - } - - @override - List get props => - [dropdownItemList, cityList, userRegistrationSheet]; -} diff --git a/lib/presentation/registration/credentials_screen/bloc/credentials_bloc.dart b/lib/presentation/registration/credentials_screen/bloc/credentials_bloc.dart deleted file mode 100644 index 91090d2..0000000 --- a/lib/presentation/registration/credentials_screen/bloc/credentials_bloc.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/credentials_screen/models/credentials_model.dart'; -part 'credentials_event.dart'; -part 'credentials_state.dart'; - -/// A bloc that manages the state of a Credentials according to the event that is dispatched to it. -class CredentialsBloc extends Bloc { - CredentialsBloc(CredentialsState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - CredentialsInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - emailController: TextEditingController(), - nameController: TextEditingController(), - passwordController: TextEditingController(), - passwordConfirmationController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/credentials_screen/bloc/credentials_state.dart b/lib/presentation/registration/credentials_screen/bloc/credentials_state.dart deleted file mode 100644 index e127da6..0000000 --- a/lib/presentation/registration/credentials_screen/bloc/credentials_state.dart +++ /dev/null @@ -1,49 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'credentials_bloc.dart'; - -/// Represents the state of Credentials in the application. -class CredentialsState extends Equatable { - CredentialsState({ - this.emailController, - this.nameController, - this.passwordController, - this.passwordConfirmationController, - this.credentialsModelObj, - }); - - TextEditingController? emailController; - - TextEditingController? nameController; - - TextEditingController? passwordController; - - TextEditingController? passwordConfirmationController; - - CredentialsModel? credentialsModelObj; - - @override - List get props => [ - emailController, - nameController, - passwordController, - passwordConfirmationController, - credentialsModelObj, - ]; - CredentialsState copyWith({ - TextEditingController? nameController, - TextEditingController? emailController, - TextEditingController? passwordController, - TextEditingController? passwordConfirmationController, - CredentialsModel? credentialsModelObj, - }) { - return CredentialsState( - emailController: emailController ?? this.emailController, - nameController: nameController ?? this.nameController, - passwordController: passwordController ?? this.passwordController, - passwordConfirmationController: - passwordConfirmationController ?? this.passwordConfirmationController, - credentialsModelObj: credentialsModelObj ?? this.credentialsModelObj, - ); - } -} diff --git a/lib/presentation/registration/credentials_screen/credentials_screen.dart b/lib/presentation/registration/credentials_screen/credentials_screen.dart deleted file mode 100644 index 90723f6..0000000 --- a/lib/presentation/registration/credentials_screen/credentials_screen.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/credentials_bloc.dart'; -import 'models/credentials_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:validators/validators.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class CredentialsScreen extends StatelessWidget { - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => CredentialsBloc( - CredentialsState( - credentialsModelObj: CredentialsModel(userRegistrationSheet: sheet), - ), - )..add(CredentialsInitialEvent()), - child: CredentialsScreen(), - ); - } - - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.05, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 39.v), - Text("user_registration".tr, style: theme.textTheme.headlineSmall), - SizedBox(height: 16.v), - Text("email".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.emailController, - builder: (context, emailController) { - return CustomTextFormField(controller: emailController, textInputAction: TextInputAction.done); - }), - SizedBox(height: 22.v), - Text("username".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.nameController, - builder: (context, nameController) { - return CustomTextFormField(controller: nameController, textInputAction: TextInputAction.done); - }), - SizedBox(height: 19.v), - Text("password".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 5.v), - BlocSelector( - selector: (state) => state.passwordController, - builder: (context, passwordController) { - return CustomTextFormField( - obscureText: true, - controller: passwordController, - ); - }), - SizedBox(height: 21.v), - Text("password_confirmation".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.passwordConfirmationController, - builder: (context, passwordConfirmationController) { - return CustomTextFormField(obscureText: true, controller: passwordConfirmationController, textInputAction: TextInputAction.done); - }), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - ]))); - } - - onTapContinue(CredentialsState state, BuildContext context) { - return () { - List errors = - validateFields(state.emailController!.text, state.nameController!.text, state.passwordController!.text, state.passwordConfirmationController!.text); - if (errors.isEmpty) { - UserRegistrationSheet sheet = state.credentialsModelObj!.userRegistrationSheet; - sheet.email = state.emailController!.text; - sheet.name = state.nameController!.text; - sheet.password = state.passwordController!.text; - sheet.passwordConfirmation = state.passwordConfirmationController!.text; - GoRouter.of(context).goNamed('nameScreen', extra: sheet); - } else { - String errorMessage = ''; - - for (var error in errors) { - errorMessage += error + '\n\n'; - } - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Ошибка'), - content: Text(errorMessage), - actions: [ - TextButton( - onPressed: onTapOk(context), - child: Text('OK'), - ), - ], - ), - ); - } - }; - } - - onTapOk(BuildContext context) { - return () { - Navigator.pop(context); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar(leadingWidth: 29.h, centerTitle: true, title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - List validateFields(String email, String name, String password, String passwordConfirmation) { - List errors = []; - - if (!isEmail(email)) { - errors.add('email_invalid'.tr); - } - - if (email.isEmpty) { - errors.add('email_empty'.tr); - } - - if (name.length < 6) { - errors.add('name_short'.tr); - } - - if (name.isEmpty) { - errors.add('name_empty'.tr); - } - - if (password.isEmpty) { - errors.add('name_empty'.tr); - } - - if (password.length < 6) { - errors.add('password_short'.tr); - } - - if (password != passwordConfirmation) { - errors.add('password_confirmation_mismatch'.tr); - } - - return errors; - } -} diff --git a/lib/presentation/registration/credentials_screen/models/credentials_model.dart b/lib/presentation/registration/credentials_screen/models/credentials_model.dart deleted file mode 100644 index ae6c320..0000000 --- a/lib/presentation/registration/credentials_screen/models/credentials_model.dart +++ /dev/null @@ -1,22 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [credentials_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class CredentialsModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - - CredentialsModel({required this.userRegistrationSheet}); - - CredentialsModel copyWith({UserRegistrationSheet? userRegistrationSheet}) { - return CredentialsModel( - userRegistrationSheet: - userRegistrationSheet ?? this.userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_bloc.dart b/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_bloc.dart deleted file mode 100644 index 78dec54..0000000 --- a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_bloc.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/date_of_birth_screen/models/date_of_birth_model.dart'; -part 'date_of_birth_event.dart'; -part 'date_of_birth_state.dart'; - -/// A bloc that manages the state of a DateOfBirth according to the event that is dispatched to it. -class DateOfBirthBloc extends Bloc { - DateOfBirthBloc(DateOfBirthState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - DateOfBirthInitialEvent event, - Emitter emit, - ) async {} -} diff --git a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_event.dart b/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_event.dart deleted file mode 100644 index 0d6938b..0000000 --- a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'date_of_birth_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///DateOfBirth widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class DateOfBirthEvent extends Equatable {} - -/// Event that is dispatched when the DateOfBirth widget is first created. -class DateOfBirthInitialEvent extends DateOfBirthEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_state.dart b/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_state.dart deleted file mode 100644 index e54b82c..0000000 --- a/lib/presentation/registration/date_of_birth_screen/bloc/date_of_birth_state.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'date_of_birth_bloc.dart'; - -/// Represents the state of DateOfBirth in the application. -class DateOfBirthState extends Equatable { - DateOfBirthState({this.dateOfBirthModelObj}); - - DateOfBirthModel? dateOfBirthModelObj; - - @override - List get props => [ - dateOfBirthModelObj, - ]; - DateOfBirthState copyWith({DateOfBirthModel? dateOfBirthModelObj}) { - return DateOfBirthState( - dateOfBirthModelObj: dateOfBirthModelObj ?? this.dateOfBirthModelObj, - ); - } -} diff --git a/lib/presentation/registration/date_of_birth_screen/date_of_birth_screen.dart b/lib/presentation/registration/date_of_birth_screen/date_of_birth_screen.dart deleted file mode 100644 index 5f68a3d..0000000 --- a/lib/presentation/registration/date_of_birth_screen/date_of_birth_screen.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/date_of_birth_bloc.dart'; -import 'models/date_of_birth_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class DateOfBirthScreen extends StatefulWidget { - const DateOfBirthScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => DateOfBirthBloc( - DateOfBirthState( - dateOfBirthModelObj: DateOfBirthModel( - userRegistrationSheet: sheet, - ), - ), - )..add(DateOfBirthInitialEvent()), - child: DateOfBirthScreen(), - ); - } - - @override - State createState() => _DateOfBirthScreenState(); -} - -class _DateOfBirthScreenState extends State { - DateTime selectedDate = DateTime.now(); - - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return BlocBuilder(builder: (context, state) { - return Scaffold( - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.24, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 38.v), - Text("date_of_birth".tr, style: theme.textTheme.headlineSmall), - Spacer(flex: 39), - _buildDateInput(context), - Spacer(flex: 60), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - ]))); - }); - } - - onTapContinue(DateOfBirthState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.dateOfBirthModelObj!.userRegistrationSheet; - sheet.birthdate = selectedDate.toString(); - GoRouter.of(context).goNamed('cityOfLivingScreen', extra: sheet); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildDateInput(BuildContext context) { - return Container( - width: 343.h, - padding: EdgeInsets.symmetric(horizontal: 4.h, vertical: 1.v), - decoration: AppDecoration.outlineBlueA.copyWith(borderRadius: BorderRadiusStyle.circleBorder8), - child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - CustomImageView(imagePath: ImageConstant.imgFavorite, height: 12.adaptSize, width: 12.adaptSize, radius: BorderRadius.circular(1.h)), - SizedBox(height: 6.v), - Align( - alignment: Alignment.center, - child: GestureDetector( - onTap: onTapCalendar(context), - child: Text('${selectedDate.day}.${selectedDate.month}.${selectedDate.year}', style: theme.textTheme.titleMedium))), - SizedBox(height: 6.v) - ])); - } - - onTapCalendar(BuildContext context) { - return () { - openDatePickerDialog(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - /// Displays a date picker dialog to update the selected date - /// - /// This function returns a `Future` that completes with `void`. - Future openDatePickerDialog(BuildContext context) async { - DateTime? dateTime = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(1924), - lastDate: DateTime( - DateTime.now().year, - DateTime.now().month, - DateTime.now().day, - ), - ); - if (dateTime != null) { - if (mounted) { - setState(() { - selectedDate = dateTime; - }); - } - } - } -} diff --git a/lib/presentation/registration/date_of_birth_screen/models/date_of_birth_model.dart b/lib/presentation/registration/date_of_birth_screen/models/date_of_birth_model.dart deleted file mode 100644 index 121b10d..0000000 --- a/lib/presentation/registration/date_of_birth_screen/models/date_of_birth_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [date_of_birth_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class DateOfBirthModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - - DateOfBirthModel({required this.userRegistrationSheet}); - - DateOfBirthModel copyWith() { - return DateOfBirthModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_bloc.dart b/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_bloc.dart deleted file mode 100644 index 05f9d90..0000000 --- a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_bloc.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/favorite_foods_screen/models/favorite_foods_model.dart'; -part 'favorite_foods_event.dart'; -part 'favorite_foods_state.dart'; - -/// A bloc that manages the state of a FavoriteFoods according to the event that is dispatched to it. -class FavoriteFoodsBloc extends Bloc { - FavoriteFoodsBloc(FavoriteFoodsState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - FavoriteFoodsInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - favoriteFoodsController: TextEditingController(), - unfavoriteFoodsController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_event.dart b/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_event.dart deleted file mode 100644 index f930b8e..0000000 --- a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'favorite_foods_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///FavoriteFoods widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class FavoriteFoodsEvent extends Equatable {} - -/// Event that is dispatched when the FavoriteFoods widget is first created. -class FavoriteFoodsInitialEvent extends FavoriteFoodsEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_state.dart b/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_state.dart deleted file mode 100644 index aa4fc3b..0000000 --- a/lib/presentation/registration/favorite_foods_screen/bloc/favorite_foods_state.dart +++ /dev/null @@ -1,39 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'favorite_foods_bloc.dart'; - -/// Represents the state of FavoriteFoods in the application. -class FavoriteFoodsState extends Equatable { - FavoriteFoodsState({ - this.favoriteFoodsController, - this.unfavoriteFoodsController, - this.favoriteFoodsModelObj, - }); - - TextEditingController? favoriteFoodsController; - - TextEditingController? unfavoriteFoodsController; - - FavoriteFoodsModel? favoriteFoodsModelObj; - - @override - List get props => [ - favoriteFoodsController, - unfavoriteFoodsController, - favoriteFoodsModelObj, - ]; - FavoriteFoodsState copyWith({ - TextEditingController? favoriteFoodsController, - TextEditingController? unfavoriteFoodsController, - FavoriteFoodsModel? favoriteFoodsModelObj, - }) { - return FavoriteFoodsState( - favoriteFoodsController: - favoriteFoodsController ?? this.favoriteFoodsController, - unfavoriteFoodsController: - unfavoriteFoodsController ?? this.unfavoriteFoodsController, - favoriteFoodsModelObj: - favoriteFoodsModelObj ?? this.favoriteFoodsModelObj, - ); - } -} diff --git a/lib/presentation/registration/favorite_foods_screen/favorite_foods_screen.dart b/lib/presentation/registration/favorite_foods_screen/favorite_foods_screen.dart deleted file mode 100644 index 94771a1..0000000 --- a/lib/presentation/registration/favorite_foods_screen/favorite_foods_screen.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/favorite_foods_bloc.dart'; -import 'models/favorite_foods_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class FavoriteFoodsScreen extends StatefulWidget { - const FavoriteFoodsScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => - FavoriteFoodsBloc(FavoriteFoodsState(favoriteFoodsModelObj: FavoriteFoodsModel(userRegistrationSheet: sheet)))..add(FavoriteFoodsInitialEvent()), - child: FavoriteFoodsScreen()); - } - - @override - State createState() => _FavoriteFoodsScreenState(); -} - -class _FavoriteFoodsScreenState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.90, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 19.v), - Container( - width: 327.h, - margin: EdgeInsets.only(left: 8.h, right: 7.h), - child: Text("favorite_unfavorite_foods".tr, - maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: theme.textTheme.headlineSmall)), - SizedBox(height: 13.v), - _buildTextFormFieldFav(context), - SizedBox(height: 12.v), - _buildTextFormFieldUnfav(context), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 40.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - BlocBuilder(builder: (context, state) { - return GestureDetector( - onTap: onTapSkip(state, context), - child: Text("skip".tr, style: theme.textTheme.bodyLarge), - ); - }), - ]))); - } - - onTapSkip(FavoriteFoodsState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.favoriteFoodsModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('additionalInformationScreen', extra: sheet); - }; - } - - onTapContinue(FavoriteFoodsState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.favoriteFoodsModelObj!.userRegistrationSheet; - sheet.favoriteFoods = state.favoriteFoodsController!.text; - sheet.unfavoriteFoods = state.unfavoriteFoodsController!.text; - GoRouter.of(context).goNamed('additionalInformationScreen', extra: sheet); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 31.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 18.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildTextFormFieldFav(BuildContext context) { - return Column(children: [ - Text("favorite_foods".tr, style: CustomTextStyles.titleMediumSegoeUI), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.favoriteFoodsController, - builder: (context, favoriteFoodsController) { - return CustomTextFormField(controller: favoriteFoodsController, hintText: "enter_information".tr, maxLines: 7); - }) - ]); - } - - /// Section Widget - _buildTextFormFieldUnfav(BuildContext context) { - return Column(children: [ - Text("unfavorite_foods".tr, style: CustomTextStyles.titleMediumSegoeUI), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.unfavoriteFoodsController, - builder: (context, unfavoriteFoodsController) { - return CustomTextFormField( - controller: unfavoriteFoodsController, hintText: "enter_information".tr, textInputAction: TextInputAction.done, maxLines: 7); - }) - ]); - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - /// Navigates to the scheduleScreen when the action is triggered. - navigateToAdditionalInformationScreen(BuildContext context) { - GoRouter.of(context).goNamed('additionalInformationScreen'); - } -} diff --git a/lib/presentation/registration/favorite_foods_screen/models/favorite_foods_model.dart b/lib/presentation/registration/favorite_foods_screen/models/favorite_foods_model.dart deleted file mode 100644 index 3aeeee2..0000000 --- a/lib/presentation/registration/favorite_foods_screen/models/favorite_foods_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [favorite_foods_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class FavoriteFoodsModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - FavoriteFoodsModel({required this.userRegistrationSheet}); - - FavoriteFoodsModel copyWith() { - return FavoriteFoodsModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_bloc.dart b/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_bloc.dart deleted file mode 100644 index 7857f8b..0000000 --- a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_bloc.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/favorite_sports_screen/models/favorite_sports_model.dart'; -part 'favorite_sports_event.dart'; -part 'favorite_sports_state.dart'; - -/// A bloc that manages the state of a FavoriteSports according to the event that is dispatched to it. -class FavoriteSportsBloc - extends Bloc { - FavoriteSportsBloc(FavoriteSportsState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - FavoriteSportsInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith(enterinformationController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_event.dart b/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_event.dart deleted file mode 100644 index ae9a018..0000000 --- a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'favorite_sports_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///FavoriteSports widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class FavoriteSportsEvent extends Equatable {} - -/// Event that is dispatched when the FavoriteSports widget is first created. -class FavoriteSportsInitialEvent extends FavoriteSportsEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_state.dart b/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_state.dart deleted file mode 100644 index c44cb2a..0000000 --- a/lib/presentation/registration/favorite_sports_screen/bloc/favorite_sports_state.dart +++ /dev/null @@ -1,32 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'favorite_sports_bloc.dart'; - -/// Represents the state of FavoriteSports in the application. -class FavoriteSportsState extends Equatable { - FavoriteSportsState({ - this.enterinformationController, - this.favoriteSportsModelObj, - }); - - TextEditingController? enterinformationController; - - FavoriteSportsModel? favoriteSportsModelObj; - - @override - List get props => [ - enterinformationController, - favoriteSportsModelObj, - ]; - FavoriteSportsState copyWith({ - TextEditingController? enterinformationController, - FavoriteSportsModel? favoriteSportsModelObj, - }) { - return FavoriteSportsState( - enterinformationController: - enterinformationController ?? this.enterinformationController, - favoriteSportsModelObj: - favoriteSportsModelObj ?? this.favoriteSportsModelObj, - ); - } -} diff --git a/lib/presentation/registration/favorite_sports_screen/favorite_sports_screen.dart b/lib/presentation/registration/favorite_sports_screen/favorite_sports_screen.dart deleted file mode 100644 index 66f98d2..0000000 --- a/lib/presentation/registration/favorite_sports_screen/favorite_sports_screen.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/favorite_sports_bloc.dart'; -import 'models/favorite_sports_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class FavoriteSportsScreen extends StatefulWidget { - const FavoriteSportsScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => FavoriteSportsBloc(FavoriteSportsState(favoriteSportsModelObj: FavoriteSportsModel(userRegistrationSheet: sheet))) - ..add(FavoriteSportsInitialEvent()), - child: FavoriteSportsScreen()); - } - - @override - State createState() => _FavoriteSportsScreenState(); -} - -class _FavoriteSportsScreenState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 5.v), - child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox(height: 20.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.83, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 38.v), - Text("your_favorite_sports".tr, style: theme.textTheme.headlineSmall), - Spacer(flex: 32), - _buildTextFormFieldSection(context), - Spacer(flex: 67), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapContinue(state, context)); - }), - BlocBuilder(builder: (context, state) { - return GestureDetector( - onTap: onTapSkip(state, context), - child: Text("skip".tr, style: theme.textTheme.bodyLarge), - ); - }), - ]))); - } - - onTapSkip(FavoriteSportsState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.favoriteSportsModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('favoriteFoodsScreen', extra: sheet); - }; - } - - onTapContinue(FavoriteSportsState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.favoriteSportsModelObj!.userRegistrationSheet; - sheet.aboutSportHobbies = state.enterinformationController!.text; - GoRouter.of(context).goNamed('favoriteFoodsScreen', extra: sheet); - }; - } - - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildTextFormFieldSection(BuildContext context) { - return Column(children: [ - Text("fill_in_information".tr, style: CustomTextStyles.titleMediumSegoeUI), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.enterinformationController, - builder: (context, enterinformationController) { - return CustomTextFormField( - controller: enterinformationController, - hintText: - "Я занимаюсь плаванием , почти каждый вечер прогулки на свежем воздухе, пару раз в месяц играю в волейбол. Стараюсь не сидеть на месте!", - textInputAction: TextInputAction.done, - maxLines: 8); - }) - ]); - } - - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/registration/favorite_sports_screen/models/favorite_sports_model.dart b/lib/presentation/registration/favorite_sports_screen/models/favorite_sports_model.dart deleted file mode 100644 index 2548170..0000000 --- a/lib/presentation/registration/favorite_sports_screen/models/favorite_sports_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [favorite_sports_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class FavoriteSportsModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - FavoriteSportsModel({required this.userRegistrationSheet}); - - FavoriteSportsModel copyWith() { - return FavoriteSportsModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/gender_screen/bloc/gender_bloc.dart b/lib/presentation/registration/gender_screen/bloc/gender_bloc.dart deleted file mode 100644 index 5f614c2..0000000 --- a/lib/presentation/registration/gender_screen/bloc/gender_bloc.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/gender_screen/models/gender_model.dart'; -part 'gender_event.dart'; -part 'gender_state.dart'; - -/// A bloc that manages the state of a Gender according to the event that is dispatched to it. -class GenderBloc extends Bloc { - GenderBloc(GenderState initialState) : super(initialState) { - on(_onInitialize); - on(_genderSelect); - } - - _onInitialize( - GenderInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith(genderModelObj: state.genderModelObj)); - } - - _genderSelect( - GenderSelectEvent event, - Emitter emit, - ) { - emit(state.copyWith(selectedRadioValue: event.value)); - state.genderModelObj?.userRegistrationSheet.gender = event.value; - } -} diff --git a/lib/presentation/registration/gender_screen/bloc/gender_event.dart b/lib/presentation/registration/gender_screen/bloc/gender_event.dart deleted file mode 100644 index f6b9f69..0000000 --- a/lib/presentation/registration/gender_screen/bloc/gender_event.dart +++ /dev/null @@ -1,26 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'gender_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Gender widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class GenderEvent extends Equatable {} - -class GenderInitialEvent extends GenderEvent { - @override - List get props => []; -} - -class GenderSelectEvent extends GenderEvent { - GenderSelectEvent({required this.value}); - - String value; - - @override - List get props => [ - value, - ]; -} diff --git a/lib/presentation/registration/gender_screen/bloc/gender_state.dart b/lib/presentation/registration/gender_screen/bloc/gender_state.dart deleted file mode 100644 index 996082e..0000000 --- a/lib/presentation/registration/gender_screen/bloc/gender_state.dart +++ /dev/null @@ -1,30 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'gender_bloc.dart'; - -/// Represents the state of Gender in the application. -class GenderState extends Equatable { - GenderState({ - this.selectedRadioValue, - this.genderModelObj, - }); - - String? selectedRadioValue; - - GenderModel? genderModelObj; - - @override - List get props => [ - selectedRadioValue, - genderModelObj, - ]; - GenderState copyWith({ - String? selectedRadioValue, - GenderModel? genderModelObj, - }) { - return GenderState( - selectedRadioValue: selectedRadioValue ?? this.selectedRadioValue, - genderModelObj: genderModelObj ?? this.genderModelObj, - ); - } -} diff --git a/lib/presentation/registration/gender_screen/gender_screen.dart b/lib/presentation/registration/gender_screen/gender_screen.dart deleted file mode 100644 index 68909d7..0000000 --- a/lib/presentation/registration/gender_screen/gender_screen.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/gender_bloc.dart'; -import 'models/gender_model.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:flutter/material.dart'; - -class GenderScreen extends StatefulWidget { - const GenderScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => GenderBloc( - GenderState( - genderModelObj: GenderModel(userRegistrationSheet: sheet), - ), - )..add(GenderInitialEvent()), - child: GenderScreen()); - } - - @override - State createState() => _GenderScreenState(); -} - -class _GenderScreenState extends State { - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return BlocBuilder(builder: (context, state) { - return Scaffold( - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.16, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 36.v), - Text("your_gender".tr, style: theme.textTheme.headlineSmall), - RadioListTile( - title: Text('Мужской'), - value: 'male', - groupValue: state.selectedRadioValue, - onChanged: onMale(context), - secondary: Image.asset( - 'assets/images/img_male.png', - width: 40, - height: 40, - ), - ), - RadioListTile( - title: Text('Женский'), - value: 'female', - groupValue: state.selectedRadioValue, - onChanged: onFemale(context), - secondary: Image.asset( - 'assets/images/img_female.png', - width: 40, - height: 40, - ), - ), - Spacer(flex: 66), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapNext(state, context)); - }), - ]))); - }); - } - - onTapNext(GenderState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.genderModelObj!.userRegistrationSheet; - sheet.gender = state.selectedRadioValue!; - GoRouter.of(context).goNamed('dateOfBirthScreen', extra: sheet); - }; - } - - onMale(BuildContext context) { - return (value) { - BlocProvider.of(context).add(GenderSelectEvent(value: 'male')); - }; - } - - onFemale(BuildContext context) { - return (value) { - BlocProvider.of(context).add(GenderSelectEvent(value: 'female')); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack()), - centerTitle: true, - title: AppbarTitleImage( - imagePath: ImageConstant.imgLogoEatvio, - ), - ); - } - - Function onTapBack() { - return () { - GoRouter.of(context).pop(); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/registration/gender_screen/models/gender_model.dart b/lib/presentation/registration/gender_screen/models/gender_model.dart deleted file mode 100644 index b314fba..0000000 --- a/lib/presentation/registration/gender_screen/models/gender_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [gender_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class GenderModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - GenderModel({required this.userRegistrationSheet}); - - GenderModel copyWith({UserRegistrationSheet? userRegistrationSheet, gender}) { - return GenderModel( - userRegistrationSheet: - userRegistrationSheet ?? this.userRegistrationSheet); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/height_screen/bloc/height_bloc.dart b/lib/presentation/registration/height_screen/bloc/height_bloc.dart deleted file mode 100644 index 70b8ba6..0000000 --- a/lib/presentation/registration/height_screen/bloc/height_bloc.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/height_screen/models/height_model.dart'; -part 'height_event.dart'; -part 'height_state.dart'; - -/// A bloc that manages the state of a Height according to the event that is dispatched to it. -class HeightBloc extends Bloc { - HeightBloc(HeightState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - HeightInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - heightModelObj: state.heightModelObj?.copyWith(), - heightController: state.heightController)); - } -} diff --git a/lib/presentation/registration/height_screen/bloc/height_event.dart b/lib/presentation/registration/height_screen/bloc/height_event.dart deleted file mode 100644 index 1d65dd8..0000000 --- a/lib/presentation/registration/height_screen/bloc/height_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'height_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Height widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class HeightEvent extends Equatable {} - -/// Event that is dispatched when the Height widget is first created. -class HeightInitialEvent extends HeightEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/height_screen/bloc/height_state.dart b/lib/presentation/registration/height_screen/bloc/height_state.dart deleted file mode 100644 index aa10592..0000000 --- a/lib/presentation/registration/height_screen/bloc/height_state.dart +++ /dev/null @@ -1,30 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'height_bloc.dart'; - -/// Represents the state of Height in the application. -class HeightState extends Equatable { - HeightState({ - this.heightController, - this.heightModelObj, - }); - - TextEditingController? heightController; - - HeightModel? heightModelObj; - - @override - List get props => [ - heightController, - heightModelObj, - ]; - HeightState copyWith({ - TextEditingController? heightController, - HeightModel? heightModelObj, - }) { - return HeightState( - heightController: heightController ?? this.heightController, - heightModelObj: heightModelObj ?? this.heightModelObj, - ); - } -} diff --git a/lib/presentation/registration/height_screen/height_screen.dart b/lib/presentation/registration/height_screen/height_screen.dart deleted file mode 100644 index 071285f..0000000 --- a/lib/presentation/registration/height_screen/height_screen.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/height_bloc.dart'; -import 'models/height_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/services.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class HeightScreen extends StatelessWidget { - const HeightScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => HeightBloc(HeightState(heightModelObj: HeightModel(userRegistrationSheet: sheet)))..add(HeightInitialEvent()), - child: HeightScreen()); - } - - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column( - children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all( - color: theme.colorScheme.primary, - width: 1.h, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.55, - backgroundColor: theme.colorScheme.onPrimary, - valueColor: AlwaysStoppedAnimation( - appTheme.blueA400, - ), - ), - ), - ), - SizedBox(height: 39.v), - Column( - children: [ - Text( - "height_measurements".tr, - style: theme.textTheme.headlineSmall, - ), - SizedBox(height: 174.v), - Column( - children: [ - Text( - "your_height".tr, - style: theme.textTheme.bodyLarge, - ), - SizedBox(height: 4.v), - BlocBuilder(builder: (context, state) { - return CustomTextFormField( - width: 150.h, - textInputAction: TextInputAction.done, - controller: state.heightController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - ); - }) - ], - ), - ], - ), - Spacer(), - BlocBuilder( - builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only( - left: 16.h, - right: 16.h, - bottom: 50.v, - ), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapNext(state, context), - ); - }, - ), - ], - ), - ), - ); - } - - onTapNext(HeightState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.heightModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('bloodPressureScreen', extra: sheet); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/registration/height_screen/models/height_model.dart b/lib/presentation/registration/height_screen/models/height_model.dart deleted file mode 100644 index caa3b75..0000000 --- a/lib/presentation/registration/height_screen/models/height_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [height_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class HeightModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - HeightModel( - {this.dropdownItemList = const [], required this.userRegistrationSheet}); - - List dropdownItemList; - - HeightModel copyWith({List? dropdownItemList}) { - return HeightModel( - userRegistrationSheet: userRegistrationSheet, - dropdownItemList: dropdownItemList ?? this.dropdownItemList, - ); - } - - @override - List get props => [dropdownItemList, userRegistrationSheet]; -} diff --git a/lib/presentation/registration/language_select_screen/bloc/language_select_bloc.dart b/lib/presentation/registration/language_select_screen/bloc/language_select_bloc.dart deleted file mode 100644 index e9b6959..0000000 --- a/lib/presentation/registration/language_select_screen/bloc/language_select_bloc.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/language_select_screen/models/language_select_model.dart'; -part 'language_select_event.dart'; -part 'language_select_state.dart'; - -/// A bloc that manages the state of a LanguageSelect according to the event that is dispatched to it. -class LanguageSelectBloc - extends Bloc { - LanguageSelectBloc(LanguageSelectState initialState) : super(initialState) { - on(_onInitialize); - on(_changeDropDown); - } - - _onInitialize( - LanguageSelectInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - languageSelectModelObj: state.languageSelectModelObj - ?.copyWith(dropdownItemList: fillDropdownItemList()))); - } - - _changeDropDown( - ChangeDropDownEvent event, - Emitter emit, - ) { - emit(state.copyWith(selectedDropDownValue: event.value)); - state.languageSelectModelObj?.userRegistrationSheet.lang = - event.value.title; - } - - List fillDropdownItemList() { - return [ - SelectionPopupModel(id: 1, title: "Русский", isSelected: true), - ]; - } -} diff --git a/lib/presentation/registration/language_select_screen/bloc/language_select_event.dart b/lib/presentation/registration/language_select_screen/bloc/language_select_event.dart deleted file mode 100644 index 5c39a95..0000000 --- a/lib/presentation/registration/language_select_screen/bloc/language_select_event.dart +++ /dev/null @@ -1,28 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'language_select_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///LanguageSelect widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class LanguageSelectEvent extends Equatable {} - -/// Event that is dispatched when the LanguageSelect widget is first created. -class LanguageSelectInitialEvent extends LanguageSelectEvent { - @override - List get props => []; -} - -///event for dropdown selection -class ChangeDropDownEvent extends LanguageSelectEvent { - ChangeDropDownEvent({required this.value}); - - SelectionPopupModel value; - - @override - List get props => [ - value, - ]; -} diff --git a/lib/presentation/registration/language_select_screen/bloc/language_select_state.dart b/lib/presentation/registration/language_select_screen/bloc/language_select_state.dart deleted file mode 100644 index 602a4ad..0000000 --- a/lib/presentation/registration/language_select_screen/bloc/language_select_state.dart +++ /dev/null @@ -1,32 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'language_select_bloc.dart'; - -/// Represents the state of LanguageSelect in the application. -class LanguageSelectState extends Equatable { - LanguageSelectState({ - this.selectedDropDownValue, - this.languageSelectModelObj, - }); - - SelectionPopupModel? selectedDropDownValue; - - LanguageSelectModel? languageSelectModelObj; - - @override - List get props => [ - selectedDropDownValue, - languageSelectModelObj, - ]; - LanguageSelectState copyWith({ - SelectionPopupModel? selectedDropDownValue, - LanguageSelectModel? languageSelectModelObj, - }) { - return LanguageSelectState( - selectedDropDownValue: - selectedDropDownValue ?? this.selectedDropDownValue, - languageSelectModelObj: - languageSelectModelObj ?? this.languageSelectModelObj, - ); - } -} diff --git a/lib/presentation/registration/language_select_screen/language_select_screen.dart b/lib/presentation/registration/language_select_screen/language_select_screen.dart deleted file mode 100644 index 75a7c1a..0000000 --- a/lib/presentation/registration/language_select_screen/language_select_screen.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:go_router/go_router.dart'; - -import 'bloc/language_select_bloc.dart'; -import 'models/language_select_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/custom_drop_down.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:flutter/material.dart'; - -class LanguageSelectScreen extends StatelessWidget { - const LanguageSelectScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context) { - return BlocProvider( - create: (context) => LanguageSelectBloc( - LanguageSelectState( - languageSelectModelObj: LanguageSelectModel(), - ), - )..add(LanguageSelectInitialEvent()), - child: LanguageSelectScreen(), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 5.v), - child: Column( - children: [ - CustomImageView(imagePath: ImageConstant.imgLogoEatvio, height: 50.adaptSize, width: 50.adaptSize), - SizedBox(height: 20.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all( - color: theme.colorScheme.primary, - width: 1.h, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0, - backgroundColor: theme.colorScheme.onPrimary, - valueColor: AlwaysStoppedAnimation(appTheme.blueA400), - ), - ), - ), - SizedBox(height: 20.v), - Container( - width: 262.h, - margin: EdgeInsets.only(left: 41.h, right: 39.h), - child: Text( - "preferred_language".tr, - maxLines: 2, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - style: theme.textTheme.headlineSmall, - ), - ), - Spacer(flex: 36), - BlocSelector( - selector: (state) => state.languageSelectModelObj, - builder: ( - context, - languageSelectModelObj, - ) { - return CustomDropDown( - icon: Container( - margin: EdgeInsets.fromLTRB(30.h, 11.v, 17.h, 11.v), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(1.h), - ), - child: CustomImageView( - imagePath: ImageConstant.imgFavorite, - height: 12.adaptSize, - width: 12.adaptSize, - ), - ), - hintText: "Не выбрано".tr, - items: languageSelectModelObj?.dropdownItemList ?? [], - onChanged: (value) => _onDropDownChanged(context, value), - ); - }), - Spacer(flex: 63), - ], - ), - ), - bottomNavigationBar: BlocBuilder( - builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: _saveAndPush(state, context), - ); - }, - ), - ); - } - - void Function()? _saveAndPush(LanguageSelectState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.languageSelectModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed( - 'credentialsScreen', - extra: sheet, - ); - }; - } - - void _onDropDownChanged(BuildContext context, value) { - context.read().add(ChangeDropDownEvent(value: value)); - } -} diff --git a/lib/presentation/registration/language_select_screen/models/language_select_model.dart b/lib/presentation/registration/language_select_screen/models/language_select_model.dart deleted file mode 100644 index 465a8ac..0000000 --- a/lib/presentation/registration/language_select_screen/models/language_select_model.dart +++ /dev/null @@ -1,50 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; - -/// This class defines the variables used in the [language_select_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class LanguageSelectModel extends Equatable { - LanguageSelectModel({this.dropdownItemList = const []}); - UserRegistrationSheet userRegistrationSheet = UserRegistrationSheet( - name: '', - firstName: '', - lastName: '', - email: '', - password: '', - passwordConfirmation: '', - termsAccepted: 'accepted', - birthdate: DateTime.now().toString(), - gender: '', - country: '', - city: '', - lang: '', - weight: '', - height: '', - chestCircumference: '', - waistCircumference: '', - hipCircumference: '', - bloodPressureUp: '', - bloodPressureDown: '', - hasHypo: '', - hasHyper: '', - aboutAllergy: '', - aboutTakingPils: '', - aboutSportHobbies: '', - favoriteFoods: '', - unfavoriteFoods: '', - additionalInfo: '', - ); - List dropdownItemList; - - LanguageSelectModel copyWith({List? dropdownItemList}) { - return LanguageSelectModel( - dropdownItemList: dropdownItemList ?? this.dropdownItemList, - ); - } - - @override - List get props => [dropdownItemList]; -} diff --git a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_bloc.dart b/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_bloc.dart deleted file mode 100644 index bd87876..0000000 --- a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_bloc.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/medicine_intake_screen/models/medicine_intake_model.dart'; -part 'medicine_intake_event.dart'; -part 'medicine_intake_state.dart'; - -/// A bloc that manages the state of a MedicineIntake according to the event that is dispatched to it. -class MedicineIntakeBloc - extends Bloc { - MedicineIntakeBloc(MedicineIntakeState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - MedicineIntakeInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith(enterInformationController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_event.dart b/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_event.dart deleted file mode 100644 index 0300b28..0000000 --- a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'medicine_intake_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///MedicineIntake widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class MedicineIntakeEvent extends Equatable {} - -/// Event that is dispatched when the MedicineIntake widget is first created. -class MedicineIntakeInitialEvent extends MedicineIntakeEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_state.dart b/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_state.dart deleted file mode 100644 index 8d7958f..0000000 --- a/lib/presentation/registration/medicine_intake_screen/bloc/medicine_intake_state.dart +++ /dev/null @@ -1,32 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'medicine_intake_bloc.dart'; - -/// Represents the state of MedicineIntake in the application. -class MedicineIntakeState extends Equatable { - MedicineIntakeState({ - this.enterInformationController, - this.medicineIntakeModelObj, - }); - - TextEditingController? enterInformationController; - - MedicineIntakeModel? medicineIntakeModelObj; - - @override - List get props => [ - enterInformationController, - medicineIntakeModelObj, - ]; - MedicineIntakeState copyWith({ - TextEditingController? enterInformationController, - MedicineIntakeModel? medicineIntakeModelObj, - }) { - return MedicineIntakeState( - enterInformationController: - enterInformationController ?? this.enterInformationController, - medicineIntakeModelObj: - medicineIntakeModelObj ?? this.medicineIntakeModelObj, - ); - } -} diff --git a/lib/presentation/registration/medicine_intake_screen/medicine_intake_screen.dart b/lib/presentation/registration/medicine_intake_screen/medicine_intake_screen.dart deleted file mode 100644 index 9f01f6f..0000000 --- a/lib/presentation/registration/medicine_intake_screen/medicine_intake_screen.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/medicine_intake_bloc.dart'; -import 'models/medicine_intake_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class MedicineIntakeScreen extends StatefulWidget { - const MedicineIntakeScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => MedicineIntakeBloc(MedicineIntakeState(medicineIntakeModelObj: MedicineIntakeModel(userRegistrationSheet: sheet))) - ..add(MedicineIntakeInitialEvent()), - child: MedicineIntakeScreen()); - } - - @override - State createState() => _MedicineIntakeScreenState(); -} - -class _MedicineIntakeScreenState extends State { - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.69, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 20.v), - Container( - width: 271.h, - margin: EdgeInsets.only(left: 35.h, right: 36.h), - child: Text("do_you_take_pills".tr, - maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: theme.textTheme.headlineSmall)), - SizedBox(height: 86.v), - _buildTextFormField(context), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapNext(state, context)); - }), - BlocBuilder(builder: (context, state) { - return GestureDetector( - onTap: onTapSkip(state, context), - child: Text("skip".tr, style: theme.textTheme.bodyLarge), - ); - }), - ]))); - } - - onTapSkip(MedicineIntakeState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.medicineIntakeModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed( - 'bloodPressureScreen', - extra: sheet, - ); - }; - } - - onTapNext(MedicineIntakeState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.medicineIntakeModelObj!.userRegistrationSheet; - sheet.aboutTakingPils = state.enterInformationController!.text; - GoRouter.of(context).goNamed( - 'bloodPressureScreen', - extra: sheet, - ); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 31.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 18.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Section Widget - _buildTextFormField(BuildContext context) { - return Column(children: [ - Text("fill_in_information".tr, style: CustomTextStyles.titleMediumSegoeUI), - SizedBox(height: 2.v), - BlocSelector( - selector: (state) => state.enterInformationController, - builder: (context, enterInformationController) { - return CustomTextFormField( - controller: enterInformationController, hintText: "enter_information".tr, textInputAction: TextInputAction.done, maxLines: 8); - }) - ]); - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/registration/medicine_intake_screen/models/medicine_intake_model.dart b/lib/presentation/registration/medicine_intake_screen/models/medicine_intake_model.dart deleted file mode 100644 index f6634de..0000000 --- a/lib/presentation/registration/medicine_intake_screen/models/medicine_intake_model.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [medicine_intake_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class MedicineIntakeModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - MedicineIntakeModel({required this.userRegistrationSheet}); - - MedicineIntakeModel copyWith() { - return MedicineIntakeModel( - userRegistrationSheet: userRegistrationSheet, - ); - } - - @override - List get props => [userRegistrationSheet]; -} diff --git a/lib/presentation/registration/name_screen/bloc/name_bloc.dart b/lib/presentation/registration/name_screen/bloc/name_bloc.dart deleted file mode 100644 index f9c47e3..0000000 --- a/lib/presentation/registration/name_screen/bloc/name_bloc.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/name_screen/models/name_model.dart'; -part 'name_event.dart'; -part 'name_state.dart'; - -/// A bloc that manages the state of a Name according to the event that is dispatched to it. -class NameBloc extends Bloc { - NameBloc(NameState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - NameInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - firstNameController: TextEditingController(), - lastNameController: TextEditingController())); - } -} diff --git a/lib/presentation/registration/name_screen/bloc/name_event.dart b/lib/presentation/registration/name_screen/bloc/name_event.dart deleted file mode 100644 index 7e10299..0000000 --- a/lib/presentation/registration/name_screen/bloc/name_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'name_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Name widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class NameEvent extends Equatable {} - -/// Event that is dispatched when the Name widget is first created. -class NameInitialEvent extends NameEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/name_screen/bloc/name_state.dart b/lib/presentation/registration/name_screen/bloc/name_state.dart deleted file mode 100644 index b3e0980..0000000 --- a/lib/presentation/registration/name_screen/bloc/name_state.dart +++ /dev/null @@ -1,36 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'name_bloc.dart'; - -/// Represents the state of Name in the application. -class NameState extends Equatable { - NameState({ - this.firstNameController, - this.lastNameController, - this.nameModelObj, - }); - - TextEditingController? firstNameController; - - TextEditingController? lastNameController; - - NameModel? nameModelObj; - - @override - List get props => [ - firstNameController, - lastNameController, - nameModelObj, - ]; - NameState copyWith({ - TextEditingController? firstNameController, - TextEditingController? lastNameController, - NameModel? nameModelObj, - }) { - return NameState( - firstNameController: firstNameController ?? this.firstNameController, - lastNameController: lastNameController ?? this.lastNameController, - nameModelObj: nameModelObj ?? this.nameModelObj, - ); - } -} diff --git a/lib/presentation/registration/name_screen/models/name_model.dart b/lib/presentation/registration/name_screen/models/name_model.dart deleted file mode 100644 index 6fa44b0..0000000 --- a/lib/presentation/registration/name_screen/models/name_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [name_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class NameModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - NameModel({required this.userRegistrationSheet}); - - NameModel copyWith({UserRegistrationSheet? userRegistrationSheet}) { - return NameModel( - userRegistrationSheet: - userRegistrationSheet ?? this.userRegistrationSheet, - ); - } - - @override - List get props => []; -} diff --git a/lib/presentation/registration/name_screen/name_screen.dart b/lib/presentation/registration/name_screen/name_screen.dart deleted file mode 100644 index e1f0327..0000000 --- a/lib/presentation/registration/name_screen/name_screen.dart +++ /dev/null @@ -1,155 +0,0 @@ -import 'package:eatvio_app/app_router.dart'; -import 'package:go_router/go_router.dart'; - -import 'bloc/name_bloc.dart'; -import 'models/name_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/material.dart'; - -class NameScreen extends StatelessWidget { - const NameScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => NameBloc( - NameState( - nameModelObj: NameModel(userRegistrationSheet: sheet), - ), - )..add(NameInitialEvent()), - child: NameScreen()); - } - - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column(children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all(color: theme.colorScheme.primary, width: 1.h)), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.1, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation(appTheme.blueA400)))), - SizedBox(height: 39.v), - Text("what_is_your_name".tr, style: theme.textTheme.headlineSmall), - SizedBox(height: 93.v), - Text("first_name".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 3.v), - BlocSelector( - selector: (state) => state.firstNameController, - builder: (context, firstNameController) { - return CustomTextFormField(controller: firstNameController, textInputAction: TextInputAction.done); - }), - SizedBox(height: 19.v), - Text("last_name".tr, style: theme.textTheme.bodyLarge), - SizedBox(height: 5.v), - BlocSelector( - selector: (state) => state.lastNameController, - builder: (context, lastNameController) { - return CustomTextFormField( - controller: lastNameController, - ); - }), - Spacer(), - BlocBuilder(builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: () => _onTapNext(context, state), // Assign callback function here - ); - }), - ]))); - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: AppbarLeadingImage( - imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: () => onTapArrowLeft(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } - - _onTapNext(BuildContext context, NameState state) { - if (state.firstNameController != null && state.lastNameController != null) { - List errors = validateFields(state.firstNameController!.text, state.lastNameController!.text); - - if (errors.isEmpty) { - UserRegistrationSheet sheet = state.nameModelObj!.userRegistrationSheet; - sheet.firstName = state.firstNameController!.text; - sheet.lastName = state.lastNameController!.text; - AppRouter.navigatorKey.currentContext?.goNamed('genderScreen', extra: sheet); - } else { - String errorMessage = ''; - - for (var error in errors) { - errorMessage += error + '\n\n'; - } - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Error'), - content: Text(errorMessage), - actions: [ - TextButton( - onPressed: () => onTapOk(context), - child: Text('OK'), - ), - ], - ), - ); - } - } - } - - void onTapOk(BuildContext context) { - Navigator.pop(context); - } - - List validateFields(String firstName, String lastName) { - List errors = []; - - if (firstName.isEmpty) { - errors.add('First name cannot be empty'); - } - - if (firstName.length < 1) { - errors.add('First name is too short'); - } - - if (lastName.isEmpty) { - errors.add('Last name cannot be empty'); - } - - if (lastName.length < 1) { - errors.add('Last name is too short'); - } - - return errors; - } -} diff --git a/lib/presentation/registration/splash_screen/bloc/splash_bloc.dart b/lib/presentation/registration/splash_screen/bloc/splash_bloc.dart deleted file mode 100644 index bdd396f..0000000 --- a/lib/presentation/registration/splash_screen/bloc/splash_bloc.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:eatvio_app/app_router.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/splash_screen/models/splash_model.dart'; - -part 'splash_event.dart'; - -part 'splash_state.dart'; - -/// A bloc that manages the state of a Splash according to the event that is dispatched to it. -class SplashBloc extends Bloc { - SplashBloc(SplashState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - SplashInitialEvent event, - Emitter emit, - ) async { - Future.delayed(const Duration(milliseconds: 3000), () { - AppRouter.navigatorKey.currentContext?.goNamed('myProfileScreen'); - }); - } -} diff --git a/lib/presentation/registration/splash_screen/bloc/splash_event.dart b/lib/presentation/registration/splash_screen/bloc/splash_event.dart deleted file mode 100644 index a78a25b..0000000 --- a/lib/presentation/registration/splash_screen/bloc/splash_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'splash_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Splash widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class SplashEvent extends Equatable {} - -/// Event that is dispatched when the Splash widget is first created. -class SplashInitialEvent extends SplashEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/splash_screen/bloc/splash_state.dart b/lib/presentation/registration/splash_screen/bloc/splash_state.dart deleted file mode 100644 index e47ce03..0000000 --- a/lib/presentation/registration/splash_screen/bloc/splash_state.dart +++ /dev/null @@ -1,20 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'splash_bloc.dart'; - -/// Represents the state of Splash in the application. -class SplashState extends Equatable { - SplashState({this.splashModelObj}); - - SplashModel? splashModelObj; - - @override - List get props => [ - splashModelObj, - ]; - SplashState copyWith({SplashModel? splashModelObj}) { - return SplashState( - splashModelObj: splashModelObj ?? this.splashModelObj, - ); - } -} diff --git a/lib/presentation/registration/splash_screen/models/splash_model.dart b/lib/presentation/registration/splash_screen/models/splash_model.dart deleted file mode 100644 index 6ad8f8f..0000000 --- a/lib/presentation/registration/splash_screen/models/splash_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; - -/// This class defines the variables used in the [splash_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class SplashModel extends Equatable { - SplashModel(); - - SplashModel copyWith() { - return SplashModel(); - } - - @override - List get props => []; -} diff --git a/lib/presentation/registration/splash_screen/splash_screen.dart b/lib/presentation/registration/splash_screen/splash_screen.dart deleted file mode 100644 index 501586f..0000000 --- a/lib/presentation/registration/splash_screen/splash_screen.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'bloc/splash_bloc.dart'; -import 'models/splash_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; - -class SplashScreen extends StatelessWidget { - const SplashScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context) { - return BlocProvider( - create: (context) => - SplashBloc(SplashState(splashModelObj: SplashModel())) - ..add(SplashInitialEvent()), - child: SplashScreen()); - } - - @override - Widget build(BuildContext context) { - mediaQueryData = MediaQuery.of(context); - return BlocBuilder(builder: (context, state) { - return SafeArea( - child: Scaffold( - body: SizedBox( - width: double.maxFinite, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: 16.v), - CustomImageView( - imagePath: ImageConstant.img2456927096976, - height: 137.adaptSize, - width: 137.adaptSize) - ])))); - }); - } -} diff --git a/lib/presentation/registration/weight_screen/bloc/weight_bloc.dart b/lib/presentation/registration/weight_screen/bloc/weight_bloc.dart deleted file mode 100644 index 69161cc..0000000 --- a/lib/presentation/registration/weight_screen/bloc/weight_bloc.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/registration/weight_screen/models/weight_model.dart'; -part 'weight_event.dart'; -part 'weight_state.dart'; - -/// A bloc that manages the state of a Weight according to the event that is dispatched to it. -class WeightBloc extends Bloc { - WeightBloc(WeightState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - WeightInitialEvent event, - Emitter emit, - ) async { - emit(state.copyWith( - weightModelObj: state.weightModelObj?.copyWith(), - weightController: state.weightController)); - } -} diff --git a/lib/presentation/registration/weight_screen/bloc/weight_event.dart b/lib/presentation/registration/weight_screen/bloc/weight_event.dart deleted file mode 100644 index 1b554c5..0000000 --- a/lib/presentation/registration/weight_screen/bloc/weight_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'weight_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Weight widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class WeightEvent extends Equatable {} - -/// Event that is dispatched when the Weight widget is first created. -class WeightInitialEvent extends WeightEvent { - @override - List get props => []; -} diff --git a/lib/presentation/registration/weight_screen/bloc/weight_state.dart b/lib/presentation/registration/weight_screen/bloc/weight_state.dart deleted file mode 100644 index 5d782df..0000000 --- a/lib/presentation/registration/weight_screen/bloc/weight_state.dart +++ /dev/null @@ -1,30 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'weight_bloc.dart'; - -/// Represents the state of Weight in the application. -class WeightState extends Equatable { - WeightState({ - this.weightController, - this.weightModelObj, - }); - - TextEditingController? weightController; - - WeightModel? weightModelObj; - - @override - List get props => [ - weightController, - weightModelObj, - ]; - WeightState copyWith({ - TextEditingController? weightController, - WeightModel? weightModelObj, - }) { - return WeightState( - weightController: weightController ?? this.weightController, - weightModelObj: weightModelObj ?? this.weightModelObj, - ); - } -} diff --git a/lib/presentation/registration/weight_screen/models/weight_model.dart b/lib/presentation/registration/weight_screen/models/weight_model.dart deleted file mode 100644 index e26b49a..0000000 --- a/lib/presentation/registration/weight_screen/models/weight_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; - -/// This class defines the variables used in the [weight_screen], -/// and is typically used to hold data that is passed between different parts of the application. -class WeightModel extends Equatable { - UserRegistrationSheet userRegistrationSheet; - WeightModel( - {this.dropdownItemList = const [], required this.userRegistrationSheet}); - - List dropdownItemList; - - WeightModel copyWith({List? dropdownItemList}) { - return WeightModel( - userRegistrationSheet: userRegistrationSheet, - dropdownItemList: dropdownItemList ?? this.dropdownItemList, - ); - } - - @override - List get props => [dropdownItemList, userRegistrationSheet]; -} diff --git a/lib/presentation/registration/weight_screen/weight_screen.dart b/lib/presentation/registration/weight_screen/weight_screen.dart deleted file mode 100644 index 7bf28f1..0000000 --- a/lib/presentation/registration/weight_screen/weight_screen.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/weight_bloc.dart'; -import 'models/weight_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:flutter/services.dart'; -import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; - -class WeightScreen extends StatelessWidget { - const WeightScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, sheet) { - return BlocProvider( - create: (context) => WeightBloc(WeightState(weightModelObj: WeightModel(userRegistrationSheet: sheet)))..add(WeightInitialEvent()), - child: WeightScreen()); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: _buildAppBar(context), - body: Container( - width: double.maxFinite, - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), - child: Column( - children: [ - SizedBox(height: 7.v), - Container( - height: 16.v, - width: 343.h, - decoration: BoxDecoration( - color: theme.colorScheme.onPrimary, - borderRadius: BorderRadius.circular(8.h), - border: Border.all( - color: theme.colorScheme.primary, - width: 1.h, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.h), - child: LinearProgressIndicator( - value: 0.55, - backgroundColor: theme.colorScheme.onPrimary, - valueColor: AlwaysStoppedAnimation( - appTheme.blueA400, - ), - ), - ), - ), - SizedBox(height: 39.v), - Column( - children: [ - Text( - "weight_measurements".tr, - style: theme.textTheme.headlineSmall, - ), - SizedBox(height: 174.v), - Column( - children: [ - Text( - "your_weight".tr, - style: theme.textTheme.bodyLarge, - ), - SizedBox(height: 4.v), - BlocBuilder(builder: (context, state) { - return CustomTextFormField( - width: 150.h, - textInputAction: TextInputAction.done, - controller: state.weightController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - ); - }) - ], - ), - ], - ), - Spacer(), - BlocBuilder( - builder: (context, state) { - return NextStepButton( - text: "continue".tr.toUpperCase(), - margin: EdgeInsets.only( - left: 16.h, - right: 16.h, - bottom: 50.v, - ), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - onPressed: onTapNext(state, context), - ); - }, - ), - ], - ), - ), - ); - } - - onTapNext(WeightState state, BuildContext context) { - return () { - UserRegistrationSheet sheet = state.weightModelObj!.userRegistrationSheet; - GoRouter.of(context).goNamed('heightScreen', extra: sheet); - }; - } - - /// Section Widget - _buildAppBar(BuildContext context) { - return CustomAppBar( - leadingWidth: 29.h, - leading: - AppbarLeadingImage(imagePath: ImageConstant.imgArrowLeft, margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), onTap: onTapBack(context)), - centerTitle: true, - title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); - } - - Function onTapBack(BuildContext context) { - return () { - onTapArrowLeft(context); - }; - } - - /// Navigates to the previous screen. - onTapArrowLeft(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/feed/feed_screen/bloc/feed_bloc.dart b/lib/presentation/users/subscribers_screen/bloc/subscribers_bloc.dart similarity index 58% rename from lib/presentation/feed/feed_screen/bloc/feed_bloc.dart rename to lib/presentation/users/subscribers_screen/bloc/subscribers_bloc.dart index 1eda1fe..a48d619 100644 --- a/lib/presentation/feed/feed_screen/bloc/feed_bloc.dart +++ b/lib/presentation/users/subscribers_screen/bloc/subscribers_bloc.dart @@ -1,30 +1,29 @@ //import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; import 'dart:async'; +import 'dart:convert'; import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/presentation/users/subscribers_screen/models/subscribers_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/feed/feed_screen/models/feed_model.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; -part 'feed_event.dart'; -part 'feed_state.dart'; +import '/core/app_export.dart'; -/// A bloc that manages the state of a Feed according to the event that is dispatched to it. -class FeedBloc extends Bloc { - FeedBloc(FeedState initialState) : super(initialState) { - on(_onInitialize); +part 'subscribers_event.dart'; +part 'subscribers_state.dart'; + +/// A bloc that manages the state of a Subscribers according to the event that is dispatched to it. +class SubscribersBloc extends Bloc { + SubscribersBloc(SubscribersState initialState) : super(initialState) { + on(_onInitialize); } Future _onInitialize( - FeedInitialEvent event, - Emitter emit, + SubscribersInitialEvent event, + Emitter emit, ) async { try { final box = await Hive.openBox('token'); @@ -33,41 +32,43 @@ class FeedBloc extends Bloc { AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); } final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/feed/index'), + Uri.parse(baseUrl + '/api/profile/subscribers'), headers: { 'Authorization': 'Bearer $token', }, ); print('Got response'); + print(response.statusCode); + print(response.body); if (response.statusCode == 200) { print('Got 200'); final data = jsonDecode(response.body); if (data is List) { print('Got List'); - if (state is FeedLoadedState) { + if (state is SubscribersLoadedState) { print('Got loaded'); - var currentState = state as FeedLoadedState; + var currentState = state as SubscribersLoadedState; emit((currentState).copyWith( - posts: data, + subscribers: data, myProfileModelObj: currentState.myProfileModelObj, )); } else { print('Got unloaded'); - emit(FeedLoadedState( - posts: data, + emit(SubscribersLoadedState( + subscribers: data, )); } } else { // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку - emit(FeedErrorState('Неверный формат ответа API.')); + emit(SubscribersErrorState('Неверный формат ответа API.')); } } else { // Статус ответа не равен 200, обрабатываем ошибку - emit(FeedErrorState('Ошибка сервера: ${response.statusCode}')); + emit(SubscribersErrorState('Ошибка сервера: ${response.statusCode}')); } } catch (e) { // Ошибка при декодировании JSON или другая ошибка выполнения - emit(FeedErrorState('Ошибка при получении данных ленты: $e')); + emit(SubscribersErrorState('Ошибка при получении данных ленты: $e')); } } } diff --git a/lib/presentation/registration/credentials_screen/bloc/credentials_event.dart b/lib/presentation/users/subscribers_screen/bloc/subscribers_event.dart similarity index 52% rename from lib/presentation/registration/credentials_screen/bloc/credentials_event.dart rename to lib/presentation/users/subscribers_screen/bloc/subscribers_event.dart index 3001076..3034e63 100644 --- a/lib/presentation/registration/credentials_screen/bloc/credentials_event.dart +++ b/lib/presentation/users/subscribers_screen/bloc/subscribers_event.dart @@ -1,16 +1,16 @@ // ignore_for_file: must_be_immutable -part of 'credentials_bloc.dart'; +part of 'subscribers_bloc.dart'; /// Abstract class for all events that can be dispatched from the -///Credentials widget. +///Subscribers widget. /// /// Events must be immutable and implement the [Equatable] interface. @immutable -abstract class CredentialsEvent extends Equatable {} +abstract class SubscribersEvent extends Equatable {} -/// Event that is dispatched when the Credentials widget is first created. -class CredentialsInitialEvent extends CredentialsEvent { +/// Event that is dispatched when the Subscribers widget is first created. +class SubscribersInitialEvent extends SubscribersEvent { @override List get props => []; } diff --git a/lib/presentation/users/subscribers_screen/bloc/subscribers_state.dart b/lib/presentation/users/subscribers_screen/bloc/subscribers_state.dart new file mode 100644 index 0000000..2b34e5b --- /dev/null +++ b/lib/presentation/users/subscribers_screen/bloc/subscribers_state.dart @@ -0,0 +1,49 @@ +// ignore_for_file: must_be_immutable + +part of 'subscribers_bloc.dart'; + +class SubscribersState extends Equatable { + const SubscribersState({this.myProfileModelObj}); + + final SubscribersModel? myProfileModelObj; + + @override + List get props => [myProfileModelObj]; +} + +class SubscribersInitialState extends SubscribersState { + SubscribersInitialState({required SubscribersModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj); +} + +/// Represents the state of Subscribers in the application. +class SubscribersLoadedState extends SubscribersState { + SubscribersLoadedState({this.myProfileModelObj, this.subscribers}) : super(myProfileModelObj: null); + + SubscribersModel? myProfileModelObj; + dynamic subscribers; + + @override + List get props => [ + myProfileModelObj, + subscribers, + ]; + + SubscribersLoadedState copyWith({ + SubscribersModel? myProfileModelObj, + dynamic subscribers, + }) { + return SubscribersLoadedState( + myProfileModelObj: myProfileModelObj ?? this.myProfileModelObj, + subscribers: subscribers ?? this.subscribers, + ); + } +} + +class SubscribersErrorState extends SubscribersState { + final String errorMessage; + + const SubscribersErrorState(this.errorMessage); + + @override + List get props => [errorMessage]; +} diff --git a/lib/presentation/feed/feed_screen/models/feed_model.dart b/lib/presentation/users/subscribers_screen/models/subscribers_model.dart similarity index 69% rename from lib/presentation/feed/feed_screen/models/feed_model.dart rename to lib/presentation/users/subscribers_screen/models/subscribers_model.dart index 9e13172..f7d0cda 100644 --- a/lib/presentation/feed/feed_screen/models/feed_model.dart +++ b/lib/presentation/users/subscribers_screen/models/subscribers_model.dart @@ -4,11 +4,11 @@ import 'package:equatable/equatable.dart'; /// This class defines the variables used in the [k0_page], /// and is typically used to hold data that is passed between different parts of the application. -class FeedModel extends Equatable { - FeedModel(); +class SubscribersModel extends Equatable { + SubscribersModel(); - FeedModel copyWith() { - return FeedModel(); + SubscribersModel copyWith() { + return SubscribersModel(); } @override diff --git a/lib/presentation/users/subscribers_screen/subscribers_screen.dart b/lib/presentation/users/subscribers_screen/subscribers_screen.dart new file mode 100644 index 0000000..bb968f2 --- /dev/null +++ b/lib/presentation/users/subscribers_screen/subscribers_screen.dart @@ -0,0 +1,206 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/presentation/feed/feed_screen/widgets/feed_search_view.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'bloc/subscribers_bloc.dart'; +import 'models/subscribers_model.dart'; + +class SubscribersScreen extends StatelessWidget { + static Widget builder(BuildContext context) { + return BlocProvider( + create: (context) => SubscribersBloc(SubscribersState(myProfileModelObj: SubscribersModel()))..add(SubscribersInitialEvent()), + child: SubscribersScreen()); + } + + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is SubscribersInitialState) { + // Это начальное состояние, данные ещё не загружены. + return CircularProgressIndicator( + color: Colors.white, + backgroundColor: Colors.white, + ); + } else if (state is SubscribersLoadedState) { + // Данные загружены, можно строить экран. + return _buildSubscribersScreen(context, state); + } else { + // Другие состояния, если они есть. + return Container(); // Пустой контейнер для необработанных состояний. + } + }, + ); + } + + _buildSubscribersScreen(BuildContext context, SubscribersLoadedState state) { + return Scaffold( + backgroundColor: Colors.grey[200], + resizeToAvoidBottomInset: true, + body: SingleChildScrollView( + child: Container( + width: double.maxFinite, + decoration: BoxDecoration(color: Colors.grey[200]), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: 10), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: CustomAppBar( + height: 54.v, + leadingWidth: 28.h, + leading: AppbarLeadingImage( + imagePath: ImageConstant.imgArrowLeft, + margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), + onTap: () => GoRouter.of(context).pop(), + ), + title: Padding( + padding: EdgeInsets.only(left: 20.h), + child: Row( + children: [ + AppbarSubtitle( + text: "Мои подписчики", + margin: EdgeInsets.only(left: 80.h, top: 12.v, bottom: 9.v), + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 20.0), + child: GestureDetector(child: Icon(Icons.create_outlined)), + ) + ], + ), + ), + ), + ), + _buildSearch(context), + SizedBox(height: 16), + _buildSubscribersList(context, state), + ], + ), + ), + ), + ), + ); + } + + _buildSearch(BuildContext context) { + return Container( + margin: EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + children: [ + CustomSearchView( + hintText: "Поиск", + ), + SizedBox(height: 10), + Row( + children: [ + Flexible( + flex: 5, + child: CustomOutlinedButton( + text: "Найти", + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + SizedBox(width: 8), // Add some spacing between the buttons + Flexible( + flex: 1, + child: CustomOutlinedButton( + text: "+", + onPressed: () => GoRouter.of(context).pushNamed('blogPostCreateScreen'), + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + ), + ), + ], + ) + ], + ), + ), + ); + } + + _buildSubscribersList(BuildContext context, SubscribersLoadedState state) { + List subscriberWidgets = []; + + if (state.subscribers != null) { + for (var subscriber in state.subscribers!) { + subscriberWidgets.add(_buildSubscriberEntry(subscriber, context)); + } + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: subscriberWidgets, + ); + } + + _buildSubscriberEntry(BuildContext context, subscriber) { + return Container( + margin: EdgeInsets.only(bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: ListTile( + leading: CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + subscriber['image'], + imageBuilder: (context, imageProvider) => CircleAvatar( + backgroundImage: imageProvider, + radius: 25, + ), + placeholder: (context, url) => CircularProgressIndicator(), + errorWidget: (context, url, error) => CircleAvatar( + child: Icon(Icons.person), + backgroundColor: Colors.white, + radius: 25, + ), + ), + title: Text( + subscriber?['title'] ?? '', + style: CustomTextStyles.titleMediumSemiBold, + ), + subtitle: Text(subscriber?['description'] ?? ''), + trailing: GestureDetector(child: Icon(Icons.edit)), + )); + } +} diff --git a/lib/theme/app_decoration.dart b/lib/theme/app_decoration.dart index f304e54..c84477e 100644 --- a/lib/theme/app_decoration.dart +++ b/lib/theme/app_decoration.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class AppDecoration { // Fill decorations @@ -15,6 +15,7 @@ class AppDecoration { width: 1.h, ), ); + static BoxDecoration get outlinePrimary => BoxDecoration( color: theme.colorScheme.onPrimary, border: Border.all( @@ -22,27 +23,35 @@ class AppDecoration { width: 1.h, ), ); + static BoxDecoration get fillDeepOrange => BoxDecoration( color: appTheme.deepOrange900.withOpacity(0.8), ); + static BoxDecoration get fillGray => BoxDecoration( color: appTheme.gray50, ); + static BoxDecoration get fillGray100 => BoxDecoration( color: appTheme.gray100, ); + static BoxDecoration get fillGray60002 => BoxDecoration( color: appTheme.gray60002, ); + static BoxDecoration get fillGreenA => BoxDecoration( color: appTheme.greenA700.withOpacity(0.8), ); + static BoxDecoration get fillPrimary => BoxDecoration( color: theme.colorScheme.primary, ); + static BoxDecoration get fillWhiteA => BoxDecoration( color: appTheme.whiteA700, ); + static BoxDecoration get outlineBlueGray => BoxDecoration( border: Border.all( color: appTheme.blueGray800, @@ -78,6 +87,7 @@ class BorderRadiusStyle { ), ], ); + static BoxDecoration get outlineBlueGray => BoxDecoration( border: Border.all( color: appTheme.blueGray800, @@ -85,13 +95,16 @@ class BorderRadiusStyle { strokeAlign: strokeAlignOutside, ), ); + // Circle borders static BorderRadius get circleBorder17 => BorderRadius.circular( 17.h, ); + static BorderRadius get circleBorder20 => BorderRadius.circular( 20.h, ); + static BorderRadius get circleBorder62 => BorderRadius.circular( 62.h, ); @@ -100,9 +113,11 @@ class BorderRadiusStyle { static BorderRadius get customBorderBL8 => BorderRadius.only( bottomLeft: Radius.circular(8.h), ); + static BorderRadius get customBorderTL5 => BorderRadius.vertical( top: Radius.circular(5.h), ); + static BorderRadius get customBorderTL51 => BorderRadius.only( topLeft: Radius.circular(5.h), bottomRight: Radius.circular(5.h), @@ -112,9 +127,11 @@ class BorderRadiusStyle { static BorderRadius get roundedBorder12 => BorderRadius.circular( 12.h, ); + static BorderRadius get roundedBorder5 => BorderRadius.circular( 5.h, ); + static BorderRadius get roundedBorder8 => BorderRadius.circular( 8.h, ); diff --git a/lib/theme/bloc/theme_bloc.dart b/lib/theme/bloc/theme_bloc.dart index 60f947d..ae2863b 100644 --- a/lib/theme/bloc/theme_bloc.dart +++ b/lib/theme/bloc/theme_bloc.dart @@ -1,6 +1,8 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; + import '../../core/app_export.dart'; + part 'theme_event.dart'; part 'theme_state.dart'; diff --git a/lib/theme/bloc/theme_state.dart b/lib/theme/bloc/theme_state.dart index 2f93fff..191bcfe 100644 --- a/lib/theme/bloc/theme_state.dart +++ b/lib/theme/bloc/theme_state.dart @@ -8,6 +8,7 @@ class ThemeState extends Equatable { @override List get props => [themeType]; + ThemeState copyWith({String? themeType}) { return ThemeState(themeType: themeType ?? this.themeType); } diff --git a/lib/theme/custom_button_style.dart b/lib/theme/custom_button_style.dart index 60204f5..bcd021c 100644 --- a/lib/theme/custom_button_style.dart +++ b/lib/theme/custom_button_style.dart @@ -14,6 +14,7 @@ class CustomButtonStyles { borderRadius: BorderRadius.circular(15.h), ), ); + // text button style static ButtonStyle get none => ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.transparent), diff --git a/lib/theme/custom_text_style.dart b/lib/theme/custom_text_style.dart index de3bee7..1ed606c 100644 --- a/lib/theme/custom_text_style.dart +++ b/lib/theme/custom_text_style.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import '../core/app_export.dart'; /// A collection of pre-defined text styles for customizing text appearance, diff --git a/lib/theme/theme_helper.dart b/lib/theme/theme_helper.dart index 7226e37..b33d056 100644 --- a/lib/theme/theme_helper.dart +++ b/lib/theme/theme_helper.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; + import '../../core/app_export.dart'; /// Helper class for managing themes and colors. @@ -9,12 +11,12 @@ class ThemeHelper { // A map of custom color themes supported by the app Map _supportedCustomColor = { - 'primary': PrimaryColors() + 'primary': PrimaryColors(), }; // A map of color schemes supported by the app Map _supportedColorScheme = { - 'primary': ColorSchemes.primaryColorScheme + 'primary': ColorSchemes.primaryColorScheme, }; /// Returns the primary colors for the current theme. @@ -22,7 +24,8 @@ class ThemeHelper { //throw exception to notify given theme is not found or not generated by the generator if (!_supportedCustomColor.containsKey(_appTheme)) { throw Exception( - "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner"); + "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner", + ); } //return theme from map @@ -34,13 +37,50 @@ class ThemeHelper { //throw exception to notify given theme is not found or not generated by the generator if (!_supportedColorScheme.containsKey(_appTheme)) { throw Exception( - "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner"); + "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner", + ); } //return theme from map - var colorScheme = - _supportedColorScheme[_appTheme] ?? ColorSchemes.primaryColorScheme; + var colorScheme = _supportedColorScheme[_appTheme] ?? ColorSchemes.primaryColorScheme; return ThemeData( + textTheme: GoogleFonts.mulishTextTheme().copyWith( + bodyLarge: TextStyle( + color: appTheme.blueGray400, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + headlineSmall: TextStyle( + color: colorScheme.primary, + fontWeight: FontWeight.w600, + fontSize: 24, + ), + titleMedium: TextStyle( + color: colorScheme.primary, + fontWeight: FontWeight.w700, + fontSize: 18, + ), + titleSmall: TextStyle( + color: colorScheme.onPrimary, + fontWeight: FontWeight.w700, + fontSize: 15, + ), + bodyMedium: TextStyle( + color: appTheme.blueGray400, + fontWeight: FontWeight.w400, + fontSize: 14, + ), + bodySmall: TextStyle( + color: appTheme.gray500, + fontWeight: FontWeight.w400, + fontSize: 10, + ), + labelLarge: TextStyle( + color: appTheme.blueGray800, + fontWeight: FontWeight.w600, + fontSize: 12, + ), + ), pageTransitionsTheme: PageTransitionsTheme( builders: { TargetPlatform.android: CupertinoPageTransitionsBuilder(), @@ -49,13 +89,16 @@ class ThemeHelper { ), visualDensity: VisualDensity.standard, colorScheme: colorScheme, - textTheme: TextThemes.textTheme(colorScheme), scaffoldBackgroundColor: colorScheme.onPrimary, appBarTheme: AppBarTheme( + scrolledUnderElevation: 0, + elevation: 0, systemOverlayStyle: SystemUiOverlayStyle( statusBarIconBrightness: Brightness.dark, statusBarBrightness: Brightness.light, systemNavigationBarColor: Colors.white, + statusBarColor: Colors.white, + systemNavigationBarIconBrightness: Brightness.dark, ), ), outlinedButtonTheme: OutlinedButtonThemeData( @@ -85,54 +128,6 @@ class ThemeHelper { ThemeData themeData() => _getThemeData(); } -/// Class containing the supported text theme styles. -class TextThemes { - static TextTheme textTheme(ColorScheme colorScheme) => TextTheme( - bodyLarge: TextStyle( - color: appTheme.blueGray400, - fontSize: 18.fSize, - fontFamily: 'Mulish', - fontWeight: FontWeight.w400, - ), - headlineSmall: TextStyle( - color: colorScheme.primary, - fontSize: 24.fSize, - fontFamily: 'Segoe UI', - fontWeight: FontWeight.w600, - ), - titleMedium: TextStyle( - color: colorScheme.primary, - fontSize: 18.fSize, - fontFamily: 'Mulish', - fontWeight: FontWeight.w700, - ), - titleSmall: TextStyle( - color: colorScheme.onPrimary, - fontSize: 15.fSize, - fontFamily: 'Mulish', - fontWeight: FontWeight.w700, - ), - bodyMedium: TextStyle( - color: appTheme.blueGray400, - fontSize: 14.fSize, - fontFamily: 'Mulish', - fontWeight: FontWeight.w400, - ), - bodySmall: TextStyle( - color: appTheme.gray500, - fontSize: 10.fSize, - fontFamily: 'Roboto', - fontWeight: FontWeight.w400, - ), - labelLarge: TextStyle( - color: appTheme.blueGray800, - fontSize: 12.fSize, - fontFamily: 'Mulish', - fontWeight: FontWeight.w600, - ), - ); -} - /// Class containing the supported color schemes. class ColorSchemes { static final primaryColorScheme = ColorScheme.light( @@ -149,10 +144,12 @@ class ColorSchemes { class PrimaryColors { // Blue Color get blue400 => Color(0XFF43A6F2); + Color get blueA400 => Color(0XFF2F80ED); // BlueGray Color get blueGray400 => Color(0XFF7B8794); + Color get black900 => Color(0XFF000000); // Blue @@ -160,7 +157,9 @@ class PrimaryColors { // BlueGray Color get blueGray300 => Color(0XFF9AA5B1); + Color get blueGray800 => Color(0XFF323F4B); + Color get blueGray900 => Color(0XFF2A2F4C); // DeepOrange @@ -168,22 +167,33 @@ class PrimaryColors { // Gray Color get gray100 => Color(0XFFF0F2F5); + Color get gray200 => Color(0XFFF0F0F0); + Color get gray400 => Color(0XFFC1C1C1); + Color get gray40001 => Color(0XFFC8C8C8); + Color get gray50 => Color(0XFFF6FAFF); + Color get gray500 => Color(0XFFA3A3A3); + Color get gray600 => Color(0XFF6D6D6D); + Color get gray60001 => Color(0XFF848484); + Color get gray60002 => Color(0XFF757575); + Color get gray60003 => Color(0XFF707070); // Green Color get greenA700 => Color(0XFF019A3E); + Color get greenA70001 => Color(0XFF00BE13); // LightGreen Color get lightGreen300 => Color(0XFFB2DF8A); + Color get lightGreenA700 => Color(0XFF18FF14); // Red @@ -191,6 +201,7 @@ class PrimaryColors { // Teal Color get teal100 => Color(0XFFA6CEE3); + Color get teal900 => Color(0XFF0B3F56); // White @@ -200,4 +211,5 @@ class PrimaryColors { } PrimaryColors get appTheme => ThemeHelper().themeColor(); + ThemeData get theme => ThemeHelper().themeData(); diff --git a/lib/widgets/app_bar/appbar_title_image.dart b/lib/widgets/app_bar/appbar_title_image.dart index 4ef20de..429ab4d 100644 --- a/lib/widgets/app_bar/appbar_title_image.dart +++ b/lib/widgets/app_bar/appbar_title_image.dart @@ -3,37 +3,16 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class AppbarTitleImage extends StatelessWidget { - AppbarTitleImage({ - Key? key, - this.imagePath, - this.margin, - this.onTap, - }) : super( - key: key, - ); + const AppbarTitleImage({required this.imagePath, super.key}); - String? imagePath; - - EdgeInsetsGeometry? margin; - - Function? onTap; + final String? imagePath; @override Widget build(BuildContext context) { - return InkWell( - onTap: onTapCall, - child: Padding( - padding: margin ?? EdgeInsets.zero, - child: CustomImageView( - imagePath: imagePath, - height: 50.adaptSize, - width: 50.adaptSize, - fit: BoxFit.contain, - ), - ), + return CustomImageView( + imagePath: imagePath, + height: 48, + fit: BoxFit.contain, ); } - - void onTapCall() { - } } diff --git a/lib/widgets/chart_axis.dart b/lib/widgets/chart_axis.dart index 5cc6448..f137c6d 100644 --- a/lib/widgets/chart_axis.dart +++ b/lib/widgets/chart_axis.dart @@ -142,4 +142,4 @@ buildChart( ), ); } -*/ \ No newline at end of file +*/ diff --git a/lib/widgets/chart_bars.dart b/lib/widgets/chart_bars.dart index 7f4fc34..eac9e99 100644 --- a/lib/widgets/chart_bars.dart +++ b/lib/widgets/chart_bars.dart @@ -76,4 +76,4 @@ class MyApp extends StatelessWidget { ); } } -*/ \ No newline at end of file +*/ diff --git a/lib/widgets/custom_about_list.dart b/lib/widgets/custom_about_list.dart index f4b91b2..90b1d3d 100644 --- a/lib/widgets/custom_about_list.dart +++ b/lib/widgets/custom_about_list.dart @@ -26,9 +26,10 @@ class _AboutListState extends State { Text( widget.title, style: TextStyle( - color: Colors.black, - fontSize: 14, - fontWeight: FontWeight.bold), + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), Icon(isExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), ], @@ -38,8 +39,9 @@ class _AboutListState extends State { Padding( padding: const EdgeInsets.only(left: 16.0), child: Column( - //children: widget.items.map((item) => Text(item)).toList(), - children: [Text(widget.items.join('\n'))]), + //children: widget.items.map((item) => Text(item)).toList(), + children: [Text(widget.items.join('\n'))], + ), ), Divider(), ], diff --git a/lib/widgets/custom_drop_down.dart b/lib/widgets/custom_drop_down.dart index 759efc1..96367d6 100644 --- a/lib/widgets/custom_drop_down.dart +++ b/lib/widgets/custom_drop_down.dart @@ -23,7 +23,7 @@ class CustomDropDown extends StatelessWidget { this.filled = true, this.validator, this.onChanged, - this.defaultValue, + this.value, }) : super( key: key, ); @@ -62,7 +62,7 @@ class CustomDropDown extends StatelessWidget { final bool? filled; - final SelectionPopupModel? defaultValue; + final SelectionPopupModel? value; final FormFieldValidator? validator; @@ -79,28 +79,34 @@ class CustomDropDown extends StatelessWidget { } _buildDropDownWidget(BuildContext context) { - return SizedBox( - width: width ?? MediaQuery.of(context).size.width - 20, - child: DropdownButtonFormField( - focusNode: focusNode ?? FocusNode(), - icon: icon, - autofocus: autofocus!, - isExpanded: true, - style: textStyle ?? Theme.of(context).textTheme.titleMedium, - items: items?.map((SelectionPopupModel item) { - return DropdownMenuItem( - value: item, - child: Text( - item.title, - overflow: TextOverflow.fade, - style: hintStyle ?? Theme.of(context).textTheme.titleMedium, - ), - ); - }).toList(), - decoration: _buildInputDecoration(context), - validator: validator, - onChanged: onDropDownChanged, - ), + return DropdownButtonFormField( + focusNode: focusNode ?? FocusNode(), + icon: Icon(Icons.keyboard_arrow_down_rounded), + autofocus: autofocus!, + value: value, + isExpanded: true, + style: textStyle ?? + TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + ), + items: items?.map((SelectionPopupModel item) { + return DropdownMenuItem( + value: item, + child: Text( + item.title, + style: hintStyle ?? + TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + ); + }).toList(), + decoration: _buildInputDecoration(context), + validator: validator, + onChanged: onDropDownChanged, ); } @@ -111,34 +117,43 @@ class CustomDropDown extends StatelessWidget { InputDecoration _buildInputDecoration(BuildContext context) { return InputDecoration( hintText: hintText ?? "", - hintStyle: hintStyle ?? Theme.of(context).textTheme.titleMedium, + hintStyle: hintStyle ?? + TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.grey.shade400, + ), prefixIcon: prefix, prefixIconConstraints: prefixConstraints, suffixIcon: suffix, suffixIconConstraints: suffixConstraints, isDense: true, - contentPadding: contentPadding ?? - EdgeInsets.only( - left: 6, - top: 6, - bottom: 6, - ), + contentPadding: contentPadding ?? EdgeInsets.all(8), fillColor: fillColor ?? Theme.of(context).colorScheme.onPrimary, filled: filled, border: borderDecoration ?? OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(8)), - borderSide: BorderSide(color: appTheme.blueA400, width: 1), + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: Colors.grey.shade400, + width: 1, + ), ), enabledBorder: borderDecoration ?? OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(8)), - borderSide: BorderSide(color: appTheme.blueA400, width: 1), + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: Colors.grey.shade400, + width: 1, + ), ), focusedBorder: borderDecoration ?? OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(8)), - borderSide: BorderSide(color: appTheme.blueA400, width: 1), + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: appTheme.blueA400, + width: 1, + ), ), ); } diff --git a/lib/widgets/custom_edit_drop_down.dart b/lib/widgets/custom_edit_drop_down.dart index 7f56bbd..26b4283 100644 --- a/lib/widgets/custom_edit_drop_down.dart +++ b/lib/widgets/custom_edit_drop_down.dart @@ -25,8 +25,8 @@ class CustomDropDown extends StatelessWidget { this.onChanged, this.defaultValue, }) : super( - key: key, - ); + key: key, + ); final Alignment? alignment; @@ -72,9 +72,9 @@ class CustomDropDown extends StatelessWidget { Widget build(BuildContext context) { return alignment != null ? Align( - alignment: alignment ?? Alignment.center, - child: _buildDropDownWidget(context), - ) + alignment: alignment ?? Alignment.center, + child: _buildDropDownWidget(context), + ) : _buildDropDownWidget(context); } @@ -85,14 +85,20 @@ class CustomDropDown extends StatelessWidget { focusNode: focusNode ?? FocusNode(), icon: icon, autofocus: autofocus!, - style: textStyle ?? Theme.of(context).textTheme.titleMedium, + style: textStyle ?? Theme + .of(context) + .textTheme + .titleMedium, items: items?.map((SelectionPopupModel item) { return DropdownMenuItem( value: item, child: Text( item.title, overflow: TextOverflow.ellipsis, - style: hintStyle ?? Theme.of(context).textTheme.titleMedium, + style: hintStyle ?? Theme + .of(context) + .textTheme + .titleMedium, ), ); }).toList(), @@ -111,7 +117,10 @@ class CustomDropDown extends StatelessWidget { InputDecoration _buildInputDecoration(BuildContext context) { return InputDecoration( hintText: hintText ?? "", - hintStyle: hintStyle ?? Theme.of(context).textTheme.titleMedium, + hintStyle: hintStyle ?? Theme + .of(context) + .textTheme + .titleMedium, prefixIcon: prefix, prefixIconConstraints: prefixConstraints, suffixIcon: suffix, @@ -123,7 +132,10 @@ class CustomDropDown extends StatelessWidget { top: 6, bottom: 6, ), - fillColor: fillColor ?? Theme.of(context).colorScheme.onPrimary, + fillColor: fillColor ?? Theme + .of(context) + .colorScheme + .onPrimary, filled: filled, border: borderDecoration ?? OutlineInputBorder( diff --git a/lib/widgets/custom_edit_text_form_field.dart b/lib/widgets/custom_edit_text_form_field.dart index 0853d3e..13a3df8 100644 --- a/lib/widgets/custom_edit_text_form_field.dart +++ b/lib/widgets/custom_edit_text_form_field.dart @@ -8,7 +8,7 @@ class CustomTextFormField extends StatelessWidget { this.width, this.controller, this.focusNode, - this.autofocus = true, + this.autofocus = false, this.textStyle, this.obscureText = false, this.textInputAction = TextInputAction.next, diff --git a/lib/widgets/custom_expandable_list.dart b/lib/widgets/custom_expandable_list.dart index c3d552b..167c68e 100644 --- a/lib/widgets/custom_expandable_list.dart +++ b/lib/widgets/custom_expandable_list.dart @@ -1,16 +1,16 @@ -import 'package:flutter/material.dart'; +import 'dart:convert'; + import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; import 'package:eatvio_app/widgets/custom_hyper_switch.dart'; import 'package:eatvio_app/widgets/custom_hypo_switch.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; import 'package:eatvio_app/widgets/next_step_button.dart'; -import 'dart:convert'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:hive/hive.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; class ExpandableList extends StatefulWidget { final String title; @@ -37,9 +37,10 @@ class _ExpandableListState extends State { Text( widget.title, style: TextStyle( - color: Colors.black, - fontSize: 14, - fontWeight: FontWeight.bold), + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), Icon(isExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), ], @@ -49,24 +50,25 @@ class _ExpandableListState extends State { Padding( padding: const EdgeInsets.only(left: 16.0), child: BlocBuilder( - builder: (context, state) { - if (state is MyProfileInitialState) { - // Это начальное состояние, данные ещё не загружены. - return CircularProgressIndicator( - color: Colors.white, - backgroundColor: Colors.white, - ); - } else if (state is MyProfileLoadedState) { - // Данные загружены, можно строить форму. - return _buildForm(context, state); - } else if (state is MyProfileErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. - } - }), + builder: (context, state) { + if (state is MyProfileInitialState) { + // Это начальное состояние, данные ещё не загружены. + return CircularProgressIndicator( + color: Colors.white, + backgroundColor: Colors.white, + ); + } else if (state is MyProfileLoadedState) { + // Данные загружены, можно строить форму. + return _buildForm(context, state); + } else if (state is MyProfileErrorState) { + // Произошла ошибка при загрузке данных. + return Center(child: Text(state.errorMessage)); + } else { + // Другие состояния, если они есть. + return Container(); // Пустой контейнер для необработанных состояний. + } + }, + ), ), Divider(), ], @@ -122,145 +124,159 @@ class _ExpandableListState extends State { 'низкий (1-3 тренировки в неделю по 20 мин)', 'умеренный (3-4 тренировки в неделю по 30-60 мин)', 'высокий (5-7 тренировок по 30-60 мин)', - 'экстремальный (несколько интенсивных тренировок в день)' + 'экстремальный (несколько интенсивных тренировок в день)', ]; final digitsOnly = FilteringTextInputFormatter.digitsOnly; - return Column(children: [ - TextField( - controller: state.firstNameFormController, - decoration: InputDecoration(labelText: 'first_name'.tr), - ), - TextField( - controller: state.lastNameFormController, - decoration: InputDecoration(labelText: 'last_name'.tr), - ), - TextField( + return Column( + children: [ + TextField( + controller: state.firstNameFormController, + decoration: InputDecoration(labelText: 'first_name'.tr), + ), + TextField( + controller: state.lastNameFormController, + decoration: InputDecoration(labelText: 'last_name'.tr), + ), + TextField( decoration: InputDecoration(labelText: 'date_of_birth'.tr), controller: state.dateFormController, - onTap: inputTime(context, state)), - DropdownButtonFormField( - value: state.selectedCountry, - hint: Text(state.selectedCountry ?? "Не выбрано"), - onChanged: setCountry(state), - items: countries.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - decoration: InputDecoration(labelText: 'country'.tr), - ), - DropdownButtonFormField( - hint: Text(state.selectedCity ?? "Не выбрано"), - value: state.selectedCity, - onChanged: setCity(state), - items: cities.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - decoration: InputDecoration(labelText: 'city_of_living'.tr), - ), - TextField( + onTap: inputTime(context, state), + ), + DropdownButtonFormField( + value: state.selectedCountry, + hint: Text(state.selectedCountry ?? "Не выбрано"), + onChanged: setCountry(state), + items: countries.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + decoration: InputDecoration(labelText: 'country'.tr), + ), + DropdownButtonFormField( + hint: Text(state.selectedCity ?? "Не выбрано"), + value: state.selectedCity, + onChanged: setCity(state), + items: cities.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + decoration: InputDecoration(labelText: 'city_of_living'.tr), + ), + TextField( controller: state.weightFormController, decoration: InputDecoration(labelText: 'weight_measurements'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.heightFormController, decoration: InputDecoration(labelText: 'height_measurements'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.chestCircumferenceFormController, decoration: InputDecoration(labelText: 'chest_circumference'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.waistCircumferenceFormController, decoration: InputDecoration(labelText: 'waist_circumference'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.hipCircumferenceFormController, decoration: InputDecoration(labelText: 'hip_circumference'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.upPressureFormController, decoration: InputDecoration(labelText: 'up_pressure'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( + inputFormatters: [digitsOnly], + ), + TextField( controller: state.downPressureFormController, decoration: InputDecoration(labelText: 'down_pressure'.tr), keyboardType: TextInputType.number, - inputFormatters: [digitsOnly]), - TextField( - controller: state.allergiesFormController, - decoration: InputDecoration(labelText: 'allergies_presence'.tr), - maxLines: null, - ), - TextField( - controller: state.pillsFormController, - decoration: InputDecoration(labelText: 'do_you_take_pills'.tr), - maxLines: null, - ), - TextField( - controller: state.sportsFormController, - decoration: InputDecoration(labelText: 'your_favorite_sports'.tr), - maxLines: null, - ), - TextField( - controller: state.favoriteFormController, - decoration: InputDecoration(labelText: 'favorite_foods'.tr), - maxLines: null, - ), - TextField( - controller: state.unfavoriteFormController, - decoration: InputDecoration(labelText: 'unfavorite_foods'.tr), - maxLines: null, - ), - TextField( - controller: state.additionalFormController, - decoration: InputDecoration(labelText: 'additional_information'.tr), - maxLines: null, - ), - DropdownButtonFormField( - hint: Text(state.selectedActivity ?? "Не выбрано"), - value: state.selectedActivity, - onChanged: setActivity(state), - items: activities.map>((String value) { - return DropdownMenuItem( - value: value, - child: SizedBox( - // Используем SizedBox для ограничения ширины элемента списка - width: MediaQuery.of(context).size.width * - 0.8, // Устанавливаем желаемую ширину элемента списка - child: Text(value), - ), - ); - }).toList(), - isExpanded: true, // Расширяем список на всю доступную ширину - decoration: InputDecoration(labelText: 'Активность'), - ), - Row( - children: [ - HypoSwitch('do_you_have_hypotension_tendency'.tr, state), - ], - ), - Row( - children: [ - HyperSwitch('do_you_have_hypertension_tendency'.tr, state), - ], - ), - NextStepButton( + inputFormatters: [digitsOnly], + ), + TextField( + controller: state.allergiesFormController, + decoration: InputDecoration(labelText: 'allergies_presence'.tr), + maxLines: null, + ), + TextField( + controller: state.pillsFormController, + decoration: InputDecoration(labelText: 'do_you_take_pills'.tr), + maxLines: null, + ), + TextField( + controller: state.sportsFormController, + decoration: InputDecoration(labelText: 'your_favorite_sports'.tr), + maxLines: null, + ), + TextField( + controller: state.favoriteFormController, + decoration: InputDecoration(labelText: 'favorite_foods'.tr), + maxLines: null, + ), + TextField( + controller: state.unfavoriteFormController, + decoration: InputDecoration(labelText: 'unfavorite_foods'.tr), + maxLines: null, + ), + TextField( + controller: state.additionalFormController, + decoration: InputDecoration(labelText: 'additional_information'.tr), + maxLines: null, + ), + DropdownButtonFormField( + hint: Text(state.selectedActivity ?? "Не выбрано"), + value: state.selectedActivity, + onChanged: setActivity(state), + items: activities.map>((String value) { + return DropdownMenuItem( + value: value, + child: SizedBox( + // Используем SizedBox для ограничения ширины элемента списка + width: MediaQuery + .of(context) + .size + .width * 0.8, // Устанавливаем желаемую ширину элемента списка + child: Text(value), + ), + ); + }).toList(), + isExpanded: true, + // Расширяем список на всю доступную ширину + decoration: InputDecoration(labelText: 'Активность'), + ), + Row( + children: [ + HypoSwitch('do_you_have_hypotension_tendency'.tr, state), + ], + ), + Row( + children: [ + HyperSwitch('do_you_have_hypertension_tendency'.tr, state), + ], + ), + NextStepButton( onPressed: () => sendProfileData(state), buttonStyle: CustomButtonStyles.outlinePrimaryTL15, text: "save".tr.toUpperCase(), - margin: EdgeInsets.only(top: 20.h, bottom: 20.h)), - ]); + margin: EdgeInsets.only(top: 20.h, bottom: 20.h), + ), + ], + ); } sendData(MyProfileLoadedState state) { @@ -300,8 +316,7 @@ class _ExpandableListState extends State { ).then((selectedDate) { if (selectedDate != null) { setState(() { - state.dateFormController!.text = - DateFormat('dd-MM-yyyy').format(selectedDate); + state.dateFormController!.text = DateFormat('dd-MM-yyyy').format(selectedDate); }); } }); @@ -367,8 +382,7 @@ class _ExpandableListState extends State { 'city': state?.selectedCity ?? 'Москва', 'has_hypo': state?.hypoFormController, 'has_hyper': state?.hyperFormController, - 'activity_coefficient': - determineActivityFactor(state?.selectedActivity ?? 'сидячий'), + 'activity_coefficient': determineActivityFactor(state?.selectedActivity ?? 'сидячий'), }; } @@ -378,11 +392,12 @@ class _ExpandableListState extends State { } String _buildApiUrl() { - return dotenv.env['SERVER_ROOT']! + '/profile/update'; + return baseUrl + '/api/profile/update'; } - Future _sendHttpRequest( - Map profileData, String apiUrl, String? token) { + Future _sendHttpRequest(Map profileData, + String apiUrl, + String? token,) { return http.post( Uri.parse(apiUrl), body: json.encode(profileData), @@ -407,16 +422,17 @@ class _ExpandableListState extends State { void _showErrorDialog(String errorMessage) { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text('Ошибка'), - content: Text(errorMessage), - actions: [ - TextButton( - onPressed: onTapOk(context), - child: Text('OK'), + builder: (context) => + AlertDialog( + title: Text('Ошибка'), + content: Text(errorMessage), + actions: [ + TextButton( + onPressed: onTapOk(context), + child: Text('OK'), + ), + ], ), - ], - ), ); } diff --git a/lib/widgets/custom_hyper_switch.dart b/lib/widgets/custom_hyper_switch.dart index 92ebf00..3d28d05 100644 --- a/lib/widgets/custom_hyper_switch.dart +++ b/lib/widgets/custom_hyper_switch.dart @@ -1,10 +1,11 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; +import 'package:flutter/material.dart'; class HyperSwitch extends StatefulWidget { final String title; final MyProfileLoadedState? state; + HyperSwitch(this.title, this.state); @override @@ -30,7 +31,10 @@ class _HyperState extends State { Text( widget.title, style: TextStyle( - color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold), + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), Switch( value: switchValue, diff --git a/lib/widgets/custom_hypo_switch.dart b/lib/widgets/custom_hypo_switch.dart index 1c625fe..9504e5f 100644 --- a/lib/widgets/custom_hypo_switch.dart +++ b/lib/widgets/custom_hypo_switch.dart @@ -1,10 +1,11 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; +import 'package:flutter/material.dart'; class HypoSwitch extends StatefulWidget { final String title; final MyProfileLoadedState? state; + HypoSwitch(this.title, this.state); @override @@ -30,7 +31,10 @@ class _HypoState extends State { Text( widget.title, style: TextStyle( - color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold), + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), Switch( value: switchValue, diff --git a/lib/widgets/custom_icon_button.dart b/lib/widgets/custom_icon_button.dart index 55766f1..d029004 100644 --- a/lib/widgets/custom_icon_button.dart +++ b/lib/widgets/custom_icon_button.dart @@ -45,7 +45,8 @@ class CustomIconButton extends StatelessWidget { color: Colors.black, borderRadius: const BorderRadius.all(Radius.circular(9)), border: const Border.fromBorderSide( - BorderSide(color: Colors.blueGrey, width: 1)), + BorderSide(color: Colors.blueGrey, width: 1), + ), ), child: child, ), diff --git a/lib/widgets/custom_language_drop_down.dart b/lib/widgets/custom_language_drop_down.dart index 7f0e3e0..f04a703 100644 --- a/lib/widgets/custom_language_drop_down.dart +++ b/lib/widgets/custom_language_drop_down.dart @@ -13,7 +13,8 @@ class _LanguageDropdownState extends State { return DropdownButton( value: selectedLanguage, onChanged: selectLanguage(), - isDense: false, // Установите isDense в false + isDense: false, + // Установите isDense в false selectedItemBuilder: getList(), items: ['Русский'].map((String language) { return DropdownMenuItem( diff --git a/lib/widgets/custom_navigation_menu.dart b/lib/widgets/custom_navigation_menu.dart index 03d11a9..b35d5fb 100644 --- a/lib/widgets/custom_navigation_menu.dart +++ b/lib/widgets/custom_navigation_menu.dart @@ -1,9 +1,8 @@ import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; import 'package:eatvio_app/widgets/custom_navigation_menu_item.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hive/hive.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; class CustomNavigationMenu extends StatelessWidget { @@ -23,19 +22,21 @@ class CustomNavigationMenu extends StatelessWidget { icon: ImageConstant.imgRecipes, text: 'Мои рецепты', onTap: () => GoRouter.of(context).push('/recipe-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgDiets, text: 'Мои диеты', onTap: () => GoRouter.of(context).push('/diet-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgPlans, text: 'Мои планы', onTap: () => GoRouter.of(context).push('/plan-select-screen'), - // Действие при нажатии на "Мои рецепты" + ), + MenuItem( + icon: ImageConstant.imgRecipes, + text: 'Календарь', + onTap: () => GoRouter.of(context).push('/calendar-screen'), ), MenuItem( icon: ImageConstant.imgFinance, @@ -45,15 +46,12 @@ class CustomNavigationMenu extends StatelessWidget { MenuItem( icon: ImageConstant.imgSupport, text: 'Поддержка', - onTap: () { - // Действие при нажатии на "Поддержка" - }, + onTap: () {}, ), MenuItem( icon: ImageConstant.imgExit, text: 'Выход', onTap: _onTapLogout(context), - // Действие при нажатии на "Выход" ), ], ), @@ -66,7 +64,7 @@ _onTapLogout(BuildContext context) { final box = await Hive.openBox('token'); final token = box.get('token'); final response = await http.post( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/logout'), + Uri.parse(baseUrl + '/api/profile/logout'), headers: { 'Authorization': 'Bearer $token', }, diff --git a/lib/widgets/custom_navigation_menu_item.dart b/lib/widgets/custom_navigation_menu_item.dart index f33d534..44850fa 100644 --- a/lib/widgets/custom_navigation_menu_item.dart +++ b/lib/widgets/custom_navigation_menu_item.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/widgets/custom_image_view.dart'; +import 'package:flutter/material.dart'; class MenuItem extends StatelessWidget { final String icon; @@ -20,13 +21,12 @@ class MenuItem extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment.center, // Выравнивание по центру вертикально + crossAxisAlignment: CrossAxisAlignment.center, // Выравнивание по центру вертикально children: [ CustomImageView(imagePath: icon), SizedBox( - width: - 8.0), // Добавляем небольшой отступ между иконкой и текстом + width: 8.0, + ), // Добавляем небольшой отступ между иконкой и текстом Text(text), ], ), diff --git a/lib/widgets/custom_notification_screen.dart b/lib/widgets/custom_notification_screen.dart index bb77844..72fd860 100644 --- a/lib/widgets/custom_notification_screen.dart +++ b/lib/widgets/custom_notification_screen.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; class NotificationSwitch extends StatefulWidget { final String title; @@ -21,7 +21,10 @@ class _NotificationSwitchState extends State { Text( widget.title, style: TextStyle( - color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold), + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), Switch( value: switchValue, diff --git a/lib/widgets/custom_outlined_button.dart b/lib/widgets/custom_outlined_button.dart index 38a7704..4b17491 100644 --- a/lib/widgets/custom_outlined_button.dart +++ b/lib/widgets/custom_outlined_button.dart @@ -89,7 +89,7 @@ class CustomOutlinedButton extends BaseButton { } } - /*_buildAppBarbuildOutlinedButtonWidget() { +/*_buildAppBarbuildOutlinedButtonWidget() { return Container( height: this.height ?? 30.v, width: this.width ?? double.maxFinite, diff --git a/lib/widgets/custom_text_form_field.dart b/lib/widgets/custom_text_form_field.dart index e70b2b5..a2b6c74 100644 --- a/lib/widgets/custom_text_form_field.dart +++ b/lib/widgets/custom_text_form_field.dart @@ -4,16 +4,15 @@ import 'package:flutter/services.dart'; class CustomTextFormField extends StatelessWidget { CustomTextFormField({ - Key? key, this.alignment, this.width, this.controller, this.focusNode, - this.autofocus = true, + this.autofocus = false, this.textStyle, this.obscureText = false, - this.textInputAction = TextInputAction.next, - this.textInputType = TextInputType.text, + this.textInputAction, + this.textInputType, this.maxLines, this.hintText, this.hintStyle, @@ -32,21 +31,23 @@ class CustomTextFormField extends StatelessWidget { this.onSaved, this.initialValue, this.onChanged, - }) : super( - key: key, - ); + this.onEditingComplete, + this.minLines = 1, + super.key, + }); final Alignment? alignment; final double? width; final TextEditingController? controller; final FocusNode? focusNode; - final bool? autofocus; + final bool autofocus; final TextStyle? textStyle; final bool? obscureText; final List? inputFormatters; final TextInputAction? textInputAction; final TextInputType? textInputType; final int? maxLines; + final int minLines; final String? hintText; final TextStyle? hintStyle; final Widget? prefix; @@ -61,161 +62,74 @@ class CustomTextFormField extends StatelessWidget { final FormFieldValidator? validator; final String? initialValue; final Function(String)? onFieldSubmitted; + final Function()? onEditingComplete; final void Function(String?)? onSaved; - final void Function(String?)? onChanged; + final void Function(String)? onChanged; @override Widget build(BuildContext context) { - return alignment != null - ? Align( - alignment: alignment ?? Alignment.center, - child: SizedBox( - width: width ?? double.maxFinite, - child: TextFormField( - controller: controller, - focusNode: focusNode ?? null, - autofocus: autofocus!, - style: textStyle ?? theme.textTheme.titleMedium, - obscureText: obscureText!, - textInputAction: textInputAction, - maxLines: maxLines ?? 1, - onFieldSubmitted: onFieldSubmitted, - onChanged: onChanged, - decoration: InputDecoration( - hintText: hintText ?? "", - hintStyle: hintStyle ?? theme.textTheme.bodyLarge, - prefixIcon: prefix, - prefixIconConstraints: prefixConstraints, - suffixIcon: suffix, - suffixIconConstraints: suffixConstraints, - isDense: true, - contentPadding: contentPadding ?? EdgeInsets.all(6.h), - fillColor: fillColor ?? theme.colorScheme.onPrimary, - filled: filled, - border: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - enabledBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - focusedBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), + return Align( + alignment: alignment ?? Alignment.center, + child: TextFormField( + minLines: minLines, + onChanged: onChanged, + controller: controller, + focusNode: focusNode ?? null, + autofocus: autofocus, + style: TextStyle( + fontSize: 16, + color: Colors.black, + ), + obscureText: obscureText!, + textInputAction: textInputAction, + maxLines: maxLines ?? 1, + initialValue: initialValue, + cursorColor: appTheme.blueA400, + decoration: InputDecoration( + hintText: hintText ?? "", + hintStyle: TextStyle( + fontSize: 16, + color: Colors.grey.shade400, + fontWeight: FontWeight.w400, + ), + prefixIcon: prefix, + prefixIconConstraints: prefixConstraints, + suffixIcon: suffix, + suffixIconConstraints: suffixConstraints, + isDense: false, + contentPadding: EdgeInsets.all(8), + fillColor: fillColor ?? theme.colorScheme.onPrimary, + filled: filled, + border: borderDecoration ?? + OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Colors.grey.shade400, + width: 1, ), - keyboardType: keyboardType, - validator: validator, - onSaved: onSaved, - inputFormatters: inputFormatters, - initialValue: initialValue, ), - ), - ) - : SizedBox( - width: width ?? double.maxFinite, - child: TextFormField( - controller: controller, - focusNode: focusNode ?? null, - autofocus: autofocus!, - style: textStyle ?? theme.textTheme.titleMedium, - obscureText: obscureText!, - textInputAction: textInputAction, - maxLines: maxLines ?? 1, - initialValue: initialValue, - decoration: InputDecoration( - hintText: hintText ?? "", - hintStyle: hintStyle ?? theme.textTheme.bodyLarge, - prefixIcon: prefix, - prefixIconConstraints: prefixConstraints, - suffixIcon: suffix, - suffixIconConstraints: suffixConstraints, - isDense: true, - contentPadding: contentPadding ?? EdgeInsets.all(6.h), - fillColor: fillColor ?? theme.colorScheme.onPrimary, - filled: filled, - border: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - enabledBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - focusedBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), + enabledBorder: borderDecoration ?? + OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Colors.grey.shade400, + width: 1, + ), ), - keyboardType: keyboardType, - validator: validator, - onSaved: onSaved, - inputFormatters: inputFormatters, - ), - ); - } -} - /* InputDecoration _buildInputDecoration() { - return InputDecoration( - hintText: hintText ?? "", - hintStyle: hintStyle ?? theme.textTheme.bodyLarge, - prefixIcon: prefix, - prefixIconConstraints: prefixConstraints, - suffixIcon: suffix, - suffixIconConstraints: suffixConstraints, - isDense: true, - contentPadding: contentPadding ?? EdgeInsets.all(6.h), - fillColor: fillColor ?? theme.colorScheme.onPrimary, - filled: filled, - border: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - enabledBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), - focusedBorder: borderDecoration ?? - OutlineInputBorder( - borderRadius: BorderRadius.circular(8.h), - borderSide: BorderSide( - color: appTheme.blueA400, - width: 1, - ), - ), + focusedBorder: borderDecoration ?? + OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: appTheme.blueA400, + width: 1, + ), + ), + ), + keyboardType: keyboardType, + validator: validator, + onSaved: onSaved, + inputFormatters: inputFormatters, + ), ); } -}*/ +} diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 0000000..d86fe75 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,18 @@ +{ + "name": "eatvio_app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/simple-git-hooks": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/simple-git-hooks/-/simple-git-hooks-2.11.1.tgz", + "integrity": "sha512-tgqwPUMDcNDhuf1Xf6KTUsyeqGdgKMhzaH4PAZZuzguOgTl5uuyeYe/8mWgAr6IBxB5V06uqEf6Dy37gIWDtDg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "simple-git-hooks": "cli.js" + } + } + } +} diff --git a/node_modules/simple-git-hooks/package.json b/node_modules/simple-git-hooks/package.json new file mode 100644 index 0000000..f3e8186 --- /dev/null +++ b/node_modules/simple-git-hooks/package.json @@ -0,0 +1,18 @@ +{ + "name": "simple-git-hooks", + "version": "2.11.1", + "description": "A simple, zero dependency tool for setting up git hooks for small projects", + "author": "Mikhail Gorbunov ", + "main": "simple-git-hooks.js", + "bin": "./cli.js", + "keywords": ["pre-commit","pre-push","git","hook","lint","linter"], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/toplenboren/simple-git-hooks.git" + }, + "scripts": { + "postinstall": "node ./postinstall.js", + "uninstall": "node ./uninstall.js" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..67e7935 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,26 @@ +{ + "name": "eatvio_app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "eatvio_app", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "simple-git-hooks": "^2.11.1" + } + }, + "node_modules/simple-git-hooks": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/simple-git-hooks/-/simple-git-hooks-2.11.1.tgz", + "integrity": "sha512-tgqwPUMDcNDhuf1Xf6KTUsyeqGdgKMhzaH4PAZZuzguOgTl5uuyeYe/8mWgAr6IBxB5V06uqEf6Dy37gIWDtDg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "simple-git-hooks": "cli.js" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9b39c56 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "eatvio_app", + "version": "1.0.0", + "description": "- Flutter (Channel stable, 3.19.0, on Ubuntu 22.04.3 LTS 6.2.0-39-generic, locale en_US.UTF-8) - Android Studio (version 2023.1) - VS Code (version 1.85.0) - Android SDK (version 34.0.0) - устанавливается из Android Studio (Tools->SDK Manager->Android Command Line Tools) - Эмулятор (2 available)", + "main": "index.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "simple-git-hooks": "^2.11.1" + }, + "simple-git-hooks": { + "pre-push": "make run-checks", + "preserveUnused": true + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 6000794..5939ba1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,9 +1,10 @@ name: eatvio_app description: A new Flutter project. version: 0.0.0+1 +publish_to: "none" environment: - sdk: '>=3.3.4 <4.0.0' + sdk: ">=3.3.4 <4.0.0" dependencies: flutter: @@ -12,47 +13,46 @@ dependencies: flutter_localizations: sdk: flutter - flutter_bloc: ^8.0.0 - connectivity_plus: ^5.0.2 - shared_preferences: ^2.0.15 - cached_network_image: ^3.3.1 - flutter_svg: ^2.0.9 - equatable: ^2.0.0 - validators: ^3.0.0 + flutter_bloc: ^8.1.6 + shared_preferences: ^2.2.3 hive: ^2.2.3 hive_flutter: ^1.1.0 - isar_flutter_libs: ^4.0.0-dev.13 - path_provider: ^2.1.0 - fl_chart: ^0.66.0 - flutter_spinkit: ^5.0.0 - flutter_dotenv: ^5.1.0 - carousel_slider: ^4.2.1 - flutter_form_builder: ^9.2.1 - image_picker: ^1.0.7 - flutter_typeahead: ^5.2.0 - bloc_test: ^9.1.6 - # navigation - go_router: ^14.1.4 - keyboard_dismisser: ^3.0.0 - - freezed_annotation: ^2.4.1 + cached_network_image: ^3.3.1 + flutter_svg: ^2.0.10 + equatable: ^2.0.5 + freezed_annotation: ^2.4.2 json_annotation: ^4.9.0 + validators: ^3.0.0 + isar_flutter_libs: ^3.1.0 + path_provider: ^2.1.3 + fl_chart: ^0.68.0 + flutter_spinkit: ^5.2.1 + carousel_slider_plus: ^7.0.0 + flutter_form_builder: ^9.3.0 + image_picker: ^1.1.2 + flutter_typeahead: ^5.2.0 + go_router: ^14.2.0 + keyboard_dismisser: ^3.0.0 retrofit: ^4.1.0 get_it: ^7.7.0 - dio: ^5.4.3+1 - - # photo viewer + dio: ^5.5.0 + dart_pusher_channels: ^1.2.2+1 photo_view: ^0.15.0 - #url launcher + dismissible_page: ^1.0.2 url_launcher: ^6.3.0 + easy_debounce: ^2.0.3 + lazy_load_scrollview: ^1.3.0 + badges: ^3.1.2 + google_fonts: ^6.2.1 + location: ^7.0.0 + syncfusion_flutter_charts: ^26.2.8 + table_calendar: ^3.1.2 dev_dependencies: - dart_code_metrics: ^5.7.6 - dart_code_metrics_presets: ^1.8.0 build_runner: ^2.4.11 freezed: ^2.5.2 json_serializable: ^6.8.0 - retrofit_generator: ^8.1.0 + retrofit_generator: ^8.1.1 flutter_test: sdk: flutter @@ -61,18 +61,4 @@ flutter: uses-material-design: true assets: - assets/ - - assets/images/ - - .env - fonts: - - family: Segoe UI - fonts: - - asset: assets/fonts/SegoeUISemibold.ttf - weight: 600 - - family: Mulish - fonts: - - asset: assets/fonts/MulishBold.ttf - weight: 700 - - asset: assets/fonts/MulishRegular.ttf - weight: 400 - - asset: assets/fonts/MulishSemiBold.ttf - weight: 600 \ No newline at end of file + - assets/images/ \ No newline at end of file diff --git a/test/add_info_test.dart b/test/add_info_test.dart deleted file mode 100644 index a4d576d..0000000 --- a/test/add_info_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/additional_information_screen/additional_information_screen.dart'; -import 'package:eatvio_app/presentation/registration/additional_information_screen/bloc/additional_information_bloc.dart'; -import 'package:eatvio_app/presentation/registration/additional_information_screen/models/additional_information_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = AdditionalInformationBloc(AdditionalInformationState( - additionalInformationModelObj: AdditionalInformationModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: AdditionalInformationScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/allergies_test.dart b/test/allergies_test.dart deleted file mode 100644 index d020b5f..0000000 --- a/test/allergies_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/allergies_screen/allergies_screen.dart'; -import 'package:eatvio_app/presentation/registration/allergies_screen/bloc/allergies_bloc.dart'; -import 'package:eatvio_app/presentation/registration/allergies_screen/models/allergies_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = AllergiesBloc(AllergiesState( - allergiesModelObj: AllergiesModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: AllergiesScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/auth_test.dart b/test/auth_test.dart index 22de3a0..e131dc8 100644 --- a/test/auth_test.dart +++ b/test/auth_test.dart @@ -2,13 +2,10 @@ import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:bloc_test/bloc_test.dart'; import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; import 'package:eatvio_app/presentation/auth/auth_screen/bloc/auth_bloc.dart'; import 'package:eatvio_app/presentation/auth/auth_screen/models/auth_model.dart'; -class MockAuthBloc extends MockBloc implements AuthBloc {} - void main() { group('AuthScreen', () { testWidgets('renders AuthScreen with initial state', diff --git a/test/blood_pressure_test.dart b/test/blood_pressure_test.dart deleted file mode 100644 index 1469343..0000000 --- a/test/blood_pressure_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/blood_pressure_screen/blood_pressure_screen.dart'; -import 'package:eatvio_app/presentation/registration/blood_pressure_screen/bloc/blood_pressure_bloc.dart'; -import 'package:eatvio_app/presentation/registration/blood_pressure_screen/models/blood_pressure_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = BloodPressureBloc(BloodPressureState( - bloodPressureModelObj: BloodPressureModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: BloodPressureScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/body_circumferences_test.dart b/test/body_circumferences_test.dart deleted file mode 100644 index e727e21..0000000 --- a/test/body_circumferences_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/body_circumferences_screen/body_circumferences_screen.dart'; -import 'package:eatvio_app/presentation/registration/body_circumferences_screen/bloc/body_circumferences_bloc.dart'; -import 'package:eatvio_app/presentation/registration/body_circumferences_screen/models/body_circumferences_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = BodyCircumferencesBloc(BodyCircumferencesState( - bodyCircumferencesModelObj: BodyCircumferencesModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: BodyCircumferencesScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/city_of_living_test.dart b/test/city_of_living_test.dart deleted file mode 100644 index d198eb2..0000000 --- a/test/city_of_living_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/city_of_living_screen/city_of_living_screen.dart'; -import 'package:eatvio_app/presentation/registration/city_of_living_screen/bloc/city_of_living_bloc.dart'; -import 'package:eatvio_app/presentation/registration/city_of_living_screen/models/city_of_living_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = CityOfLivingBloc(CityOfLivingState( - cityOfLivingModelObj: CityOfLivingModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: CityOfLivingScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/credentials_test.dart b/test/credentials_test.dart deleted file mode 100644 index 851a7df..0000000 --- a/test/credentials_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/credentials_screen/credentials_screen.dart'; -import 'package:eatvio_app/presentation/registration/credentials_screen/bloc/credentials_bloc.dart'; -import 'package:eatvio_app/presentation/registration/credentials_screen/models/credentials_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = CredentialsBloc(CredentialsState( - credentialsModelObj: CredentialsModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: CredentialsScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/date_of_birth_test.dart b/test/date_of_birth_test.dart deleted file mode 100644 index 4d79b57..0000000 --- a/test/date_of_birth_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/date_of_birth_screen/date_of_birth_screen.dart'; -import 'package:eatvio_app/presentation/registration/date_of_birth_screen/bloc/date_of_birth_bloc.dart'; -import 'package:eatvio_app/presentation/registration/date_of_birth_screen/models/date_of_birth_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = DateOfBirthBloc(DateOfBirthState( - dateOfBirthModelObj: DateOfBirthModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: DateOfBirthScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/diary_test.dart b/test/diary_test.dart deleted file mode 100644 index c7570d3..0000000 --- a/test/diary_test.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/diary_edit_screen.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart'; -import 'package:eatvio_app/presentation/diary/diary_edit_screen/models/diary_edit_model.dart'; - -void main() { - group('DiaryEditScreen', () { - /*testWidgets('renders CircularProgressIndicator when in initial state', - (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: DiaryEditScreen(), - ), - ); - });*/ - - testWidgets('renders _buildDiaryEditScreen when in loaded state', (WidgetTester tester) async { - final diaryEditBloc = DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel())); - final loadedState = DiaryEditLoadedState( - diaryId: 1, - selectedSatiety: 4, - autocompleteList: [], - photos: [], - portions: [], - wakeupExpanded: false, - moderationExpanded: false, - recommendedChartValues: [10, 10, 10, 10], - consumedChartValues: [1, 2, 3, 4], - moodExpanded: false); - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: diaryEditBloc, - child: DiaryEditScreen(), - ), - ), - ); - - diaryEditBloc.emit(loadedState); - await tester.pump(); - - //expect(find.byType(_buildDiaryEditScreen), findsOneWidget); - }); - - /*testWidgets('renders error message when in error state', - (WidgetTester tester) async { - final diaryEditBloc = - DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel())); - final errorState = DiaryEditErrorState("error"); - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: diaryEditBloc, - child: DiaryEditScreen(), - ), - ), - ); - - diaryEditBloc.emit(errorState); - await tester.pump(); - - expect(find.text('Ошибка'), findsOneWidget); - });*/ - - // Add more tests for other scenarios if needed - }); -} diff --git a/test/favorite_foods_test.dart b/test/favorite_foods_test.dart deleted file mode 100644 index 2fbd838..0000000 --- a/test/favorite_foods_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/favorite_foods_screen/favorite_foods_screen.dart'; -import 'package:eatvio_app/presentation/registration/favorite_foods_screen/bloc/favorite_foods_bloc.dart'; -import 'package:eatvio_app/presentation/registration/favorite_foods_screen/models/favorite_foods_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = FavoriteFoodsBloc(FavoriteFoodsState( - favoriteFoodsModelObj: FavoriteFoodsModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: FavoriteFoodsScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/favorite_sports_test.dart b/test/favorite_sports_test.dart deleted file mode 100644 index ed7ff4c..0000000 --- a/test/favorite_sports_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/favorite_sports_screen/favorite_sports_screen.dart'; -import 'package:eatvio_app/presentation/registration/favorite_sports_screen/bloc/favorite_sports_bloc.dart'; -import 'package:eatvio_app/presentation/registration/favorite_sports_screen/models/favorite_sports_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = FavoriteSportsBloc(FavoriteSportsState( - favoriteSportsModelObj: FavoriteSportsModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteSports", - unfavoriteFoods: "unfavoriteSports", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: FavoriteSportsScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/gender_test.dart b/test/gender_test.dart deleted file mode 100644 index e05ba6f..0000000 --- a/test/gender_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/gender_screen/gender_screen.dart'; -import 'package:eatvio_app/presentation/registration/gender_screen/bloc/gender_bloc.dart'; -import 'package:eatvio_app/presentation/registration/gender_screen/models/gender_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = GenderBloc(GenderState( - genderModelObj: GenderModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteSports", - unfavoriteFoods: "unfavoriteSports", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: GenderScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/height_test.dart b/test/height_test.dart deleted file mode 100644 index 9338fa7..0000000 --- a/test/height_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/height_screen/height_screen.dart'; -import 'package:eatvio_app/presentation/registration/height_screen/bloc/height_bloc.dart'; -import 'package:eatvio_app/presentation/registration/height_screen/models/height_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = HeightBloc(HeightState( - heightModelObj: HeightModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - height: "height", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - gender: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteSports", - unfavoriteFoods: "unfavoriteSports", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: HeightScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/language_select_test.dart b/test/language_select_test.dart deleted file mode 100644 index 447592f..0000000 --- a/test/language_select_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/language_select_screen/language_select_screen.dart'; -import 'package:eatvio_app/presentation/registration/language_select_screen/bloc/language_select_bloc.dart'; -import 'package:eatvio_app/presentation/registration/language_select_screen/models/language_select_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = LanguageSelectBloc(LanguageSelectState( - languageSelectModelObj: - LanguageSelectModel())); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: LanguageSelectScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/launch_test.dart b/test/launch_test.dart deleted file mode 100644 index 4f1eafe..0000000 --- a/test/launch_test.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/main.dart' as app; - -void main() { - testWidgets('Smoke test', (WidgetTester tester) async { - // Запустить приложение - app.main(); - - // Подождать, пока приложение загрузится - await tester.pumpAndSettle(); - - // Проверить, что нет ошибок - expect(tester.takeException(), isNull); - }); -} diff --git a/test/medicine_intake_test.dart b/test/medicine_intake_test.dart deleted file mode 100644 index fd92e71..0000000 --- a/test/medicine_intake_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/medicine_intake_screen/medicine_intake_screen.dart'; -import 'package:eatvio_app/presentation/registration/medicine_intake_screen/bloc/medicine_intake_bloc.dart'; -import 'package:eatvio_app/presentation/registration/medicine_intake_screen/models/medicine_intake_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = MedicineIntakeBloc(MedicineIntakeState( - medicineIntakeModelObj: MedicineIntakeModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: MedicineIntakeScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/name_test.dart b/test/name_test.dart deleted file mode 100644 index 408a01c..0000000 --- a/test/name_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/name_screen/name_screen.dart'; -import 'package:eatvio_app/presentation/registration/name_screen/bloc/name_bloc.dart'; -import 'package:eatvio_app/presentation/registration/name_screen/models/name_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = NameBloc(NameState( - nameModelObj: NameModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: NameScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file diff --git a/test/profile_test.dart b/test/profile_test.dart deleted file mode 100644 index 20f3f34..0000000 --- a/test/profile_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/my_profile_screen.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart'; - -void main() { - group('MyProfileScreen', () { - testWidgets('renders CircularProgressIndicator in initial state', - (WidgetTester tester) async { - final myProfileBloc = MyProfileBloc(MyProfileState( - myProfileModelObj: - MyProfileModel())); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: MyProfileScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/settings_test.dart b/test/settings_test.dart deleted file mode 100644 index b866ba4..0000000 --- a/test/settings_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/my_settings_screen.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/bloc/my_profile_bloc.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/models/my_profile_model.dart'; - -void main() { - group('MyProfileScreen', () { - testWidgets('renders CircularProgressIndicator in initial state', - (WidgetTester tester) async { - final myProfileBloc = MyProfileBloc(MyProfileState( - myProfileModelObj: - MyProfileModel())); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: MySettingsScreen(), - ), - ), - ); - }); - }); -} diff --git a/test/weight_test.dart b/test/weight_test.dart deleted file mode 100644 index adf8f8f..0000000 --- a/test/weight_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:eatvio_app/data/models/userRegistrationModel/user_registration_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:eatvio_app/presentation/registration/weight_screen/weight_screen.dart'; -import 'package:eatvio_app/presentation/registration/weight_screen/bloc/weight_bloc.dart'; -import 'package:eatvio_app/presentation/registration/weight_screen/models/weight_model.dart'; - -void main() { - group('AdditionalInfoScreen', () { - testWidgets('renders screen in initial state', (WidgetTester tester) async { - final myProfileBloc = WeightBloc(WeightState( - weightModelObj: WeightModel( - userRegistrationSheet: UserRegistrationSheet( - name: "name", - firstName: "firstName", - lastName: "lastName", - email: "email", - password: "password", - passwordConfirmation: "passwordConfirmation", - termsAccepted: "termsAccepted", - birthdate: "birthdate", - gender: "gender", - country: "country", - city: "city", - lang: "lang", - weight: "weight", - height: "height", - chestCircumference: 'asdasd', - waistCircumference: "waistCircumference", - hipCircumference: "hipCircumference", - bloodPressureUp: "bloodPressureUp", - bloodPressureDown: "bloodPressureDown", - hasHypo: "hasHypo", - hasHyper: "hasHyper", - aboutAllergy: "aboutAllergy", - aboutTakingPils: "aboutTakingPils", - aboutSportHobbies: "aboutSportHobbies", - favoriteFoods: "favoriteFoods", - unfavoriteFoods: "unfavoriteFoods", - additionalInfo: - "additionalInfo")))); // Ensure that MyProfileModel is non-nullable - - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: myProfileBloc, - child: WeightScreen(), - ), - ), - ); - }); - }); -} -//sports \ No newline at end of file