├── .gitignore
├── .metadata
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── recipes
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── settings_aar.gradle
├── build-old.yaml
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── config
│ └── constants.dart
├── main.dart
├── models
│ ├── categories
│ │ ├── categories.dart
│ │ ├── categories.g.dart
│ │ ├── category.dart
│ │ └── category.g.dart
│ ├── recipes
│ │ ├── recipe.dart
│ │ ├── recipe.g.dart
│ │ ├── recipes.dart
│ │ └── recipes.g.dart
│ └── server_error.dart
├── services
│ ├── hive.dart
│ └── network.dart
└── ui
│ ├── items
│ ├── category.dart
│ ├── recipe.dart
│ └── recipe_random.dart
│ └── screens
│ ├── category
│ ├── bloc
│ │ ├── bloc.dart
│ │ ├── bloc.freezed.dart
│ │ ├── events.dart
│ │ └── states.dart
│ └── category.dart
│ ├── favorite
│ └── favorite.dart
│ ├── home
│ ├── bloc
│ │ ├── bloc.dart
│ │ ├── bloc.freezed.dart
│ │ ├── events.dart
│ │ └── states.dart
│ └── home.dart
│ ├── recipe
│ ├── bloc
│ │ ├── bloc.dart
│ │ ├── bloc.freezed.dart
│ │ ├── events.dart
│ │ └── states.dart
│ └── recipe.dart
│ ├── search
│ ├── bloc
│ │ ├── bloc.dart
│ │ ├── bloc.freezed.dart
│ │ ├── events.dart
│ │ └── states.dart
│ └── search.dart
│ └── video.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshot
├── 0.jpg
├── 1.jpg
└── 2.jpg
├── test
└── widget_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
└── Icon-512.png
├── index.html
└── manifest.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Exceptions to above rules.
44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
45 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: e606910f28be51c8151f6169072afe3b3a8b3c5e
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Recipes
2 |
3 |
4 |
5 |
6 |
7 | ## 🔌 Plugins
8 | | Name |
9 | |------|
10 | |[**Dio**](https://pub.dev/packages/dio)
11 | |[**Freezed**](https://pub.dev/packages/freezed)
12 | |[**Google_fonts**](https://pub.dev/packages/google_fonts)
13 | |[**Flutter_bloc**](https://pub.dev/packages/flutter_bloc)
14 | |[**Cached_network_image**](https://pub.dev/packages/cached_network_image)
15 | |[**Dartz**](https://pub.dev/packages/dartz)
16 | |[**Json_serializable**](https://pub.dev/packages/json_serializable)
17 | |[**Youtube_player_flutter**](https://pub.dev/packages/youtube_player_flutter)
18 | |[**Hive**](https://pub.dev/packages/hive)
19 |
20 | ---
21 |
22 | #### Developer [Abdelouahed Medjoudja](https://www.facebook.com/AbdelouahedMedjoudja)
23 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.example.recipes"
42 | minSdkVersion 17
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | }
47 |
48 | buildTypes {
49 | release {
50 | // TODO: Add your own signing config for the release build.
51 | // Signing with the debug keys for now, so `flutter run --release` works.
52 | signingConfig signingConfigs.debug
53 | }
54 | }
55 | }
56 |
57 | flutter {
58 | source '../..'
59 | }
60 |
61 | dependencies {
62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
63 | }
64 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
13 |
20 |
24 |
28 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/recipes/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.recipes
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/build-old.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | json_serializable:
5 | options:
6 | # Options configure how source code is generated for every
7 | # `@JsonSerializable`-annotated class in the package.
8 | #
9 | # The default value for each is listed.
10 | any_map: false
11 | checked: false
12 | create_factory: true
13 | create_to_json: true
14 | disallow_unrecognized_keys: false
15 | explicit_to_json: true
16 | field_rename: none
17 | generic_argument_factories: false
18 | ignore_unannotated: false
19 | include_if_null: true
20 | nullable: true
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1020;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | );
177 | inputPaths = (
178 | );
179 | name = "Thin Binary";
180 | outputPaths = (
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | shellPath = /bin/sh;
184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
185 | };
186 | 9740EEB61CF901F6004384FC /* Run Script */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | inputPaths = (
192 | );
193 | name = "Run Script";
194 | outputPaths = (
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | shellPath = /bin/sh;
198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
199 | };
200 | /* End PBXShellScriptBuildPhase section */
201 |
202 | /* Begin PBXSourcesBuildPhase section */
203 | 97C146EA1CF9000F007C117D /* Sources */ = {
204 | isa = PBXSourcesBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | };
212 | /* End PBXSourcesBuildPhase section */
213 |
214 | /* Begin PBXVariantGroup section */
215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
216 | isa = PBXVariantGroup;
217 | children = (
218 | 97C146FB1CF9000F007C117D /* Base */,
219 | );
220 | name = Main.storyboard;
221 | sourceTree = "";
222 | };
223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
224 | isa = PBXVariantGroup;
225 | children = (
226 | 97C147001CF9000F007C117D /* Base */,
227 | );
228 | name = LaunchScreen.storyboard;
229 | sourceTree = "";
230 | };
231 | /* End PBXVariantGroup section */
232 |
233 | /* Begin XCBuildConfiguration section */
234 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_ANALYZER_NONNULL = YES;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
244 | CLANG_WARN_BOOL_CONVERSION = YES;
245 | CLANG_WARN_COMMA = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
249 | CLANG_WARN_EMPTY_BODY = YES;
250 | CLANG_WARN_ENUM_CONVERSION = YES;
251 | CLANG_WARN_INFINITE_RECURSION = YES;
252 | CLANG_WARN_INT_CONVERSION = YES;
253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
258 | CLANG_WARN_STRICT_PROTOTYPES = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNREACHABLE_CODE = YES;
261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu99;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | SDKROOT = iphoneos;
278 | SUPPORTED_PLATFORMS = iphoneos;
279 | TARGETED_DEVICE_FAMILY = "1,2";
280 | VALIDATE_PRODUCT = YES;
281 | };
282 | name = Profile;
283 | };
284 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
285 | isa = XCBuildConfiguration;
286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | CLANG_ENABLE_MODULES = YES;
290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
291 | ENABLE_BITCODE = NO;
292 | FRAMEWORK_SEARCH_PATHS = (
293 | "$(inherited)",
294 | "$(PROJECT_DIR)/Flutter",
295 | );
296 | INFOPLIST_FILE = Runner/Info.plist;
297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
298 | LIBRARY_SEARCH_PATHS = (
299 | "$(inherited)",
300 | "$(PROJECT_DIR)/Flutter",
301 | );
302 | PRODUCT_BUNDLE_IDENTIFIER = com.example.recipes;
303 | PRODUCT_NAME = "$(TARGET_NAME)";
304 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
305 | SWIFT_VERSION = 5.0;
306 | VERSIONING_SYSTEM = "apple-generic";
307 | };
308 | name = Profile;
309 | };
310 | 97C147031CF9000F007C117D /* Debug */ = {
311 | isa = XCBuildConfiguration;
312 | buildSettings = {
313 | ALWAYS_SEARCH_USER_PATHS = NO;
314 | CLANG_ANALYZER_NONNULL = YES;
315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
316 | CLANG_CXX_LIBRARY = "libc++";
317 | CLANG_ENABLE_MODULES = YES;
318 | CLANG_ENABLE_OBJC_ARC = YES;
319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
320 | CLANG_WARN_BOOL_CONVERSION = YES;
321 | CLANG_WARN_COMMA = YES;
322 | CLANG_WARN_CONSTANT_CONVERSION = YES;
323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
325 | CLANG_WARN_EMPTY_BODY = YES;
326 | CLANG_WARN_ENUM_CONVERSION = YES;
327 | CLANG_WARN_INFINITE_RECURSION = YES;
328 | CLANG_WARN_INT_CONVERSION = YES;
329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
334 | CLANG_WARN_STRICT_PROTOTYPES = YES;
335 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
336 | CLANG_WARN_UNREACHABLE_CODE = YES;
337 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
339 | COPY_PHASE_STRIP = NO;
340 | DEBUG_INFORMATION_FORMAT = dwarf;
341 | ENABLE_STRICT_OBJC_MSGSEND = YES;
342 | ENABLE_TESTABILITY = YES;
343 | GCC_C_LANGUAGE_STANDARD = gnu99;
344 | GCC_DYNAMIC_NO_PIC = NO;
345 | GCC_NO_COMMON_BLOCKS = YES;
346 | GCC_OPTIMIZATION_LEVEL = 0;
347 | GCC_PREPROCESSOR_DEFINITIONS = (
348 | "DEBUG=1",
349 | "$(inherited)",
350 | );
351 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
352 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
353 | GCC_WARN_UNDECLARED_SELECTOR = YES;
354 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
355 | GCC_WARN_UNUSED_FUNCTION = YES;
356 | GCC_WARN_UNUSED_VARIABLE = YES;
357 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
358 | MTL_ENABLE_DEBUG_INFO = YES;
359 | ONLY_ACTIVE_ARCH = YES;
360 | SDKROOT = iphoneos;
361 | TARGETED_DEVICE_FAMILY = "1,2";
362 | };
363 | name = Debug;
364 | };
365 | 97C147041CF9000F007C117D /* Release */ = {
366 | isa = XCBuildConfiguration;
367 | buildSettings = {
368 | ALWAYS_SEARCH_USER_PATHS = NO;
369 | CLANG_ANALYZER_NONNULL = YES;
370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
371 | CLANG_CXX_LIBRARY = "libc++";
372 | CLANG_ENABLE_MODULES = YES;
373 | CLANG_ENABLE_OBJC_ARC = YES;
374 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
375 | CLANG_WARN_BOOL_CONVERSION = YES;
376 | CLANG_WARN_COMMA = YES;
377 | CLANG_WARN_CONSTANT_CONVERSION = YES;
378 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
379 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
380 | CLANG_WARN_EMPTY_BODY = YES;
381 | CLANG_WARN_ENUM_CONVERSION = YES;
382 | CLANG_WARN_INFINITE_RECURSION = YES;
383 | CLANG_WARN_INT_CONVERSION = YES;
384 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
385 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
386 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
387 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
388 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
389 | CLANG_WARN_STRICT_PROTOTYPES = YES;
390 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
391 | CLANG_WARN_UNREACHABLE_CODE = YES;
392 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
393 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
394 | COPY_PHASE_STRIP = NO;
395 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
396 | ENABLE_NS_ASSERTIONS = NO;
397 | ENABLE_STRICT_OBJC_MSGSEND = YES;
398 | GCC_C_LANGUAGE_STANDARD = gnu99;
399 | GCC_NO_COMMON_BLOCKS = YES;
400 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
401 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
402 | GCC_WARN_UNDECLARED_SELECTOR = YES;
403 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
404 | GCC_WARN_UNUSED_FUNCTION = YES;
405 | GCC_WARN_UNUSED_VARIABLE = YES;
406 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
407 | MTL_ENABLE_DEBUG_INFO = NO;
408 | SDKROOT = iphoneos;
409 | SUPPORTED_PLATFORMS = iphoneos;
410 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
411 | TARGETED_DEVICE_FAMILY = "1,2";
412 | VALIDATE_PRODUCT = YES;
413 | };
414 | name = Release;
415 | };
416 | 97C147061CF9000F007C117D /* Debug */ = {
417 | isa = XCBuildConfiguration;
418 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
419 | buildSettings = {
420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
421 | CLANG_ENABLE_MODULES = YES;
422 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
423 | ENABLE_BITCODE = NO;
424 | FRAMEWORK_SEARCH_PATHS = (
425 | "$(inherited)",
426 | "$(PROJECT_DIR)/Flutter",
427 | );
428 | INFOPLIST_FILE = Runner/Info.plist;
429 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
430 | LIBRARY_SEARCH_PATHS = (
431 | "$(inherited)",
432 | "$(PROJECT_DIR)/Flutter",
433 | );
434 | PRODUCT_BUNDLE_IDENTIFIER = com.example.recipes;
435 | PRODUCT_NAME = "$(TARGET_NAME)";
436 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
437 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
438 | SWIFT_VERSION = 5.0;
439 | VERSIONING_SYSTEM = "apple-generic";
440 | };
441 | name = Debug;
442 | };
443 | 97C147071CF9000F007C117D /* Release */ = {
444 | isa = XCBuildConfiguration;
445 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
446 | buildSettings = {
447 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
448 | CLANG_ENABLE_MODULES = YES;
449 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
450 | ENABLE_BITCODE = NO;
451 | FRAMEWORK_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "$(PROJECT_DIR)/Flutter",
454 | );
455 | INFOPLIST_FILE = Runner/Info.plist;
456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
457 | LIBRARY_SEARCH_PATHS = (
458 | "$(inherited)",
459 | "$(PROJECT_DIR)/Flutter",
460 | );
461 | PRODUCT_BUNDLE_IDENTIFIER = com.example.recipes;
462 | PRODUCT_NAME = "$(TARGET_NAME)";
463 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
464 | SWIFT_VERSION = 5.0;
465 | VERSIONING_SYSTEM = "apple-generic";
466 | };
467 | name = Release;
468 | };
469 | /* End XCBuildConfiguration section */
470 |
471 | /* Begin XCConfigurationList section */
472 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
473 | isa = XCConfigurationList;
474 | buildConfigurations = (
475 | 97C147031CF9000F007C117D /* Debug */,
476 | 97C147041CF9000F007C117D /* Release */,
477 | 249021D3217E4FDB00AE95B9 /* Profile */,
478 | );
479 | defaultConfigurationIsVisible = 0;
480 | defaultConfigurationName = Release;
481 | };
482 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
483 | isa = XCConfigurationList;
484 | buildConfigurations = (
485 | 97C147061CF9000F007C117D /* Debug */,
486 | 97C147071CF9000F007C117D /* Release */,
487 | 249021D4217E4FDB00AE95B9 /* Profile */,
488 | );
489 | defaultConfigurationIsVisible = 0;
490 | defaultConfigurationName = Release;
491 | };
492 | /* End XCConfigurationList section */
493 | };
494 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
495 | }
496 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | io.flutter.embedded_views_preview
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | recipes
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/config/constants.dart:
--------------------------------------------------------------------------------
1 | class AppConstants {
2 | AppConstants._();
3 |
4 | static const String HOST = 'https://www.themealdb.com/';
5 | static const String API = '${HOST}api/json/v1/1/';
6 | }
7 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 | import 'package:recipes/services/hive.dart';
4 | import 'package:recipes/ui/screens/home/home.dart';
5 |
6 | import 'services/network.dart';
7 |
8 | void main() async {
9 | WidgetsFlutterBinding.ensureInitialized();
10 | await AppHive.instance.init();
11 | runApp(MyApp());
12 | }
13 |
14 | class MyApp extends StatefulWidget {
15 | @override
16 | State createState() => _MyAppState();
17 | }
18 |
19 | class _MyAppState extends State {
20 | @override
21 | Widget build(BuildContext context) => MaterialApp(
22 | title: 'Flutter Recipes',
23 | debugShowCheckedModeBanner: false,
24 | theme: ThemeData(
25 | primarySwatch: Colors.red,
26 | scaffoldBackgroundColor: Colors.grey[200],
27 | visualDensity: VisualDensity.adaptivePlatformDensity,
28 | appBarTheme: AppBarTheme(
29 | textTheme: GoogleFonts.latoTextTheme(
30 | Theme.of(context).textTheme,
31 | ).apply(bodyColor: Colors.white),
32 | ),
33 | textTheme: GoogleFonts.latoTextTheme(
34 | Theme.of(context).textTheme,
35 | ),
36 | ),
37 | home: HomeScreen(),
38 | );
39 |
40 | @override
41 | void dispose() {
42 | AppNetwork.instance.close();
43 | AppHive.instance.close();
44 | super.dispose();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/models/categories/categories.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | import 'category.dart';
4 |
5 | part 'categories.g.dart';
6 |
7 | @JsonSerializable(explicitToJson: true)
8 | class Categories {
9 | @JsonKey(name: 'categories')
10 | final List items;
11 |
12 | Categories({this.items});
13 |
14 | factory Categories.fromJson(Map json) =>
15 | _$CategoriesFromJson(json);
16 |
17 | Map toJson() => _$CategoriesToJson(this);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/models/categories/categories.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'categories.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Categories _$CategoriesFromJson(Map json) {
10 | return Categories(
11 | items: (json['categories'] as List)
12 | ?.map((e) =>
13 | e == null ? null : Category.fromJson(e as Map))
14 | ?.toList(),
15 | );
16 | }
17 |
18 | Map _$CategoriesToJson(Categories instance) =>
19 | {
20 | 'categories': instance.items?.map((e) => e?.toJson())?.toList(),
21 | };
22 |
--------------------------------------------------------------------------------
/lib/models/categories/category.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | part 'category.g.dart';
4 |
5 | @JsonSerializable()
6 | class Category {
7 | @JsonKey(name: 'idCategory')
8 | final id;
9 | @JsonKey(name: 'strCategory')
10 | final name;
11 | @JsonKey(name: 'strCategoryThumb')
12 | final image;
13 | @JsonKey(name: 'strCategoryDescription')
14 | final description;
15 |
16 | Category({this.id, this.name, this.image, this.description});
17 |
18 | factory Category.fromJson(Map json) =>
19 | _$CategoryFromJson(json);
20 |
21 | Map toJson() => _$CategoryToJson(this);
22 | }
23 |
--------------------------------------------------------------------------------
/lib/models/categories/category.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'category.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Category _$CategoryFromJson(Map json) {
10 | return Category(
11 | id: json['idCategory'],
12 | name: json['strCategory'],
13 | image: json['strCategoryThumb'],
14 | description: json['strCategoryDescription'],
15 | );
16 | }
17 |
18 | Map _$CategoryToJson(Category instance) => {
19 | 'idCategory': instance.id,
20 | 'strCategory': instance.name,
21 | 'strCategoryThumb': instance.image,
22 | 'strCategoryDescription': instance.description,
23 | };
24 |
--------------------------------------------------------------------------------
/lib/models/recipes/recipe.dart:
--------------------------------------------------------------------------------
1 | import 'package:hive/hive.dart';
2 | import 'package:json_annotation/json_annotation.dart';
3 |
4 | part 'recipe.g.dart';
5 |
6 | @HiveType()
7 | @JsonSerializable(nullable: false)
8 | class Recipe {
9 | @HiveField(0)
10 | @JsonKey(name: 'idMeal')
11 | final id;
12 | @HiveField(1)
13 | @JsonKey(name: 'strMeal')
14 | final title;
15 | @JsonKey(name: 'strInstructions')
16 | final instructions;
17 | @HiveField(2)
18 | @JsonKey(name: 'strMealThumb')
19 | final image;
20 | @JsonKey(name: 'strTags')
21 | final tags;
22 | @JsonKey(name: 'strYoutube')
23 | final video;
24 | @JsonKey(name: 'strCategory')
25 | final category;
26 | @JsonKey(name: 'strIngredient1')
27 | final ingredient1;
28 | @JsonKey(name: 'strIngredient2')
29 | final ingredient2;
30 | @JsonKey(name: 'strIngredient3')
31 | final ingredient3;
32 | @JsonKey(name: 'strIngredient4')
33 | final ingredient4;
34 | @JsonKey(name: 'strIngredient5')
35 | final ingredient5;
36 | @JsonKey(name: 'strIngredient6')
37 | final ingredient6;
38 | @JsonKey(name: 'strIngredient7')
39 | final ingredient7;
40 | @JsonKey(name: 'strIngredient8')
41 | final ingredient8;
42 | @JsonKey(name: 'strIngredient9')
43 | final ingredient9;
44 | @JsonKey(name: 'strIngredient10')
45 | final ingredient10;
46 | @JsonKey(name: 'strIngredient11')
47 | final ingredient11;
48 | @JsonKey(name: 'strIngredient12')
49 | final ingredient12;
50 | @JsonKey(name: 'strIngredient13')
51 | final ingredient13;
52 | @JsonKey(name: 'strIngredient14')
53 | final ingredient14;
54 | @JsonKey(name: 'strIngredient15')
55 | final ingredient15;
56 | @JsonKey(name: 'strIngredient16')
57 | final ingredient16;
58 | @JsonKey(name: 'strIngredient17')
59 | final ingredient17;
60 | @JsonKey(name: 'strIngredient18')
61 | final ingredient18;
62 | @JsonKey(name: 'strIngredient19')
63 | final ingredient19;
64 | @JsonKey(name: 'strIngredient20')
65 | final ingredient20;
66 | @JsonKey(name: 'strMeasure1')
67 | final measure1;
68 | @JsonKey(name: 'strMeasure2')
69 | final measure2;
70 | @JsonKey(name: 'strMeasure3')
71 | final measure3;
72 | @JsonKey(name: 'strMeasure4')
73 | final measure4;
74 | @JsonKey(name: 'strMeasure5')
75 | final measure5;
76 | @JsonKey(name: 'strMeasure6')
77 | final measure6;
78 | @JsonKey(name: 'strMeasure7')
79 | final measure7;
80 | @JsonKey(name: 'strMeasure8')
81 | final measure8;
82 | @JsonKey(name: 'strMeasure9')
83 | final measure9;
84 | @JsonKey(name: 'strMeasure10')
85 | final measure10;
86 | @JsonKey(name: 'strMeasure11')
87 | final measure11;
88 | @JsonKey(name: 'strMeasure12')
89 | final measure12;
90 | @JsonKey(name: 'strMeasure13')
91 | final measure13;
92 | @JsonKey(name: 'strMeasure14')
93 | final measure14;
94 | @JsonKey(name: 'strMeasure15')
95 | final measure15;
96 | @JsonKey(name: 'strMeasure16')
97 | final measure16;
98 | @JsonKey(name: 'strMeasure17')
99 | final measure17;
100 | @JsonKey(name: 'strMeasure18')
101 | final measure18;
102 | @JsonKey(name: 'strMeasure19')
103 | final measure19;
104 | @JsonKey(name: 'strMeasure20')
105 | final measure20;
106 |
107 | Recipe({
108 | this.id,
109 | this.title,
110 | this.instructions,
111 | this.image,
112 | this.tags,
113 | this.video,
114 | this.category,
115 | this.ingredient1,
116 | this.ingredient2,
117 | this.ingredient3,
118 | this.ingredient4,
119 | this.ingredient5,
120 | this.ingredient6,
121 | this.ingredient7,
122 | this.ingredient8,
123 | this.ingredient9,
124 | this.ingredient10,
125 | this.ingredient11,
126 | this.ingredient12,
127 | this.ingredient13,
128 | this.ingredient14,
129 | this.ingredient15,
130 | this.ingredient16,
131 | this.ingredient17,
132 | this.ingredient18,
133 | this.ingredient19,
134 | this.ingredient20,
135 | this.measure1,
136 | this.measure2,
137 | this.measure3,
138 | this.measure4,
139 | this.measure5,
140 | this.measure6,
141 | this.measure7,
142 | this.measure8,
143 | this.measure9,
144 | this.measure10,
145 | this.measure11,
146 | this.measure12,
147 | this.measure13,
148 | this.measure14,
149 | this.measure15,
150 | this.measure16,
151 | this.measure17,
152 | this.measure18,
153 | this.measure19,
154 | this.measure20,
155 | });
156 |
157 | factory Recipe.fromJson(Map json) => _$RecipeFromJson(json);
158 |
159 | Map toJson() => _$RecipeToJson(this);
160 | }
161 |
--------------------------------------------------------------------------------
/lib/models/recipes/recipe.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'recipe.dart';
4 |
5 | // **************************************************************************
6 | // TypeAdapterGenerator
7 | // **************************************************************************
8 |
9 | class RecipeAdapter extends TypeAdapter {
10 | @override
11 | Recipe read(BinaryReader reader) {
12 | var numOfFields = reader.readByte();
13 | var fields = {
14 | for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
15 | };
16 | return Recipe(
17 | id: fields[0] as dynamic,
18 | title: fields[1] as dynamic,
19 | image: fields[2] as dynamic,
20 | );
21 | }
22 |
23 | @override
24 | void write(BinaryWriter writer, Recipe obj) {
25 | writer
26 | ..writeByte(3)
27 | ..writeByte(0)
28 | ..write(obj.id)
29 | ..writeByte(1)
30 | ..write(obj.title)
31 | ..writeByte(2)
32 | ..write(obj.image);
33 | }
34 |
35 | @override
36 | int get typeId => 0;
37 | }
38 |
39 | // **************************************************************************
40 | // JsonSerializableGenerator
41 | // **************************************************************************
42 |
43 | Recipe _$RecipeFromJson(Map json) {
44 | return Recipe(
45 | id: json['idMeal'],
46 | title: json['strMeal'],
47 | instructions: json['strInstructions'],
48 | image: json['strMealThumb'],
49 | tags: json['strTags'],
50 | video: json['strYoutube'],
51 | category: json['strCategory'],
52 | ingredient1: json['strIngredient1'],
53 | ingredient2: json['strIngredient2'],
54 | ingredient3: json['strIngredient3'],
55 | ingredient4: json['strIngredient4'],
56 | ingredient5: json['strIngredient5'],
57 | ingredient6: json['strIngredient6'],
58 | ingredient7: json['strIngredient7'],
59 | ingredient8: json['strIngredient8'],
60 | ingredient9: json['strIngredient9'],
61 | ingredient10: json['strIngredient10'],
62 | ingredient11: json['strIngredient11'],
63 | ingredient12: json['strIngredient12'],
64 | ingredient13: json['strIngredient13'],
65 | ingredient14: json['strIngredient14'],
66 | ingredient15: json['strIngredient15'],
67 | ingredient16: json['strIngredient16'],
68 | ingredient17: json['strIngredient17'],
69 | ingredient18: json['strIngredient18'],
70 | ingredient19: json['strIngredient19'],
71 | ingredient20: json['strIngredient20'],
72 | measure1: json['strMeasure1'],
73 | measure2: json['strMeasure2'],
74 | measure3: json['strMeasure3'],
75 | measure4: json['strMeasure4'],
76 | measure5: json['strMeasure5'],
77 | measure6: json['strMeasure6'],
78 | measure7: json['strMeasure7'],
79 | measure8: json['strMeasure8'],
80 | measure9: json['strMeasure9'],
81 | measure10: json['strMeasure10'],
82 | measure11: json['strMeasure11'],
83 | measure12: json['strMeasure12'],
84 | measure13: json['strMeasure13'],
85 | measure14: json['strMeasure14'],
86 | measure15: json['strMeasure15'],
87 | measure16: json['strMeasure16'],
88 | measure17: json['strMeasure17'],
89 | measure18: json['strMeasure18'],
90 | measure19: json['strMeasure19'],
91 | measure20: json['strMeasure20'],
92 | );
93 | }
94 |
95 | Map _$RecipeToJson(Recipe instance) => {
96 | 'idMeal': instance.id,
97 | 'strMeal': instance.title,
98 | 'strInstructions': instance.instructions,
99 | 'strMealThumb': instance.image,
100 | 'strTags': instance.tags,
101 | 'strYoutube': instance.video,
102 | 'strCategory': instance.category,
103 | 'strIngredient1': instance.ingredient1,
104 | 'strIngredient2': instance.ingredient2,
105 | 'strIngredient3': instance.ingredient3,
106 | 'strIngredient4': instance.ingredient4,
107 | 'strIngredient5': instance.ingredient5,
108 | 'strIngredient6': instance.ingredient6,
109 | 'strIngredient7': instance.ingredient7,
110 | 'strIngredient8': instance.ingredient8,
111 | 'strIngredient9': instance.ingredient9,
112 | 'strIngredient10': instance.ingredient10,
113 | 'strIngredient11': instance.ingredient11,
114 | 'strIngredient12': instance.ingredient12,
115 | 'strIngredient13': instance.ingredient13,
116 | 'strIngredient14': instance.ingredient14,
117 | 'strIngredient15': instance.ingredient15,
118 | 'strIngredient16': instance.ingredient16,
119 | 'strIngredient17': instance.ingredient17,
120 | 'strIngredient18': instance.ingredient18,
121 | 'strIngredient19': instance.ingredient19,
122 | 'strIngredient20': instance.ingredient20,
123 | 'strMeasure1': instance.measure1,
124 | 'strMeasure2': instance.measure2,
125 | 'strMeasure3': instance.measure3,
126 | 'strMeasure4': instance.measure4,
127 | 'strMeasure5': instance.measure5,
128 | 'strMeasure6': instance.measure6,
129 | 'strMeasure7': instance.measure7,
130 | 'strMeasure8': instance.measure8,
131 | 'strMeasure9': instance.measure9,
132 | 'strMeasure10': instance.measure10,
133 | 'strMeasure11': instance.measure11,
134 | 'strMeasure12': instance.measure12,
135 | 'strMeasure13': instance.measure13,
136 | 'strMeasure14': instance.measure14,
137 | 'strMeasure15': instance.measure15,
138 | 'strMeasure16': instance.measure16,
139 | 'strMeasure17': instance.measure17,
140 | 'strMeasure18': instance.measure18,
141 | 'strMeasure19': instance.measure19,
142 | 'strMeasure20': instance.measure20,
143 | };
144 |
--------------------------------------------------------------------------------
/lib/models/recipes/recipes.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | import 'recipe.dart';
4 |
5 | part 'recipes.g.dart';
6 |
7 | @JsonSerializable(explicitToJson: true)
8 | class Recipes {
9 | @JsonKey(name: 'meals')
10 | final List items;
11 |
12 | Recipes({this.items});
13 |
14 | factory Recipes.fromJson(Map json) =>
15 | _$RecipesFromJson(json);
16 |
17 | Map toJson() => _$RecipesToJson(this);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/models/recipes/recipes.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'recipes.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Recipes _$RecipesFromJson(Map json) {
10 | return Recipes(
11 | items: (json['meals'] as List)
12 | ?.map((e) =>
13 | e == null ? null : Recipe.fromJson(e as Map))
14 | ?.toList(),
15 | );
16 | }
17 |
18 | Map _$RecipesToJson(Recipes instance) => {
19 | 'meals': instance.items?.map((e) => e?.toJson())?.toList(),
20 | };
21 |
--------------------------------------------------------------------------------
/lib/models/server_error.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | class ServerError {
4 | final String message;
5 |
6 | ServerError({@required this.message});
7 | }
8 |
--------------------------------------------------------------------------------
/lib/services/hive.dart:
--------------------------------------------------------------------------------
1 | import 'package:hive/hive.dart';
2 | import 'package:path_provider/path_provider.dart';
3 |
4 | import '../models/recipes/recipe.dart';
5 |
6 | class AppHive {
7 | static const KEY_NAME = 'recipes';
8 |
9 | AppHive._();
10 |
11 | static AppHive _instance;
12 |
13 | static AppHive get instance {
14 | if (_instance == null) _instance = AppHive._();
15 | return _instance;
16 | }
17 |
18 | Box _box;
19 |
20 | Future init() async {
21 | final appDocumentDir = await getApplicationDocumentsDirectory();
22 | Hive
23 | ..init(appDocumentDir.path)
24 | ..registerAdapter(RecipeAdapter());
25 | _box = await Hive.openBox(KEY_NAME);
26 | return Future.value();
27 | }
28 |
29 | Future insert(Recipe recipe) => _box.put(recipe.id, recipe);
30 |
31 | Future delete(Recipe recipe) => _box.delete(recipe.id);
32 |
33 | Box selectAll() => _box;
34 |
35 | bool isExist(id) => _box.containsKey(id);
36 |
37 | Future close() async {
38 | await _box.compact();
39 | return Hive.close();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/services/network.dart:
--------------------------------------------------------------------------------
1 | import 'package:dartz/dartz.dart';
2 | import 'package:dio/dio.dart';
3 |
4 | import '../models/server_error.dart';
5 | import '../config/constants.dart';
6 |
7 | class AppNetwork {
8 | final _dio = Dio(BaseOptions(baseUrl: AppConstants.API));
9 |
10 | AppNetwork._();
11 |
12 | static AppNetwork _instance;
13 |
14 | static AppNetwork get instance {
15 | if (_instance == null) _instance = AppNetwork._();
16 | return _instance;
17 | }
18 |
19 | Future> get(
20 | String path, {
21 | Map queries,
22 | }) async {
23 | try {
24 | Response response =
25 | await _dio.get(path, queryParameters: queries).catchError((error) {
26 | return left(ServerError(message: '$error'));
27 | });
28 |
29 | return right(response.data);
30 | } catch (e) {
31 | return left(ServerError(message: '$e'));
32 | }
33 | }
34 |
35 | void close() {
36 | _dio.close();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/ui/items/category.dart:
--------------------------------------------------------------------------------
1 | import 'package:cached_network_image/cached_network_image.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:recipes/models/categories/category.dart';
5 | import 'package:recipes/ui/screens/category/category.dart';
6 |
7 | class CategoryItem extends StatelessWidget {
8 | final Category category;
9 |
10 | void _onTap(BuildContext context) {
11 | Navigator.push(
12 | context,
13 | CupertinoPageRoute(
14 | builder: (_) => CategoryScreen(categoryName: category.name),
15 | ),
16 | );
17 | }
18 |
19 | const CategoryItem({Key key, @required this.category}) : super(key: key);
20 |
21 | @override
22 | Widget build(BuildContext context) => Card(
23 | clipBehavior: Clip.antiAlias,
24 | margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
25 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
26 | child: ListTile(
27 | title: Text(
28 | category.name,
29 | style: TextStyle(
30 | color: Colors.black87,
31 | fontWeight: FontWeight.bold,
32 | ),
33 | ),
34 | trailing: CachedNetworkImage(imageUrl: category.image),
35 | contentPadding: const EdgeInsets.symmetric(
36 | horizontal: 25,
37 | vertical: 15,
38 | ),
39 | onTap: () {
40 | _onTap(context);
41 | },
42 | ),
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/lib/ui/items/recipe.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:recipes/models/recipes/recipe.dart';
4 | import 'package:recipes/services/hive.dart';
5 | import 'package:recipes/ui/screens/recipe/recipe.dart';
6 |
7 | class RecipeItem extends StatefulWidget {
8 | final Recipe recipe;
9 |
10 | const RecipeItem({Key key, @required this.recipe}) : super(key: key);
11 |
12 | @override
13 | _RecipeItemState createState() => _RecipeItemState();
14 | }
15 |
16 | class _RecipeItemState extends State {
17 | bool _isFavorite = false;
18 |
19 | void _tapFavorite() {
20 | setState(() {
21 | _isFavorite = !_isFavorite;
22 | });
23 |
24 | if (_isFavorite)
25 | AppHive.instance.insert(widget.recipe);
26 | else
27 | AppHive.instance.delete(widget.recipe);
28 | }
29 |
30 | void _onTap() {
31 | Navigator.push(
32 | context,
33 | CupertinoPageRoute(
34 | builder: (_) => RecipeScreen(
35 | recipeId: widget.recipe.id,
36 | ),
37 | ),
38 | );
39 | }
40 |
41 | @override
42 | void initState() {
43 | super.initState();
44 |
45 | // check is favorite
46 | _isFavorite = AppHive.instance.isExist(widget.recipe.id);
47 | }
48 |
49 | @override
50 | Widget build(BuildContext context) => InkWell(
51 | onTap: _onTap,
52 | child: AspectRatio(
53 | aspectRatio: 1.5,
54 | child: Container(
55 | margin: const EdgeInsets.only(bottom: 5),
56 | decoration: BoxDecoration(
57 | image: DecorationImage(
58 | fit: BoxFit.cover,
59 | image: NetworkImage(
60 | widget.recipe.image,
61 | ),
62 | ),
63 | ),
64 | child: Container(
65 | color: Colors.black.withOpacity(.5),
66 | alignment: Alignment.bottomLeft,
67 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
68 | child: Row(
69 | children: [
70 | Expanded(
71 | child: Text(
72 | widget.recipe.title,
73 | maxLines: 1,
74 | overflow: TextOverflow.ellipsis,
75 | style: TextStyle(
76 | color: Colors.white,
77 | fontSize: 20,
78 | fontWeight: FontWeight.bold,
79 | ),
80 | ),
81 | ),
82 | IconButton(
83 | onPressed: _tapFavorite,
84 | color: Colors.white,
85 | icon: Icon(
86 | _isFavorite ? Icons.favorite : Icons.favorite_border,
87 | ),
88 | ),
89 | ],
90 | ),
91 | ),
92 | ),
93 | ),
94 | );
95 | }
96 |
--------------------------------------------------------------------------------
/lib/ui/items/recipe_random.dart:
--------------------------------------------------------------------------------
1 | import 'package:cached_network_image/cached_network_image.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:recipes/models/recipes/recipe.dart';
5 | import 'package:recipes/services/hive.dart';
6 | import 'package:recipes/ui/screens/recipe/recipe.dart';
7 |
8 | class RecipeRandomItem extends StatefulWidget {
9 | final Recipe recipe;
10 |
11 | const RecipeRandomItem({Key key, @required this.recipe}) : super(key: key);
12 |
13 | @override
14 | _RecipeRandomItemState createState() => _RecipeRandomItemState();
15 | }
16 |
17 | class _RecipeRandomItemState extends State {
18 | bool _isFavorite = false;
19 |
20 | void _tapFavorite() {
21 | setState(() {
22 | _isFavorite = !_isFavorite;
23 | });
24 |
25 | if (_isFavorite)
26 | AppHive.instance.insert(widget.recipe);
27 | else
28 | AppHive.instance.delete(widget.recipe);
29 | }
30 |
31 | void _onTap() {
32 | Navigator.push(
33 | context,
34 | CupertinoPageRoute(
35 | builder: (_) => RecipeScreen(
36 | recipeId: widget.recipe.id,
37 | ),
38 | ),
39 | );
40 | }
41 |
42 | @override
43 | void initState() {
44 | super.initState();
45 | // check is favorite
46 | _isFavorite = AppHive.instance.isExist(widget.recipe.id);
47 | }
48 |
49 | @override
50 | Widget build(BuildContext context) => InkWell(
51 | onTap: _onTap,
52 | child: Stack(
53 | children: [
54 | Positioned(
55 | top: 0,
56 | left: 0,
57 | right: 0,
58 | bottom: 15,
59 | child: ClipRRect(
60 | borderRadius: BorderRadius.circular(20),
61 | child: Stack(
62 | children: [
63 | SizedBox.expand(
64 | child: CachedNetworkImage(
65 | imageUrl: widget.recipe.image,
66 | fit: BoxFit.cover,
67 | ),
68 | ),
69 | Container(
70 | color: Colors.black.withOpacity(.25),
71 | ),
72 | Positioned(
73 | top: 0,
74 | left: 0,
75 | child: Container(
76 | padding: const EdgeInsets.symmetric(
77 | horizontal: 25,
78 | vertical: 10,
79 | ),
80 | decoration: BoxDecoration(
81 | color: Theme.of(context).accentColor,
82 | borderRadius: BorderRadius.only(
83 | bottomRight: Radius.circular(20),
84 | ),
85 | ),
86 | child: Text(
87 | widget.recipe.category ?? '',
88 | style: TextStyle(
89 | color: Colors.white,
90 | ),
91 | ),
92 | ),
93 | ),
94 | Positioned(
95 | top: 0,
96 | right: 0,
97 | child: IconButton(
98 | onPressed: _tapFavorite,
99 | color: Colors.white,
100 | icon: Icon(
101 | _isFavorite ? Icons.favorite : Icons.favorite_border,
102 | ),
103 | ),
104 | ),
105 | ],
106 | ),
107 | ),
108 | ),
109 | Positioned(
110 | bottom: 0,
111 | right: 20,
112 | left: 20,
113 | child: Container(
114 | alignment: Alignment.center,
115 | padding: const EdgeInsets.symmetric(
116 | horizontal: 20,
117 | vertical: 10,
118 | ),
119 | decoration: BoxDecoration(
120 | color: Colors.white,
121 | borderRadius: BorderRadius.circular(20),
122 | ),
123 | child: Text(
124 | widget.recipe.title,
125 | maxLines: 1,
126 | overflow: TextOverflow.ellipsis,
127 | style: TextStyle(
128 | color: Colors.black,
129 | fontSize: 18,
130 | fontWeight: FontWeight.bold,
131 | ),
132 | ),
133 | ),
134 | )
135 | ],
136 | ),
137 | );
138 | }
139 |
--------------------------------------------------------------------------------
/lib/ui/screens/category/bloc/bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 |
5 | import '../../../../models/recipes/recipes.dart';
6 | import '../../../../models/server_error.dart';
7 | import '../../../../services/network.dart';
8 |
9 | part 'bloc.freezed.dart';
10 |
11 | part 'events.dart';
12 |
13 | part 'states.dart';
14 |
15 | class CategoryBloc extends Bloc {
16 | final _appNetwork = AppNetwork.instance;
17 |
18 | @override
19 | CategoryState get initialState => CategoryState.initial();
20 |
21 | @override
22 | Stream mapEventToState(CategoryEvent event) async* {
23 | yield* event.when(getRecipes: _getRecipes);
24 | }
25 |
26 | Stream _getRecipes(String categoryName) async* {
27 | yield CategoryState.recipesLoading();
28 | final response = await _appNetwork.get('filter.php?c=$categoryName');
29 | yield* response.fold(
30 | (error) async* {
31 | yield CategoryState.recipesError(serverError: error);
32 | },
33 | (json) async* {
34 | yield CategoryState.recipesLoaded(recipes: Recipes.fromJson(json));
35 | },
36 | );
37 | }
38 |
39 | @override
40 | Future close() {
41 | return super.close();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/ui/screens/category/bloc/bloc.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: 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
3 |
4 | part of 'bloc.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 |
12 | class _$CategoryEventTearOff {
13 | const _$CategoryEventTearOff();
14 |
15 | // ignore: unused_element
16 | GetRecipes getRecipes({@required String categoryName}) {
17 | return GetRecipes(
18 | categoryName: categoryName,
19 | );
20 | }
21 | }
22 |
23 | // ignore: unused_element
24 | const $CategoryEvent = _$CategoryEventTearOff();
25 |
26 | mixin _$CategoryEvent {
27 | String get categoryName;
28 |
29 | @optionalTypeArgs
30 | Result when({
31 | @required Result getRecipes(String categoryName),
32 | });
33 | @optionalTypeArgs
34 | Result maybeWhen({
35 | Result getRecipes(String categoryName),
36 | @required Result orElse(),
37 | });
38 | @optionalTypeArgs
39 | Result map({
40 | @required Result getRecipes(GetRecipes value),
41 | });
42 | @optionalTypeArgs
43 | Result maybeMap({
44 | Result getRecipes(GetRecipes value),
45 | @required Result orElse(),
46 | });
47 |
48 | $CategoryEventCopyWith get copyWith;
49 | }
50 |
51 | abstract class $CategoryEventCopyWith<$Res> {
52 | factory $CategoryEventCopyWith(
53 | CategoryEvent value, $Res Function(CategoryEvent) then) =
54 | _$CategoryEventCopyWithImpl<$Res>;
55 | $Res call({String categoryName});
56 | }
57 |
58 | class _$CategoryEventCopyWithImpl<$Res>
59 | implements $CategoryEventCopyWith<$Res> {
60 | _$CategoryEventCopyWithImpl(this._value, this._then);
61 |
62 | final CategoryEvent _value;
63 | // ignore: unused_field
64 | final $Res Function(CategoryEvent) _then;
65 |
66 | @override
67 | $Res call({
68 | Object categoryName = freezed,
69 | }) {
70 | return _then(_value.copyWith(
71 | categoryName: categoryName == freezed
72 | ? _value.categoryName
73 | : categoryName as String,
74 | ));
75 | }
76 | }
77 |
78 | abstract class $GetRecipesCopyWith<$Res>
79 | implements $CategoryEventCopyWith<$Res> {
80 | factory $GetRecipesCopyWith(
81 | GetRecipes value, $Res Function(GetRecipes) then) =
82 | _$GetRecipesCopyWithImpl<$Res>;
83 | @override
84 | $Res call({String categoryName});
85 | }
86 |
87 | class _$GetRecipesCopyWithImpl<$Res> extends _$CategoryEventCopyWithImpl<$Res>
88 | implements $GetRecipesCopyWith<$Res> {
89 | _$GetRecipesCopyWithImpl(GetRecipes _value, $Res Function(GetRecipes) _then)
90 | : super(_value, (v) => _then(v as GetRecipes));
91 |
92 | @override
93 | GetRecipes get _value => super._value as GetRecipes;
94 |
95 | @override
96 | $Res call({
97 | Object categoryName = freezed,
98 | }) {
99 | return _then(GetRecipes(
100 | categoryName: categoryName == freezed
101 | ? _value.categoryName
102 | : categoryName as String,
103 | ));
104 | }
105 | }
106 |
107 | class _$GetRecipes with DiagnosticableTreeMixin implements GetRecipes {
108 | const _$GetRecipes({@required this.categoryName})
109 | : assert(categoryName != null);
110 |
111 | @override
112 | final String categoryName;
113 |
114 | @override
115 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
116 | return 'CategoryEvent.getRecipes(categoryName: $categoryName)';
117 | }
118 |
119 | @override
120 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
121 | super.debugFillProperties(properties);
122 | properties
123 | ..add(DiagnosticsProperty('type', 'CategoryEvent.getRecipes'))
124 | ..add(DiagnosticsProperty('categoryName', categoryName));
125 | }
126 |
127 | @override
128 | bool operator ==(dynamic other) {
129 | return identical(this, other) ||
130 | (other is GetRecipes &&
131 | (identical(other.categoryName, categoryName) ||
132 | const DeepCollectionEquality()
133 | .equals(other.categoryName, categoryName)));
134 | }
135 |
136 | @override
137 | int get hashCode =>
138 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(categoryName);
139 |
140 | @override
141 | $GetRecipesCopyWith get copyWith =>
142 | _$GetRecipesCopyWithImpl(this, _$identity);
143 |
144 | @override
145 | @optionalTypeArgs
146 | Result when({
147 | @required Result getRecipes(String categoryName),
148 | }) {
149 | assert(getRecipes != null);
150 | return getRecipes(categoryName);
151 | }
152 |
153 | @override
154 | @optionalTypeArgs
155 | Result maybeWhen({
156 | Result getRecipes(String categoryName),
157 | @required Result orElse(),
158 | }) {
159 | assert(orElse != null);
160 | if (getRecipes != null) {
161 | return getRecipes(categoryName);
162 | }
163 | return orElse();
164 | }
165 |
166 | @override
167 | @optionalTypeArgs
168 | Result map({
169 | @required Result getRecipes(GetRecipes value),
170 | }) {
171 | assert(getRecipes != null);
172 | return getRecipes(this);
173 | }
174 |
175 | @override
176 | @optionalTypeArgs
177 | Result maybeMap({
178 | Result getRecipes(GetRecipes value),
179 | @required Result orElse(),
180 | }) {
181 | assert(orElse != null);
182 | if (getRecipes != null) {
183 | return getRecipes(this);
184 | }
185 | return orElse();
186 | }
187 | }
188 |
189 | abstract class GetRecipes implements CategoryEvent {
190 | const factory GetRecipes({@required String categoryName}) = _$GetRecipes;
191 |
192 | @override
193 | String get categoryName;
194 | @override
195 | $GetRecipesCopyWith get copyWith;
196 | }
197 |
198 | class _$CategoryStateTearOff {
199 | const _$CategoryStateTearOff();
200 |
201 | // ignore: unused_element
202 | Initial initial() {
203 | return const Initial();
204 | }
205 |
206 | // ignore: unused_element
207 | RecipesLoading recipesLoading() {
208 | return const RecipesLoading();
209 | }
210 |
211 | // ignore: unused_element
212 | RecipesLoaded recipesLoaded({@required Recipes recipes}) {
213 | return RecipesLoaded(
214 | recipes: recipes,
215 | );
216 | }
217 |
218 | // ignore: unused_element
219 | RecipesError recipesError({@required ServerError serverError}) {
220 | return RecipesError(
221 | serverError: serverError,
222 | );
223 | }
224 | }
225 |
226 | // ignore: unused_element
227 | const $CategoryState = _$CategoryStateTearOff();
228 |
229 | mixin _$CategoryState {
230 | @optionalTypeArgs
231 | Result when({
232 | @required Result initial(),
233 | @required Result recipesLoading(),
234 | @required Result recipesLoaded(Recipes recipes),
235 | @required Result recipesError(ServerError serverError),
236 | });
237 | @optionalTypeArgs
238 | Result maybeWhen({
239 | Result initial(),
240 | Result recipesLoading(),
241 | Result recipesLoaded(Recipes recipes),
242 | Result recipesError(ServerError serverError),
243 | @required Result orElse(),
244 | });
245 | @optionalTypeArgs
246 | Result map({
247 | @required Result initial(Initial value),
248 | @required Result recipesLoading(RecipesLoading value),
249 | @required Result recipesLoaded(RecipesLoaded value),
250 | @required Result recipesError(RecipesError value),
251 | });
252 | @optionalTypeArgs
253 | Result maybeMap({
254 | Result initial(Initial value),
255 | Result recipesLoading(RecipesLoading value),
256 | Result recipesLoaded(RecipesLoaded value),
257 | Result recipesError(RecipesError value),
258 | @required Result orElse(),
259 | });
260 | }
261 |
262 | abstract class $CategoryStateCopyWith<$Res> {
263 | factory $CategoryStateCopyWith(
264 | CategoryState value, $Res Function(CategoryState) then) =
265 | _$CategoryStateCopyWithImpl<$Res>;
266 | }
267 |
268 | class _$CategoryStateCopyWithImpl<$Res>
269 | implements $CategoryStateCopyWith<$Res> {
270 | _$CategoryStateCopyWithImpl(this._value, this._then);
271 |
272 | final CategoryState _value;
273 | // ignore: unused_field
274 | final $Res Function(CategoryState) _then;
275 | }
276 |
277 | abstract class $InitialCopyWith<$Res> {
278 | factory $InitialCopyWith(Initial value, $Res Function(Initial) then) =
279 | _$InitialCopyWithImpl<$Res>;
280 | }
281 |
282 | class _$InitialCopyWithImpl<$Res> extends _$CategoryStateCopyWithImpl<$Res>
283 | implements $InitialCopyWith<$Res> {
284 | _$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then)
285 | : super(_value, (v) => _then(v as Initial));
286 |
287 | @override
288 | Initial get _value => super._value as Initial;
289 | }
290 |
291 | class _$Initial with DiagnosticableTreeMixin implements Initial {
292 | const _$Initial();
293 |
294 | @override
295 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
296 | return 'CategoryState.initial()';
297 | }
298 |
299 | @override
300 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
301 | super.debugFillProperties(properties);
302 | properties..add(DiagnosticsProperty('type', 'CategoryState.initial'));
303 | }
304 |
305 | @override
306 | bool operator ==(dynamic other) {
307 | return identical(this, other) || (other is Initial);
308 | }
309 |
310 | @override
311 | int get hashCode => runtimeType.hashCode;
312 |
313 | @override
314 | @optionalTypeArgs
315 | Result when({
316 | @required Result initial(),
317 | @required Result recipesLoading(),
318 | @required Result recipesLoaded(Recipes recipes),
319 | @required Result recipesError(ServerError serverError),
320 | }) {
321 | assert(initial != null);
322 | assert(recipesLoading != null);
323 | assert(recipesLoaded != null);
324 | assert(recipesError != null);
325 | return initial();
326 | }
327 |
328 | @override
329 | @optionalTypeArgs
330 | Result maybeWhen({
331 | Result initial(),
332 | Result recipesLoading(),
333 | Result recipesLoaded(Recipes recipes),
334 | Result recipesError(ServerError serverError),
335 | @required Result orElse(),
336 | }) {
337 | assert(orElse != null);
338 | if (initial != null) {
339 | return initial();
340 | }
341 | return orElse();
342 | }
343 |
344 | @override
345 | @optionalTypeArgs
346 | Result map({
347 | @required Result initial(Initial value),
348 | @required Result recipesLoading(RecipesLoading value),
349 | @required Result recipesLoaded(RecipesLoaded value),
350 | @required Result recipesError(RecipesError value),
351 | }) {
352 | assert(initial != null);
353 | assert(recipesLoading != null);
354 | assert(recipesLoaded != null);
355 | assert(recipesError != null);
356 | return initial(this);
357 | }
358 |
359 | @override
360 | @optionalTypeArgs
361 | Result maybeMap({
362 | Result initial(Initial value),
363 | Result recipesLoading(RecipesLoading value),
364 | Result recipesLoaded(RecipesLoaded value),
365 | Result recipesError(RecipesError value),
366 | @required Result orElse(),
367 | }) {
368 | assert(orElse != null);
369 | if (initial != null) {
370 | return initial(this);
371 | }
372 | return orElse();
373 | }
374 | }
375 |
376 | abstract class Initial implements CategoryState {
377 | const factory Initial() = _$Initial;
378 | }
379 |
380 | abstract class $RecipesLoadingCopyWith<$Res> {
381 | factory $RecipesLoadingCopyWith(
382 | RecipesLoading value, $Res Function(RecipesLoading) then) =
383 | _$RecipesLoadingCopyWithImpl<$Res>;
384 | }
385 |
386 | class _$RecipesLoadingCopyWithImpl<$Res>
387 | extends _$CategoryStateCopyWithImpl<$Res>
388 | implements $RecipesLoadingCopyWith<$Res> {
389 | _$RecipesLoadingCopyWithImpl(
390 | RecipesLoading _value, $Res Function(RecipesLoading) _then)
391 | : super(_value, (v) => _then(v as RecipesLoading));
392 |
393 | @override
394 | RecipesLoading get _value => super._value as RecipesLoading;
395 | }
396 |
397 | class _$RecipesLoading with DiagnosticableTreeMixin implements RecipesLoading {
398 | const _$RecipesLoading();
399 |
400 | @override
401 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
402 | return 'CategoryState.recipesLoading()';
403 | }
404 |
405 | @override
406 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
407 | super.debugFillProperties(properties);
408 | properties
409 | ..add(DiagnosticsProperty('type', 'CategoryState.recipesLoading'));
410 | }
411 |
412 | @override
413 | bool operator ==(dynamic other) {
414 | return identical(this, other) || (other is RecipesLoading);
415 | }
416 |
417 | @override
418 | int get hashCode => runtimeType.hashCode;
419 |
420 | @override
421 | @optionalTypeArgs
422 | Result when({
423 | @required Result initial(),
424 | @required Result recipesLoading(),
425 | @required Result recipesLoaded(Recipes recipes),
426 | @required Result recipesError(ServerError serverError),
427 | }) {
428 | assert(initial != null);
429 | assert(recipesLoading != null);
430 | assert(recipesLoaded != null);
431 | assert(recipesError != null);
432 | return recipesLoading();
433 | }
434 |
435 | @override
436 | @optionalTypeArgs
437 | Result maybeWhen({
438 | Result initial(),
439 | Result recipesLoading(),
440 | Result recipesLoaded(Recipes recipes),
441 | Result recipesError(ServerError serverError),
442 | @required Result orElse(),
443 | }) {
444 | assert(orElse != null);
445 | if (recipesLoading != null) {
446 | return recipesLoading();
447 | }
448 | return orElse();
449 | }
450 |
451 | @override
452 | @optionalTypeArgs
453 | Result map({
454 | @required Result initial(Initial value),
455 | @required Result recipesLoading(RecipesLoading value),
456 | @required Result recipesLoaded(RecipesLoaded value),
457 | @required Result recipesError(RecipesError value),
458 | }) {
459 | assert(initial != null);
460 | assert(recipesLoading != null);
461 | assert(recipesLoaded != null);
462 | assert(recipesError != null);
463 | return recipesLoading(this);
464 | }
465 |
466 | @override
467 | @optionalTypeArgs
468 | Result maybeMap({
469 | Result initial(Initial value),
470 | Result recipesLoading(RecipesLoading value),
471 | Result recipesLoaded(RecipesLoaded value),
472 | Result recipesError(RecipesError value),
473 | @required Result orElse(),
474 | }) {
475 | assert(orElse != null);
476 | if (recipesLoading != null) {
477 | return recipesLoading(this);
478 | }
479 | return orElse();
480 | }
481 | }
482 |
483 | abstract class RecipesLoading implements CategoryState {
484 | const factory RecipesLoading() = _$RecipesLoading;
485 | }
486 |
487 | abstract class $RecipesLoadedCopyWith<$Res> {
488 | factory $RecipesLoadedCopyWith(
489 | RecipesLoaded value, $Res Function(RecipesLoaded) then) =
490 | _$RecipesLoadedCopyWithImpl<$Res>;
491 | $Res call({Recipes recipes});
492 | }
493 |
494 | class _$RecipesLoadedCopyWithImpl<$Res>
495 | extends _$CategoryStateCopyWithImpl<$Res>
496 | implements $RecipesLoadedCopyWith<$Res> {
497 | _$RecipesLoadedCopyWithImpl(
498 | RecipesLoaded _value, $Res Function(RecipesLoaded) _then)
499 | : super(_value, (v) => _then(v as RecipesLoaded));
500 |
501 | @override
502 | RecipesLoaded get _value => super._value as RecipesLoaded;
503 |
504 | @override
505 | $Res call({
506 | Object recipes = freezed,
507 | }) {
508 | return _then(RecipesLoaded(
509 | recipes: recipes == freezed ? _value.recipes : recipes as Recipes,
510 | ));
511 | }
512 | }
513 |
514 | class _$RecipesLoaded with DiagnosticableTreeMixin implements RecipesLoaded {
515 | const _$RecipesLoaded({@required this.recipes}) : assert(recipes != null);
516 |
517 | @override
518 | final Recipes recipes;
519 |
520 | @override
521 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
522 | return 'CategoryState.recipesLoaded(recipes: $recipes)';
523 | }
524 |
525 | @override
526 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
527 | super.debugFillProperties(properties);
528 | properties
529 | ..add(DiagnosticsProperty('type', 'CategoryState.recipesLoaded'))
530 | ..add(DiagnosticsProperty('recipes', recipes));
531 | }
532 |
533 | @override
534 | bool operator ==(dynamic other) {
535 | return identical(this, other) ||
536 | (other is RecipesLoaded &&
537 | (identical(other.recipes, recipes) ||
538 | const DeepCollectionEquality().equals(other.recipes, recipes)));
539 | }
540 |
541 | @override
542 | int get hashCode =>
543 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(recipes);
544 |
545 | @override
546 | $RecipesLoadedCopyWith get copyWith =>
547 | _$RecipesLoadedCopyWithImpl(this, _$identity);
548 |
549 | @override
550 | @optionalTypeArgs
551 | Result when({
552 | @required Result initial(),
553 | @required Result recipesLoading(),
554 | @required Result recipesLoaded(Recipes recipes),
555 | @required Result recipesError(ServerError serverError),
556 | }) {
557 | assert(initial != null);
558 | assert(recipesLoading != null);
559 | assert(recipesLoaded != null);
560 | assert(recipesError != null);
561 | return recipesLoaded(recipes);
562 | }
563 |
564 | @override
565 | @optionalTypeArgs
566 | Result maybeWhen({
567 | Result initial(),
568 | Result recipesLoading(),
569 | Result recipesLoaded(Recipes recipes),
570 | Result recipesError(ServerError serverError),
571 | @required Result orElse(),
572 | }) {
573 | assert(orElse != null);
574 | if (recipesLoaded != null) {
575 | return recipesLoaded(recipes);
576 | }
577 | return orElse();
578 | }
579 |
580 | @override
581 | @optionalTypeArgs
582 | Result map({
583 | @required Result initial(Initial value),
584 | @required Result recipesLoading(RecipesLoading value),
585 | @required Result recipesLoaded(RecipesLoaded value),
586 | @required Result recipesError(RecipesError value),
587 | }) {
588 | assert(initial != null);
589 | assert(recipesLoading != null);
590 | assert(recipesLoaded != null);
591 | assert(recipesError != null);
592 | return recipesLoaded(this);
593 | }
594 |
595 | @override
596 | @optionalTypeArgs
597 | Result maybeMap({
598 | Result initial(Initial value),
599 | Result recipesLoading(RecipesLoading value),
600 | Result recipesLoaded(RecipesLoaded value),
601 | Result recipesError(RecipesError value),
602 | @required Result orElse(),
603 | }) {
604 | assert(orElse != null);
605 | if (recipesLoaded != null) {
606 | return recipesLoaded(this);
607 | }
608 | return orElse();
609 | }
610 | }
611 |
612 | abstract class RecipesLoaded implements CategoryState {
613 | const factory RecipesLoaded({@required Recipes recipes}) = _$RecipesLoaded;
614 |
615 | Recipes get recipes;
616 | $RecipesLoadedCopyWith get copyWith;
617 | }
618 |
619 | abstract class $RecipesErrorCopyWith<$Res> {
620 | factory $RecipesErrorCopyWith(
621 | RecipesError value, $Res Function(RecipesError) then) =
622 | _$RecipesErrorCopyWithImpl<$Res>;
623 | $Res call({ServerError serverError});
624 | }
625 |
626 | class _$RecipesErrorCopyWithImpl<$Res> extends _$CategoryStateCopyWithImpl<$Res>
627 | implements $RecipesErrorCopyWith<$Res> {
628 | _$RecipesErrorCopyWithImpl(
629 | RecipesError _value, $Res Function(RecipesError) _then)
630 | : super(_value, (v) => _then(v as RecipesError));
631 |
632 | @override
633 | RecipesError get _value => super._value as RecipesError;
634 |
635 | @override
636 | $Res call({
637 | Object serverError = freezed,
638 | }) {
639 | return _then(RecipesError(
640 | serverError: serverError == freezed
641 | ? _value.serverError
642 | : serverError as ServerError,
643 | ));
644 | }
645 | }
646 |
647 | class _$RecipesError with DiagnosticableTreeMixin implements RecipesError {
648 | const _$RecipesError({@required this.serverError})
649 | : assert(serverError != null);
650 |
651 | @override
652 | final ServerError serverError;
653 |
654 | @override
655 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
656 | return 'CategoryState.recipesError(serverError: $serverError)';
657 | }
658 |
659 | @override
660 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
661 | super.debugFillProperties(properties);
662 | properties
663 | ..add(DiagnosticsProperty('type', 'CategoryState.recipesError'))
664 | ..add(DiagnosticsProperty('serverError', serverError));
665 | }
666 |
667 | @override
668 | bool operator ==(dynamic other) {
669 | return identical(this, other) ||
670 | (other is RecipesError &&
671 | (identical(other.serverError, serverError) ||
672 | const DeepCollectionEquality()
673 | .equals(other.serverError, serverError)));
674 | }
675 |
676 | @override
677 | int get hashCode =>
678 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(serverError);
679 |
680 | @override
681 | $RecipesErrorCopyWith get copyWith =>
682 | _$RecipesErrorCopyWithImpl(this, _$identity);
683 |
684 | @override
685 | @optionalTypeArgs
686 | Result when({
687 | @required Result initial(),
688 | @required Result recipesLoading(),
689 | @required Result recipesLoaded(Recipes recipes),
690 | @required Result recipesError(ServerError serverError),
691 | }) {
692 | assert(initial != null);
693 | assert(recipesLoading != null);
694 | assert(recipesLoaded != null);
695 | assert(recipesError != null);
696 | return recipesError(serverError);
697 | }
698 |
699 | @override
700 | @optionalTypeArgs
701 | Result maybeWhen({
702 | Result initial(),
703 | Result recipesLoading(),
704 | Result recipesLoaded(Recipes recipes),
705 | Result recipesError(ServerError serverError),
706 | @required Result orElse(),
707 | }) {
708 | assert(orElse != null);
709 | if (recipesError != null) {
710 | return recipesError(serverError);
711 | }
712 | return orElse();
713 | }
714 |
715 | @override
716 | @optionalTypeArgs
717 | Result map({
718 | @required Result initial(Initial value),
719 | @required Result recipesLoading(RecipesLoading value),
720 | @required Result recipesLoaded(RecipesLoaded value),
721 | @required Result recipesError(RecipesError value),
722 | }) {
723 | assert(initial != null);
724 | assert(recipesLoading != null);
725 | assert(recipesLoaded != null);
726 | assert(recipesError != null);
727 | return recipesError(this);
728 | }
729 |
730 | @override
731 | @optionalTypeArgs
732 | Result maybeMap({
733 | Result initial(Initial value),
734 | Result recipesLoading(RecipesLoading value),
735 | Result recipesLoaded(RecipesLoaded value),
736 | Result recipesError(RecipesError value),
737 | @required Result orElse(),
738 | }) {
739 | assert(orElse != null);
740 | if (recipesError != null) {
741 | return recipesError(this);
742 | }
743 | return orElse();
744 | }
745 | }
746 |
747 | abstract class RecipesError implements CategoryState {
748 | const factory RecipesError({@required ServerError serverError}) =
749 | _$RecipesError;
750 |
751 | ServerError get serverError;
752 | $RecipesErrorCopyWith get copyWith;
753 | }
754 |
--------------------------------------------------------------------------------
/lib/ui/screens/category/bloc/events.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class CategoryEvent with _$CategoryEvent {
5 | const factory CategoryEvent.getRecipes({@required String categoryName}) =
6 | GetRecipes;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/ui/screens/category/bloc/states.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class CategoryState with _$CategoryState {
5 | const factory CategoryState.initial() = Initial;
6 |
7 | const factory CategoryState.recipesLoading() = RecipesLoading;
8 |
9 | const factory CategoryState.recipesLoaded({@required Recipes recipes}) =
10 | RecipesLoaded;
11 |
12 | const factory CategoryState.recipesError(
13 | {@required ServerError serverError}) = RecipesError;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/ui/screens/category/category.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 |
4 | import '../../../ui/items/recipe.dart';
5 | import 'bloc/bloc.dart';
6 |
7 | class CategoryScreen extends StatefulWidget {
8 | final String categoryName;
9 |
10 | const CategoryScreen({Key key, @required this.categoryName})
11 | : super(key: key);
12 |
13 | @override
14 | _CategoryScreenState createState() => _CategoryScreenState();
15 | }
16 |
17 | class _CategoryScreenState extends State {
18 | final _bloc = CategoryBloc();
19 |
20 | void _loadData() {
21 | _bloc..add(CategoryEvent.getRecipes(categoryName: widget.categoryName));
22 | }
23 |
24 | Future _onRefresh() {
25 | _loadData();
26 | return Future.value();
27 | }
28 |
29 | @override
30 | void initState() {
31 | super.initState();
32 | _loadData();
33 | }
34 |
35 | @override
36 | Widget build(BuildContext context) => Scaffold(
37 | body: RefreshIndicator(
38 | onRefresh: _onRefresh,
39 | child: CustomScrollView(
40 | slivers: [
41 | SliverAppBar(
42 | floating: true,
43 | centerTitle: true,
44 | title: Text(widget.categoryName),
45 | ),
46 | BlocBuilder(
47 | bloc: _bloc,
48 | builder: (_, state) => state.maybeWhen(
49 | recipesLoading: () => SliverFillRemaining(
50 | child: Center(child: CircularProgressIndicator()),
51 | ),
52 | recipesLoaded: (recipes) => SliverList(
53 | delegate: SliverChildBuilderDelegate(
54 | (_, index) => RecipeItem(
55 | recipe: recipes.items[index],
56 | ),
57 | childCount: recipes.items.length,
58 | ),
59 | ),
60 | orElse: () => SliverPadding(padding: const EdgeInsets.all(0)),
61 | ),
62 | ),
63 | ],
64 | ),
65 | ),
66 | );
67 |
68 | @override
69 | void dispose() {
70 | _bloc.close();
71 | super.dispose();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/ui/screens/favorite/favorite.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hive/hive.dart';
3 | import 'package:hive_flutter/hive_flutter.dart';
4 | import 'package:recipes/models/recipes/recipe.dart';
5 | import 'package:recipes/services/hive.dart';
6 | import 'package:recipes/ui/items/recipe.dart';
7 |
8 | class FavoriteScreen extends StatefulWidget {
9 | @override
10 | _FavoriteScreenState createState() => _FavoriteScreenState();
11 | }
12 |
13 | class _FavoriteScreenState extends State {
14 | @override
15 | Widget build(BuildContext context) => Scaffold(
16 | body: ValueListenableBuilder>(
17 | valueListenable: AppHive.instance.selectAll().listenable(),
18 | builder: (_, box, __) => CustomScrollView(
19 | slivers: [
20 | SliverAppBar(
21 | floating: true,
22 | centerTitle: true,
23 | title: Text('Favorite'),
24 | ),
25 | SliverList(
26 | delegate: SliverChildBuilderDelegate(
27 | (_, index) => RecipeItem(
28 | key: ValueKey(box.getAt(index).id),
29 | recipe: box.getAt(index),
30 | ),
31 | childCount: box.length,
32 | ),
33 | ),
34 | ],
35 | ),
36 | ),
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/lib/ui/screens/home/bloc/bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 |
5 | import '../../../../models/categories/categories.dart';
6 | import '../../../../models/recipes/recipe.dart';
7 | import '../../../../models/recipes/recipes.dart';
8 | import '../../../../models/server_error.dart';
9 | import '../../../../services/network.dart';
10 |
11 | part 'bloc.freezed.dart';
12 |
13 | part 'events.dart';
14 |
15 | part 'states.dart';
16 |
17 | class HomeBloc extends Bloc {
18 | final _appNetwork = AppNetwork.instance;
19 |
20 | @override
21 | HomeState get initialState => HomeState.initial();
22 |
23 | @override
24 | Stream mapEventToState(HomeEvent event) async* {
25 | yield* event.when(
26 | getRandomRecipe: _getRandomRecipe,
27 | getCategories: _getCategories,
28 | );
29 | }
30 |
31 | Stream _getRandomRecipe() async* {
32 | yield HomeState.randomRecipeLoading();
33 | final response = await _appNetwork.get('random.php');
34 | yield* response.fold(
35 | (error) async* {
36 | yield HomeState.randomRecipeError(serverError: error);
37 | },
38 | (json) async* {
39 | yield HomeState.randomRecipeLoaded(
40 | recipe: Recipes.fromJson(json).items[0]);
41 | },
42 | );
43 | }
44 |
45 | Stream _getCategories() async* {
46 | yield HomeState.categoriesLoading();
47 | final response = await _appNetwork.get('categories.php');
48 | yield* response.fold(
49 | (error) async* {
50 | yield HomeState.categoriesError(serverError: error);
51 | },
52 | (json) async* {
53 | yield HomeState.categoriesLoaded(categories: Categories.fromJson(json));
54 | },
55 | );
56 | }
57 |
58 | @override
59 | Future close() {
60 | return super.close();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/ui/screens/home/bloc/events.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class HomeEvent with _$HomeEvent {
5 | const factory HomeEvent.getRandomRecipe() = GetRandomRecipe;
6 |
7 | const factory HomeEvent.getCategories() = GetCategories;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/ui/screens/home/bloc/states.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class HomeState with _$HomeState {
5 | const factory HomeState.initial() = Initial;
6 |
7 | const factory HomeState.randomRecipeLoading() = RandomRecipeLoading;
8 |
9 | const factory HomeState.randomRecipeLoaded({@required Recipe recipe}) =
10 | RandomRecipeLoaded;
11 |
12 | const factory HomeState.randomRecipeError(
13 | {@required ServerError serverError}) = RandomRecipeError;
14 |
15 | const factory HomeState.categoriesLoading() = CategoriesLoading;
16 |
17 | const factory HomeState.categoriesLoaded({@required Categories categories}) =
18 | CategoriesLoaded;
19 |
20 | const factory HomeState.categoriesError({@required ServerError serverError}) =
21 | CategoriesError;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/ui/screens/home/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:recipes/ui/screens/favorite/favorite.dart';
5 | import 'package:recipes/ui/screens/search/search.dart';
6 |
7 | import '../../../ui/items/category.dart';
8 | import '../../../ui/items/recipe_random.dart';
9 | import 'bloc/bloc.dart';
10 |
11 | class HomeScreen extends StatefulWidget {
12 | @override
13 | _HomeScreenState createState() => _HomeScreenState();
14 | }
15 |
16 | class _HomeScreenState extends State {
17 | final _bloc = HomeBloc();
18 |
19 | void _loadData() {
20 | _bloc..add(HomeEvent.getRandomRecipe())..add(HomeEvent.getCategories());
21 | }
22 |
23 | Future _onRefresh() {
24 | _loadData();
25 | return Future.value();
26 | }
27 |
28 | @override
29 | void initState() {
30 | super.initState();
31 | _loadData();
32 | }
33 |
34 | @override
35 | Widget build(BuildContext context) => Scaffold(
36 | body: RefreshIndicator(
37 | onRefresh: _onRefresh,
38 | child: CustomScrollView(
39 | slivers: [
40 | SliverAppBar(
41 | floating: true,
42 | centerTitle: true,
43 | title: Text('Recipes'),
44 | actions: [
45 | IconButton(
46 | onPressed: () {
47 | Navigator.push(
48 | context,
49 | CupertinoPageRoute(builder: (_) => FavoriteScreen()),
50 | );
51 | },
52 | icon: Icon(Icons.favorite_border),
53 | ),
54 | IconButton(
55 | onPressed: () {
56 | showSearch(
57 | context: context,
58 | delegate: SearchScreen(),
59 | );
60 | },
61 | icon: Icon(Icons.search),
62 | ),
63 | ],
64 | ),
65 | SliverToBoxAdapter(
66 | child: Padding(
67 | padding: const EdgeInsetsDirectional.only(
68 | start: 20,
69 | top: 20,
70 | bottom: 5,
71 | ),
72 | child: Text(
73 | 'RANDOM RECIPE',
74 | style: TextStyle(
75 | color: Colors.black,
76 | fontSize: 20,
77 | fontWeight: FontWeight.w500,
78 | ),
79 | ),
80 | ),
81 | ),
82 | SliverToBoxAdapter(
83 | child: BlocBuilder(
84 | bloc: _bloc,
85 | condition: (_, state) => state.maybeWhen(
86 | randomRecipeLoading: () => true,
87 | randomRecipeLoaded: (_) => true,
88 | randomRecipeError: (_) => true,
89 | orElse: () => false,
90 | ),
91 | builder: (_, state) => state.maybeWhen(
92 | randomRecipeLoading: () => Center(
93 | child: CircularProgressIndicator(),
94 | ),
95 | randomRecipeLoaded: (recipe) => Padding(
96 | padding: const EdgeInsets.symmetric(horizontal: 20),
97 | child: AspectRatio(
98 | aspectRatio: 1.3,
99 | child: RecipeRandomItem(recipe: recipe),
100 | ),
101 | ),
102 | orElse: () => const SizedBox(),
103 | ),
104 | ),
105 | ),
106 | SliverToBoxAdapter(
107 | child: Padding(
108 | padding: const EdgeInsetsDirectional.only(
109 | start: 20,
110 | top: 20,
111 | bottom: 5,
112 | ),
113 | child: Text(
114 | 'CATEGORIES',
115 | style: TextStyle(
116 | color: Colors.black,
117 | fontSize: 20,
118 | fontWeight: FontWeight.w500,
119 | ),
120 | ),
121 | ),
122 | ),
123 | BlocBuilder(
124 | bloc: _bloc,
125 | condition: (_, state) => state.maybeWhen(
126 | categoriesLoading: () => true,
127 | categoriesLoaded: (_) => true,
128 | categoriesError: (_) => true,
129 | orElse: () => false,
130 | ),
131 | builder: (_, state) => state.maybeWhen(
132 | categoriesLoading: () => SliverFillRemaining(
133 | child: Center(child: CircularProgressIndicator()),
134 | ),
135 | categoriesLoaded: (categories) => SliverList(
136 | delegate: SliverChildBuilderDelegate(
137 | (_, index) => CategoryItem(
138 | category: categories.items[index],
139 | ),
140 | childCount: categories.items.length,
141 | ),
142 | ),
143 | orElse: () => SliverPadding(padding: const EdgeInsets.all(0)),
144 | ),
145 | ),
146 | ],
147 | ),
148 | ),
149 | );
150 |
151 | @override
152 | void dispose() {
153 | _bloc.close();
154 | super.dispose();
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/lib/ui/screens/recipe/bloc/bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 |
5 | import '../../../../models/recipes/recipe.dart';
6 | import '../../../../models/recipes/recipes.dart';
7 | import '../../../../models/server_error.dart';
8 | import '../../../../services/network.dart';
9 |
10 | part 'bloc.freezed.dart';
11 |
12 | part 'events.dart';
13 |
14 | part 'states.dart';
15 |
16 | class RecipeBloc extends Bloc {
17 | final _appNetwork = AppNetwork.instance;
18 |
19 | @override
20 | RecipeState get initialState => RecipeState.initial();
21 |
22 | @override
23 | Stream mapEventToState(RecipeEvent event) async* {
24 | yield* event.when(getDetails: _getDetails);
25 | }
26 |
27 | Stream _getDetails(dynamic recipeId) async* {
28 | yield RecipeState.detailsLoading();
29 | final response = await _appNetwork.get('lookup.php?i=$recipeId');
30 | yield* response.fold(
31 | (error) async* {
32 | yield RecipeState.detailsError(serverError: error);
33 | },
34 | (json) async* {
35 | yield RecipeState.detailsLoaded(
36 | recipe: Recipes.fromJson(json).items[0],
37 | );
38 | },
39 | );
40 | }
41 |
42 | @override
43 | Future close() {
44 | return super.close();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/ui/screens/recipe/bloc/bloc.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: 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
3 |
4 | part of 'bloc.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 |
12 | class _$RecipeEventTearOff {
13 | const _$RecipeEventTearOff();
14 |
15 | // ignore: unused_element
16 | GetDetails getDetails({@required dynamic recipeId}) {
17 | return GetDetails(
18 | recipeId: recipeId,
19 | );
20 | }
21 | }
22 |
23 | // ignore: unused_element
24 | const $RecipeEvent = _$RecipeEventTearOff();
25 |
26 | mixin _$RecipeEvent {
27 | dynamic get recipeId;
28 |
29 | @optionalTypeArgs
30 | Result when({
31 | @required Result getDetails(dynamic recipeId),
32 | });
33 | @optionalTypeArgs
34 | Result maybeWhen({
35 | Result getDetails(dynamic recipeId),
36 | @required Result orElse(),
37 | });
38 | @optionalTypeArgs
39 | Result map({
40 | @required Result getDetails(GetDetails value),
41 | });
42 | @optionalTypeArgs
43 | Result maybeMap({
44 | Result getDetails(GetDetails value),
45 | @required Result orElse(),
46 | });
47 |
48 | $RecipeEventCopyWith get copyWith;
49 | }
50 |
51 | abstract class $RecipeEventCopyWith<$Res> {
52 | factory $RecipeEventCopyWith(
53 | RecipeEvent value, $Res Function(RecipeEvent) then) =
54 | _$RecipeEventCopyWithImpl<$Res>;
55 | $Res call({dynamic recipeId});
56 | }
57 |
58 | class _$RecipeEventCopyWithImpl<$Res> implements $RecipeEventCopyWith<$Res> {
59 | _$RecipeEventCopyWithImpl(this._value, this._then);
60 |
61 | final RecipeEvent _value;
62 | // ignore: unused_field
63 | final $Res Function(RecipeEvent) _then;
64 |
65 | @override
66 | $Res call({
67 | Object recipeId = freezed,
68 | }) {
69 | return _then(_value.copyWith(
70 | recipeId: recipeId == freezed ? _value.recipeId : recipeId as dynamic,
71 | ));
72 | }
73 | }
74 |
75 | abstract class $GetDetailsCopyWith<$Res> implements $RecipeEventCopyWith<$Res> {
76 | factory $GetDetailsCopyWith(
77 | GetDetails value, $Res Function(GetDetails) then) =
78 | _$GetDetailsCopyWithImpl<$Res>;
79 | @override
80 | $Res call({dynamic recipeId});
81 | }
82 |
83 | class _$GetDetailsCopyWithImpl<$Res> extends _$RecipeEventCopyWithImpl<$Res>
84 | implements $GetDetailsCopyWith<$Res> {
85 | _$GetDetailsCopyWithImpl(GetDetails _value, $Res Function(GetDetails) _then)
86 | : super(_value, (v) => _then(v as GetDetails));
87 |
88 | @override
89 | GetDetails get _value => super._value as GetDetails;
90 |
91 | @override
92 | $Res call({
93 | Object recipeId = freezed,
94 | }) {
95 | return _then(GetDetails(
96 | recipeId: recipeId == freezed ? _value.recipeId : recipeId as dynamic,
97 | ));
98 | }
99 | }
100 |
101 | class _$GetDetails with DiagnosticableTreeMixin implements GetDetails {
102 | const _$GetDetails({@required this.recipeId}) : assert(recipeId != null);
103 |
104 | @override
105 | final dynamic recipeId;
106 |
107 | @override
108 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
109 | return 'RecipeEvent.getDetails(recipeId: $recipeId)';
110 | }
111 |
112 | @override
113 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
114 | super.debugFillProperties(properties);
115 | properties
116 | ..add(DiagnosticsProperty('type', 'RecipeEvent.getDetails'))
117 | ..add(DiagnosticsProperty('recipeId', recipeId));
118 | }
119 |
120 | @override
121 | bool operator ==(dynamic other) {
122 | return identical(this, other) ||
123 | (other is GetDetails &&
124 | (identical(other.recipeId, recipeId) ||
125 | const DeepCollectionEquality()
126 | .equals(other.recipeId, recipeId)));
127 | }
128 |
129 | @override
130 | int get hashCode =>
131 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(recipeId);
132 |
133 | @override
134 | $GetDetailsCopyWith get copyWith =>
135 | _$GetDetailsCopyWithImpl(this, _$identity);
136 |
137 | @override
138 | @optionalTypeArgs
139 | Result when({
140 | @required Result getDetails(dynamic recipeId),
141 | }) {
142 | assert(getDetails != null);
143 | return getDetails(recipeId);
144 | }
145 |
146 | @override
147 | @optionalTypeArgs
148 | Result maybeWhen({
149 | Result getDetails(dynamic recipeId),
150 | @required Result orElse(),
151 | }) {
152 | assert(orElse != null);
153 | if (getDetails != null) {
154 | return getDetails(recipeId);
155 | }
156 | return orElse();
157 | }
158 |
159 | @override
160 | @optionalTypeArgs
161 | Result map({
162 | @required Result getDetails(GetDetails value),
163 | }) {
164 | assert(getDetails != null);
165 | return getDetails(this);
166 | }
167 |
168 | @override
169 | @optionalTypeArgs
170 | Result maybeMap({
171 | Result getDetails(GetDetails value),
172 | @required Result orElse(),
173 | }) {
174 | assert(orElse != null);
175 | if (getDetails != null) {
176 | return getDetails(this);
177 | }
178 | return orElse();
179 | }
180 | }
181 |
182 | abstract class GetDetails implements RecipeEvent {
183 | const factory GetDetails({@required dynamic recipeId}) = _$GetDetails;
184 |
185 | @override
186 | dynamic get recipeId;
187 | @override
188 | $GetDetailsCopyWith get copyWith;
189 | }
190 |
191 | class _$RecipeStateTearOff {
192 | const _$RecipeStateTearOff();
193 |
194 | // ignore: unused_element
195 | Initial initial() {
196 | return const Initial();
197 | }
198 |
199 | // ignore: unused_element
200 | RecipesLoading detailsLoading() {
201 | return const RecipesLoading();
202 | }
203 |
204 | // ignore: unused_element
205 | RecipesLoaded detailsLoaded({@required Recipe recipe}) {
206 | return RecipesLoaded(
207 | recipe: recipe,
208 | );
209 | }
210 |
211 | // ignore: unused_element
212 | RecipesError detailsError({@required ServerError serverError}) {
213 | return RecipesError(
214 | serverError: serverError,
215 | );
216 | }
217 | }
218 |
219 | // ignore: unused_element
220 | const $RecipeState = _$RecipeStateTearOff();
221 |
222 | mixin _$RecipeState {
223 | @optionalTypeArgs
224 | Result when({
225 | @required Result initial(),
226 | @required Result detailsLoading(),
227 | @required Result detailsLoaded(Recipe recipe),
228 | @required Result detailsError(ServerError serverError),
229 | });
230 | @optionalTypeArgs
231 | Result maybeWhen({
232 | Result initial(),
233 | Result detailsLoading(),
234 | Result detailsLoaded(Recipe recipe),
235 | Result detailsError(ServerError serverError),
236 | @required Result orElse(),
237 | });
238 | @optionalTypeArgs
239 | Result map({
240 | @required Result initial(Initial value),
241 | @required Result detailsLoading(RecipesLoading value),
242 | @required Result detailsLoaded(RecipesLoaded value),
243 | @required Result detailsError(RecipesError value),
244 | });
245 | @optionalTypeArgs
246 | Result maybeMap({
247 | Result initial(Initial value),
248 | Result detailsLoading(RecipesLoading value),
249 | Result detailsLoaded(RecipesLoaded value),
250 | Result detailsError(RecipesError value),
251 | @required Result orElse(),
252 | });
253 | }
254 |
255 | abstract class $RecipeStateCopyWith<$Res> {
256 | factory $RecipeStateCopyWith(
257 | RecipeState value, $Res Function(RecipeState) then) =
258 | _$RecipeStateCopyWithImpl<$Res>;
259 | }
260 |
261 | class _$RecipeStateCopyWithImpl<$Res> implements $RecipeStateCopyWith<$Res> {
262 | _$RecipeStateCopyWithImpl(this._value, this._then);
263 |
264 | final RecipeState _value;
265 | // ignore: unused_field
266 | final $Res Function(RecipeState) _then;
267 | }
268 |
269 | abstract class $InitialCopyWith<$Res> {
270 | factory $InitialCopyWith(Initial value, $Res Function(Initial) then) =
271 | _$InitialCopyWithImpl<$Res>;
272 | }
273 |
274 | class _$InitialCopyWithImpl<$Res> extends _$RecipeStateCopyWithImpl<$Res>
275 | implements $InitialCopyWith<$Res> {
276 | _$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then)
277 | : super(_value, (v) => _then(v as Initial));
278 |
279 | @override
280 | Initial get _value => super._value as Initial;
281 | }
282 |
283 | class _$Initial with DiagnosticableTreeMixin implements Initial {
284 | const _$Initial();
285 |
286 | @override
287 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
288 | return 'RecipeState.initial()';
289 | }
290 |
291 | @override
292 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
293 | super.debugFillProperties(properties);
294 | properties..add(DiagnosticsProperty('type', 'RecipeState.initial'));
295 | }
296 |
297 | @override
298 | bool operator ==(dynamic other) {
299 | return identical(this, other) || (other is Initial);
300 | }
301 |
302 | @override
303 | int get hashCode => runtimeType.hashCode;
304 |
305 | @override
306 | @optionalTypeArgs
307 | Result when({
308 | @required Result initial(),
309 | @required Result detailsLoading(),
310 | @required Result detailsLoaded(Recipe recipe),
311 | @required Result detailsError(ServerError serverError),
312 | }) {
313 | assert(initial != null);
314 | assert(detailsLoading != null);
315 | assert(detailsLoaded != null);
316 | assert(detailsError != null);
317 | return initial();
318 | }
319 |
320 | @override
321 | @optionalTypeArgs
322 | Result maybeWhen({
323 | Result initial(),
324 | Result detailsLoading(),
325 | Result detailsLoaded(Recipe recipe),
326 | Result detailsError(ServerError serverError),
327 | @required Result orElse(),
328 | }) {
329 | assert(orElse != null);
330 | if (initial != null) {
331 | return initial();
332 | }
333 | return orElse();
334 | }
335 |
336 | @override
337 | @optionalTypeArgs
338 | Result map({
339 | @required Result initial(Initial value),
340 | @required Result detailsLoading(RecipesLoading value),
341 | @required Result detailsLoaded(RecipesLoaded value),
342 | @required Result detailsError(RecipesError value),
343 | }) {
344 | assert(initial != null);
345 | assert(detailsLoading != null);
346 | assert(detailsLoaded != null);
347 | assert(detailsError != null);
348 | return initial(this);
349 | }
350 |
351 | @override
352 | @optionalTypeArgs
353 | Result maybeMap({
354 | Result initial(Initial value),
355 | Result detailsLoading(RecipesLoading value),
356 | Result detailsLoaded(RecipesLoaded value),
357 | Result detailsError(RecipesError value),
358 | @required Result orElse(),
359 | }) {
360 | assert(orElse != null);
361 | if (initial != null) {
362 | return initial(this);
363 | }
364 | return orElse();
365 | }
366 | }
367 |
368 | abstract class Initial implements RecipeState {
369 | const factory Initial() = _$Initial;
370 | }
371 |
372 | abstract class $RecipesLoadingCopyWith<$Res> {
373 | factory $RecipesLoadingCopyWith(
374 | RecipesLoading value, $Res Function(RecipesLoading) then) =
375 | _$RecipesLoadingCopyWithImpl<$Res>;
376 | }
377 |
378 | class _$RecipesLoadingCopyWithImpl<$Res> extends _$RecipeStateCopyWithImpl<$Res>
379 | implements $RecipesLoadingCopyWith<$Res> {
380 | _$RecipesLoadingCopyWithImpl(
381 | RecipesLoading _value, $Res Function(RecipesLoading) _then)
382 | : super(_value, (v) => _then(v as RecipesLoading));
383 |
384 | @override
385 | RecipesLoading get _value => super._value as RecipesLoading;
386 | }
387 |
388 | class _$RecipesLoading with DiagnosticableTreeMixin implements RecipesLoading {
389 | const _$RecipesLoading();
390 |
391 | @override
392 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
393 | return 'RecipeState.detailsLoading()';
394 | }
395 |
396 | @override
397 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
398 | super.debugFillProperties(properties);
399 | properties..add(DiagnosticsProperty('type', 'RecipeState.detailsLoading'));
400 | }
401 |
402 | @override
403 | bool operator ==(dynamic other) {
404 | return identical(this, other) || (other is RecipesLoading);
405 | }
406 |
407 | @override
408 | int get hashCode => runtimeType.hashCode;
409 |
410 | @override
411 | @optionalTypeArgs
412 | Result when({
413 | @required Result initial(),
414 | @required Result detailsLoading(),
415 | @required Result detailsLoaded(Recipe recipe),
416 | @required Result detailsError(ServerError serverError),
417 | }) {
418 | assert(initial != null);
419 | assert(detailsLoading != null);
420 | assert(detailsLoaded != null);
421 | assert(detailsError != null);
422 | return detailsLoading();
423 | }
424 |
425 | @override
426 | @optionalTypeArgs
427 | Result maybeWhen({
428 | Result initial(),
429 | Result detailsLoading(),
430 | Result detailsLoaded(Recipe recipe),
431 | Result detailsError(ServerError serverError),
432 | @required Result orElse(),
433 | }) {
434 | assert(orElse != null);
435 | if (detailsLoading != null) {
436 | return detailsLoading();
437 | }
438 | return orElse();
439 | }
440 |
441 | @override
442 | @optionalTypeArgs
443 | Result map({
444 | @required Result initial(Initial value),
445 | @required Result detailsLoading(RecipesLoading value),
446 | @required Result detailsLoaded(RecipesLoaded value),
447 | @required Result detailsError(RecipesError value),
448 | }) {
449 | assert(initial != null);
450 | assert(detailsLoading != null);
451 | assert(detailsLoaded != null);
452 | assert(detailsError != null);
453 | return detailsLoading(this);
454 | }
455 |
456 | @override
457 | @optionalTypeArgs
458 | Result maybeMap({
459 | Result initial(Initial value),
460 | Result detailsLoading(RecipesLoading value),
461 | Result detailsLoaded(RecipesLoaded value),
462 | Result detailsError(RecipesError value),
463 | @required Result orElse(),
464 | }) {
465 | assert(orElse != null);
466 | if (detailsLoading != null) {
467 | return detailsLoading(this);
468 | }
469 | return orElse();
470 | }
471 | }
472 |
473 | abstract class RecipesLoading implements RecipeState {
474 | const factory RecipesLoading() = _$RecipesLoading;
475 | }
476 |
477 | abstract class $RecipesLoadedCopyWith<$Res> {
478 | factory $RecipesLoadedCopyWith(
479 | RecipesLoaded value, $Res Function(RecipesLoaded) then) =
480 | _$RecipesLoadedCopyWithImpl<$Res>;
481 | $Res call({Recipe recipe});
482 | }
483 |
484 | class _$RecipesLoadedCopyWithImpl<$Res> extends _$RecipeStateCopyWithImpl<$Res>
485 | implements $RecipesLoadedCopyWith<$Res> {
486 | _$RecipesLoadedCopyWithImpl(
487 | RecipesLoaded _value, $Res Function(RecipesLoaded) _then)
488 | : super(_value, (v) => _then(v as RecipesLoaded));
489 |
490 | @override
491 | RecipesLoaded get _value => super._value as RecipesLoaded;
492 |
493 | @override
494 | $Res call({
495 | Object recipe = freezed,
496 | }) {
497 | return _then(RecipesLoaded(
498 | recipe: recipe == freezed ? _value.recipe : recipe as Recipe,
499 | ));
500 | }
501 | }
502 |
503 | class _$RecipesLoaded with DiagnosticableTreeMixin implements RecipesLoaded {
504 | const _$RecipesLoaded({@required this.recipe}) : assert(recipe != null);
505 |
506 | @override
507 | final Recipe recipe;
508 |
509 | @override
510 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
511 | return 'RecipeState.detailsLoaded(recipe: $recipe)';
512 | }
513 |
514 | @override
515 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
516 | super.debugFillProperties(properties);
517 | properties
518 | ..add(DiagnosticsProperty('type', 'RecipeState.detailsLoaded'))
519 | ..add(DiagnosticsProperty('recipe', recipe));
520 | }
521 |
522 | @override
523 | bool operator ==(dynamic other) {
524 | return identical(this, other) ||
525 | (other is RecipesLoaded &&
526 | (identical(other.recipe, recipe) ||
527 | const DeepCollectionEquality().equals(other.recipe, recipe)));
528 | }
529 |
530 | @override
531 | int get hashCode =>
532 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(recipe);
533 |
534 | @override
535 | $RecipesLoadedCopyWith get copyWith =>
536 | _$RecipesLoadedCopyWithImpl(this, _$identity);
537 |
538 | @override
539 | @optionalTypeArgs
540 | Result when({
541 | @required Result initial(),
542 | @required Result detailsLoading(),
543 | @required Result detailsLoaded(Recipe recipe),
544 | @required Result detailsError(ServerError serverError),
545 | }) {
546 | assert(initial != null);
547 | assert(detailsLoading != null);
548 | assert(detailsLoaded != null);
549 | assert(detailsError != null);
550 | return detailsLoaded(recipe);
551 | }
552 |
553 | @override
554 | @optionalTypeArgs
555 | Result maybeWhen({
556 | Result initial(),
557 | Result detailsLoading(),
558 | Result detailsLoaded(Recipe recipe),
559 | Result detailsError(ServerError serverError),
560 | @required Result orElse(),
561 | }) {
562 | assert(orElse != null);
563 | if (detailsLoaded != null) {
564 | return detailsLoaded(recipe);
565 | }
566 | return orElse();
567 | }
568 |
569 | @override
570 | @optionalTypeArgs
571 | Result map({
572 | @required Result initial(Initial value),
573 | @required Result detailsLoading(RecipesLoading value),
574 | @required Result detailsLoaded(RecipesLoaded value),
575 | @required Result detailsError(RecipesError value),
576 | }) {
577 | assert(initial != null);
578 | assert(detailsLoading != null);
579 | assert(detailsLoaded != null);
580 | assert(detailsError != null);
581 | return detailsLoaded(this);
582 | }
583 |
584 | @override
585 | @optionalTypeArgs
586 | Result maybeMap({
587 | Result initial(Initial value),
588 | Result detailsLoading(RecipesLoading value),
589 | Result detailsLoaded(RecipesLoaded value),
590 | Result detailsError(RecipesError value),
591 | @required Result orElse(),
592 | }) {
593 | assert(orElse != null);
594 | if (detailsLoaded != null) {
595 | return detailsLoaded(this);
596 | }
597 | return orElse();
598 | }
599 | }
600 |
601 | abstract class RecipesLoaded implements RecipeState {
602 | const factory RecipesLoaded({@required Recipe recipe}) = _$RecipesLoaded;
603 |
604 | Recipe get recipe;
605 | $RecipesLoadedCopyWith get copyWith;
606 | }
607 |
608 | abstract class $RecipesErrorCopyWith<$Res> {
609 | factory $RecipesErrorCopyWith(
610 | RecipesError value, $Res Function(RecipesError) then) =
611 | _$RecipesErrorCopyWithImpl<$Res>;
612 | $Res call({ServerError serverError});
613 | }
614 |
615 | class _$RecipesErrorCopyWithImpl<$Res> extends _$RecipeStateCopyWithImpl<$Res>
616 | implements $RecipesErrorCopyWith<$Res> {
617 | _$RecipesErrorCopyWithImpl(
618 | RecipesError _value, $Res Function(RecipesError) _then)
619 | : super(_value, (v) => _then(v as RecipesError));
620 |
621 | @override
622 | RecipesError get _value => super._value as RecipesError;
623 |
624 | @override
625 | $Res call({
626 | Object serverError = freezed,
627 | }) {
628 | return _then(RecipesError(
629 | serverError: serverError == freezed
630 | ? _value.serverError
631 | : serverError as ServerError,
632 | ));
633 | }
634 | }
635 |
636 | class _$RecipesError with DiagnosticableTreeMixin implements RecipesError {
637 | const _$RecipesError({@required this.serverError})
638 | : assert(serverError != null);
639 |
640 | @override
641 | final ServerError serverError;
642 |
643 | @override
644 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
645 | return 'RecipeState.detailsError(serverError: $serverError)';
646 | }
647 |
648 | @override
649 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
650 | super.debugFillProperties(properties);
651 | properties
652 | ..add(DiagnosticsProperty('type', 'RecipeState.detailsError'))
653 | ..add(DiagnosticsProperty('serverError', serverError));
654 | }
655 |
656 | @override
657 | bool operator ==(dynamic other) {
658 | return identical(this, other) ||
659 | (other is RecipesError &&
660 | (identical(other.serverError, serverError) ||
661 | const DeepCollectionEquality()
662 | .equals(other.serverError, serverError)));
663 | }
664 |
665 | @override
666 | int get hashCode =>
667 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(serverError);
668 |
669 | @override
670 | $RecipesErrorCopyWith get copyWith =>
671 | _$RecipesErrorCopyWithImpl(this, _$identity);
672 |
673 | @override
674 | @optionalTypeArgs
675 | Result when({
676 | @required Result initial(),
677 | @required Result detailsLoading(),
678 | @required Result detailsLoaded(Recipe recipe),
679 | @required Result detailsError(ServerError serverError),
680 | }) {
681 | assert(initial != null);
682 | assert(detailsLoading != null);
683 | assert(detailsLoaded != null);
684 | assert(detailsError != null);
685 | return detailsError(serverError);
686 | }
687 |
688 | @override
689 | @optionalTypeArgs
690 | Result maybeWhen({
691 | Result initial(),
692 | Result detailsLoading(),
693 | Result detailsLoaded(Recipe recipe),
694 | Result detailsError(ServerError serverError),
695 | @required Result orElse(),
696 | }) {
697 | assert(orElse != null);
698 | if (detailsError != null) {
699 | return detailsError(serverError);
700 | }
701 | return orElse();
702 | }
703 |
704 | @override
705 | @optionalTypeArgs
706 | Result map({
707 | @required Result initial(Initial value),
708 | @required Result detailsLoading(RecipesLoading value),
709 | @required Result detailsLoaded(RecipesLoaded value),
710 | @required Result detailsError(RecipesError value),
711 | }) {
712 | assert(initial != null);
713 | assert(detailsLoading != null);
714 | assert(detailsLoaded != null);
715 | assert(detailsError != null);
716 | return detailsError(this);
717 | }
718 |
719 | @override
720 | @optionalTypeArgs
721 | Result maybeMap({
722 | Result initial(Initial value),
723 | Result detailsLoading(RecipesLoading value),
724 | Result detailsLoaded(RecipesLoaded value),
725 | Result detailsError(RecipesError value),
726 | @required Result orElse(),
727 | }) {
728 | assert(orElse != null);
729 | if (detailsError != null) {
730 | return detailsError(this);
731 | }
732 | return orElse();
733 | }
734 | }
735 |
736 | abstract class RecipesError implements RecipeState {
737 | const factory RecipesError({@required ServerError serverError}) =
738 | _$RecipesError;
739 |
740 | ServerError get serverError;
741 | $RecipesErrorCopyWith get copyWith;
742 | }
743 |
--------------------------------------------------------------------------------
/lib/ui/screens/recipe/bloc/events.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class RecipeEvent with _$RecipeEvent {
5 | const factory RecipeEvent.getDetails({@required dynamic recipeId}) = GetDetails;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/ui/screens/recipe/bloc/states.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class RecipeState with _$RecipeState {
5 | const factory RecipeState.initial() = Initial;
6 |
7 | const factory RecipeState.detailsLoading() = RecipesLoading;
8 |
9 | const factory RecipeState.detailsLoaded({@required Recipe recipe}) =
10 | RecipesLoaded;
11 |
12 | const factory RecipeState.detailsError({@required ServerError serverError}) =
13 | RecipesError;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/ui/screens/recipe/recipe.dart:
--------------------------------------------------------------------------------
1 | import 'package:cached_network_image/cached_network_image.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_bloc/flutter_bloc.dart';
5 | import 'package:recipes/services/hive.dart';
6 | import 'package:recipes/ui/screens/category/category.dart';
7 |
8 | import '../../../config/constants.dart';
9 | import '../../../models/recipes/recipe.dart';
10 | import '../../../ui/screens/video.dart';
11 | import 'bloc/bloc.dart';
12 |
13 | class RecipeScreen extends StatefulWidget {
14 | final recipeId;
15 |
16 | const RecipeScreen({Key key, @required this.recipeId}) : super(key: key);
17 |
18 | @override
19 | _RecipeScreenState createState() => _RecipeScreenState();
20 | }
21 |
22 | class _RecipeScreenState extends State {
23 | final _bloc = RecipeBloc();
24 |
25 | Recipe _recipe;
26 |
27 | bool _isFavorite = false;
28 |
29 | void _tapCategory(String categoryName) {
30 | Navigator.push(
31 | context,
32 | CupertinoPageRoute(
33 | builder: (_) => CategoryScreen(
34 | categoryName: categoryName,
35 | ),
36 | ),
37 | );
38 | }
39 |
40 | void _tapFavorite() {
41 | setState(() {
42 | _isFavorite = !_isFavorite;
43 | });
44 | if (_isFavorite)
45 | AppHive.instance.insert(_recipe);
46 | else
47 | AppHive.instance.delete(_recipe);
48 | }
49 |
50 | void _watchVideo(videoUrl) {
51 | Navigator.push(
52 | context,
53 | CupertinoPageRoute(builder: (_) => VideoScreen(videoUrl: videoUrl)),
54 | );
55 | }
56 |
57 | @override
58 | void initState() {
59 | super.initState();
60 | _isFavorite = AppHive.instance.isExist(widget.recipeId);
61 |
62 | _bloc
63 | ..add(RecipeEvent.getDetails(recipeId: widget.recipeId))
64 | ..listen((state) {
65 | state.maybeWhen(
66 | detailsLoaded: (recipe) {
67 | _recipe = recipe;
68 | },
69 | orElse: () {},
70 | );
71 | });
72 | }
73 |
74 | @override
75 | Widget build(BuildContext context) => Scaffold(
76 | body: BlocBuilder(
77 | bloc: _bloc,
78 | builder: (_, state) => state.maybeWhen(
79 | detailsLoading: () => Center(
80 | child: CircularProgressIndicator(),
81 | ),
82 | detailsLoaded: (recipe) => Stack(
83 | children: [
84 | CachedNetworkImage(
85 | imageUrl: recipe.image,
86 | fit: BoxFit.cover,
87 | ),
88 | CustomScrollView(
89 | slivers: [
90 | SliverAppBar(
91 | elevation: 0,
92 | expandedHeight: 250,
93 | backgroundColor: Colors.transparent,
94 | leading: Align(
95 | child: InkWell(
96 | onTap: () {
97 | Navigator.pop(context);
98 | },
99 | child: Container(
100 | padding: const EdgeInsets.all(10),
101 | decoration: BoxDecoration(
102 | shape: BoxShape.circle,
103 | color: Colors.white,
104 | ),
105 | child: Icon(
106 | Icons.arrow_back_ios,
107 | color: Theme.of(context).accentColor,
108 | ),
109 | ),
110 | ),
111 | ),
112 | actions: [
113 | InkWell(
114 | onTap: _tapFavorite,
115 | child: Container(
116 | padding: const EdgeInsets.all(10),
117 | decoration: BoxDecoration(
118 | shape: BoxShape.circle,
119 | color: Colors.white,
120 | ),
121 | child: Icon(
122 | _isFavorite
123 | ? Icons.favorite
124 | : Icons.favorite_border,
125 | color: Theme.of(context).accentColor,
126 | ),
127 | ),
128 | ),
129 | const SizedBox(width: 10),
130 | ],
131 | ),
132 | SliverToBoxAdapter(
133 | child: Container(
134 | padding: const EdgeInsets.symmetric(horizontal: 20),
135 | decoration: BoxDecoration(
136 | color: Colors.white,
137 | borderRadius: BorderRadius.vertical(
138 | top: Radius.circular(20),
139 | ),
140 | ),
141 | child: Column(
142 | crossAxisAlignment: CrossAxisAlignment.start,
143 | children: [
144 | const SizedBox(height: 20),
145 | Center(
146 | child: Container(
147 | width: 100,
148 | height: 5,
149 | decoration: BoxDecoration(
150 | color: Colors.grey[300],
151 | borderRadius: BorderRadius.circular(20),
152 | ),
153 | ),
154 | ),
155 | const SizedBox(height: 25),
156 | Row(
157 | children: [
158 | Expanded(
159 | child: Text(
160 | recipe.title,
161 | style: TextStyle(
162 | color: Colors.black,
163 | fontSize: 25,
164 | fontWeight: FontWeight.bold,
165 | ),
166 | ),
167 | ),
168 | const SizedBox(width: 10),
169 | recipe.video?.isNotEmpty ?? false
170 | ? Container(
171 | decoration: BoxDecoration(
172 | shape: BoxShape.circle,
173 | color: Colors.grey[100],
174 | ),
175 | child: IconButton(
176 | onPressed: () {
177 | _watchVideo(recipe.video);
178 | },
179 | icon: Icon(Icons.video_library),
180 | tooltip: 'watch video',
181 | ),
182 | )
183 | : const SizedBox(),
184 | ],
185 | ),
186 | InkWell(
187 | onTap: () {
188 | _tapCategory(recipe.category);
189 | },
190 | child: Text(
191 | recipe.category.toLowerCase(),
192 | style: TextStyle(
193 | color: Theme.of(context).accentColor,
194 | fontSize: 12.5,
195 | fontWeight: FontWeight.w900,
196 | ),
197 | ),
198 | ),
199 | const SizedBox(height: 25),
200 | Text(
201 | 'Ingredients',
202 | style: TextStyle(
203 | color: Colors.black,
204 | fontSize: 18,
205 | fontWeight: FontWeight.w600,
206 | ),
207 | ),
208 | ..._getIngredients(recipe),
209 | const SizedBox(height: 25),
210 | Text(
211 | 'Instructions',
212 | style: TextStyle(
213 | color: Colors.black,
214 | fontSize: 18,
215 | fontWeight: FontWeight.w600,
216 | ),
217 | ),
218 | const SizedBox(height: 5),
219 | Text(
220 | recipe.instructions,
221 | style: TextStyle(
222 | color: Colors.grey[800],
223 | wordSpacing: 2.5,
224 | height: 1.5,
225 | ),
226 | ),
227 | const SizedBox(height: 25),
228 | ],
229 | ),
230 | ),
231 | ),
232 | ],
233 | ),
234 | ],
235 | ),
236 | orElse: () => const SizedBox(),
237 | ),
238 | ),
239 | );
240 |
241 | List _getIngredients(Recipe recipe) => List.generate(
242 | 20,
243 | (index) {
244 | String ingredient = recipe.toJson()['strIngredient$index'];
245 | String measure = recipe.toJson()['strMeasure$index'];
246 | return (ingredient != null && ingredient.isNotEmpty)
247 | ? ListTile(
248 | title: Text('$measure $ingredient'),
249 | leading: Container(
250 | height: 40,
251 | width: 40,
252 | padding: const EdgeInsets.all(5),
253 | decoration: BoxDecoration(
254 | color: Colors.grey[100],
255 | shape: BoxShape.circle,
256 | ),
257 | child: CachedNetworkImage(
258 | imageUrl:
259 | '${AppConstants.HOST}images/ingredients/$ingredient-Small.png',
260 | fit: BoxFit.cover,
261 | ),
262 | ),
263 | )
264 | : const SizedBox();
265 | },
266 | ).toList();
267 |
268 | @override
269 | void dispose() {
270 | _bloc.close();
271 | super.dispose();
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/lib/ui/screens/search/bloc/bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 |
5 | import '../../../../models/recipes/recipes.dart';
6 | import '../../../../models/server_error.dart';
7 | import '../../../../services/network.dart';
8 |
9 | part 'bloc.freezed.dart';
10 |
11 | part 'events.dart';
12 |
13 | part 'states.dart';
14 |
15 | class SearchBloc extends Bloc {
16 | final _appNetwork = AppNetwork.instance;
17 |
18 | @override
19 | SearchState get initialState => SearchState.initial();
20 |
21 | @override
22 | Stream mapEventToState(SearchEvent event) async* {
23 | yield* event.when(searchRecipes: _searchRecipes);
24 | }
25 |
26 | Stream _searchRecipes(String query) async* {
27 | yield SearchState.loading();
28 | final response = await _appNetwork.get('search.php?s=$query');
29 | yield* response.fold(
30 | (error) async* {
31 | yield SearchState.error(serverError: error);
32 | },
33 | (json) async* {
34 | final recipes = Recipes.fromJson(json).items ?? [];
35 | if (recipes.isEmpty)
36 | yield SearchState.error(
37 | serverError: ServerError(message: "Empty recipes!"));
38 | else
39 | yield SearchState.loaded(recipes: Recipes.fromJson(json));
40 | },
41 | );
42 | }
43 |
44 | @override
45 | Future close() {
46 | return super.close();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/screens/search/bloc/bloc.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: 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
3 |
4 | part of 'bloc.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 |
12 | class _$SearchEventTearOff {
13 | const _$SearchEventTearOff();
14 |
15 | // ignore: unused_element
16 | SearchRecipes searchRecipes({@required String query}) {
17 | return SearchRecipes(
18 | query: query,
19 | );
20 | }
21 | }
22 |
23 | // ignore: unused_element
24 | const $SearchEvent = _$SearchEventTearOff();
25 |
26 | mixin _$SearchEvent {
27 | String get query;
28 |
29 | @optionalTypeArgs
30 | Result when({
31 | @required Result searchRecipes(String query),
32 | });
33 | @optionalTypeArgs
34 | Result maybeWhen({
35 | Result searchRecipes(String query),
36 | @required Result orElse(),
37 | });
38 | @optionalTypeArgs
39 | Result map({
40 | @required Result searchRecipes(SearchRecipes value),
41 | });
42 | @optionalTypeArgs
43 | Result maybeMap({
44 | Result searchRecipes(SearchRecipes value),
45 | @required Result orElse(),
46 | });
47 |
48 | $SearchEventCopyWith get copyWith;
49 | }
50 |
51 | abstract class $SearchEventCopyWith<$Res> {
52 | factory $SearchEventCopyWith(
53 | SearchEvent value, $Res Function(SearchEvent) then) =
54 | _$SearchEventCopyWithImpl<$Res>;
55 | $Res call({String query});
56 | }
57 |
58 | class _$SearchEventCopyWithImpl<$Res> implements $SearchEventCopyWith<$Res> {
59 | _$SearchEventCopyWithImpl(this._value, this._then);
60 |
61 | final SearchEvent _value;
62 | // ignore: unused_field
63 | final $Res Function(SearchEvent) _then;
64 |
65 | @override
66 | $Res call({
67 | Object query = freezed,
68 | }) {
69 | return _then(_value.copyWith(
70 | query: query == freezed ? _value.query : query as String,
71 | ));
72 | }
73 | }
74 |
75 | abstract class $SearchRecipesCopyWith<$Res>
76 | implements $SearchEventCopyWith<$Res> {
77 | factory $SearchRecipesCopyWith(
78 | SearchRecipes value, $Res Function(SearchRecipes) then) =
79 | _$SearchRecipesCopyWithImpl<$Res>;
80 | @override
81 | $Res call({String query});
82 | }
83 |
84 | class _$SearchRecipesCopyWithImpl<$Res> extends _$SearchEventCopyWithImpl<$Res>
85 | implements $SearchRecipesCopyWith<$Res> {
86 | _$SearchRecipesCopyWithImpl(
87 | SearchRecipes _value, $Res Function(SearchRecipes) _then)
88 | : super(_value, (v) => _then(v as SearchRecipes));
89 |
90 | @override
91 | SearchRecipes get _value => super._value as SearchRecipes;
92 |
93 | @override
94 | $Res call({
95 | Object query = freezed,
96 | }) {
97 | return _then(SearchRecipes(
98 | query: query == freezed ? _value.query : query as String,
99 | ));
100 | }
101 | }
102 |
103 | class _$SearchRecipes with DiagnosticableTreeMixin implements SearchRecipes {
104 | const _$SearchRecipes({@required this.query}) : assert(query != null);
105 |
106 | @override
107 | final String query;
108 |
109 | @override
110 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
111 | return 'SearchEvent.searchRecipes(query: $query)';
112 | }
113 |
114 | @override
115 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
116 | super.debugFillProperties(properties);
117 | properties
118 | ..add(DiagnosticsProperty('type', 'SearchEvent.searchRecipes'))
119 | ..add(DiagnosticsProperty('query', query));
120 | }
121 |
122 | @override
123 | bool operator ==(dynamic other) {
124 | return identical(this, other) ||
125 | (other is SearchRecipes &&
126 | (identical(other.query, query) ||
127 | const DeepCollectionEquality().equals(other.query, query)));
128 | }
129 |
130 | @override
131 | int get hashCode =>
132 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(query);
133 |
134 | @override
135 | $SearchRecipesCopyWith get copyWith =>
136 | _$SearchRecipesCopyWithImpl(this, _$identity);
137 |
138 | @override
139 | @optionalTypeArgs
140 | Result when({
141 | @required Result searchRecipes(String query),
142 | }) {
143 | assert(searchRecipes != null);
144 | return searchRecipes(query);
145 | }
146 |
147 | @override
148 | @optionalTypeArgs
149 | Result maybeWhen({
150 | Result searchRecipes(String query),
151 | @required Result orElse(),
152 | }) {
153 | assert(orElse != null);
154 | if (searchRecipes != null) {
155 | return searchRecipes(query);
156 | }
157 | return orElse();
158 | }
159 |
160 | @override
161 | @optionalTypeArgs
162 | Result map({
163 | @required Result searchRecipes(SearchRecipes value),
164 | }) {
165 | assert(searchRecipes != null);
166 | return searchRecipes(this);
167 | }
168 |
169 | @override
170 | @optionalTypeArgs
171 | Result maybeMap({
172 | Result searchRecipes(SearchRecipes value),
173 | @required Result orElse(),
174 | }) {
175 | assert(orElse != null);
176 | if (searchRecipes != null) {
177 | return searchRecipes(this);
178 | }
179 | return orElse();
180 | }
181 | }
182 |
183 | abstract class SearchRecipes implements SearchEvent {
184 | const factory SearchRecipes({@required String query}) = _$SearchRecipes;
185 |
186 | @override
187 | String get query;
188 | @override
189 | $SearchRecipesCopyWith get copyWith;
190 | }
191 |
192 | class _$SearchStateTearOff {
193 | const _$SearchStateTearOff();
194 |
195 | // ignore: unused_element
196 | Initial initial() {
197 | return const Initial();
198 | }
199 |
200 | // ignore: unused_element
201 | Loading loading() {
202 | return const Loading();
203 | }
204 |
205 | // ignore: unused_element
206 | Loaded loaded({@required Recipes recipes}) {
207 | return Loaded(
208 | recipes: recipes,
209 | );
210 | }
211 |
212 | // ignore: unused_element
213 | Error error({@required ServerError serverError}) {
214 | return Error(
215 | serverError: serverError,
216 | );
217 | }
218 | }
219 |
220 | // ignore: unused_element
221 | const $SearchState = _$SearchStateTearOff();
222 |
223 | mixin _$SearchState {
224 | @optionalTypeArgs
225 | Result when({
226 | @required Result initial(),
227 | @required Result loading(),
228 | @required Result loaded(Recipes recipes),
229 | @required Result error(ServerError serverError),
230 | });
231 | @optionalTypeArgs
232 | Result maybeWhen({
233 | Result initial(),
234 | Result loading(),
235 | Result loaded(Recipes recipes),
236 | Result error(ServerError serverError),
237 | @required Result orElse(),
238 | });
239 | @optionalTypeArgs
240 | Result map({
241 | @required Result initial(Initial value),
242 | @required Result loading(Loading value),
243 | @required Result loaded(Loaded value),
244 | @required Result error(Error value),
245 | });
246 | @optionalTypeArgs
247 | Result maybeMap({
248 | Result initial(Initial value),
249 | Result loading(Loading value),
250 | Result loaded(Loaded value),
251 | Result error(Error value),
252 | @required Result orElse(),
253 | });
254 | }
255 |
256 | abstract class $SearchStateCopyWith<$Res> {
257 | factory $SearchStateCopyWith(
258 | SearchState value, $Res Function(SearchState) then) =
259 | _$SearchStateCopyWithImpl<$Res>;
260 | }
261 |
262 | class _$SearchStateCopyWithImpl<$Res> implements $SearchStateCopyWith<$Res> {
263 | _$SearchStateCopyWithImpl(this._value, this._then);
264 |
265 | final SearchState _value;
266 | // ignore: unused_field
267 | final $Res Function(SearchState) _then;
268 | }
269 |
270 | abstract class $InitialCopyWith<$Res> {
271 | factory $InitialCopyWith(Initial value, $Res Function(Initial) then) =
272 | _$InitialCopyWithImpl<$Res>;
273 | }
274 |
275 | class _$InitialCopyWithImpl<$Res> extends _$SearchStateCopyWithImpl<$Res>
276 | implements $InitialCopyWith<$Res> {
277 | _$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then)
278 | : super(_value, (v) => _then(v as Initial));
279 |
280 | @override
281 | Initial get _value => super._value as Initial;
282 | }
283 |
284 | class _$Initial with DiagnosticableTreeMixin implements Initial {
285 | const _$Initial();
286 |
287 | @override
288 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
289 | return 'SearchState.initial()';
290 | }
291 |
292 | @override
293 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
294 | super.debugFillProperties(properties);
295 | properties..add(DiagnosticsProperty('type', 'SearchState.initial'));
296 | }
297 |
298 | @override
299 | bool operator ==(dynamic other) {
300 | return identical(this, other) || (other is Initial);
301 | }
302 |
303 | @override
304 | int get hashCode => runtimeType.hashCode;
305 |
306 | @override
307 | @optionalTypeArgs
308 | Result when({
309 | @required Result initial(),
310 | @required Result loading(),
311 | @required Result loaded(Recipes recipes),
312 | @required Result error(ServerError serverError),
313 | }) {
314 | assert(initial != null);
315 | assert(loading != null);
316 | assert(loaded != null);
317 | assert(error != null);
318 | return initial();
319 | }
320 |
321 | @override
322 | @optionalTypeArgs
323 | Result maybeWhen({
324 | Result initial(),
325 | Result loading(),
326 | Result loaded(Recipes recipes),
327 | Result error(ServerError serverError),
328 | @required Result orElse(),
329 | }) {
330 | assert(orElse != null);
331 | if (initial != null) {
332 | return initial();
333 | }
334 | return orElse();
335 | }
336 |
337 | @override
338 | @optionalTypeArgs
339 | Result map({
340 | @required Result initial(Initial value),
341 | @required Result loading(Loading value),
342 | @required Result loaded(Loaded value),
343 | @required Result error(Error value),
344 | }) {
345 | assert(initial != null);
346 | assert(loading != null);
347 | assert(loaded != null);
348 | assert(error != null);
349 | return initial(this);
350 | }
351 |
352 | @override
353 | @optionalTypeArgs
354 | Result maybeMap({
355 | Result initial(Initial value),
356 | Result loading(Loading value),
357 | Result loaded(Loaded value),
358 | Result error(Error value),
359 | @required Result orElse(),
360 | }) {
361 | assert(orElse != null);
362 | if (initial != null) {
363 | return initial(this);
364 | }
365 | return orElse();
366 | }
367 | }
368 |
369 | abstract class Initial implements SearchState {
370 | const factory Initial() = _$Initial;
371 | }
372 |
373 | abstract class $LoadingCopyWith<$Res> {
374 | factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) =
375 | _$LoadingCopyWithImpl<$Res>;
376 | }
377 |
378 | class _$LoadingCopyWithImpl<$Res> extends _$SearchStateCopyWithImpl<$Res>
379 | implements $LoadingCopyWith<$Res> {
380 | _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then)
381 | : super(_value, (v) => _then(v as Loading));
382 |
383 | @override
384 | Loading get _value => super._value as Loading;
385 | }
386 |
387 | class _$Loading with DiagnosticableTreeMixin implements Loading {
388 | const _$Loading();
389 |
390 | @override
391 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
392 | return 'SearchState.loading()';
393 | }
394 |
395 | @override
396 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
397 | super.debugFillProperties(properties);
398 | properties..add(DiagnosticsProperty('type', 'SearchState.loading'));
399 | }
400 |
401 | @override
402 | bool operator ==(dynamic other) {
403 | return identical(this, other) || (other is Loading);
404 | }
405 |
406 | @override
407 | int get hashCode => runtimeType.hashCode;
408 |
409 | @override
410 | @optionalTypeArgs
411 | Result when({
412 | @required Result initial(),
413 | @required Result loading(),
414 | @required Result loaded(Recipes recipes),
415 | @required Result error(ServerError serverError),
416 | }) {
417 | assert(initial != null);
418 | assert(loading != null);
419 | assert(loaded != null);
420 | assert(error != null);
421 | return loading();
422 | }
423 |
424 | @override
425 | @optionalTypeArgs
426 | Result maybeWhen({
427 | Result initial(),
428 | Result loading(),
429 | Result loaded(Recipes recipes),
430 | Result error(ServerError serverError),
431 | @required Result orElse(),
432 | }) {
433 | assert(orElse != null);
434 | if (loading != null) {
435 | return loading();
436 | }
437 | return orElse();
438 | }
439 |
440 | @override
441 | @optionalTypeArgs
442 | Result map({
443 | @required Result initial(Initial value),
444 | @required Result loading(Loading value),
445 | @required Result loaded(Loaded value),
446 | @required Result error(Error value),
447 | }) {
448 | assert(initial != null);
449 | assert(loading != null);
450 | assert(loaded != null);
451 | assert(error != null);
452 | return loading(this);
453 | }
454 |
455 | @override
456 | @optionalTypeArgs
457 | Result maybeMap({
458 | Result initial(Initial value),
459 | Result loading(Loading value),
460 | Result loaded(Loaded value),
461 | Result error(Error value),
462 | @required Result orElse(),
463 | }) {
464 | assert(orElse != null);
465 | if (loading != null) {
466 | return loading(this);
467 | }
468 | return orElse();
469 | }
470 | }
471 |
472 | abstract class Loading implements SearchState {
473 | const factory Loading() = _$Loading;
474 | }
475 |
476 | abstract class $LoadedCopyWith<$Res> {
477 | factory $LoadedCopyWith(Loaded value, $Res Function(Loaded) then) =
478 | _$LoadedCopyWithImpl<$Res>;
479 | $Res call({Recipes recipes});
480 | }
481 |
482 | class _$LoadedCopyWithImpl<$Res> extends _$SearchStateCopyWithImpl<$Res>
483 | implements $LoadedCopyWith<$Res> {
484 | _$LoadedCopyWithImpl(Loaded _value, $Res Function(Loaded) _then)
485 | : super(_value, (v) => _then(v as Loaded));
486 |
487 | @override
488 | Loaded get _value => super._value as Loaded;
489 |
490 | @override
491 | $Res call({
492 | Object recipes = freezed,
493 | }) {
494 | return _then(Loaded(
495 | recipes: recipes == freezed ? _value.recipes : recipes as Recipes,
496 | ));
497 | }
498 | }
499 |
500 | class _$Loaded with DiagnosticableTreeMixin implements Loaded {
501 | const _$Loaded({@required this.recipes}) : assert(recipes != null);
502 |
503 | @override
504 | final Recipes recipes;
505 |
506 | @override
507 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
508 | return 'SearchState.loaded(recipes: $recipes)';
509 | }
510 |
511 | @override
512 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
513 | super.debugFillProperties(properties);
514 | properties
515 | ..add(DiagnosticsProperty('type', 'SearchState.loaded'))
516 | ..add(DiagnosticsProperty('recipes', recipes));
517 | }
518 |
519 | @override
520 | bool operator ==(dynamic other) {
521 | return identical(this, other) ||
522 | (other is Loaded &&
523 | (identical(other.recipes, recipes) ||
524 | const DeepCollectionEquality().equals(other.recipes, recipes)));
525 | }
526 |
527 | @override
528 | int get hashCode =>
529 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(recipes);
530 |
531 | @override
532 | $LoadedCopyWith get copyWith =>
533 | _$LoadedCopyWithImpl(this, _$identity);
534 |
535 | @override
536 | @optionalTypeArgs
537 | Result when({
538 | @required Result initial(),
539 | @required Result loading(),
540 | @required Result loaded(Recipes recipes),
541 | @required Result error(ServerError serverError),
542 | }) {
543 | assert(initial != null);
544 | assert(loading != null);
545 | assert(loaded != null);
546 | assert(error != null);
547 | return loaded(recipes);
548 | }
549 |
550 | @override
551 | @optionalTypeArgs
552 | Result maybeWhen({
553 | Result initial(),
554 | Result loading(),
555 | Result loaded(Recipes recipes),
556 | Result error(ServerError serverError),
557 | @required Result orElse(),
558 | }) {
559 | assert(orElse != null);
560 | if (loaded != null) {
561 | return loaded(recipes);
562 | }
563 | return orElse();
564 | }
565 |
566 | @override
567 | @optionalTypeArgs
568 | Result map({
569 | @required Result initial(Initial value),
570 | @required Result loading(Loading value),
571 | @required Result loaded(Loaded value),
572 | @required Result error(Error value),
573 | }) {
574 | assert(initial != null);
575 | assert(loading != null);
576 | assert(loaded != null);
577 | assert(error != null);
578 | return loaded(this);
579 | }
580 |
581 | @override
582 | @optionalTypeArgs
583 | Result maybeMap({
584 | Result initial(Initial value),
585 | Result loading(Loading value),
586 | Result loaded(Loaded value),
587 | Result error(Error value),
588 | @required Result orElse(),
589 | }) {
590 | assert(orElse != null);
591 | if (loaded != null) {
592 | return loaded(this);
593 | }
594 | return orElse();
595 | }
596 | }
597 |
598 | abstract class Loaded implements SearchState {
599 | const factory Loaded({@required Recipes recipes}) = _$Loaded;
600 |
601 | Recipes get recipes;
602 | $LoadedCopyWith get copyWith;
603 | }
604 |
605 | abstract class $ErrorCopyWith<$Res> {
606 | factory $ErrorCopyWith(Error value, $Res Function(Error) then) =
607 | _$ErrorCopyWithImpl<$Res>;
608 | $Res call({ServerError serverError});
609 | }
610 |
611 | class _$ErrorCopyWithImpl<$Res> extends _$SearchStateCopyWithImpl<$Res>
612 | implements $ErrorCopyWith<$Res> {
613 | _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then)
614 | : super(_value, (v) => _then(v as Error));
615 |
616 | @override
617 | Error get _value => super._value as Error;
618 |
619 | @override
620 | $Res call({
621 | Object serverError = freezed,
622 | }) {
623 | return _then(Error(
624 | serverError: serverError == freezed
625 | ? _value.serverError
626 | : serverError as ServerError,
627 | ));
628 | }
629 | }
630 |
631 | class _$Error with DiagnosticableTreeMixin implements Error {
632 | const _$Error({@required this.serverError}) : assert(serverError != null);
633 |
634 | @override
635 | final ServerError serverError;
636 |
637 | @override
638 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
639 | return 'SearchState.error(serverError: $serverError)';
640 | }
641 |
642 | @override
643 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
644 | super.debugFillProperties(properties);
645 | properties
646 | ..add(DiagnosticsProperty('type', 'SearchState.error'))
647 | ..add(DiagnosticsProperty('serverError', serverError));
648 | }
649 |
650 | @override
651 | bool operator ==(dynamic other) {
652 | return identical(this, other) ||
653 | (other is Error &&
654 | (identical(other.serverError, serverError) ||
655 | const DeepCollectionEquality()
656 | .equals(other.serverError, serverError)));
657 | }
658 |
659 | @override
660 | int get hashCode =>
661 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(serverError);
662 |
663 | @override
664 | $ErrorCopyWith get copyWith =>
665 | _$ErrorCopyWithImpl(this, _$identity);
666 |
667 | @override
668 | @optionalTypeArgs
669 | Result when({
670 | @required Result initial(),
671 | @required Result loading(),
672 | @required Result loaded(Recipes recipes),
673 | @required Result error(ServerError serverError),
674 | }) {
675 | assert(initial != null);
676 | assert(loading != null);
677 | assert(loaded != null);
678 | assert(error != null);
679 | return error(serverError);
680 | }
681 |
682 | @override
683 | @optionalTypeArgs
684 | Result maybeWhen({
685 | Result initial(),
686 | Result loading(),
687 | Result loaded(Recipes recipes),
688 | Result error(ServerError serverError),
689 | @required Result orElse(),
690 | }) {
691 | assert(orElse != null);
692 | if (error != null) {
693 | return error(serverError);
694 | }
695 | return orElse();
696 | }
697 |
698 | @override
699 | @optionalTypeArgs
700 | Result map({
701 | @required Result initial(Initial value),
702 | @required Result loading(Loading value),
703 | @required Result loaded(Loaded value),
704 | @required Result error(Error value),
705 | }) {
706 | assert(initial != null);
707 | assert(loading != null);
708 | assert(loaded != null);
709 | assert(error != null);
710 | return error(this);
711 | }
712 |
713 | @override
714 | @optionalTypeArgs
715 | Result maybeMap({
716 | Result initial(Initial value),
717 | Result loading(Loading value),
718 | Result loaded(Loaded value),
719 | Result error(Error value),
720 | @required Result orElse(),
721 | }) {
722 | assert(orElse != null);
723 | if (error != null) {
724 | return error(this);
725 | }
726 | return orElse();
727 | }
728 | }
729 |
730 | abstract class Error implements SearchState {
731 | const factory Error({@required ServerError serverError}) = _$Error;
732 |
733 | ServerError get serverError;
734 | $ErrorCopyWith get copyWith;
735 | }
736 |
--------------------------------------------------------------------------------
/lib/ui/screens/search/bloc/events.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class SearchEvent with _$SearchEvent {
5 | const factory SearchEvent.searchRecipes({@required String query}) =
6 | SearchRecipes;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/ui/screens/search/bloc/states.dart:
--------------------------------------------------------------------------------
1 | part of 'bloc.dart';
2 |
3 | @freezed
4 | abstract class SearchState with _$SearchState {
5 | const factory SearchState.initial() = Initial;
6 |
7 | const factory SearchState.loading() = Loading;
8 |
9 | const factory SearchState.loaded({@required Recipes recipes}) = Loaded;
10 |
11 | const factory SearchState.error({@required ServerError serverError}) = Error;
12 | }
13 |
--------------------------------------------------------------------------------
/lib/ui/screens/search/search.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:recipes/ui/items/recipe.dart';
4 |
5 | import 'bloc/bloc.dart';
6 |
7 | class SearchScreen extends SearchDelegate {
8 | final _bloc = SearchBloc();
9 |
10 | @override
11 | List buildActions(BuildContext context) => [
12 | IconButton(
13 | icon: Icon(Icons.clear),
14 | onPressed: () {
15 | query = '';
16 | },
17 | ),
18 | ];
19 |
20 | @override
21 | Widget buildLeading(BuildContext context) => IconButton(
22 | onPressed: () {
23 | close(context, null);
24 | },
25 | icon: Icon(Icons.arrow_back_ios),
26 | );
27 |
28 | @override
29 | Widget buildResults(BuildContext context) =>
30 | BlocBuilder(
31 | bloc: _bloc..add(SearchEvent.searchRecipes(query: query)),
32 | builder: (_, state) => state.when(
33 | initial: () => const SizedBox(),
34 | loading: () => Center(
35 | child: CircularProgressIndicator(),
36 | ),
37 | loaded: (recipes) => ListView.builder(
38 | itemBuilder: (_, index) => RecipeItem(
39 | recipe: recipes.items[index],
40 | ),
41 | itemCount: recipes.items.length,
42 | ),
43 | error: (error) => Center(
44 | child: Column(
45 | mainAxisSize: MainAxisSize.min,
46 | children: [
47 | Icon(
48 | Icons.check_box_outline_blank,
49 | size: 75,
50 | color: Colors.grey[500],
51 | ),
52 | const SizedBox(height: 20),
53 | Text(
54 | 'RECIPES NOT FOUND',
55 | style: TextStyle(
56 | fontSize: 20,
57 | color: Colors.grey[500],
58 | ),
59 | ),
60 | ],
61 | ),
62 | ),
63 | ),
64 | );
65 |
66 | @override
67 | Widget buildSuggestions(BuildContext context) => const SizedBox();
68 |
69 | @override
70 | void close(BuildContext context, result) {
71 | _bloc.close();
72 | super.close(context, result);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/ui/screens/video.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:youtube_player_flutter/youtube_player_flutter.dart';
3 |
4 | class VideoScreen extends StatefulWidget {
5 | final String videoUrl;
6 |
7 | const VideoScreen({Key key, @required this.videoUrl}) : super(key: key);
8 |
9 | @override
10 | _VideoScreenState createState() => _VideoScreenState();
11 | }
12 |
13 | class _VideoScreenState extends State {
14 | @override
15 | Widget build(BuildContext context) => Scaffold(
16 | backgroundColor: Colors.black,
17 | appBar: AppBar(backgroundColor: Colors.black),
18 | body: Center(
19 | child: YoutubePlayer(
20 | controller: YoutubePlayerController(
21 | initialVideoId: YoutubePlayer.convertUrlToId(widget.videoUrl),
22 | ),
23 | ),
24 | ),
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "6.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "0.39.14"
18 | args:
19 | dependency: transitive
20 | description:
21 | name: args
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.6.0"
25 | async:
26 | dependency: transitive
27 | description:
28 | name: async
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.4.2"
32 | bloc:
33 | dependency: transitive
34 | description:
35 | name: bloc
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "4.0.0"
39 | boolean_selector:
40 | dependency: transitive
41 | description:
42 | name: boolean_selector
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "2.0.0"
46 | build:
47 | dependency: transitive
48 | description:
49 | name: build
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.3.0"
53 | build_config:
54 | dependency: transitive
55 | description:
56 | name: build_config
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.4.2"
60 | build_daemon:
61 | dependency: transitive
62 | description:
63 | name: build_daemon
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "2.1.4"
67 | build_resolvers:
68 | dependency: transitive
69 | description:
70 | name: build_resolvers
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "1.3.11"
74 | build_runner:
75 | dependency: "direct dev"
76 | description:
77 | name: build_runner
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.10.0"
81 | build_runner_core:
82 | dependency: transitive
83 | description:
84 | name: build_runner_core
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "5.2.0"
88 | built_collection:
89 | dependency: transitive
90 | description:
91 | name: built_collection
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "4.3.2"
95 | built_value:
96 | dependency: transitive
97 | description:
98 | name: built_value
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "7.1.0"
102 | cached_network_image:
103 | dependency: "direct main"
104 | description:
105 | name: cached_network_image
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "2.2.0+1"
109 | characters:
110 | dependency: transitive
111 | description:
112 | name: characters
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "1.0.0"
116 | charcode:
117 | dependency: transitive
118 | description:
119 | name: charcode
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "1.1.3"
123 | checked_yaml:
124 | dependency: transitive
125 | description:
126 | name: checked_yaml
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "1.0.2"
130 | cli_util:
131 | dependency: transitive
132 | description:
133 | name: cli_util
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "0.1.4"
137 | clock:
138 | dependency: transitive
139 | description:
140 | name: clock
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "1.0.1"
144 | code_builder:
145 | dependency: transitive
146 | description:
147 | name: code_builder
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "3.4.1"
151 | collection:
152 | dependency: transitive
153 | description:
154 | name: collection
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "1.14.13"
158 | convert:
159 | dependency: transitive
160 | description:
161 | name: convert
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "2.1.1"
165 | crypto:
166 | dependency: transitive
167 | description:
168 | name: crypto
169 | url: "https://pub.dartlang.org"
170 | source: hosted
171 | version: "2.1.5"
172 | csslib:
173 | dependency: transitive
174 | description:
175 | name: csslib
176 | url: "https://pub.dartlang.org"
177 | source: hosted
178 | version: "0.16.2"
179 | cupertino_icons:
180 | dependency: "direct main"
181 | description:
182 | name: cupertino_icons
183 | url: "https://pub.dartlang.org"
184 | source: hosted
185 | version: "0.1.3"
186 | dart_style:
187 | dependency: transitive
188 | description:
189 | name: dart_style
190 | url: "https://pub.dartlang.org"
191 | source: hosted
192 | version: "1.3.6"
193 | dartz:
194 | dependency: "direct main"
195 | description:
196 | name: dartz
197 | url: "https://pub.dartlang.org"
198 | source: hosted
199 | version: "0.9.1"
200 | dio:
201 | dependency: "direct main"
202 | description:
203 | name: dio
204 | url: "https://pub.dartlang.org"
205 | source: hosted
206 | version: "3.0.10"
207 | fake_async:
208 | dependency: transitive
209 | description:
210 | name: fake_async
211 | url: "https://pub.dartlang.org"
212 | source: hosted
213 | version: "1.1.0"
214 | file:
215 | dependency: transitive
216 | description:
217 | name: file
218 | url: "https://pub.dartlang.org"
219 | source: hosted
220 | version: "5.2.1"
221 | fixnum:
222 | dependency: transitive
223 | description:
224 | name: fixnum
225 | url: "https://pub.dartlang.org"
226 | source: hosted
227 | version: "0.10.11"
228 | flutter:
229 | dependency: "direct main"
230 | description: flutter
231 | source: sdk
232 | version: "0.0.0"
233 | flutter_bloc:
234 | dependency: "direct main"
235 | description:
236 | name: flutter_bloc
237 | url: "https://pub.dartlang.org"
238 | source: hosted
239 | version: "4.0.1"
240 | flutter_cache_manager:
241 | dependency: transitive
242 | description:
243 | name: flutter_cache_manager
244 | url: "https://pub.dartlang.org"
245 | source: hosted
246 | version: "1.4.2"
247 | flutter_inappwebview:
248 | dependency: transitive
249 | description:
250 | name: flutter_inappwebview
251 | url: "https://pub.dartlang.org"
252 | source: hosted
253 | version: "4.0.0+4"
254 | flutter_test:
255 | dependency: "direct dev"
256 | description: flutter
257 | source: sdk
258 | version: "0.0.0"
259 | freezed:
260 | dependency: "direct dev"
261 | description:
262 | name: freezed
263 | url: "https://pub.dartlang.org"
264 | source: hosted
265 | version: "0.11.6"
266 | freezed_annotation:
267 | dependency: "direct main"
268 | description:
269 | name: freezed_annotation
270 | url: "https://pub.dartlang.org"
271 | source: hosted
272 | version: "0.11.0+1"
273 | glob:
274 | dependency: transitive
275 | description:
276 | name: glob
277 | url: "https://pub.dartlang.org"
278 | source: hosted
279 | version: "1.2.0"
280 | google_fonts:
281 | dependency: "direct main"
282 | description:
283 | name: google_fonts
284 | url: "https://pub.dartlang.org"
285 | source: hosted
286 | version: "1.1.0"
287 | graphs:
288 | dependency: transitive
289 | description:
290 | name: graphs
291 | url: "https://pub.dartlang.org"
292 | source: hosted
293 | version: "0.2.0"
294 | hive:
295 | dependency: "direct main"
296 | description:
297 | name: hive
298 | url: "https://pub.dartlang.org"
299 | source: hosted
300 | version: "1.4.4"
301 | hive_flutter:
302 | dependency: "direct main"
303 | description:
304 | name: hive_flutter
305 | url: "https://pub.dartlang.org"
306 | source: hosted
307 | version: "0.3.1"
308 | hive_generator:
309 | dependency: "direct dev"
310 | description:
311 | name: hive_generator
312 | url: "https://pub.dartlang.org"
313 | source: hosted
314 | version: "0.5.2"
315 | html:
316 | dependency: transitive
317 | description:
318 | name: html
319 | url: "https://pub.dartlang.org"
320 | source: hosted
321 | version: "0.14.0+3"
322 | http:
323 | dependency: transitive
324 | description:
325 | name: http
326 | url: "https://pub.dartlang.org"
327 | source: hosted
328 | version: "0.12.2"
329 | http_multi_server:
330 | dependency: transitive
331 | description:
332 | name: http_multi_server
333 | url: "https://pub.dartlang.org"
334 | source: hosted
335 | version: "2.2.0"
336 | http_parser:
337 | dependency: transitive
338 | description:
339 | name: http_parser
340 | url: "https://pub.dartlang.org"
341 | source: hosted
342 | version: "3.1.4"
343 | intl:
344 | dependency: transitive
345 | description:
346 | name: intl
347 | url: "https://pub.dartlang.org"
348 | source: hosted
349 | version: "0.16.1"
350 | io:
351 | dependency: transitive
352 | description:
353 | name: io
354 | url: "https://pub.dartlang.org"
355 | source: hosted
356 | version: "0.3.4"
357 | js:
358 | dependency: transitive
359 | description:
360 | name: js
361 | url: "https://pub.dartlang.org"
362 | source: hosted
363 | version: "0.6.2"
364 | json_annotation:
365 | dependency: transitive
366 | description:
367 | name: json_annotation
368 | url: "https://pub.dartlang.org"
369 | source: hosted
370 | version: "3.0.1"
371 | json_serializable:
372 | dependency: "direct main"
373 | description:
374 | name: json_serializable
375 | url: "https://pub.dartlang.org"
376 | source: hosted
377 | version: "3.4.1"
378 | logging:
379 | dependency: transitive
380 | description:
381 | name: logging
382 | url: "https://pub.dartlang.org"
383 | source: hosted
384 | version: "0.11.4"
385 | matcher:
386 | dependency: transitive
387 | description:
388 | name: matcher
389 | url: "https://pub.dartlang.org"
390 | source: hosted
391 | version: "0.12.8"
392 | meta:
393 | dependency: transitive
394 | description:
395 | name: meta
396 | url: "https://pub.dartlang.org"
397 | source: hosted
398 | version: "1.1.8"
399 | mime:
400 | dependency: transitive
401 | description:
402 | name: mime
403 | url: "https://pub.dartlang.org"
404 | source: hosted
405 | version: "0.9.7"
406 | nested:
407 | dependency: transitive
408 | description:
409 | name: nested
410 | url: "https://pub.dartlang.org"
411 | source: hosted
412 | version: "0.0.4"
413 | node_interop:
414 | dependency: transitive
415 | description:
416 | name: node_interop
417 | url: "https://pub.dartlang.org"
418 | source: hosted
419 | version: "1.1.1"
420 | node_io:
421 | dependency: transitive
422 | description:
423 | name: node_io
424 | url: "https://pub.dartlang.org"
425 | source: hosted
426 | version: "1.1.1"
427 | package_config:
428 | dependency: transitive
429 | description:
430 | name: package_config
431 | url: "https://pub.dartlang.org"
432 | source: hosted
433 | version: "1.9.3"
434 | path:
435 | dependency: transitive
436 | description:
437 | name: path
438 | url: "https://pub.dartlang.org"
439 | source: hosted
440 | version: "1.7.0"
441 | path_provider:
442 | dependency: transitive
443 | description:
444 | name: path_provider
445 | url: "https://pub.dartlang.org"
446 | source: hosted
447 | version: "1.6.14"
448 | path_provider_linux:
449 | dependency: transitive
450 | description:
451 | name: path_provider_linux
452 | url: "https://pub.dartlang.org"
453 | source: hosted
454 | version: "0.0.1+2"
455 | path_provider_macos:
456 | dependency: transitive
457 | description:
458 | name: path_provider_macos
459 | url: "https://pub.dartlang.org"
460 | source: hosted
461 | version: "0.0.4+4"
462 | path_provider_platform_interface:
463 | dependency: transitive
464 | description:
465 | name: path_provider_platform_interface
466 | url: "https://pub.dartlang.org"
467 | source: hosted
468 | version: "1.0.3"
469 | pedantic:
470 | dependency: transitive
471 | description:
472 | name: pedantic
473 | url: "https://pub.dartlang.org"
474 | source: hosted
475 | version: "1.9.0"
476 | platform:
477 | dependency: transitive
478 | description:
479 | name: platform
480 | url: "https://pub.dartlang.org"
481 | source: hosted
482 | version: "2.2.1"
483 | plugin_platform_interface:
484 | dependency: transitive
485 | description:
486 | name: plugin_platform_interface
487 | url: "https://pub.dartlang.org"
488 | source: hosted
489 | version: "1.0.2"
490 | pool:
491 | dependency: transitive
492 | description:
493 | name: pool
494 | url: "https://pub.dartlang.org"
495 | source: hosted
496 | version: "1.4.0"
497 | process:
498 | dependency: transitive
499 | description:
500 | name: process
501 | url: "https://pub.dartlang.org"
502 | source: hosted
503 | version: "3.0.13"
504 | provider:
505 | dependency: transitive
506 | description:
507 | name: provider
508 | url: "https://pub.dartlang.org"
509 | source: hosted
510 | version: "4.3.2+2"
511 | pub_semver:
512 | dependency: transitive
513 | description:
514 | name: pub_semver
515 | url: "https://pub.dartlang.org"
516 | source: hosted
517 | version: "1.4.4"
518 | pubspec_parse:
519 | dependency: transitive
520 | description:
521 | name: pubspec_parse
522 | url: "https://pub.dartlang.org"
523 | source: hosted
524 | version: "0.1.5"
525 | quiver:
526 | dependency: transitive
527 | description:
528 | name: quiver
529 | url: "https://pub.dartlang.org"
530 | source: hosted
531 | version: "2.1.3"
532 | rxdart:
533 | dependency: transitive
534 | description:
535 | name: rxdart
536 | url: "https://pub.dartlang.org"
537 | source: hosted
538 | version: "0.24.1"
539 | shelf:
540 | dependency: transitive
541 | description:
542 | name: shelf
543 | url: "https://pub.dartlang.org"
544 | source: hosted
545 | version: "0.7.9"
546 | shelf_web_socket:
547 | dependency: transitive
548 | description:
549 | name: shelf_web_socket
550 | url: "https://pub.dartlang.org"
551 | source: hosted
552 | version: "0.2.3"
553 | sky_engine:
554 | dependency: transitive
555 | description: flutter
556 | source: sdk
557 | version: "0.0.99"
558 | source_gen:
559 | dependency: transitive
560 | description:
561 | name: source_gen
562 | url: "https://pub.dartlang.org"
563 | source: hosted
564 | version: "0.9.6"
565 | source_span:
566 | dependency: transitive
567 | description:
568 | name: source_span
569 | url: "https://pub.dartlang.org"
570 | source: hosted
571 | version: "1.7.0"
572 | sqflite:
573 | dependency: transitive
574 | description:
575 | name: sqflite
576 | url: "https://pub.dartlang.org"
577 | source: hosted
578 | version: "1.3.1+1"
579 | sqflite_common:
580 | dependency: transitive
581 | description:
582 | name: sqflite_common
583 | url: "https://pub.dartlang.org"
584 | source: hosted
585 | version: "1.0.2+1"
586 | stack_trace:
587 | dependency: transitive
588 | description:
589 | name: stack_trace
590 | url: "https://pub.dartlang.org"
591 | source: hosted
592 | version: "1.9.5"
593 | stream_channel:
594 | dependency: transitive
595 | description:
596 | name: stream_channel
597 | url: "https://pub.dartlang.org"
598 | source: hosted
599 | version: "2.0.0"
600 | stream_transform:
601 | dependency: transitive
602 | description:
603 | name: stream_transform
604 | url: "https://pub.dartlang.org"
605 | source: hosted
606 | version: "1.2.0"
607 | string_scanner:
608 | dependency: transitive
609 | description:
610 | name: string_scanner
611 | url: "https://pub.dartlang.org"
612 | source: hosted
613 | version: "1.0.5"
614 | synchronized:
615 | dependency: transitive
616 | description:
617 | name: synchronized
618 | url: "https://pub.dartlang.org"
619 | source: hosted
620 | version: "2.2.0+2"
621 | term_glyph:
622 | dependency: transitive
623 | description:
624 | name: term_glyph
625 | url: "https://pub.dartlang.org"
626 | source: hosted
627 | version: "1.1.0"
628 | test_api:
629 | dependency: transitive
630 | description:
631 | name: test_api
632 | url: "https://pub.dartlang.org"
633 | source: hosted
634 | version: "0.2.17"
635 | timing:
636 | dependency: transitive
637 | description:
638 | name: timing
639 | url: "https://pub.dartlang.org"
640 | source: hosted
641 | version: "0.1.1+2"
642 | typed_data:
643 | dependency: transitive
644 | description:
645 | name: typed_data
646 | url: "https://pub.dartlang.org"
647 | source: hosted
648 | version: "1.2.0"
649 | uuid:
650 | dependency: transitive
651 | description:
652 | name: uuid
653 | url: "https://pub.dartlang.org"
654 | source: hosted
655 | version: "2.2.2"
656 | vector_math:
657 | dependency: transitive
658 | description:
659 | name: vector_math
660 | url: "https://pub.dartlang.org"
661 | source: hosted
662 | version: "2.0.8"
663 | watcher:
664 | dependency: transitive
665 | description:
666 | name: watcher
667 | url: "https://pub.dartlang.org"
668 | source: hosted
669 | version: "0.9.7+15"
670 | web_socket_channel:
671 | dependency: transitive
672 | description:
673 | name: web_socket_channel
674 | url: "https://pub.dartlang.org"
675 | source: hosted
676 | version: "1.1.0"
677 | xdg_directories:
678 | dependency: transitive
679 | description:
680 | name: xdg_directories
681 | url: "https://pub.dartlang.org"
682 | source: hosted
683 | version: "0.1.0"
684 | yaml:
685 | dependency: transitive
686 | description:
687 | name: yaml
688 | url: "https://pub.dartlang.org"
689 | source: hosted
690 | version: "2.2.1"
691 | youtube_player_flutter:
692 | dependency: "direct main"
693 | description:
694 | name: youtube_player_flutter
695 | url: "https://pub.dartlang.org"
696 | source: hosted
697 | version: "7.0.0+7"
698 | sdks:
699 | dart: ">=2.9.0-14.0.dev <3.0.0"
700 | flutter: ">=1.17.0 <2.0.0"
701 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: recipes
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.6.0 <3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 |
27 |
28 | # The following adds the Cupertino Icons font to your application.
29 | # Use with the CupertinoIcons class for iOS style icons.
30 | cupertino_icons: ^0.1.3
31 | dio: ^3.0.10
32 | freezed_annotation:
33 | google_fonts: ^1.1.0
34 | flutter_bloc: ^4.0.0
35 | cached_network_image: ^2.2.0+1
36 | dartz: ^0.9.1
37 | json_serializable: ^3.4.1
38 | youtube_player_flutter: ^7.0.0+7
39 | hive: ^1.4.4
40 | hive_flutter: ^0.3.1
41 |
42 | dev_dependencies:
43 | flutter_test:
44 | sdk: flutter
45 | build_runner:
46 | freezed:
47 | hive_generator: ^0.5.1
48 |
49 | # For information on the generic Dart part of this file, see the
50 | # following page: https://dart.dev/tools/pub/pubspec
51 |
52 | # The following section is specific to Flutter.
53 | flutter:
54 |
55 | # The following line ensures that the Material Icons font is
56 | # included with your application, so that you can use the icons in
57 | # the material Icons class.
58 | uses-material-design: true
59 |
60 | # To add assets to your application, add an assets section, like this:
61 | # assets:
62 | # - images/a_dot_burr.jpeg
63 | # - images/a_dot_ham.jpeg
64 |
65 | # An image asset can refer to one or more resolution-specific "variants", see
66 | # https://flutter.dev/assets-and-images/#resolution-aware.
67 |
68 | # For details regarding adding assets from package dependencies, see
69 | # https://flutter.dev/assets-and-images/#from-packages
70 |
71 | # To add custom fonts to your application, add a fonts section here,
72 | # in this "flutter" section. Each entry in this list should have a
73 | # "family" key with the font family name, and a "fonts" key with a
74 | # list giving the asset and other descriptors for the font. For
75 | # example:
76 | # fonts:
77 | # - family: Schyler
78 | # fonts:
79 | # - asset: fonts/Schyler-Regular.ttf
80 | # - asset: fonts/Schyler-Italic.ttf
81 | # style: italic
82 | # - family: Trajan Pro
83 | # fonts:
84 | # - asset: fonts/TrajanPro.ttf
85 | # - asset: fonts/TrajanPro_Bold.ttf
86 | # weight: 700
87 | #
88 | # For details regarding fonts from package dependencies,
89 | # see https://flutter.dev/custom-fonts/#from-packages
90 |
--------------------------------------------------------------------------------
/screenshot/0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/screenshot/0.jpg
--------------------------------------------------------------------------------
/screenshot/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/screenshot/1.jpg
--------------------------------------------------------------------------------
/screenshot/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/screenshot/2.jpg
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:recipes/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeekAbdelouahed/Flutter-Recipes/2d07e23b58ce8a3191d0ab1e7a87fcfb7e74b4ff/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | recipes
18 |
19 |
20 |
21 |
24 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "recipes",
3 | "short_name": "recipes",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------