├── .gitignore ├── .metadata ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md ├── android ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── de │ │ │ └── feuerbergsoftware │ │ │ └── advancedflutterexample │ │ │ └── MainActivity.java │ │ └── res │ │ ├── drawable │ │ └── launch_background.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── launcher_icon.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── launcher_icon.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── launcher_icon.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── launcher_icon.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── launcher_icon.png │ │ └── values │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── json │ └── solarsystem.json └── logo_fae.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── 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 │ └── main.m ├── lib ├── DefaultAppBar.dart ├── ExampleList.dart ├── Loading.dart ├── basic │ ├── BlocProvider.dart │ └── GlobalBloc.dart ├── examples │ ├── filterList │ │ ├── Car.dart │ │ ├── Example1.dart │ │ └── README.md │ ├── globalMessage │ │ ├── Example6.dart │ │ ├── GlobalMessageWrapper.dart │ │ ├── Message.dart │ │ ├── MessageBloc.dart │ │ └── README.md │ ├── managingFavoritesInSharedPreferences │ │ ├── Example3.dart │ │ └── README.md │ ├── managingInputsWithinModalBottomsheet │ │ ├── Example4.dart │ │ └── README.md │ ├── readingJsonFile │ │ ├── Example2.dart │ │ ├── Planet.dart │ │ ├── Planet.g.dart │ │ └── README.md │ └── shoppingCart │ │ ├── Example5.dart │ │ ├── Product.dart │ │ ├── README.md │ │ ├── ShoppingCart.dart │ │ ├── ShoppingCartAppBarIcon.dart │ │ ├── ShoppingCartBloc.dart │ │ └── ShoppingCartScreen.dart ├── generated │ └── i18n.dart └── main.dart ├── pubspec.yaml ├── res └── values │ └── strings_en.arb └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Custom 2 | assets/cfg 3 | main_live.dart 4 | key.properties 5 | android/app/build.gradle 6 | 7 | # Miscellaneous 8 | *.class 9 | *.lock 10 | *.log 11 | *.pyc 12 | *.swp 13 | .DS_Store 14 | .atom/ 15 | .buildlog/ 16 | .history 17 | .svn/ 18 | 19 | # IntelliJ related 20 | *.iml 21 | *.ipr 22 | *.iws 23 | .idea/ 24 | 25 | # Visual Studio Code related 26 | .vscode/ 27 | 28 | # Flutter/Dart/Pub related 29 | **/doc/api/ 30 | .dart_tool/ 31 | .flutter-plugins 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | build/ 36 | 37 | # Android related 38 | **/android/**/gradle-wrapper.jar 39 | **/android/.gradle 40 | **/android/captures/ 41 | **/android/gradlew 42 | **/android/gradlew.bat 43 | **/android/local.properties 44 | **/android/**/GeneratedPluginRegistrant.java 45 | 46 | # iOS/XCode related 47 | **/ios/**/*.mode1v3 48 | **/ios/**/*.mode2v3 49 | **/ios/**/*.moved-aside 50 | **/ios/**/*.pbxuser 51 | **/ios/**/*.perspectivev3 52 | **/ios/**/*sync/ 53 | **/ios/**/.sconsign.dblite 54 | **/ios/**/.tags* 55 | **/ios/**/.vagrant/ 56 | **/ios/**/DerivedData/ 57 | **/ios/**/Icon? 58 | **/ios/**/Pods/ 59 | **/ios/**/.symlinks/ 60 | **/ios/**/profile 61 | **/ios/**/xcuserdata 62 | **/ios/.generated/ 63 | **/ios/Flutter/App.framework 64 | **/ios/Flutter/Flutter.framework 65 | **/ios/Flutter/Generated.xcconfig 66 | **/ios/Flutter/app.flx 67 | **/ios/Flutter/app.zip 68 | **/ios/Flutter/flutter_assets/ 69 | **/ios/ServiceDefinitions.json 70 | **/ios/Runner/GeneratedPluginRegistrant.* 71 | 72 | # Exceptions to above rules. 73 | !**/ios/**/default.mode1v3 74 | !**/ios/**/default.mode2v3 75 | !**/ios/**/default.pbxuser 76 | !**/ios/**/default.perspectivev3 77 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -------------------------------------------------------------------------------- /.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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.0] - 2019-04-26 4 | 5 | * Initial release -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | You want to see new examples ? You have a nice example, that you want to share with others ? Feel free to make a pull request! 4 | 5 | ## How To 6 | 7 | * Create an folder for each example. 8 | * Each example needs a README.md file with detailed explaination of the example. 9 | * Use the following pattern for naming the main file of the example : example*{$number}*.dart 10 | * Make a pull request with all your files -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Advanced Examples 2 | 3 | An advanced flutter example project. 4 | 5 | ## Table of Contents 6 | 7 | 1. [Install](#install) 8 | 2. [Structure](#structure) 9 | 3. [Examples](#examples) 10 | * [Filtering list](#filtering-list) 11 | * [Reading json file](#reading-json-file) 12 | * [Managing favorites in shared preferences](#managing-favorites-in-shared-preferences) 13 | * [Managing inputs within a modal or bottom sheet](#managing-inputs-within-a-modal-or-bottom-sheet) 14 | * [Shopping Cart](#shopping-cart) 15 | * [Global Message](#global-message) 16 | 4. [Changelog](#changelog) 17 | 5. [Contributing](#contributing) 18 | 6. [Support](#support) 19 | 7. [Copyright and license](#copyright-and-license) 20 | 21 | ## Structure 22 | 23 | Every example has it's own folder containing a **README.md** file and other files needed for that example. 24 | Thse **README.md** files contain more detailed explanations of the examples. 25 | 26 | ## Install 27 | 28 | You can find the corresponding app for this examples in the [play store](https://play.google.com/store/apps/details?id=de.feuerbergsoftware.advancedflutterexample). 29 | It shows every example in action and has a link to the corresponding files within this repository. 30 | 31 | ## Examples 32 | 33 | ### Filtering list 34 | 35 | Sorting a list of objects by different filters. The example contains a list of cars that can be filtered in different ways. 36 | 37 | * [Example1.dart](lib/examples/filterList/Example1.dart) 38 | * [Documentation](lib/examples/filterList/README.md) 39 | 40 | ### Reading json file 41 | 42 | Reading a json file from the asset folder and displaying it's content in the ui. 43 | 44 | * [Example2.dart](lib/examples/readingJsonFile/Example2.dart) 45 | * [Documentation](lib/examples/readingJsonFile/README.md) 46 | 47 | ### Managing favorites in shared preferences 48 | 49 | Mark items from a list as your favorite and save the favorites in the shared preferences. The example contains a list of meals. 50 | Each meal can be marked as favorite. 51 | 52 | * [Example3.dart](lib/examples/managingFavoritesInSharedPreferences/Example3.dart) 53 | * [Documentation](lib/examples/managingFavoritesInSharedPreferences/README.md) 54 | 55 | ### Managing inputs within a modal or bottom sheet 56 | 57 | Outsourcing checkboxes, radiobuttons and switches to a modal or a bottomsheet. 58 | 59 | * [Example4.dart](lib/examples/managingInputsWithinModalBottomsheet/Example4.dart) 60 | * [Documentation](lib/examples/managingInputsWithinModalBottomsheet/README.md) 61 | 62 | ### Shopping Cart 63 | 64 | A simple shopping cart with the possibility to add an remove items. The example consist of an app bar icon which displays the amount of items in the cart, a product list screen and the shopping cart screen, displaying each item of the cart and the calculated costs of the cart. This example uses BLOC logic. 65 | 66 | * [Example5.dart](lib/examples/shoppingCart/Example5.dart) 67 | * [Documentation](lib/examples/shoppingCart/README.md) 68 | 69 | ### Global Message 70 | 71 | Display messages that were created anywhere in the app. Simply push messge to the MessageBloc and the messagewrapper will display them. This example uses BLOC logic. 72 | 73 | * [Example6.dart](lib/examples/globalMessage/Example6.dart) 74 | * [Documentation](lib/examples/globalMessage/README.md) 75 | 76 | ## Changelog 77 | 78 | For a detailed changelog, see the [CHANGELOG.md](CHANGELOG.md) file 79 | 80 | ## Contributing 81 | 82 | You want to see new examples ? You have a nice example, that you want to share with others ? Feel free to make a pull request! 83 | Check [CONTRIBUTING.md](CONTRIBUTING.md) for more details. 84 | 85 | ## Support 86 | 87 | You like this repository or even use it in one of your projects? Feel free to donate a cup of 88 | coffee! 89 | Flattr : 90 | 91 | ## Copyright and license 92 | 93 | MIT License 94 | 95 | Copyright (c) 2019 Ephenodrom 96 | 97 | Permission is hereby granted, free of charge, to any person obtaining a copy 98 | of this software and associated documentation files (the "Software"), to deal 99 | in the Software without restriction, including without limitation the rights 100 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101 | copies of the Software, and to permit persons to whom the Software is 102 | furnished to do so, subject to the following conditions: 103 | 104 | The above copyright notice and this permission notice shall be included in all 105 | copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 108 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 109 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 110 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 111 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 112 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 113 | SOFTWARE. 114 | -------------------------------------------------------------------------------- /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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 27 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "de.feuerbergsoftware.advancedflutterexample" 37 | minSdkVersion 16 38 | targetSdkVersion 27 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /android/app/src/main/java/de/feuerbergsoftware/advancedflutterexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package de.feuerbergsoftware.advancedflutterexample; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /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-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /assets/json/solarsystem.json: -------------------------------------------------------------------------------- 1 | { 2 | "data" : [ 3 | { 4 | "name": "Sun", 5 | "distance": "0" 6 | }, 7 | { 8 | "name": "Mercury", 9 | "distance": "57.9" 10 | }, 11 | { 12 | "name": "Venus", 13 | "distance": "108.2" 14 | }, 15 | { 16 | "name": "Earth", 17 | "distance": "149.6" 18 | }, 19 | { 20 | "name": "Mars", 21 | "distance": "227.9" 22 | }, 23 | { 24 | "name": "Jupiter", 25 | "distance": "778.6" 26 | }, 27 | { 28 | "name": "Saturn", 29 | "distance": "1433.5" 30 | }, 31 | { 32 | "name": "Uranus", 33 | "distance": "2872.5" 34 | }, 35 | { 36 | "name": "Neptune", 37 | "distance": "4495.1" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /assets/logo_fae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/assets/logo_fae.png -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = ""; 30 | dstSubfolderSpec = 10; 31 | files = ( 32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 34 | ); 35 | name = "Embed Frameworks"; 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXCopyFilesBuildPhase section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 9740EEB11CF90186004384FC /* Flutter */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 77 | 3B80C3931E831B6300D905FE /* App.framework */, 78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 83 | ); 84 | name = Flutter; 85 | sourceTree = ""; 86 | }; 87 | 97C146E51CF9000F007C117D = { 88 | isa = PBXGroup; 89 | children = ( 90 | 9740EEB11CF90186004384FC /* Flutter */, 91 | 97C146F01CF9000F007C117D /* Runner */, 92 | 97C146EF1CF9000F007C117D /* Products */, 93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 97C146EF1CF9000F007C117D /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 97C146EE1CF9000F007C117D /* Runner.app */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | 97C146F01CF9000F007C117D /* Runner */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 110 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 113 | 97C147021CF9000F007C117D /* Info.plist */, 114 | 97C146F11CF9000F007C117D /* Supporting Files */, 115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 117 | ); 118 | path = Runner; 119 | sourceTree = ""; 120 | }; 121 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 97C146F21CF9000F007C117D /* main.m */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | 97C146ED1CF9000F007C117D /* Runner */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 135 | buildPhases = ( 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 0910; 159 | ORGANIZATIONNAME = "The Chromium Authors"; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | }; 164 | }; 165 | }; 166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 167 | compatibilityVersion = "Xcode 3.2"; 168 | developmentRegion = English; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | Base, 173 | ); 174 | mainGroup = 97C146E51CF9000F007C117D; 175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | 97C146ED1CF9000F007C117D /* Runner */, 180 | ); 181 | }; 182 | /* End PBXProject section */ 183 | 184 | /* Begin PBXResourcesBuildPhase section */ 185 | 97C146EC1CF9000F007C117D /* Resources */ = { 186 | isa = PBXResourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXShellScriptBuildPhase section */ 201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | ); 206 | inputPaths = ( 207 | ); 208 | name = "Thin Binary"; 209 | outputPaths = ( 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | shellPath = /bin/sh; 213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 214 | }; 215 | 9740EEB61CF901F6004384FC /* Run Script */ = { 216 | isa = PBXShellScriptBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | inputPaths = ( 221 | ); 222 | name = "Run Script"; 223 | outputPaths = ( 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | shellPath = /bin/sh; 227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 228 | }; 229 | /* End PBXShellScriptBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 97C146EA1CF9000F007C117D /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 237 | 97C146F31CF9000F007C117D /* main.m in Sources */, 238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | /* End PBXSourcesBuildPhase section */ 243 | 244 | /* Begin PBXVariantGroup section */ 245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 97C146FB1CF9000F007C117D /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 97C147001CF9000F007C117D /* Base */, 257 | ); 258 | name = LaunchScreen.storyboard; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXVariantGroup section */ 262 | 263 | /* Begin XCBuildConfiguration section */ 264 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 265 | isa = XCBuildConfiguration; 266 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_COMMA = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 287 | CLANG_WARN_STRICT_PROTOTYPES = YES; 288 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 294 | ENABLE_NS_ASSERTIONS = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_NO_COMMON_BLOCKS = YES; 298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 300 | GCC_WARN_UNDECLARED_SELECTOR = YES; 301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 302 | GCC_WARN_UNUSED_FUNCTION = YES; 303 | GCC_WARN_UNUSED_VARIABLE = YES; 304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 305 | MTL_ENABLE_DEBUG_INFO = NO; 306 | SDKROOT = iphoneos; 307 | TARGETED_DEVICE_FAMILY = "1,2"; 308 | VALIDATE_PRODUCT = YES; 309 | }; 310 | name = Profile; 311 | }; 312 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 313 | isa = XCBuildConfiguration; 314 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 315 | buildSettings = { 316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 317 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 318 | DEVELOPMENT_TEAM = S8QB4VV633; 319 | ENABLE_BITCODE = NO; 320 | FRAMEWORK_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "$(PROJECT_DIR)/Flutter", 323 | ); 324 | INFOPLIST_FILE = Runner/Info.plist; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | LIBRARY_SEARCH_PATHS = ( 327 | "$(inherited)", 328 | "$(PROJECT_DIR)/Flutter", 329 | ); 330 | PRODUCT_BUNDLE_IDENTIFIER = de.feuerbergsoftware.advancedFlutterExample; 331 | PRODUCT_NAME = "$(TARGET_NAME)"; 332 | VERSIONING_SYSTEM = "apple-generic"; 333 | }; 334 | name = Profile; 335 | }; 336 | 97C147031CF9000F007C117D /* Debug */ = { 337 | isa = XCBuildConfiguration; 338 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 339 | buildSettings = { 340 | ALWAYS_SEARCH_USER_PATHS = NO; 341 | CLANG_ANALYZER_NONNULL = YES; 342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 343 | CLANG_CXX_LIBRARY = "libc++"; 344 | CLANG_ENABLE_MODULES = YES; 345 | CLANG_ENABLE_OBJC_ARC = YES; 346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_COMMA = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 351 | CLANG_WARN_EMPTY_BODY = YES; 352 | CLANG_WARN_ENUM_CONVERSION = YES; 353 | CLANG_WARN_INFINITE_RECURSION = YES; 354 | CLANG_WARN_INT_CONVERSION = YES; 355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 359 | CLANG_WARN_STRICT_PROTOTYPES = YES; 360 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 361 | CLANG_WARN_UNREACHABLE_CODE = YES; 362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 364 | COPY_PHASE_STRIP = NO; 365 | DEBUG_INFORMATION_FORMAT = dwarf; 366 | ENABLE_STRICT_OBJC_MSGSEND = YES; 367 | ENABLE_TESTABILITY = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu99; 369 | GCC_DYNAMIC_NO_PIC = NO; 370 | GCC_NO_COMMON_BLOCKS = YES; 371 | GCC_OPTIMIZATION_LEVEL = 0; 372 | GCC_PREPROCESSOR_DEFINITIONS = ( 373 | "DEBUG=1", 374 | "$(inherited)", 375 | ); 376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 378 | GCC_WARN_UNDECLARED_SELECTOR = YES; 379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 380 | GCC_WARN_UNUSED_FUNCTION = YES; 381 | GCC_WARN_UNUSED_VARIABLE = YES; 382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 383 | MTL_ENABLE_DEBUG_INFO = YES; 384 | ONLY_ACTIVE_ARCH = YES; 385 | SDKROOT = iphoneos; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Debug; 389 | }; 390 | 97C147041CF9000F007C117D /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 393 | buildSettings = { 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | CLANG_ANALYZER_NONNULL = YES; 396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 397 | CLANG_CXX_LIBRARY = "libc++"; 398 | CLANG_ENABLE_MODULES = YES; 399 | CLANG_ENABLE_OBJC_ARC = YES; 400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 401 | CLANG_WARN_BOOL_CONVERSION = YES; 402 | CLANG_WARN_COMMA = YES; 403 | CLANG_WARN_CONSTANT_CONVERSION = YES; 404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 413 | CLANG_WARN_STRICT_PROTOTYPES = YES; 414 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 415 | CLANG_WARN_UNREACHABLE_CODE = YES; 416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 418 | COPY_PHASE_STRIP = NO; 419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 420 | ENABLE_NS_ASSERTIONS = NO; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu99; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 426 | GCC_WARN_UNDECLARED_SELECTOR = YES; 427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 428 | GCC_WARN_UNUSED_FUNCTION = YES; 429 | GCC_WARN_UNUSED_VARIABLE = YES; 430 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 431 | MTL_ENABLE_DEBUG_INFO = NO; 432 | SDKROOT = iphoneos; 433 | TARGETED_DEVICE_FAMILY = "1,2"; 434 | VALIDATE_PRODUCT = YES; 435 | }; 436 | name = Release; 437 | }; 438 | 97C147061CF9000F007C117D /* Debug */ = { 439 | isa = XCBuildConfiguration; 440 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 441 | buildSettings = { 442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 443 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 444 | ENABLE_BITCODE = NO; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(inherited)", 447 | "$(PROJECT_DIR)/Flutter", 448 | ); 449 | INFOPLIST_FILE = Runner/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 451 | LIBRARY_SEARCH_PATHS = ( 452 | "$(inherited)", 453 | "$(PROJECT_DIR)/Flutter", 454 | ); 455 | PRODUCT_BUNDLE_IDENTIFIER = de.feuerbergsoftware.advancedFlutterExample; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | VERSIONING_SYSTEM = "apple-generic"; 458 | }; 459 | name = Debug; 460 | }; 461 | 97C147071CF9000F007C117D /* Release */ = { 462 | isa = XCBuildConfiguration; 463 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 467 | ENABLE_BITCODE = NO; 468 | FRAMEWORK_SEARCH_PATHS = ( 469 | "$(inherited)", 470 | "$(PROJECT_DIR)/Flutter", 471 | ); 472 | INFOPLIST_FILE = Runner/Info.plist; 473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 474 | LIBRARY_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "$(PROJECT_DIR)/Flutter", 477 | ); 478 | PRODUCT_BUNDLE_IDENTIFIER = de.feuerbergsoftware.advancedFlutterExample; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | VERSIONING_SYSTEM = "apple-generic"; 481 | }; 482 | name = Release; 483 | }; 484 | /* End XCBuildConfiguration section */ 485 | 486 | /* Begin XCConfigurationList section */ 487 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 488 | isa = XCConfigurationList; 489 | buildConfigurations = ( 490 | 97C147031CF9000F007C117D /* Debug */, 491 | 97C147041CF9000F007C117D /* Release */, 492 | 249021D3217E4FDB00AE95B9 /* Profile */, 493 | ); 494 | defaultConfigurationIsVisible = 0; 495 | defaultConfigurationName = Release; 496 | }; 497 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | 97C147061CF9000F007C117D /* Debug */, 501 | 97C147071CF9000F007C117D /* Release */, 502 | 249021D4217E4FDB00AE95B9 /* Profile */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | /* End XCConfigurationList section */ 508 | }; 509 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 510 | } 511 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/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 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | advanced_flutter_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/DefaultAppBar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:url_launcher/url_launcher.dart'; 3 | 4 | class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { 5 | final String title; 6 | final String url; 7 | 8 | final PreferredSizeWidget bottom; 9 | final List customActions; 10 | @override 11 | final Size preferredSize; 12 | 13 | DefaultAppBar(this.title, this.url, {this.bottom, this.customActions}) 14 | : preferredSize = Size.fromHeight( 15 | kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | List actions = []; 20 | actions.add(FlatButton( 21 | child: Icon(Icons.info_outline, color: Colors.white), 22 | onPressed: _launchURL)); 23 | if (customActions != null) { 24 | actions.addAll(customActions); 25 | } 26 | return AppBar(title: Text(title), actions: actions); 27 | } 28 | 29 | _launchURL() async { 30 | if (await canLaunch(url)) { 31 | await launch(url); 32 | } else { 33 | throw 'Could not launch $url'; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/ExampleList.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/examples/filterList/Example1.dart'; 2 | import 'package:advanced_flutter_example/examples/globalMessage/Example6.dart'; 3 | import 'package:advanced_flutter_example/examples/managingFavoritesInSharedPreferences/Example3.dart'; 4 | import 'package:advanced_flutter_example/examples/managingInputsWithinModalBottomsheet/Example4.dart'; 5 | import 'package:advanced_flutter_example/examples/readingJsonFile/Example2.dart'; 6 | import 'package:advanced_flutter_example/examples/shoppingCart/Example5.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | class ExampleList extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return ListView( 13 | children: [ 14 | ListTile( 15 | title: new Text("Filtering List"), 16 | subtitle: new Text("Apply different filters to a list of cars."), 17 | onTap: () { 18 | Navigator.push( 19 | context, 20 | MaterialPageRoute(builder: (context) => Example1()), 21 | ); 22 | }, 23 | trailing: Icon(Icons.arrow_right), 24 | ), 25 | ListTile( 26 | title: new Text("Reading Json files"), 27 | subtitle: new Text( 28 | "Loading data from a json file inside the asset folder."), 29 | onTap: () { 30 | Navigator.push( 31 | context, 32 | MaterialPageRoute(builder: (context) => Example2()), 33 | ); 34 | }, 35 | trailing: Icon(Icons.arrow_right), 36 | ), 37 | ListTile( 38 | title: new Text("Managing Favorites"), 39 | subtitle: new Text( 40 | "Mark your favorite meal and save it in the shared preferences."), 41 | onTap: () { 42 | Navigator.push( 43 | context, 44 | MaterialPageRoute(builder: (context) => Example3()), 45 | ); 46 | }, 47 | trailing: Icon(Icons.arrow_right), 48 | ), 49 | ListTile( 50 | title: new Text("Managing inputs within modal / bottom sheet"), 51 | subtitle: new Text( 52 | "Outsourcing checkboxes, radiobuttons and switches to a modal or a bottomsheet."), 53 | onTap: () { 54 | Navigator.push( 55 | context, 56 | MaterialPageRoute(builder: (context) => Example4()), 57 | ); 58 | }, 59 | trailing: Icon(Icons.arrow_right), 60 | ), 61 | ListTile( 62 | title: new Text("Shopping Cart"), 63 | subtitle: new Text("Managing a shopping cart with BLOC logic"), 64 | onTap: () { 65 | Navigator.push( 66 | context, 67 | MaterialPageRoute(builder: (context) => Example5()), 68 | ); 69 | }, 70 | trailing: Icon(Icons.arrow_right), 71 | ), 72 | ListTile( 73 | title: new Text("Global Message"), 74 | subtitle: new Text( 75 | "Displaying messages from anywhere in the app with BLOC logic"), 76 | onTap: () { 77 | Navigator.push( 78 | context, 79 | MaterialPageRoute(builder: (context) => Example6()), 80 | ); 81 | }, 82 | trailing: Icon(Icons.arrow_right), 83 | ) 84 | ], 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/Loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Loading extends StatelessWidget { 4 | Loading(); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Scaffold( 9 | body: Container( 10 | child: Center( 11 | child: Text("Loading ..."), 12 | ), 13 | ), 14 | ); 15 | } 16 | } -------------------------------------------------------------------------------- /lib/basic/BlocProvider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | abstract class BlocBase { 4 | void dispose(); 5 | } 6 | 7 | class BlocProvider extends StatefulWidget { 8 | BlocProvider({ 9 | Key key, 10 | @required this.child, 11 | @required this.bloc, 12 | }) : super(key: key); 13 | 14 | final T bloc; 15 | final Widget child; 16 | 17 | @override 18 | _BlocProviderState createState() => _BlocProviderState(); 19 | 20 | static T of(BuildContext context) { 21 | final type = _typeOf>(); 22 | BlocProvider provider = context.ancestorWidgetOfExactType(type); 23 | return provider.bloc; 24 | } 25 | 26 | static Type _typeOf() => T; 27 | } 28 | 29 | class _BlocProviderState extends State> { 30 | @override 31 | void dispose() { 32 | widget.bloc.dispose(); 33 | super.dispose(); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return widget.child; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/basic/GlobalBloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 2 | import 'package:advanced_flutter_example/examples/globalMessage/MessageBloc.dart'; 3 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCartBloc.dart'; 4 | 5 | class GlobalBloc implements BlocBase { 6 | ShoppingCartBloc shoppingCartBloc; 7 | MessageBloc messageBloc; 8 | 9 | GlobalBloc() { 10 | shoppingCartBloc = ShoppingCartBloc(); 11 | messageBloc = MessageBloc(); 12 | } 13 | 14 | void dispose() { 15 | shoppingCartBloc.dispose(); 16 | messageBloc.dispose(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/examples/filterList/Car.dart: -------------------------------------------------------------------------------- 1 | class Car { 2 | final String name; 3 | final String brand; 4 | final String type; 5 | final int maxSpeed; 6 | final int horsePower; 7 | final String year; 8 | final bool selfDriving; 9 | final double price; 10 | 11 | Car({ 12 | this.name, 13 | this.brand, 14 | this.type, 15 | this.maxSpeed, 16 | this.horsePower, 17 | this.year, 18 | this.selfDriving, 19 | this.price, 20 | }); 21 | 22 | static final cars = [ 23 | new Car( 24 | name: "Jazz", 25 | brand: "Honda", 26 | type: "gas", 27 | maxSpeed: 200, 28 | horsePower: 83, 29 | year: "2001", 30 | selfDriving: false, 31 | price: 2000.00), 32 | new Car( 33 | name: "Citigo", 34 | brand: "Skoda", 35 | type: "gas", 36 | maxSpeed: 200, 37 | horsePower: 75, 38 | year: "2011", 39 | selfDriving: false, 40 | price: 10840.00), 41 | new Car( 42 | name: "Octavia Combi", 43 | brand: "Skoda", 44 | type: "diesel", 45 | maxSpeed: 240, 46 | horsePower: 149, 47 | year: "2016", 48 | selfDriving: false, 49 | price: 32650.00), 50 | new Car( 51 | name: "Rapid", 52 | brand: "Skoda", 53 | type: "diesel", 54 | maxSpeed: 240, 55 | horsePower: 95, 56 | year: "2012", 57 | selfDriving: false, 58 | price: 20190.00), 59 | new Car( 60 | name: "Q2", 61 | brand: "Audi", 62 | type: "gas", 63 | maxSpeed: 280, 64 | horsePower: 140, 65 | year: "2018", 66 | selfDriving: false, 67 | price: 28000.00), 68 | new Car( 69 | name: "Model 3", 70 | brand: "Tesla", 71 | type: "electric", 72 | maxSpeed: 280, 73 | horsePower: 140, 74 | year: "2018", 75 | selfDriving: true, 76 | price: 35000), 77 | ]; 78 | } 79 | -------------------------------------------------------------------------------- /lib/examples/filterList/Example1.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:advanced_flutter_example/examples/filterList/Car.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class Example1 extends StatefulWidget { 6 | Example1(); 7 | 8 | final String title = "Filtering List"; 9 | final String exampleUrl = "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/filterList"; 10 | 11 | @override 12 | _Example1State createState() => _Example1State(); 13 | } 14 | 15 | class _Example1State extends State { 16 | List initialList = Car.cars; 17 | List currentList = []; 18 | 19 | //filter 20 | bool selfDriving = false; 21 | double maxPrice = 100000; 22 | String carType = "all"; 23 | 24 | final controller = new TextEditingController(); 25 | 26 | @override 27 | initState() { 28 | super.initState(); 29 | controller.addListener(onChange); 30 | filterCars(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | filterCars(); 36 | return Scaffold( 37 | appBar: DefaultAppBar(widget.title,widget.exampleUrl), 38 | body: Container( 39 | margin: EdgeInsets.only(top: 10), 40 | child: Column(children: [ 41 | Text("Search for your car",style: Theme.of(context).textTheme.headline,), 42 | Padding( 43 | padding: const EdgeInsets.symmetric(horizontal: 16.0), 44 | child: TextField( 45 | controller: controller 46 | ), 47 | ), 48 | SwitchListTile( 49 | title: Text('Selfdriving'), 50 | value: selfDriving, 51 | onChanged: (changed){ 52 | setState(() => selfDriving = changed); 53 | } 54 | ), 55 | Slider( 56 | label: '${maxPrice.round()} \$', 57 | activeColor: Colors.indigoAccent, 58 | min: 0.0, 59 | max: 100000.0, 60 | divisions: 20, 61 | onChanged: (newRating) { 62 | setState(() => maxPrice = newRating); 63 | }, 64 | value: maxPrice, 65 | ), 66 | ListTile( 67 | leading: Text("Engine Type"), 68 | trailing: DropdownButton( 69 | elevation: 16, 70 | onChanged: (item){ 71 | setState(() { 72 | carType = item; 73 | }); 74 | }, 75 | hint:Text(carType), 76 | items: [ 77 | DropdownMenuItem( 78 | child: new Text("All"), 79 | value: "All" 80 | ), 81 | DropdownMenuItem( 82 | child: new Text("Gas"), 83 | value: "Gas" 84 | ), 85 | DropdownMenuItem( 86 | child: new Text("Diesel"), 87 | value: "Diesel" 88 | ), 89 | DropdownMenuItem( 90 | child: new Text("Electric"), 91 | value: "Electric" 92 | ) 93 | ], 94 | ) 95 | ), 96 | Expanded( 97 | child: ListView.builder( 98 | itemCount: currentList.length, 99 | itemBuilder: (BuildContext context, int index) { 100 | Car current = currentList.elementAt(index); 101 | return Card( 102 | elevation: 4, 103 | child: ListTile( 104 | title: Text(current.name), 105 | subtitle: Text(current.brand), 106 | trailing: Text(current.price.toString()+" \$"), 107 | leading: Text(current.year), 108 | ), 109 | ); 110 | }), 111 | ), 112 | ]), 113 | )); 114 | } 115 | 116 | onChange() { 117 | setState((){}); 118 | } 119 | 120 | filterCars() { 121 | // Prepare lists 122 | List tmp = []; 123 | currentList.clear(); 124 | 125 | String name = controller.text; 126 | print("filter cars for name " + name); 127 | if (name.isEmpty) { 128 | tmp.addAll(initialList); 129 | } else { 130 | for (Car c in initialList) { 131 | if (c.name.toLowerCase().startsWith(name.toLowerCase())) { 132 | tmp.add(c); 133 | } 134 | } 135 | } 136 | currentList = tmp; 137 | 138 | if(selfDriving) { 139 | tmp = []; 140 | print("filter cars for selfdriving " + selfDriving.toString()); 141 | for (Car c in currentList) { 142 | if (c.selfDriving == selfDriving) { 143 | tmp.add(c); 144 | } 145 | } 146 | currentList = tmp; 147 | } 148 | 149 | print("filter cars for max price " + maxPrice.toString()); 150 | tmp = []; 151 | for (Car c in currentList) { 152 | if(c.price < maxPrice){ 153 | tmp.add(c); 154 | } 155 | } 156 | currentList = tmp; 157 | if(carType.toLowerCase() != "all") { 158 | tmp = []; 159 | print("filter cars for type " + carType); 160 | for (Car c in currentList) { 161 | if (c.type == carType.toLowerCase()) { 162 | tmp.add(c); 163 | } 164 | } 165 | currentList = tmp; 166 | } 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /lib/examples/filterList/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | A list of cars is filtered by different filters. 3 | 4 | # Structure 5 | 6 | For filtering a list, we need two lists. The **initialList** is the list that contains all cars. For this 7 | example the list ist setup manually. But it can also be loaded from a different source. 8 | The next important list is the **currentList**. It contains all cars that matches the filters. 9 | ```dart 10 | List initialList = Car.cars; 11 | List currentList = []; 12 | ``` 13 | 14 | The cars can be filtered with this filters. Each value is controlled by one of the corresponding 15 | ```dart 16 | bool selfDriving = false; 17 | double maxPrice = 100000; 18 | String carType = "all"; 19 | final controller = new TextEditingController(); 20 | ``` 21 | 22 | The method **filterCars()** updates the **currentList** depending on the filters. 23 | ```dart 24 | filterCars() { 25 | // Prepare lists 26 | List tmp = []; 27 | currentList.clear(); 28 | 29 | String name = controller.text; 30 | print("filter cars for name " + name); 31 | if (name.isEmpty) { 32 | tmp.addAll(initialList); 33 | } else { 34 | for (Car c in initialList) { 35 | if (c.name.toLowerCase().startsWith(name.toLowerCase())) { 36 | tmp.add(c); 37 | } 38 | } 39 | } 40 | currentList = tmp; 41 | 42 | if(selfDriving) { 43 | tmp = []; 44 | print("filter cars for selfdriving " + selfDriving.toString()); 45 | for (Car c in currentList) { 46 | if (c.selfDriving == selfDriving) { 47 | tmp.add(c); 48 | } 49 | } 50 | currentList = tmp; 51 | } 52 | 53 | print("filter cars for max price " + maxPrice.toString()); 54 | tmp = []; 55 | for (Car c in currentList) { 56 | if(c.price < maxPrice){ 57 | tmp.add(c); 58 | } 59 | } 60 | currentList = tmp; 61 | if(carType.toLowerCase() != "all") { 62 | tmp = []; 63 | print("filter cars for type " + carType); 64 | for (Car c in currentList) { 65 | if (c.type == carType.toLowerCase()) { 66 | tmp.add(c); 67 | } 68 | } 69 | currentList = tmp; 70 | } 71 | } 72 | ``` 73 | -------------------------------------------------------------------------------- /lib/examples/globalMessage/Example6.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 3 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 4 | import 'package:advanced_flutter_example/examples/globalMessage/GlobalMessageWrapper.dart'; 5 | import 'package:advanced_flutter_example/examples/globalMessage/Message.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | class Example6 extends StatefulWidget { 9 | Example6(); 10 | 11 | final String title = "Global Message"; 12 | final String exampleUrl = 13 | "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/globalMessage"; 14 | 15 | @override 16 | _Example6State createState() => _Example6State(); 17 | } 18 | 19 | class _Example6State extends State { 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: DefaultAppBar(widget.title, widget.exampleUrl), 24 | body: GlobalMessageWrapper(Center( 25 | child: Column( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | RaisedButton( 29 | child: Text("Succes"), 30 | onPressed: () { 31 | BlocProvider.of(context) 32 | .messageBloc 33 | .addition 34 | .add(Message("This is a success message", "success")); 35 | }, 36 | ), 37 | RaisedButton( 38 | child: Text("Info"), 39 | onPressed: () { 40 | BlocProvider.of(context) 41 | .messageBloc 42 | .addition 43 | .add(Message("This is a info message", "info")); 44 | }, 45 | ), 46 | RaisedButton( 47 | child: Text("Warning"), 48 | onPressed: () { 49 | BlocProvider.of(context) 50 | .messageBloc 51 | .addition 52 | .add(Message("This is a warning message", "warning")); 53 | }, 54 | ), 55 | RaisedButton( 56 | child: Text("Error"), 57 | onPressed: () { 58 | BlocProvider.of(context) 59 | .messageBloc 60 | .addition 61 | .add(Message("This is a error message", "error")); 62 | }, 63 | ), 64 | ], 65 | )))); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/examples/globalMessage/GlobalMessageWrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 2 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 3 | import 'package:advanced_flutter_example/examples/globalMessage/Message.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class GlobalMessageWrapper extends StatefulWidget { 7 | final Widget child; 8 | 9 | GlobalMessageWrapper(this.child); 10 | @override 11 | _GlobalMessageWrapperState createState() => _GlobalMessageWrapperState(); 12 | } 13 | 14 | class _GlobalMessageWrapperState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return StreamBuilder( 18 | initialData: null, 19 | stream: BlocProvider.of(context).messageBloc.messageStream, 20 | builder: (BuildContext context, AsyncSnapshot snapshot) { 21 | Message msg = snapshot.data; 22 | if (msg != null) { 23 | WidgetsBinding.instance 24 | .addPostFrameCallback((_) => _showMessage(msg)); 25 | } 26 | return Container(child: widget.child); 27 | }); 28 | } 29 | 30 | void _showMessage(Message message) { 31 | Color color = Colors.grey; 32 | 33 | switch (message.type) { 34 | case "success": 35 | color = Colors.green; 36 | break; 37 | case "info": 38 | color = Colors.blue; 39 | break; 40 | case "warning": 41 | color = Colors.orange; 42 | break; 43 | case "error": 44 | color = Colors.red; 45 | break; 46 | default: 47 | } 48 | SnackBar bar = SnackBar( 49 | content: Padding( 50 | padding: const EdgeInsets.only(bottom: 50.0), 51 | child: Text(message.text), 52 | ), 53 | backgroundColor: color); 54 | 55 | Scaffold.of(context) 56 | ..hideCurrentSnackBar() 57 | ..showSnackBar(bar); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/examples/globalMessage/Message.dart: -------------------------------------------------------------------------------- 1 | class Message { 2 | final String text; 3 | final String type; 4 | 5 | Message(this.text, this.type); 6 | } 7 | -------------------------------------------------------------------------------- /lib/examples/globalMessage/MessageBloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 3 | import 'package:advanced_flutter_example/examples/globalMessage/Message.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | 6 | class MessageBloc implements BlocBase { 7 | /// Sinks 8 | Sink get addition => messageAdditionController.sink; 9 | final messageAdditionController = StreamController(); 10 | 11 | /// Streams 12 | Stream get messageStream => _message.stream; 13 | final _message = BehaviorSubject(); 14 | 15 | MessageBloc() { 16 | messageAdditionController.stream.listen(handleMessageAdd); 17 | } 18 | 19 | /// 20 | /// Logic for message added . 21 | /// 22 | void handleMessageAdd(Message msg) { 23 | _message.add(msg); 24 | return; 25 | } 26 | 27 | @override 28 | void dispose() { 29 | messageAdditionController.close(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/examples/globalMessage/README.md: -------------------------------------------------------------------------------- 1 | # Global Message 2 | 3 | ## Description 4 | 5 | Displaying message in a snackbar, that appear anywhere in the app. 6 | 7 | ## Structure 8 | 9 | The [GlobalMessageWrapper](GlobalMessageWrapper.dart) displays every message that is passed to the [MessageBloc](MessageBloc.dart). The GlobalMessageWrapper uses a StreamBuilder to fetch the messages from the MessageBloc and displays the message in the _showMessage method. 10 | 11 | ```dart 12 | @override 13 | Widget build(BuildContext context) { 14 | return StreamBuilder( 15 | initialData: null, 16 | stream: BlocProvider.of(context).messageBloc.messageStream, 17 | builder: (BuildContext context, AsyncSnapshot snapshot) { 18 | Message msg = snapshot.data; 19 | if (msg != null) { 20 | WidgetsBinding.instance 21 | .addPostFrameCallback((_) => _showMessage(msg)); 22 | } 23 | return Container(child: widget.child); 24 | } 25 | ); 26 | } 27 | ``` 28 | 29 | It is important to use the following lines of code. You can't display a snackbar inside the streambuilder, due to the snackbar will call setState during the streambuilder **builds** the widget. Flutter will throw "setState() or markNeedsBuild() called during build.". 30 | A streambuilder should only build widgets! 31 | 32 | ```dart 33 | WidgetsBinding.instance.addPostFrameCallback((_) => _showMessage(msg)); 34 | ``` 35 | 36 | The [Message](Message.dart) class is used to store the message information like text and type. It can easily be extended! 37 | 38 | ```dart 39 | class Message { 40 | final String text; 41 | final String type; 42 | 43 | Message(this.text, this.type); 44 | } 45 | ``` 46 | 47 | To display a message, just add one to the MessageBloc. 48 | 49 | ```dart 50 | BlocProvider.of(context) 51 | .messageBloc 52 | .addition 53 | .add(Message("This is a success message", "success")); 54 | ``` 55 | 56 | ## Additional Information 57 | 58 | To use the [GlobalMessageWrapper](GlobalMessageWrapper.dart) globally in your app, put him on top of the widget tree. You could put it under your MaterialApp Widget in the main.dart file. -------------------------------------------------------------------------------- /lib/examples/managingFavoritesInSharedPreferences/Example3.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | class Example3 extends StatefulWidget { 6 | Example3(); 7 | 8 | final String title = "Managing Favorites"; 9 | final String exampleUrl = "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/managingFavoritesInSharedPreferences"; 10 | 11 | @override 12 | _Example3State createState() => _Example3State(); 13 | } 14 | 15 | class _Example3State extends State { 16 | 17 | final List meals = new List(); 18 | final List favs = new List(); 19 | 20 | @override 21 | initState() { 22 | super.initState(); 23 | setUp(); 24 | if(favs.isEmpty){ 25 | SharedPreferences.getInstance().then((prefs){ 26 | if(prefs.getStringList("favs") != null) { 27 | favs.addAll(prefs.getStringList("favs")); 28 | } 29 | setState((){}); 30 | }); 31 | } 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Scaffold( 37 | appBar: DefaultAppBar(widget.title,widget.exampleUrl), 38 | body: Container( 39 | child: ListView.builder( 40 | // Let the ListView know how many items it needs to build 41 | itemCount: meals.length, 42 | // Provide a builder function. 43 | itemBuilder: (context, index) { 44 | String meal = meals[index]; 45 | return ListTile( 46 | title: new Text(meal), 47 | trailing: Icon(isFavorite(meal) ? Icons.favorite : Icons.favorite_border), 48 | onTap: (){ 49 | setState(() { 50 | addRemFavorite(meal); 51 | }); 52 | }, 53 | ); 54 | }), 55 | ), 56 | ); 57 | } 58 | 59 | void setUp() { 60 | meals.add("Pizza"); 61 | meals.add("Spaghetti"); 62 | meals.add("Lasagne"); 63 | meals.add("Steak"); 64 | meals.add("French Fries"); 65 | meals.add("Mac & Cheese"); 66 | meals.add("Schnitzel"); 67 | meals.add("Brezel"); 68 | } 69 | 70 | bool isFavorite(String meal){ 71 | return favs.contains(meal); 72 | } 73 | 74 | void addRemFavorite(String meal) async { 75 | if(favs.contains(meal)){ 76 | favs.remove(meal); 77 | }else{ 78 | favs.add(meal); 79 | } 80 | SharedPreferences prefs = await SharedPreferences.getInstance(); 81 | prefs.setStringList("favs", favs); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/examples/managingFavoritesInSharedPreferences/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | This example holds a list of meals. Each meal can be marked as a favorite. The favorite meals will 3 | be stored in the shared preferences. 4 | 5 | # Structure 6 | In the Example3.dart file, you will find two lists at the beginning : 7 | ```dart 8 | List meals 9 | List favs 10 | ``` 11 | 12 | The list meals contains all meals. The list is filled with strings by hand in the **setUp()** method. 13 | ```dart 14 | void setUp() { 15 | meals.add("Pizza"); 16 | meals.add("Spaghetti"); 17 | meals.add("Lasagne"); 18 | meals.add("Steak"); 19 | meals.add("French Fries"); 20 | meals.add("Mac & Cheese"); 21 | meals.add("Schnitzel"); 22 | meals.add("Brezel"); 23 | } 24 | ``` 25 | The list favs is loaded from the shared preferences in the **initState()** method. It contains all meals, 26 | that are marked as a favorite. 27 | ```dart 28 | if(widget.favs.isEmpty){ 29 | SharedPreferences.getInstance().then((prefs){ 30 | widget.favs.addAll(prefs.getStringList("favs")); 31 | setState((){}); 32 | }); 33 | } 34 | ``` 35 | 36 | The list is build with a simple **ListView.builder** in the **build()** method of the state. For each meal 37 | it builds a list tile. 38 | ```dart 39 | return ListTile( 40 | title: new Text(meal), 41 | trailing: Icon(isFavorite(meal) ? Icons.favorite : Icons.favorite_border), 42 | onTap: (){ 43 | setState(() { 44 | addRemFavorite(meal); 45 | }); 46 | }, 47 | ); 48 | ``` 49 | 50 | Each ListTile contains an Icon. The method **isFavorite()** is used to determine if the meal is a favorite 51 | or not. 52 | ```dart 53 | bool isFavorite(String meal){ 54 | return widget.favs.contains(meal); 55 | } 56 | ``` 57 | 58 | If you tap the tile, the method **addRemFavorite()** is called and adds or removes the meal from 59 | the **favs** list. It also updates the data in the shared preferences. 60 | ```dart 61 | void addRemFavorite(String meal) async { 62 | if(widget.favs.contains(meal)){ 63 | widget.favs.remove(meal); 64 | }else{ 65 | widget.favs.add(meal); 66 | } 67 | SharedPreferences prefs = await SharedPreferences.getInstance(); 68 | prefs.setStringList("favs", widget.favs); 69 | } 70 | ``` -------------------------------------------------------------------------------- /lib/examples/managingInputsWithinModalBottomsheet/Example4.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class Example4 extends StatefulWidget { 5 | Example4(); 6 | 7 | final String title = "Managing inputs within modal / bottom sheet"; 8 | final String exampleUrl = 9 | "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/managingInputsWithinModalBottomsheet"; 10 | 11 | @override 12 | _Example4State createState() => _Example4State(); 13 | } 14 | 15 | class _Example4State extends State { 16 | // Modal 17 | bool modalIsChecked = false; 18 | bool modalIsSwitched = false; 19 | int modalRadioValue = 0; 20 | 21 | // Bottomsheet 22 | bool bottomIsChecked = false; 23 | bool bottomIsSwitched = false; 24 | int bottomRadioValue = 0; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: DefaultAppBar(widget.title, widget.exampleUrl), 30 | body: Center( 31 | child: Column( 32 | mainAxisAlignment: MainAxisAlignment.center, 33 | children: [ 34 | RaisedButton( 35 | onPressed: () { 36 | showDialog( 37 | context: context, 38 | builder: (BuildContext context) { 39 | return StatefulBuilder( 40 | builder: (BuildContext context, StateSetter state) { 41 | return SimpleDialog( 42 | children: [ 43 | Center( 44 | child: Padding( 45 | padding: const EdgeInsets.all(8.0), 46 | child: Text( 47 | "These inputs wouldn't work without StatefulBuilder!"), 48 | )), 49 | CheckboxListTile( 50 | value: modalIsChecked, 51 | title: Text("modalIsChecked"), 52 | onChanged: (value) { 53 | state(() { 54 | modalIsChecked = value; 55 | }); 56 | }, 57 | ), 58 | SwitchListTile( 59 | value: modalIsSwitched, 60 | title: Text("modalIsSwitched"), 61 | onChanged: (value) { 62 | state(() { 63 | modalIsSwitched = value; 64 | }); 65 | }, 66 | ), 67 | new Row( 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | new Radio( 71 | value: 0, 72 | groupValue: modalRadioValue, 73 | onChanged: (value) { 74 | state(() { 75 | modalRadioValue = value; 76 | }); 77 | }, 78 | ), 79 | new Text( 80 | 'Pizza', 81 | ), 82 | new Radio( 83 | value: 1, 84 | groupValue: modalRadioValue, 85 | onChanged: (value) { 86 | state(() { 87 | modalRadioValue = value; 88 | }); 89 | }, 90 | ), 91 | new Text('Spaghetti'), 92 | new Radio( 93 | value: 2, 94 | groupValue: modalRadioValue, 95 | onChanged: (value) { 96 | state(() { 97 | modalRadioValue = value; 98 | }); 99 | }, 100 | ), 101 | new Text('Burger'), 102 | ], 103 | ), 104 | ], 105 | ); 106 | }); 107 | }); 108 | }, 109 | child: Text("Show modal"), 110 | ), 111 | RaisedButton( 112 | onPressed: () { 113 | showModalBottomSheet( 114 | context: context, 115 | builder: (BuildContext context) { 116 | return StatefulBuilder( 117 | builder: (BuildContext context, StateSetter state) { 118 | return Container( 119 | padding: EdgeInsets.only(bottom: 50), 120 | child: Column( 121 | mainAxisSize: MainAxisSize.min, 122 | children: [ 123 | Center( 124 | child: Padding( 125 | padding: const EdgeInsets.all(8.0), 126 | child: Text( 127 | "These inputs wouldn't work without StatefulBuilder!"), 128 | )), 129 | CheckboxListTile( 130 | value: bottomIsChecked, 131 | title: Text("bottomIsChecked"), 132 | onChanged: (value) { 133 | state(() { 134 | bottomIsChecked = value; 135 | }); 136 | }, 137 | ), 138 | SwitchListTile( 139 | value: bottomIsSwitched, 140 | title: Text("bottomIsSwitched"), 141 | onChanged: (value) { 142 | state(() { 143 | bottomIsSwitched = value; 144 | }); 145 | }, 146 | ), 147 | new Row( 148 | mainAxisAlignment: MainAxisAlignment.center, 149 | children: [ 150 | new Radio( 151 | value: 0, 152 | groupValue: bottomRadioValue, 153 | onChanged: (value) { 154 | state(() { 155 | bottomRadioValue = value; 156 | }); 157 | }, 158 | ), 159 | new Text( 160 | 'Pizza', 161 | ), 162 | new Radio( 163 | value: 1, 164 | groupValue: bottomRadioValue, 165 | onChanged: (value) { 166 | state(() { 167 | bottomRadioValue = value; 168 | }); 169 | }, 170 | ), 171 | new Text( 172 | 'Spaghetti', 173 | ), 174 | new Radio( 175 | value: 2, 176 | groupValue: bottomRadioValue, 177 | onChanged: (value) { 178 | state(() { 179 | bottomRadioValue = value; 180 | }); 181 | }, 182 | ), 183 | new Text( 184 | 'Burger', 185 | ), 186 | ], 187 | ), 188 | ], 189 | ), 190 | ); 191 | }); 192 | }); 193 | }, 194 | child: Text("Show bottom sheet"), 195 | ) 196 | ], 197 | ), 198 | ), 199 | ); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /lib/examples/managingInputsWithinModalBottomsheet/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | Outsourcing some checkboxes, radiobuttons and switches to a modal and a bottomsheet. We have to use 3 | a **StatefullWidgetBuilder** so that the input fields will be updated within the ui. 4 | The reason for this is that the status of the modal / bottom sheet is independent of the status of 5 | the current screen. 6 | So when we call the **setState((){ ... })** it will update the ui in the background but not the ui in the 7 | modal / bottom sheet. 8 | 9 | # Structure 10 | 11 | We setup some variables that will be used by the checkboxes, switches and radiobuttons. 12 | 13 | ```dart 14 | bool modalIsChecked = false; 15 | bool modalIsSwitched = false; 16 | int modalRadioValue = 0; 17 | 18 | bool bottomIsChecked = false; 19 | bool bottomIsSwitched = false; 20 | int bottomRadioValue = 0; 21 | ``` 22 | We setup two buttons to display the modal and the bottom sheet. 23 | 24 | ```dart 25 | RaisedButton( 26 | onPressed: () { 27 | // display modal 28 | }, 29 | child: Text("Show modal"), 30 | ), 31 | RaisedButton( 32 | onPressed: () { 33 | // display bottom sheet 34 | }, 35 | child: Text("Show bottom sheet"), 36 | ), 37 | ``` 38 | When we press the button to display the bottom sheet, we will call the **showModalBottomSheet()** method. 39 | We set a normal builder and return a StatefulBuilder. This is very important because we need the StateSetter 40 | to update the ui in the bottom sheet. 41 | ```dart 42 | showModalBottomSheet( 43 | context: context, 44 | builder: (BuildContext context) { 45 | return StatefulBuilder( 46 | builder: (BuildContext context, StateSetter state) { 47 | // Build the layout 48 | } 49 | } 50 | ); 51 | ``` 52 | Here comes the most important part. We don't call the **setState((){ ... })** method. We use the 53 | **StateSetter** called **state** from the **StatefulBuilder**. 54 | Use **state((){ ... })** to update the ui of the bottom sheet. 55 | 56 | ```dart 57 | onChanged: (value) { 58 | state(() { 59 | bottomIsChecked = value; 60 | }); 61 | } 62 | ``` 63 | 64 | _Additional information : **state** is just the name of the StateSetter variable, it is possible to use 65 | another name and therefore change the method._ -------------------------------------------------------------------------------- /lib/examples/readingJsonFile/Example2.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 4 | import 'package:advanced_flutter_example/examples/readingJsonFile/Planet.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart' show rootBundle; 7 | import 'dart:convert'; 8 | 9 | class Example2 extends StatefulWidget { 10 | Example2(); 11 | 12 | final String title = "Reading Json files"; 13 | final String exampleUrl = 14 | "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/readingJsonFile"; 15 | 16 | @override 17 | _Example2State createState() => _Example2State(); 18 | } 19 | 20 | class _Example2State extends State { 21 | List planets = []; 22 | 23 | @override 24 | void initState() { 25 | super.initState(); 26 | loadPlanetsFromAsset().then((planets) { 27 | setState(() { 28 | this.planets.addAll(planets); 29 | }); 30 | }); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | appBar: DefaultAppBar(widget.title, widget.exampleUrl), 37 | body: ListView.builder( 38 | itemCount: planets.length, 39 | itemBuilder: (BuildContext context, index) { 40 | return ListTile( 41 | title: Text(planets.elementAt(index).name), 42 | subtitle: Text("Distance from sun : " + 43 | planets.elementAt(index).distance + 44 | " km"), 45 | ); 46 | })); 47 | } 48 | 49 | Future> loadPlanetsFromAsset() async { 50 | String content = 51 | await rootBundle.loadString("assets/json/solarsystem.json"); 52 | Map contentAsMap = json.decode(content); 53 | List data = contentAsMap["data"]; 54 | List list = []; 55 | data.forEach((e) { 56 | Planet planet = new Planet.fromJson(e); 57 | list.add(planet); 58 | }); 59 | return list; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/examples/readingJsonFile/Planet.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'Planet.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Planet { 7 | final String name; 8 | final String distance; 9 | 10 | Planet({this.name, this.distance}); 11 | 12 | factory Planet.fromJson(Map json) => _$PlanetFromJson(json); 13 | 14 | Map toJson() => _$PlanetToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/examples/readingJsonFile/Planet.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Planet.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Planet _$PlanetFromJson(Map json) { 10 | return Planet( 11 | name: json['name'] as String, distance: json['distance'] as String); 12 | } 13 | 14 | Map _$PlanetToJson(Planet instance) => 15 | {'name': instance.name, 'distance': instance.distance}; 16 | -------------------------------------------------------------------------------- /lib/examples/readingJsonFile/README.md: -------------------------------------------------------------------------------- 1 | # Reading Json File 2 | 3 | ## Description 4 | 5 | Reading a json file from the asset folder and displaying it's content in the ui. 6 | 7 | ## Structure 8 | 9 | We have the empty list of planets at the beginning. 10 | 11 | ```dart 12 | List planets = []; 13 | ``` 14 | 15 | We load the data from the json file in the **initState()** method. When we receive the lists of planets, 16 | we update the screen by calling the **setState()** method. We simple build the list of planets with 17 | the help of a **ListView** builder in the **build()** method. 18 | 19 | ```dart 20 | loadPlanetsFromAsset().then((planets) { 21 | setState(() { 22 | this.planets.addAll(planets); 23 | }); 24 | }); 25 | ``` 26 | 27 | We use the rootBundle to load the json as a string, then converting it to our model. 28 | 29 | ```dart 30 | Future> loadPlanetsFromAsset() async { 31 | String content = await rootBundle.loadString("assets/json/solarsystem.json"); 32 | Map contentAsMap = json.decode(content); 33 | List data = contentAsMap["data"]; 34 | List list = []; 35 | data.forEach((e) { 36 | Planet planet = new Planet.fromJson(e); 37 | list.add(planet); 38 | }); 39 | return list; 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/Example5.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 3 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 4 | import 'package:advanced_flutter_example/examples/shoppingCart/Product.dart'; 5 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCartAppBarIcon.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | class Example5 extends StatefulWidget { 9 | Example5(); 10 | 11 | final String title = "Shopping Cart"; 12 | final String exampleUrl = 13 | "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/shoppingCart"; 14 | 15 | @override 16 | _Example5State createState() => _Example5State(); 17 | } 18 | 19 | class _Example5State extends State { 20 | List productList = products; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | List actions = []; 25 | actions.add(ShoppingCartAppBarIcon()); 26 | return Scaffold( 27 | appBar: DefaultAppBar( 28 | widget.title, 29 | widget.exampleUrl, 30 | customActions: actions, 31 | ), 32 | body: ListView.builder( 33 | itemCount: productList.length, 34 | itemBuilder: (BuildContext context, index) { 35 | return ListTile( 36 | title: Text(products.elementAt(index).name), 37 | subtitle: Text( 38 | productList.elementAt(index).priceNet.toString() + " €"), 39 | trailing: Icon(Icons.add_shopping_cart), 40 | onTap: () { 41 | BlocProvider.of(context) 42 | .shoppingCartBloc 43 | .addition 44 | .add(productList.elementAt(index)); 45 | }, 46 | ); 47 | })); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/Product.dart: -------------------------------------------------------------------------------- 1 | class Product { 2 | final String name; 3 | final double priceNet; 4 | final double priceGross; 5 | final double vatAmount; 6 | final double tax; 7 | 8 | Product( 9 | {this.name, this.priceNet, this.priceGross, this.vatAmount, this.tax}); 10 | } 11 | 12 | List products = [ 13 | new Product( 14 | name: "Bread", priceNet: 3.0, priceGross: 2.72, vatAmount: 0.28, tax: 10), 15 | new Product( 16 | name: "Tomatos", 17 | priceNet: 2.0, 18 | priceGross: 1.81, 19 | vatAmount: 0.19, 20 | tax: 10), 21 | new Product( 22 | name: "Salad", priceNet: 2.0, priceGross: 1.81, vatAmount: 0.19, tax: 10), 23 | new Product( 24 | name: "Butter", 25 | priceNet: 2.5, 26 | priceGross: 2.27, 27 | vatAmount: 0.23, 28 | tax: 10), 29 | new Product( 30 | name: "Milk", priceNet: 0.99, priceGross: 0.9, vatAmount: 0.09, tax: 10), 31 | new Product( 32 | name: "Honey", 33 | priceNet: 5.35, 34 | priceGross: 4.86, 35 | vatAmount: 0.49, 36 | tax: 10), 37 | ]; 38 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/README.md: -------------------------------------------------------------------------------- 1 | # Shopping Cart 2 | 3 | ## Description 4 | 5 | Managing a shopping cart system with BLOC logic using the rxdart package. 6 | 7 | ## Structure 8 | 9 | First of all activate the [GlobalBloc](../../basic/GlobalBloc.dart) with [BlocProvider](../../basic/BlocProvider.dart) in the [main](../../main.dart) file. 10 | 11 | ```dart 12 | @override 13 | Widget build(BuildContext context) { 14 | return BlocProvider( 15 | bloc: GlobalBloc(), 16 | child: MaterialApp( 17 | title: 'Flutter Advanced Example', 18 | home: Home(title: 'Flutter Advanced Examples'), 19 | ) 20 | ); 21 | } 22 | ``` 23 | 24 | The example has two widgets that represents the shopping cart : 25 | 26 | * ShoppingCartAppBarIcon 27 | * ShoppingCartScreen 28 | 29 | The ShoppingCartAppBarIcon displays the amount of [products](Product.dart) in the shopping cart. 30 | 31 | ```dart 32 | StreamBuilder( 33 | stream: BlocProvider.of(context).shoppingCartBloc.cartStream, 34 | initialData: ShoppingCart(), 35 | builder: (context, snapshot) { 36 | int count = 0; 37 | if (snapshot.hasData) { 38 | if (snapshot.data is ShoppingCart) { 39 | count = snapshot.data.products.length; 40 | } 41 | } 42 | return Chip( 43 | label: Text(count.toString()), 44 | backgroundColor: Colors.transparent, 45 | avatar: Icon( 46 | Icons.shopping_cart, 47 | color: Theme.of(context).primaryColor, 48 | ), 49 | ); 50 | }, 51 | ), 52 | ``` 53 | 54 | It also links to the [ShoppingCartScreen](ShoppingCartScreen.dart). 55 | 56 | ```dart 57 | onPressed: () { 58 | Navigator.push( 59 | context, 60 | MaterialPageRoute(builder: (context) => ShoppingCartScreen()), 61 | ); 62 | } 63 | ``` 64 | 65 | The widget [Example5](Example5.dart) displays a list of products. Each product can be added to the shopping cart. 66 | 67 | ```dart 68 | onTap: () { 69 | BlocProvider.of(context) 70 | .shoppingCartBloc 71 | .addition 72 | .add(productList.elementAt(index)); 73 | } 74 | ``` 75 | 76 | The [ShoppingCartBloc](ShoppingCartBloc.dart) handles adding and removing items to the cart. 77 | We have a sink for adding and removing items. 78 | 79 | ```dart 80 | /// Sinks 81 | Sink get addition => itemAdditionController.sink; 82 | final itemAdditionController = StreamController(); 83 | 84 | Sink get substraction => itemSubtractionController.sink; 85 | final itemSubtractionController = StreamController(); 86 | 87 | ShoppingCartBloc() { 88 | itemAdditionController.stream.listen(handleItemAdd); 89 | itemSubtractionController.stream.listen(handleItemRem); 90 | } 91 | ``` 92 | 93 | We have two methods that will be called when an item is pushed into the sink. We add or remove the [Product](Product.dart) from the [ShoppingCart](ShoppingCart.dart). After recalculating, the cart is added to the stream. 94 | 95 | ```dart 96 | void handleItemAdd(Product item) { 97 | Logger(TAG).info("Add product to the shopping cart"); 98 | cart.addProduct(item); 99 | cart.calculate(); 100 | _cart.add(cart); 101 | } 102 | 103 | void handleItemRem(Product item) { 104 | Logger(TAG).info("Remove product from the shopping cart"); 105 | cart.remProduct(item); 106 | cart.calculate(); 107 | _cart.add(cart); 108 | } 109 | ``` 110 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/ShoppingCart.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/examples/shoppingCart/Product.dart'; 2 | 3 | class ShoppingCart { 4 | List products = []; 5 | double priceNet; 6 | double priceGross; 7 | double vatAmount; 8 | 9 | void addProduct(Product p) { 10 | products.add(p); 11 | } 12 | 13 | void remProduct(Product p) { 14 | products.remove(p); 15 | } 16 | 17 | void calculate() { 18 | priceNet = 0; 19 | priceGross = 0; 20 | vatAmount = 0; 21 | products.forEach((p) { 22 | priceNet += p.priceNet; 23 | priceGross += p.priceGross; 24 | vatAmount += p.vatAmount; 25 | }); 26 | } 27 | 28 | void clear() { 29 | products = []; 30 | priceNet = 0; 31 | priceGross = 0; 32 | vatAmount = 0; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/ShoppingCartAppBarIcon.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 2 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 3 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCart.dart'; 4 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCartScreen.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class ShoppingCartAppBarIcon extends StatefulWidget { 8 | ShoppingCartAppBarIcon(); 9 | 10 | @override 11 | ShoppingCartAppBarIconState createState() => ShoppingCartAppBarIconState(); 12 | } 13 | 14 | class ShoppingCartAppBarIconState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return FlatButton( 18 | child: StreamBuilder( 19 | stream: 20 | BlocProvider.of(context).shoppingCartBloc.cartStream, 21 | initialData: ShoppingCart(), 22 | builder: (context, snapshot) { 23 | int count = 0; 24 | if (snapshot.hasData) { 25 | if (snapshot.data is ShoppingCart) { 26 | count = snapshot.data.products.length; 27 | } 28 | } 29 | return Chip( 30 | label: Text(count.toString()), 31 | backgroundColor: Colors.transparent, 32 | avatar: Icon( 33 | Icons.shopping_cart, 34 | color: Theme.of(context).primaryColor, 35 | ), 36 | ); 37 | }, 38 | ), 39 | onPressed: () { 40 | Navigator.push( 41 | context, 42 | MaterialPageRoute(builder: (context) => ShoppingCartScreen()), 43 | ); 44 | }, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/ShoppingCartBloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 4 | import 'package:advanced_flutter_example/examples/shoppingCart/Product.dart'; 5 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCart.dart'; 6 | import 'package:logging/logging.dart'; 7 | import 'package:rxdart/rxdart.dart'; 8 | 9 | class ShoppingCartBloc implements BlocBase { 10 | static const String TAG = "ShoppingCartBloc"; 11 | 12 | ShoppingCart cart = ShoppingCart(); 13 | 14 | /// Sinks 15 | Sink get addition => itemAdditionController.sink; 16 | final itemAdditionController = StreamController(); 17 | 18 | Sink get substraction => itemSubtractionController.sink; 19 | final itemSubtractionController = StreamController(); 20 | 21 | /// Streams 22 | Stream get cartStream => _cart.stream; 23 | final _cart = BehaviorSubject(); 24 | 25 | ShoppingCartBloc() { 26 | itemAdditionController.stream.listen(handleItemAdd); 27 | itemSubtractionController.stream.listen(handleItemRem); 28 | } 29 | 30 | /// 31 | /// Logic for product added to shopping cart. 32 | /// 33 | void handleItemAdd(Product item) { 34 | Logger(TAG).info("Add product to the shopping cart"); 35 | cart.addProduct(item); 36 | cart.calculate(); 37 | _cart.add(cart); 38 | return; 39 | } 40 | 41 | /// 42 | /// Logic for product removed from shopping cart. 43 | /// 44 | void handleItemRem(Product item) { 45 | Logger(TAG).info("Remove product from the shopping cart"); 46 | cart.remProduct(item); 47 | cart.calculate(); 48 | _cart.add(cart); 49 | return; 50 | } 51 | 52 | /// 53 | /// Clears the shopping cart 54 | /// 55 | void clearCart() { 56 | cart.clear(); 57 | } 58 | 59 | @override 60 | void dispose() { 61 | itemAdditionController.close(); 62 | itemSubtractionController.close(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/examples/shoppingCart/ShoppingCartScreen.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/DefaultAppBar.dart'; 2 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 3 | import 'package:advanced_flutter_example/examples/shoppingCart/Example5.dart'; 4 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 5 | import 'package:advanced_flutter_example/examples/shoppingCart/Product.dart'; 6 | import 'package:advanced_flutter_example/examples/shoppingCart/ShoppingCart.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | class ShoppingCartScreen extends StatefulWidget { 10 | ShoppingCartScreen(); 11 | 12 | final String title = "Shopping Cart"; 13 | final String exampleUrl = 14 | "https://github.com/Ephenodrom/FlutterAdvancedExamples/tree/master/lib/examples/shoppingCart"; 15 | 16 | @override 17 | _ShoppingCartState createState() => _ShoppingCartState(); 18 | } 19 | 20 | class _ShoppingCartState extends State { 21 | ShoppingCart cart; 22 | 23 | @override 24 | void initState() { 25 | super.initState(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: DefaultAppBar(widget.title, widget.exampleUrl), 32 | body: StreamBuilder( 33 | stream: BlocProvider.of(context) 34 | .shoppingCartBloc 35 | .cartStream, 36 | builder: (context, snapshot) { 37 | if (!snapshot.hasData) { 38 | return Center(child: Text("Shopping cart is empty")); 39 | } else { 40 | cart = snapshot.data; 41 | if (cart.products.length == 0) { 42 | return Center(child: Text("Shopping cart is empty")); 43 | } 44 | return Container( 45 | padding: EdgeInsets.all(16), 46 | child: Column(children: [ 47 | Expanded( 48 | child: ListView( 49 | children: [ 50 | Card( 51 | child: ListTile( 52 | leading: Text("Total - Gross", 53 | style: Theme.of(context).textTheme.subhead), 54 | trailing: Text(cart.priceNet.toString() + " €", 55 | style: 56 | Theme.of(context).textTheme.headline), 57 | ), 58 | ), 59 | Card( 60 | child: ExpansionTile( 61 | title: Text("Products (" + 62 | cart.products.length.toString() + 63 | ")"), 64 | children: getProductTiles()), 65 | ) 66 | ], 67 | ), 68 | ), 69 | Padding( 70 | padding: const EdgeInsets.only(bottom: 50.0), 71 | child: SizedBox( 72 | width: double.infinity, 73 | child: RaisedButton( 74 | child: Text("Order now!"), 75 | onPressed: () { 76 | BlocProvider.of(context) 77 | .shoppingCartBloc 78 | .clearCart(); 79 | Scaffold.of(context).showSnackBar( 80 | SnackBar(content: Text("Order completed!"))); 81 | Navigator.push( 82 | context, 83 | MaterialPageRoute( 84 | builder: (context) => Example5()), 85 | ); 86 | }, 87 | ), 88 | ), 89 | ) 90 | ])); 91 | } 92 | })); 93 | } 94 | 95 | List getProductTiles() { 96 | List list = []; 97 | if (cart != null) { 98 | for (Product p in cart.products) { 99 | String name = p.name; 100 | String price = p.priceNet.toString(); 101 | list.add(ListTile( 102 | title: Text(name), 103 | subtitle: Text(price + " €"), 104 | trailing: FlatButton( 105 | padding: EdgeInsets.only(left: 0, right: 0), 106 | child: Icon(Icons.clear, color: Colors.red), 107 | onPressed: () { 108 | BlocProvider.of(context) 109 | .shoppingCartBloc 110 | .substraction 111 | .add(p); 112 | }, 113 | ), 114 | )); 115 | } 116 | } 117 | return list; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lib/generated/i18n.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | // ignore_for_file: non_constant_identifier_names 7 | // ignore_for_file: camel_case_types 8 | // ignore_for_file: prefer_single_quotes 9 | 10 | //This file is automatically generated. DO NOT EDIT, all your changes would be lost. 11 | class S implements WidgetsLocalizations { 12 | const S(); 13 | 14 | static const GeneratedLocalizationsDelegate delegate = 15 | GeneratedLocalizationsDelegate(); 16 | 17 | static S of(BuildContext context) => Localizations.of(context, S); 18 | 19 | @override 20 | TextDirection get textDirection => TextDirection.ltr; 21 | 22 | } 23 | 24 | class $en extends S { 25 | const $en(); 26 | } 27 | 28 | class GeneratedLocalizationsDelegate extends LocalizationsDelegate { 29 | const GeneratedLocalizationsDelegate(); 30 | 31 | List get supportedLocales { 32 | return const [ 33 | Locale("en", ""), 34 | ]; 35 | } 36 | 37 | LocaleListResolutionCallback listResolution({Locale fallback}) { 38 | return (List locales, Iterable supported) { 39 | if (locales == null || locales.isEmpty) { 40 | return fallback ?? supported.first; 41 | } else { 42 | return _resolve(locales.first, fallback, supported); 43 | } 44 | }; 45 | } 46 | 47 | LocaleResolutionCallback resolution({Locale fallback}) { 48 | return (Locale locale, Iterable supported) { 49 | return _resolve(locale, fallback, supported); 50 | }; 51 | } 52 | 53 | Locale _resolve(Locale locale, Locale fallback, Iterable supported) { 54 | if (locale == null || !isSupported(locale)) { 55 | return fallback ?? supported.first; 56 | } 57 | 58 | final Locale languageLocale = Locale(locale.languageCode, ""); 59 | if (supported.contains(locale)) { 60 | return locale; 61 | } else if (supported.contains(languageLocale)) { 62 | return languageLocale; 63 | } else { 64 | final Locale fallbackLocale = fallback ?? supported.first; 65 | return fallbackLocale; 66 | } 67 | } 68 | 69 | @override 70 | Future load(Locale locale) { 71 | final String lang = getLang(locale); 72 | if (lang != null) { 73 | switch (lang) { 74 | case "en": 75 | return SynchronousFuture(const $en()); 76 | default: 77 | // NO-OP. 78 | } 79 | } 80 | return SynchronousFuture(const S()); 81 | } 82 | 83 | @override 84 | bool isSupported(Locale locale) => 85 | locale != null && supportedLocales.contains(locale); 86 | 87 | @override 88 | bool shouldReload(GeneratedLocalizationsDelegate old) => false; 89 | } 90 | 91 | String getLang(Locale l) => l == null 92 | ? null 93 | : l.countryCode != null && l.countryCode.isEmpty 94 | ? l.languageCode 95 | : l.toString(); 96 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:advanced_flutter_example/ExampleList.dart'; 2 | import 'package:advanced_flutter_example/basic/BlocProvider.dart'; 3 | import 'package:advanced_flutter_example/basic/GlobalBloc.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | void main() async { 7 | runApp(MyApp()); 8 | } 9 | 10 | class MyApp extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | return BlocProvider( 14 | bloc: GlobalBloc(), 15 | child: MaterialApp( 16 | title: 'Flutter Advanced Example', 17 | home: Home(title: 'Examples'), 18 | )); 19 | } 20 | } 21 | 22 | class Home extends StatefulWidget { 23 | final String title; 24 | 25 | Home({this.title}); 26 | 27 | @override 28 | HomeState createState() => HomeState(); 29 | } 30 | 31 | class HomeState extends State { 32 | HomeState(); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Scaffold( 37 | appBar: AppBar( 38 | title: Text(widget.title), 39 | ), 40 | body: Container(child: ExampleList()), 41 | ); 42 | } 43 | 44 | @override 45 | void dispose() { 46 | super.dispose(); 47 | } 48 | 49 | @override 50 | void initState() { 51 | super.initState(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: advanced_flutter_example 2 | description: A advanced flutter example project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+3 11 | 12 | environment: 13 | sdk: ">=2.0.0-dev.68.0 <3.0.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | # The following adds the Cupertino Icons font to your application. 20 | # Use with the CupertinoIcons class for iOS style icons. 21 | cupertino_icons: ^0.1.2 22 | build_runner: ^1.1.3 23 | shared_preferences: ^0.4.3 24 | firebase_admob: 0.6.1 25 | json_serializable: ^2.0.1 26 | url_launcher: ^4.0.3 27 | global_configuration: ^0.1.4 28 | rxdart: ^0.20.0 29 | 30 | dev_dependencies: 31 | flutter_test: 32 | sdk: flutter 33 | flutter_launcher_icons: "^0.7.0" 34 | 35 | flutter_icons: 36 | android: "launcher_icon" 37 | ios: true 38 | image_path: "assets/logo_fae.png" 39 | 40 | 41 | # For information on the generic Dart part of this file, see the 42 | # following page: https://www.dartlang.org/tools/pub/pubspec 43 | 44 | # The following section is specific to Flutter. 45 | flutter: 46 | 47 | # The following line ensures that the Material Icons font is 48 | # included with your application, so that you can use the icons in 49 | # the material Icons class. 50 | uses-material-design: true 51 | 52 | # To add assets to your application, add an assets section, like this: 53 | # assets: 54 | # - assets/json/ 55 | # - images/a_dot_ham.jpeg 56 | assets: 57 | - assets/json/ 58 | - assets/cfg/ 59 | 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.io/assets-and-images/#resolution-aware. 62 | 63 | # For details regarding adding assets from package dependencies, see 64 | # https://flutter.io/assets-and-images/#from-packages 65 | 66 | # To add custom fonts to your application, add a fonts section here, 67 | # in this "flutter" section. Each entry in this list should have a 68 | # "family" key with the font family name, and a "fonts" key with a 69 | # list giving the asset and other descriptors for the font. For 70 | # example: 71 | # fonts: 72 | # - family: Schyler 73 | # fonts: 74 | # - asset: fonts/Schyler-Regular.ttf 75 | # - asset: fonts/Schyler-Italic.ttf 76 | # style: italic 77 | # - family: Trajan Pro 78 | # fonts: 79 | # - asset: fonts/TrajanPro.ttf 80 | # - asset: fonts/TrajanPro_Bold.ttf 81 | # weight: 700 82 | # 83 | # For details regarding fonts from package dependencies, 84 | # see https://flutter.io/custom-fonts/#from-packages 85 | -------------------------------------------------------------------------------- /res/values/strings_en.arb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ephenodrom/Flutter-Advanced-Examples/1f25b8005dfe696d6611236a89cec9729b1e2143/res/values/strings_en.arb -------------------------------------------------------------------------------- /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:advanced_flutter_example/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 | --------------------------------------------------------------------------------