├── .gitignore ├── .metadata ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── friendlyeats │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── friendlyeater.png ├── firebase.json ├── firestore.indexes.json ├── firestore.rules ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── GoogleService-Info.plist │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── main.dart └── src │ ├── app.dart │ ├── home_page.dart │ ├── model │ ├── data.dart │ ├── filter.dart │ ├── restaurant.dart │ ├── review.dart │ └── values.dart │ ├── restaurant_page.dart │ └── widgets │ ├── app_bar.dart │ ├── card.dart │ ├── dialogs │ ├── filter_select.dart │ └── review_create.dart │ ├── empty_list.dart │ ├── filter_bar.dart │ ├── grid.dart │ ├── review.dart │ └── stars.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Firebase 37 | .firebase 38 | .firebaserc 39 | 40 | # Exceptions to above rules. 41 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 42 | -------------------------------------------------------------------------------- /.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: b7d221227ca1c9916974784f682f4bb8d2513878 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Firebase FriendlyChat Codelab 2 | 3 | We'd love for you to contribute to our source code and to make the Firebase FriendlyChat Codelab even better than it is today! Here are the guidelines we'd like you to follow: 4 | 5 | - [Code of Conduct](#coc) 6 | - [Question or Problem?](#question) 7 | - [Issues and Bugs](#issue) 8 | - [Feature Requests](#feature) 9 | - [Submission Guidelines](#submit) 10 | - [Coding Rules](#rules) 11 | - [Signing the CLA](#cla) 12 | 13 | ## Code of Conduct 14 | 15 | As contributors and maintainers of the Firebase FriendlyChat Codelab project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. 16 | 17 | Communication through any of Firebase's channels (GitHub, StackOverflow, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 18 | 19 | We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the project to do the same. 20 | 21 | If any member of the community violates this code of conduct, the maintainers of the Firebase Android Quickstarts project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate. 22 | 23 | If you are subject to or witness unacceptable behavior, or have any other concerns, please drop us a line at nivco@google.com. 24 | 25 | ## Got a Question or Problem? 26 | 27 | If you have questions about how to use the Firebase FriendlyChat Codelab, please direct these to [StackOverflow][stackoverflow] and use the `firebase` tag. We are also available on GitHub issues. 28 | 29 | If you feel that we're missing an important bit of documentation, feel free to 30 | file an issue so we can help. Here's an example to get you started: 31 | 32 | ``` 33 | What are you trying to do or find out more about? 34 | 35 | Where have you looked? 36 | 37 | Where did you expect to find this information? 38 | ``` 39 | 40 | ## Found an Issue? 41 | If you find a bug in the source code or a mistake in the documentation, you can help us by 42 | submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request 43 | with a fix. 44 | 45 | See [below](#submit) for some guidelines. 46 | 47 | ## Submission Guidelines 48 | 49 | ### Submitting an Issue 50 | Before you submit your issue search the archive, maybe your question was already answered. 51 | 52 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 53 | Help us to maximize the effort we can spend fixing issues and adding new 54 | features, by not reporting duplicate issues. Providing the following information will increase the 55 | chances of your issue being dealt with quickly: 56 | 57 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 58 | * **Motivation for or Use Case** - explain why this is a bug for you 59 | * **Browsers and Operating System** - is this a problem with all browsers or only IE9? 60 | * **Reproduce the Error** - provide a live example (using JSBin) or a unambiguous set of steps. 61 | * **Related Issues** - has a similar issue been reported before? 62 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 63 | causing the problem (line of code or commit) 64 | 65 | **If you get help, help others. Good karma rulez!** 66 | 67 | Here's a template to get you started: 68 | 69 | ``` 70 | Browser: 71 | Browser version: 72 | Operating system: 73 | Operating system version: 74 | 75 | What steps will reproduce the problem: 76 | 1. 77 | 2. 78 | 3. 79 | 80 | What is the expected result? 81 | 82 | What happens instead of that? 83 | 84 | Please provide any other information below, and attach a screenshot if possible. 85 | ``` 86 | 87 | ### Submitting a Pull Request 88 | Before you submit your pull request consider the following guidelines: 89 | 90 | * Search [GitHub](https://github.com/firebase/codelab-friendlychat/pulls) for an open or closed Pull Request 91 | that relates to your submission. You don't want to duplicate effort. 92 | * Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull 93 | requests. We cannot accept code without this. 94 | * Make your changes in a new git branch: 95 | 96 | ```shell 97 | git checkout -b my-fix-branch master 98 | ``` 99 | 100 | * Create your patch, **including appropriate test cases**. 101 | * Follow our [Coding Rules](#rules). 102 | * Avoid checking in files that shouldn't be tracked (e.g `node_modules`, `gulp-cache`, `.tmp`, `.idea`). We recommend using a [global](#global-gitignore) gitignore for this. 103 | * Make sure **not** to include a recompiled version of the files found in `/css` and `/js` as part of your PR. We will generate these automatically. 104 | * Commit your changes using a descriptive commit message. 105 | 106 | ```shell 107 | git commit -a 108 | ``` 109 | Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files. 110 | 111 | * Build your changes locally to ensure all the tests pass: 112 | 113 | ```shell 114 | gulp 115 | ``` 116 | 117 | * Push your branch to GitHub: 118 | 119 | ```shell 120 | git push origin my-fix-branch 121 | ``` 122 | 123 | * In GitHub, send a pull request to `codelab-friendlychat:master`. 124 | * If we suggest changes then: 125 | * Make the required updates. 126 | * Rebase your branch and force push to your GitHub repository (this will update your Pull Request): 127 | 128 | ```shell 129 | git rebase master -i 130 | git push origin my-fix-branch -f 131 | ``` 132 | 133 | That's it! Thank you for your contribution! 134 | 135 | #### After your pull request is merged 136 | 137 | After your pull request is merged, you can safely delete your branch and pull the changes 138 | from the main (upstream) repository: 139 | 140 | * Delete the remote branch on GitHub either through the GitHub Android UI or your local shell as follows: 141 | 142 | ```shell 143 | git push origin --delete my-fix-branch 144 | ``` 145 | 146 | * Check out the master branch: 147 | 148 | ```shell 149 | git checkout master -f 150 | ``` 151 | 152 | * Delete the local branch: 153 | 154 | ```shell 155 | git branch -D my-fix-branch 156 | ``` 157 | 158 | * Update your master with the latest upstream version: 159 | 160 | ```shell 161 | git pull --ff upstream master 162 | ``` 163 | 164 | ## Signing the CLA 165 | 166 | Please sign our [Contributor License Agreement][google-cla] (CLA) before sending pull requests. For any code 167 | changes to be accepted, the CLA must be signed. It's a quick process, we promise! 168 | 169 | *This guide was inspired by the [AngularJS contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).* 170 | 171 | [github]: https://github.com/firebase/friendlychat 172 | [google-cla]: https://cla.developers.google.com 173 | [js-style-guide]: http://google.github.io/styleguide/javascriptguide.xml 174 | [py-style-guide]: http://google.github.io/styleguide/pyguide.html 175 | [jsbin]: http://jsbin.com/ 176 | [stackoverflow]: http://stackoverflow.com/questions/tagged/firebase 177 | [global-gitignore]: https://help.github.com/articles/ignoring-files/#create-a-global-gitignore -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlutterFire Codelab: Friendly Eats 2 | A cross-platform Flutter port of the "Friendly Eats" Firestore codelab. 3 | 4 | This is the source code for the FlutterFire Friendly Eats codelab. It includes 5 | start and end versions of the required code. -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.yaml -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 29 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.friendlyeats" 42 | minSdkVersion 21 43 | targetSdkVersion 29 44 | multiDexEnabled true 45 | versionCode flutterVersionCode.toInteger() 46 | versionName flutterVersionName 47 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 48 | } 49 | 50 | buildTypes { 51 | release { 52 | // TODO: Add your own signing config for the release build. 53 | // Signing with the debug keys for now, so `flutter run --release` works. 54 | signingConfig signingConfigs.debug 55 | } 56 | } 57 | } 58 | 59 | flutter { 60 | source '../..' 61 | } 62 | 63 | dependencies { 64 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 65 | implementation 'com.android.support:multidex:1.0.3' 66 | testImplementation 'junit:junit:4.12' 67 | androidTestImplementation 'androidx.test:runner:1.3.0' 68 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 69 | } 70 | 71 | apply plugin: 'com.google.gms.google-services' 72 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 24 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/friendlyeats/MainActivity.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package com.example.friendlyeats 16 | 17 | import androidx.annotation.NonNull; 18 | import io.flutter.embedding.android.FlutterActivity 19 | import io.flutter.embedding.engine.FlutterEngine 20 | import io.flutter.plugins.GeneratedPluginRegistrant 21 | 22 | class MainActivity: FlutterActivity() { 23 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 24 | GeneratedPluginRegistrant.registerWith(flutterEngine); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 24 | 25 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.0.1' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.3' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | } 26 | subprojects { 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 06 18:43:15 CEST 2020 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-6.1.1-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/friendlyeater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/assets/friendlyeater.png -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "predeploy": "flutter clean && flutter build web", 4 | "public": "build/web", 5 | "ignore": [ 6 | "firebase.json", 7 | "**/.*", 8 | "**/node_modules/**" 9 | ], 10 | "rewrites": [ 11 | { 12 | "source": "**", 13 | "destination": "/index.html" 14 | } 15 | ] 16 | }, 17 | "firestore": { 18 | "rules": "firestore.rules", 19 | "indexes": "firestore.indexes.json" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [ 3 | { 4 | "collectionGroup": "restaurants", 5 | "queryScope": "COLLECTION", 6 | "fields": [ 7 | { 8 | "fieldPath": "price", 9 | "order": "ASCENDING" 10 | }, 11 | { 12 | "fieldPath": "avgRating", 13 | "order": "DESCENDING" 14 | } 15 | ] 16 | }, 17 | { 18 | "collectionGroup": "restaurants", 19 | "queryScope": "COLLECTION", 20 | "fields": [ 21 | { 22 | "fieldPath": "city", 23 | "order": "ASCENDING" 24 | }, 25 | { 26 | "fieldPath": "avgRating", 27 | "order": "DESCENDING" 28 | } 29 | ] 30 | }, 31 | { 32 | "collectionGroup": "restaurants", 33 | "queryScope": "COLLECTION", 34 | "fields": [ 35 | { 36 | "fieldPath": "price", 37 | "order": "ASCENDING" 38 | }, 39 | { 40 | "fieldPath": "numRatings", 41 | "order": "DESCENDING" 42 | } 43 | ] 44 | }, 45 | { 46 | "collectionGroup": "restaurants", 47 | "queryScope": "COLLECTION", 48 | "fields": [ 49 | { 50 | "fieldPath": "city", 51 | "order": "ASCENDING" 52 | }, 53 | { 54 | "fieldPath": "numRatings", 55 | "order": "DESCENDING" 56 | } 57 | ] 58 | }, 59 | { 60 | "collectionGroup": "restaurants", 61 | "queryScope": "COLLECTION", 62 | "fields": [ 63 | { 64 | "fieldPath": "category", 65 | "order": "ASCENDING" 66 | }, 67 | { 68 | "fieldPath": "avgRating", 69 | "order": "DESCENDING" 70 | } 71 | ] 72 | }, 73 | { 74 | "collectionGroup": "restaurants", 75 | "queryScope": "COLLECTION", 76 | "fields": [ 77 | { 78 | "fieldPath": "category", 79 | "order": "ASCENDING" 80 | }, 81 | { 82 | "fieldPath": "price", 83 | "order": "ASCENDING" 84 | } 85 | ] 86 | }, 87 | { 88 | "collectionGroup": "restaurants", 89 | "queryScope": "COLLECTION", 90 | "fields": [ 91 | { 92 | "fieldPath": "city", 93 | "order": "ASCENDING" 94 | }, 95 | { 96 | "fieldPath": "price", 97 | "order": "ASCENDING" 98 | } 99 | ] 100 | }, 101 | { 102 | "collectionGroup": "restaurants", 103 | "queryScope": "COLLECTION", 104 | "fields": [ 105 | { 106 | "fieldPath": "category", 107 | "order": "ASCENDING" 108 | }, 109 | { 110 | "fieldPath": "numRatings", 111 | "order": "DESCENDING" 112 | } 113 | ] 114 | } 115 | ], 116 | "fieldOverrides": [] 117 | } -------------------------------------------------------------------------------- /firestore.rules: -------------------------------------------------------------------------------- 1 | service cloud.firestore { 2 | match /databases/{database}/documents { 3 | // Restaurants: 4 | // - Authenticated user can read 5 | // - Authenticated user can create/update (for demo) 6 | // - Validate updates 7 | // - Deletes are not allowed 8 | match /restaurants/{restaurantId} { 9 | allow read, create: if request.auth != null; 10 | allow update: if request.auth != null 11 | && request.resource.data.name == resource.data.name 12 | allow delete: if false; 13 | 14 | // Ratings: 15 | // - Authenticated user can read 16 | // - Authenticated user can create if userId matches 17 | // - Deletes and updates are not allowed 18 | match /ratings/{ratingId} { 19 | allow read: if request.auth != null; 20 | allow create: if request.auth != null 21 | && request.resource.data.userId == request.auth.uid; 22 | allow update, delete: if false; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 82 | install! 'cocoapods', :disable_input_output_paths => true 83 | 84 | post_install do |installer| 85 | installer.pods_project.targets.each do |target| 86 | target.build_configurations.each do |config| 87 | config.build_settings['ENABLE_BITCODE'] = 'NO' 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - abseil/algorithm (0.20190808): 3 | - abseil/algorithm/algorithm (= 0.20190808) 4 | - abseil/algorithm/container (= 0.20190808) 5 | - abseil/algorithm/algorithm (0.20190808) 6 | - abseil/algorithm/container (0.20190808): 7 | - abseil/algorithm/algorithm 8 | - abseil/base/core_headers 9 | - abseil/meta/type_traits 10 | - abseil/base (0.20190808): 11 | - abseil/base/atomic_hook (= 0.20190808) 12 | - abseil/base/base (= 0.20190808) 13 | - abseil/base/base_internal (= 0.20190808) 14 | - abseil/base/bits (= 0.20190808) 15 | - abseil/base/config (= 0.20190808) 16 | - abseil/base/core_headers (= 0.20190808) 17 | - abseil/base/dynamic_annotations (= 0.20190808) 18 | - abseil/base/endian (= 0.20190808) 19 | - abseil/base/log_severity (= 0.20190808) 20 | - abseil/base/malloc_internal (= 0.20190808) 21 | - abseil/base/pretty_function (= 0.20190808) 22 | - abseil/base/spinlock_wait (= 0.20190808) 23 | - abseil/base/throw_delegate (= 0.20190808) 24 | - abseil/base/atomic_hook (0.20190808) 25 | - abseil/base/base (0.20190808): 26 | - abseil/base/atomic_hook 27 | - abseil/base/base_internal 28 | - abseil/base/config 29 | - abseil/base/core_headers 30 | - abseil/base/dynamic_annotations 31 | - abseil/base/log_severity 32 | - abseil/base/spinlock_wait 33 | - abseil/meta/type_traits 34 | - abseil/base/base_internal (0.20190808): 35 | - abseil/meta/type_traits 36 | - abseil/base/bits (0.20190808): 37 | - abseil/base/core_headers 38 | - abseil/base/config (0.20190808) 39 | - abseil/base/core_headers (0.20190808): 40 | - abseil/base/config 41 | - abseil/base/dynamic_annotations (0.20190808) 42 | - abseil/base/endian (0.20190808): 43 | - abseil/base/config 44 | - abseil/base/core_headers 45 | - abseil/base/log_severity (0.20190808): 46 | - abseil/base/core_headers 47 | - abseil/base/malloc_internal (0.20190808): 48 | - abseil/base/base 49 | - abseil/base/config 50 | - abseil/base/core_headers 51 | - abseil/base/dynamic_annotations 52 | - abseil/base/spinlock_wait 53 | - abseil/base/pretty_function (0.20190808) 54 | - abseil/base/spinlock_wait (0.20190808): 55 | - abseil/base/core_headers 56 | - abseil/base/throw_delegate (0.20190808): 57 | - abseil/base/base 58 | - abseil/base/config 59 | - abseil/memory (0.20190808): 60 | - abseil/memory/memory (= 0.20190808) 61 | - abseil/memory/memory (0.20190808): 62 | - abseil/base/core_headers 63 | - abseil/meta/type_traits 64 | - abseil/meta (0.20190808): 65 | - abseil/meta/type_traits (= 0.20190808) 66 | - abseil/meta/type_traits (0.20190808): 67 | - abseil/base/config 68 | - abseil/numeric/int128 (0.20190808): 69 | - abseil/base/config 70 | - abseil/base/core_headers 71 | - abseil/strings/internal (0.20190808): 72 | - abseil/base/core_headers 73 | - abseil/base/endian 74 | - abseil/meta/type_traits 75 | - abseil/strings/strings (0.20190808): 76 | - abseil/base/base 77 | - abseil/base/bits 78 | - abseil/base/config 79 | - abseil/base/core_headers 80 | - abseil/base/endian 81 | - abseil/base/throw_delegate 82 | - abseil/memory/memory 83 | - abseil/meta/type_traits 84 | - abseil/numeric/int128 85 | - abseil/strings/internal 86 | - abseil/time (0.20190808): 87 | - abseil/time/internal (= 0.20190808) 88 | - abseil/time/time (= 0.20190808) 89 | - abseil/time/internal (0.20190808): 90 | - abseil/time/internal/cctz (= 0.20190808) 91 | - abseil/time/internal/cctz (0.20190808): 92 | - abseil/time/internal/cctz/civil_time (= 0.20190808) 93 | - abseil/time/internal/cctz/includes (= 0.20190808) 94 | - abseil/time/internal/cctz/time_zone (= 0.20190808) 95 | - abseil/time/internal/cctz/civil_time (0.20190808) 96 | - abseil/time/internal/cctz/includes (0.20190808) 97 | - abseil/time/internal/cctz/time_zone (0.20190808): 98 | - abseil/time/internal/cctz/civil_time 99 | - abseil/time/time (0.20190808): 100 | - abseil/base/base 101 | - abseil/base/core_headers 102 | - abseil/numeric/int128 103 | - abseil/strings/strings 104 | - abseil/time/internal/cctz/civil_time 105 | - abseil/time/internal/cctz/time_zone 106 | - abseil/types (0.20190808): 107 | - abseil/types/any (= 0.20190808) 108 | - abseil/types/bad_any_cast (= 0.20190808) 109 | - abseil/types/bad_any_cast_impl (= 0.20190808) 110 | - abseil/types/bad_optional_access (= 0.20190808) 111 | - abseil/types/bad_variant_access (= 0.20190808) 112 | - abseil/types/compare (= 0.20190808) 113 | - abseil/types/optional (= 0.20190808) 114 | - abseil/types/span (= 0.20190808) 115 | - abseil/types/variant (= 0.20190808) 116 | - abseil/types/any (0.20190808): 117 | - abseil/base/config 118 | - abseil/base/core_headers 119 | - abseil/meta/type_traits 120 | - abseil/types/bad_any_cast 121 | - abseil/utility/utility 122 | - abseil/types/bad_any_cast (0.20190808): 123 | - abseil/base/config 124 | - abseil/types/bad_any_cast_impl 125 | - abseil/types/bad_any_cast_impl (0.20190808): 126 | - abseil/base/base 127 | - abseil/base/config 128 | - abseil/types/bad_optional_access (0.20190808): 129 | - abseil/base/base 130 | - abseil/base/config 131 | - abseil/types/bad_variant_access (0.20190808): 132 | - abseil/base/base 133 | - abseil/base/config 134 | - abseil/types/compare (0.20190808): 135 | - abseil/base/core_headers 136 | - abseil/meta/type_traits 137 | - abseil/types/optional (0.20190808): 138 | - abseil/base/base_internal 139 | - abseil/base/config 140 | - abseil/base/core_headers 141 | - abseil/memory/memory 142 | - abseil/meta/type_traits 143 | - abseil/types/bad_optional_access 144 | - abseil/utility/utility 145 | - abseil/types/span (0.20190808): 146 | - abseil/algorithm/algorithm 147 | - abseil/base/core_headers 148 | - abseil/base/throw_delegate 149 | - abseil/meta/type_traits 150 | - abseil/types/variant (0.20190808): 151 | - abseil/base/base_internal 152 | - abseil/base/config 153 | - abseil/base/core_headers 154 | - abseil/meta/type_traits 155 | - abseil/types/bad_variant_access 156 | - abseil/utility/utility 157 | - abseil/utility/utility (0.20190808): 158 | - abseil/base/base_internal 159 | - abseil/base/config 160 | - abseil/meta/type_traits 161 | - BoringSSL-GRPC (0.0.3): 162 | - BoringSSL-GRPC/Implementation (= 0.0.3) 163 | - BoringSSL-GRPC/Interface (= 0.0.3) 164 | - BoringSSL-GRPC/Implementation (0.0.3): 165 | - BoringSSL-GRPC/Interface (= 0.0.3) 166 | - BoringSSL-GRPC/Interface (0.0.3) 167 | - cloud_firestore (0.0.1): 168 | - Firebase/Core 169 | - Firebase/Firestore (~> 6.0) 170 | - Flutter 171 | - cloud_firestore_web (0.1.0): 172 | - Flutter 173 | - Firebase/Auth (6.14.0): 174 | - Firebase/CoreOnly 175 | - FirebaseAuth (~> 6.4.1) 176 | - Firebase/Core (6.14.0): 177 | - Firebase/CoreOnly 178 | - FirebaseAnalytics (= 6.1.7) 179 | - Firebase/CoreOnly (6.14.0): 180 | - FirebaseCore (= 6.5.0) 181 | - Firebase/Firestore (6.14.0): 182 | - Firebase/CoreOnly 183 | - FirebaseFirestore (~> 1.8.2) 184 | - firebase_auth (0.0.1): 185 | - Firebase/Auth (~> 6.3) 186 | - Firebase/Core 187 | - Flutter 188 | - firebase_auth_web (0.1.0): 189 | - Flutter 190 | - firebase_core (0.0.1): 191 | - Firebase/Core 192 | - Flutter 193 | - firebase_core_web (0.1.0): 194 | - Flutter 195 | - FirebaseAnalytics (6.1.7): 196 | - FirebaseCore (~> 6.5) 197 | - FirebaseInstanceID (~> 4.2) 198 | - GoogleAppMeasurement (= 6.1.7) 199 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 200 | - GoogleUtilities/MethodSwizzler (~> 6.0) 201 | - GoogleUtilities/Network (~> 6.0) 202 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 203 | - nanopb (= 0.3.9011) 204 | - FirebaseAuth (6.4.1): 205 | - FirebaseAuthInterop (~> 1.0) 206 | - FirebaseCore (~> 6.2) 207 | - GoogleUtilities/AppDelegateSwizzler (~> 6.2) 208 | - GoogleUtilities/Environment (~> 6.2) 209 | - GTMSessionFetcher/Core (~> 1.1) 210 | - FirebaseAuthInterop (1.0.0) 211 | - FirebaseCore (6.5.0): 212 | - FirebaseCoreDiagnostics (~> 1.0) 213 | - FirebaseCoreDiagnosticsInterop (~> 1.0) 214 | - GoogleUtilities/Environment (~> 6.4) 215 | - GoogleUtilities/Logger (~> 6.4) 216 | - FirebaseCoreDiagnostics (1.1.2): 217 | - FirebaseCoreDiagnosticsInterop (~> 1.0) 218 | - GoogleDataTransportCCTSupport (~> 1.0) 219 | - GoogleUtilities/Environment (~> 6.2) 220 | - GoogleUtilities/Logger (~> 6.2) 221 | - nanopb (~> 0.3.901) 222 | - FirebaseCoreDiagnosticsInterop (1.1.0) 223 | - FirebaseFirestore (1.8.3): 224 | - abseil/algorithm (= 0.20190808) 225 | - abseil/base (= 0.20190808) 226 | - abseil/memory (= 0.20190808) 227 | - abseil/meta (= 0.20190808) 228 | - abseil/strings/strings (= 0.20190808) 229 | - abseil/time (= 0.20190808) 230 | - abseil/types (= 0.20190808) 231 | - FirebaseAuthInterop (~> 1.0) 232 | - FirebaseCore (~> 6.2) 233 | - "gRPC-C++ (= 0.0.9)" 234 | - leveldb-library (~> 1.22) 235 | - nanopb (~> 0.3.901) 236 | - FirebaseInstanceID (4.2.8): 237 | - FirebaseCore (~> 6.5) 238 | - GoogleUtilities/Environment (~> 6.4) 239 | - GoogleUtilities/UserDefaults (~> 6.4) 240 | - Flutter (1.0.0) 241 | - GoogleAppMeasurement (6.1.7): 242 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 243 | - GoogleUtilities/MethodSwizzler (~> 6.0) 244 | - GoogleUtilities/Network (~> 6.0) 245 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 246 | - nanopb (= 0.3.9011) 247 | - GoogleDataTransport (3.2.0) 248 | - GoogleDataTransportCCTSupport (1.2.3): 249 | - GoogleDataTransport (~> 3.2) 250 | - nanopb (~> 0.3.901) 251 | - GoogleUtilities/AppDelegateSwizzler (6.4.0): 252 | - GoogleUtilities/Environment 253 | - GoogleUtilities/Logger 254 | - GoogleUtilities/Network 255 | - GoogleUtilities/Environment (6.4.0) 256 | - GoogleUtilities/Logger (6.4.0): 257 | - GoogleUtilities/Environment 258 | - GoogleUtilities/MethodSwizzler (6.4.0): 259 | - GoogleUtilities/Logger 260 | - GoogleUtilities/Network (6.4.0): 261 | - GoogleUtilities/Logger 262 | - "GoogleUtilities/NSData+zlib" 263 | - GoogleUtilities/Reachability 264 | - "GoogleUtilities/NSData+zlib (6.4.0)" 265 | - GoogleUtilities/Reachability (6.4.0): 266 | - GoogleUtilities/Logger 267 | - GoogleUtilities/UserDefaults (6.4.0): 268 | - GoogleUtilities/Logger 269 | - "gRPC-C++ (0.0.9)": 270 | - "gRPC-C++/Implementation (= 0.0.9)" 271 | - "gRPC-C++/Interface (= 0.0.9)" 272 | - "gRPC-C++/Implementation (0.0.9)": 273 | - "gRPC-C++/Interface (= 0.0.9)" 274 | - gRPC-Core (= 1.21.0) 275 | - nanopb (~> 0.3) 276 | - "gRPC-C++/Interface (0.0.9)" 277 | - gRPC-Core (1.21.0): 278 | - gRPC-Core/Implementation (= 1.21.0) 279 | - gRPC-Core/Interface (= 1.21.0) 280 | - gRPC-Core/Implementation (1.21.0): 281 | - BoringSSL-GRPC (= 0.0.3) 282 | - gRPC-Core/Interface (= 1.21.0) 283 | - nanopb (~> 0.3) 284 | - gRPC-Core/Interface (1.21.0) 285 | - GTMSessionFetcher/Core (1.3.0) 286 | - leveldb-library (1.22) 287 | - nanopb (0.3.9011): 288 | - nanopb/decode (= 0.3.9011) 289 | - nanopb/encode (= 0.3.9011) 290 | - nanopb/decode (0.3.9011) 291 | - nanopb/encode (0.3.9011) 292 | 293 | DEPENDENCIES: 294 | - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) 295 | - cloud_firestore_web (from `.symlinks/plugins/cloud_firestore_web/ios`) 296 | - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) 297 | - firebase_auth_web (from `.symlinks/plugins/firebase_auth_web/ios`) 298 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`) 299 | - firebase_core_web (from `.symlinks/plugins/firebase_core_web/ios`) 300 | - Flutter (from `Flutter`) 301 | 302 | SPEC REPOS: 303 | trunk: 304 | - abseil 305 | - BoringSSL-GRPC 306 | - Firebase 307 | - FirebaseAnalytics 308 | - FirebaseAuth 309 | - FirebaseAuthInterop 310 | - FirebaseCore 311 | - FirebaseCoreDiagnostics 312 | - FirebaseCoreDiagnosticsInterop 313 | - FirebaseFirestore 314 | - FirebaseInstanceID 315 | - GoogleAppMeasurement 316 | - GoogleDataTransport 317 | - GoogleDataTransportCCTSupport 318 | - GoogleUtilities 319 | - "gRPC-C++" 320 | - gRPC-Core 321 | - GTMSessionFetcher 322 | - leveldb-library 323 | - nanopb 324 | 325 | EXTERNAL SOURCES: 326 | cloud_firestore: 327 | :path: ".symlinks/plugins/cloud_firestore/ios" 328 | cloud_firestore_web: 329 | :path: ".symlinks/plugins/cloud_firestore_web/ios" 330 | firebase_auth: 331 | :path: ".symlinks/plugins/firebase_auth/ios" 332 | firebase_auth_web: 333 | :path: ".symlinks/plugins/firebase_auth_web/ios" 334 | firebase_core: 335 | :path: ".symlinks/plugins/firebase_core/ios" 336 | firebase_core_web: 337 | :path: ".symlinks/plugins/firebase_core_web/ios" 338 | Flutter: 339 | :path: Flutter 340 | 341 | SPEC CHECKSUMS: 342 | abseil: 18063d773f5366ff8736a050fe035a28f635fd27 343 | BoringSSL-GRPC: db8764df3204ccea016e1c8dd15d9a9ad63ff318 344 | cloud_firestore: b5f108f6c57f1ad913b9388b1dc60f925ada9066 345 | cloud_firestore_web: 9ec3dc7f5f98de5129339802d491c1204462bfec 346 | Firebase: 0219bb4782eb1406f1b9b0628a2e625484ce910d 347 | firebase_auth: 6838289663da45c488af0a82c246928588fcddc5 348 | firebase_auth_web: 0955c07bcc06e84af76b9d4e32e6f31518f2d7de 349 | firebase_core: 87e4c7cef68de46c0326ce2ee907fc7e365ead7e 350 | firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1 351 | FirebaseAnalytics: f68b9f3f1241385129ae0a83b63627fc420c05e5 352 | FirebaseAuth: 831577b184ecaba38bc886768c1c22a450cc44e3 353 | FirebaseAuthInterop: 0ffa57668be100582bb7643d4fcb7615496c41fc 354 | FirebaseCore: 632e05cc5e1199d9147122c16d92305eb04c34bd 355 | FirebaseCoreDiagnostics: 511f4f3ed7d440bb69127e8b97c2bc8befae639e 356 | FirebaseCoreDiagnosticsInterop: e9b1b023157e3a2fc6418b5cb601e79b9af7b3a0 357 | FirebaseFirestore: 52120e2833f804a874ba1a9f59aab864a8ae2286 358 | FirebaseInstanceID: ce993a3c3670a8f5d47ce371ac5d143c560608c5 359 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 360 | GoogleAppMeasurement: db118eb61a97dd8c4f7014e368d3c335cbbcf80a 361 | GoogleDataTransport: 8e9b210c97d55fbff306cc5468ff91b9cb32dcf5 362 | GoogleDataTransportCCTSupport: 202d7cdf9c4a7d81a2bb7f7e7e1ba6faa421b1f2 363 | GoogleUtilities: 29bd0d8f850efbd28cff6d99e8b7da1f8d236bcf 364 | "gRPC-C++": 9dfe7b44821e7b3e44aacad2af29d2c21f7cde83 365 | gRPC-Core: c9aef9a261a1247e881b18059b84d597293c9947 366 | GTMSessionFetcher: 43b8b64263023d4f32caa0b40f4c8bfa3c5f36d8 367 | leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 368 | nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd 369 | 370 | PODFILE CHECKSUM: 083258d7f5e80b42ea9bfee905fe93049bc04c64 371 | 372 | COCOAPODS: 1.8.4 373 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 4E6AE99023C5523B0054CD0B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4E6AE98F23C5523B0054CD0B /* GoogleService-Info.plist */; }; 15 | 5994BF50A55C9234F6CE2437 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8DC4D9D63AA5628988D997 /* Pods_Runner.framework */; }; 16 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 17 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 18 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 4E6AE98F23C5523B0054CD0B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 45 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 46 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 48 | 82B4EE027F4730CA59A1D524 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 49 | 929D4C38AF7A5D083948F514 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 50 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 51 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 52 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 53 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 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 | D3730576206202E2BBF69A90 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 59 | FC8DC4D9D63AA5628988D997 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 68 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 69 | 5994BF50A55C9234F6CE2437 /* Pods_Runner.framework in Frameworks */, 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | 2AD26530CE3D81EC486539A5 /* Pods */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 929D4C38AF7A5D083948F514 /* Pods-Runner.debug.xcconfig */, 80 | 82B4EE027F4730CA59A1D524 /* Pods-Runner.release.xcconfig */, 81 | D3730576206202E2BBF69A90 /* Pods-Runner.profile.xcconfig */, 82 | ); 83 | path = Pods; 84 | sourceTree = ""; 85 | }; 86 | 4E2F694171925FA0034EFEC6 /* Frameworks */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | FC8DC4D9D63AA5628988D997 /* Pods_Runner.framework */, 90 | ); 91 | name = Frameworks; 92 | sourceTree = ""; 93 | }; 94 | 9740EEB11CF90186004384FC /* Flutter */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 3B80C3931E831B6300D905FE /* App.framework */, 98 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 99 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 100 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 101 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 102 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 103 | ); 104 | name = Flutter; 105 | sourceTree = ""; 106 | }; 107 | 97C146E51CF9000F007C117D = { 108 | isa = PBXGroup; 109 | children = ( 110 | 9740EEB11CF90186004384FC /* Flutter */, 111 | 97C146F01CF9000F007C117D /* Runner */, 112 | 97C146EF1CF9000F007C117D /* Products */, 113 | 2AD26530CE3D81EC486539A5 /* Pods */, 114 | 4E2F694171925FA0034EFEC6 /* Frameworks */, 115 | ); 116 | sourceTree = ""; 117 | }; 118 | 97C146EF1CF9000F007C117D /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 97C146EE1CF9000F007C117D /* Runner.app */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | 97C146F01CF9000F007C117D /* Runner */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 4E6AE98F23C5523B0054CD0B /* GoogleService-Info.plist */, 130 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 131 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 132 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 133 | 97C147021CF9000F007C117D /* Info.plist */, 134 | 97C146F11CF9000F007C117D /* Supporting Files */, 135 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 136 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 137 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 138 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 139 | ); 140 | path = Runner; 141 | sourceTree = ""; 142 | }; 143 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | ); 147 | name = "Supporting Files"; 148 | sourceTree = ""; 149 | }; 150 | /* End PBXGroup section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | 97C146ED1CF9000F007C117D /* Runner */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 156 | buildPhases = ( 157 | 8D34655A799084B65C947429 /* [CP] Check Pods Manifest.lock */, 158 | 9740EEB61CF901F6004384FC /* Run Script */, 159 | 97C146EA1CF9000F007C117D /* Sources */, 160 | 97C146EB1CF9000F007C117D /* Frameworks */, 161 | 97C146EC1CF9000F007C117D /* Resources */, 162 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 163 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 164 | 2102BF0CA61E3896152D724B /* [CP] Embed Pods Frameworks */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = Runner; 171 | productName = Runner; 172 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | /* End PBXNativeTarget section */ 176 | 177 | /* Begin PBXProject section */ 178 | 97C146E61CF9000F007C117D /* Project object */ = { 179 | isa = PBXProject; 180 | attributes = { 181 | LastUpgradeCheck = 1020; 182 | ORGANIZATIONNAME = ""; 183 | TargetAttributes = { 184 | 97C146ED1CF9000F007C117D = { 185 | CreatedOnToolsVersion = 7.3.1; 186 | DevelopmentTeam = WQ96K2ZV89; 187 | LastSwiftMigration = 1100; 188 | }; 189 | }; 190 | }; 191 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 192 | compatibilityVersion = "Xcode 3.2"; 193 | developmentRegion = en; 194 | hasScannedForEncodings = 0; 195 | knownRegions = ( 196 | en, 197 | Base, 198 | ); 199 | mainGroup = 97C146E51CF9000F007C117D; 200 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 201 | projectDirPath = ""; 202 | projectRoot = ""; 203 | targets = ( 204 | 97C146ED1CF9000F007C117D /* Runner */, 205 | ); 206 | }; 207 | /* End PBXProject section */ 208 | 209 | /* Begin PBXResourcesBuildPhase section */ 210 | 97C146EC1CF9000F007C117D /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 215 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 216 | 4E6AE99023C5523B0054CD0B /* GoogleService-Info.plist in Resources */, 217 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 218 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXResourcesBuildPhase section */ 223 | 224 | /* Begin PBXShellScriptBuildPhase section */ 225 | 2102BF0CA61E3896152D724B /* [CP] Embed Pods Frameworks */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | ); 230 | inputPaths = ( 231 | ); 232 | name = "[CP] Embed Pods Frameworks"; 233 | outputPaths = ( 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/sh; 237 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 238 | showEnvVarsInLog = 0; 239 | }; 240 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputPaths = ( 246 | ); 247 | name = "Thin Binary"; 248 | outputPaths = ( 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | shellPath = /bin/sh; 252 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 253 | }; 254 | 8D34655A799084B65C947429 /* [CP] Check Pods Manifest.lock */ = { 255 | isa = PBXShellScriptBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | inputFileListPaths = ( 260 | ); 261 | inputPaths = ( 262 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 263 | "${PODS_ROOT}/Manifest.lock", 264 | ); 265 | name = "[CP] Check Pods Manifest.lock"; 266 | outputFileListPaths = ( 267 | ); 268 | outputPaths = ( 269 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | shellPath = /bin/sh; 273 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 274 | showEnvVarsInLog = 0; 275 | }; 276 | 9740EEB61CF901F6004384FC /* Run Script */ = { 277 | isa = PBXShellScriptBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | ); 281 | inputPaths = ( 282 | ); 283 | name = "Run Script"; 284 | outputPaths = ( 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | shellPath = /bin/sh; 288 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 289 | }; 290 | /* End PBXShellScriptBuildPhase section */ 291 | 292 | /* Begin PBXSourcesBuildPhase section */ 293 | 97C146EA1CF9000F007C117D /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 298 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | /* End PBXSourcesBuildPhase section */ 303 | 304 | /* Begin PBXVariantGroup section */ 305 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 306 | isa = PBXVariantGroup; 307 | children = ( 308 | 97C146FB1CF9000F007C117D /* Base */, 309 | ); 310 | name = Main.storyboard; 311 | sourceTree = ""; 312 | }; 313 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 314 | isa = PBXVariantGroup; 315 | children = ( 316 | 97C147001CF9000F007C117D /* Base */, 317 | ); 318 | name = LaunchScreen.storyboard; 319 | sourceTree = ""; 320 | }; 321 | /* End PBXVariantGroup section */ 322 | 323 | /* Begin XCBuildConfiguration section */ 324 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 325 | isa = XCBuildConfiguration; 326 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 327 | buildSettings = { 328 | ALWAYS_SEARCH_USER_PATHS = NO; 329 | CLANG_ANALYZER_NONNULL = YES; 330 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 331 | CLANG_CXX_LIBRARY = "libc++"; 332 | CLANG_ENABLE_MODULES = YES; 333 | CLANG_ENABLE_OBJC_ARC = YES; 334 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 335 | CLANG_WARN_BOOL_CONVERSION = YES; 336 | CLANG_WARN_COMMA = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 339 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 340 | CLANG_WARN_EMPTY_BODY = YES; 341 | CLANG_WARN_ENUM_CONVERSION = YES; 342 | CLANG_WARN_INFINITE_RECURSION = YES; 343 | CLANG_WARN_INT_CONVERSION = YES; 344 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 345 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 346 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 349 | CLANG_WARN_STRICT_PROTOTYPES = YES; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNREACHABLE_CODE = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = NO; 355 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 356 | ENABLE_NS_ASSERTIONS = NO; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu99; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 367 | MTL_ENABLE_DEBUG_INFO = NO; 368 | SDKROOT = iphoneos; 369 | SUPPORTED_PLATFORMS = iphoneos; 370 | TARGETED_DEVICE_FAMILY = "1,2"; 371 | VALIDATE_PRODUCT = YES; 372 | }; 373 | name = Profile; 374 | }; 375 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | CLANG_ENABLE_MODULES = YES; 381 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 382 | DEVELOPMENT_TEAM = WQ96K2ZV89; 383 | ENABLE_BITCODE = NO; 384 | FRAMEWORK_SEARCH_PATHS = ( 385 | "$(inherited)", 386 | "$(PROJECT_DIR)/Flutter", 387 | ); 388 | INFOPLIST_FILE = Runner/Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 390 | LIBRARY_SEARCH_PATHS = ( 391 | "$(inherited)", 392 | "$(PROJECT_DIR)/Flutter", 393 | ); 394 | PRODUCT_BUNDLE_IDENTIFIER = com.example.friendlyeats; 395 | PRODUCT_NAME = Runner; 396 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 397 | SWIFT_VERSION = 5.0; 398 | VERSIONING_SYSTEM = "apple-generic"; 399 | }; 400 | name = Profile; 401 | }; 402 | 97C147031CF9000F007C117D /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_ANALYZER_NONNULL = YES; 408 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 409 | CLANG_CXX_LIBRARY = "libc++"; 410 | CLANG_ENABLE_MODULES = YES; 411 | CLANG_ENABLE_OBJC_ARC = YES; 412 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 413 | CLANG_WARN_BOOL_CONVERSION = YES; 414 | CLANG_WARN_COMMA = YES; 415 | CLANG_WARN_CONSTANT_CONVERSION = YES; 416 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 417 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 418 | CLANG_WARN_EMPTY_BODY = YES; 419 | CLANG_WARN_ENUM_CONVERSION = YES; 420 | CLANG_WARN_INFINITE_RECURSION = YES; 421 | CLANG_WARN_INT_CONVERSION = YES; 422 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 423 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 424 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 425 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 426 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 427 | CLANG_WARN_STRICT_PROTOTYPES = YES; 428 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 432 | COPY_PHASE_STRIP = NO; 433 | DEBUG_INFORMATION_FORMAT = dwarf; 434 | ENABLE_STRICT_OBJC_MSGSEND = YES; 435 | ENABLE_TESTABILITY = YES; 436 | GCC_C_LANGUAGE_STANDARD = gnu99; 437 | GCC_DYNAMIC_NO_PIC = NO; 438 | GCC_NO_COMMON_BLOCKS = YES; 439 | GCC_OPTIMIZATION_LEVEL = 0; 440 | GCC_PREPROCESSOR_DEFINITIONS = ( 441 | "DEBUG=1", 442 | "$(inherited)", 443 | ); 444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 446 | GCC_WARN_UNDECLARED_SELECTOR = YES; 447 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 448 | GCC_WARN_UNUSED_FUNCTION = YES; 449 | GCC_WARN_UNUSED_VARIABLE = YES; 450 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 451 | MTL_ENABLE_DEBUG_INFO = YES; 452 | ONLY_ACTIVE_ARCH = YES; 453 | SDKROOT = iphoneos; 454 | TARGETED_DEVICE_FAMILY = "1,2"; 455 | }; 456 | name = Debug; 457 | }; 458 | 97C147041CF9000F007C117D /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 461 | buildSettings = { 462 | ALWAYS_SEARCH_USER_PATHS = NO; 463 | CLANG_ANALYZER_NONNULL = YES; 464 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 465 | CLANG_CXX_LIBRARY = "libc++"; 466 | CLANG_ENABLE_MODULES = YES; 467 | CLANG_ENABLE_OBJC_ARC = YES; 468 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 469 | CLANG_WARN_BOOL_CONVERSION = YES; 470 | CLANG_WARN_COMMA = YES; 471 | CLANG_WARN_CONSTANT_CONVERSION = YES; 472 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 473 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 474 | CLANG_WARN_EMPTY_BODY = YES; 475 | CLANG_WARN_ENUM_CONVERSION = YES; 476 | CLANG_WARN_INFINITE_RECURSION = YES; 477 | CLANG_WARN_INT_CONVERSION = YES; 478 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 479 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 480 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 481 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 482 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 483 | CLANG_WARN_STRICT_PROTOTYPES = YES; 484 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 485 | CLANG_WARN_UNREACHABLE_CODE = YES; 486 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 487 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 488 | COPY_PHASE_STRIP = NO; 489 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 490 | ENABLE_NS_ASSERTIONS = NO; 491 | ENABLE_STRICT_OBJC_MSGSEND = YES; 492 | GCC_C_LANGUAGE_STANDARD = gnu99; 493 | GCC_NO_COMMON_BLOCKS = YES; 494 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 495 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 496 | GCC_WARN_UNDECLARED_SELECTOR = YES; 497 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 498 | GCC_WARN_UNUSED_FUNCTION = YES; 499 | GCC_WARN_UNUSED_VARIABLE = YES; 500 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 501 | MTL_ENABLE_DEBUG_INFO = NO; 502 | SDKROOT = iphoneos; 503 | SUPPORTED_PLATFORMS = iphoneos; 504 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 505 | TARGETED_DEVICE_FAMILY = "1,2"; 506 | VALIDATE_PRODUCT = YES; 507 | }; 508 | name = Release; 509 | }; 510 | 97C147061CF9000F007C117D /* Debug */ = { 511 | isa = XCBuildConfiguration; 512 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 513 | buildSettings = { 514 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 515 | CLANG_ENABLE_MODULES = YES; 516 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 517 | DEVELOPMENT_TEAM = WQ96K2ZV89; 518 | ENABLE_BITCODE = NO; 519 | FRAMEWORK_SEARCH_PATHS = ( 520 | "$(inherited)", 521 | "$(PROJECT_DIR)/Flutter", 522 | ); 523 | INFOPLIST_FILE = Runner/Info.plist; 524 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 525 | LIBRARY_SEARCH_PATHS = ( 526 | "$(inherited)", 527 | "$(PROJECT_DIR)/Flutter", 528 | ); 529 | PRODUCT_BUNDLE_IDENTIFIER = com.example.friendlyeats; 530 | PRODUCT_NAME = Runner; 531 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 532 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 533 | SWIFT_VERSION = 5.0; 534 | VERSIONING_SYSTEM = "apple-generic"; 535 | }; 536 | name = Debug; 537 | }; 538 | 97C147071CF9000F007C117D /* Release */ = { 539 | isa = XCBuildConfiguration; 540 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 541 | buildSettings = { 542 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 543 | CLANG_ENABLE_MODULES = YES; 544 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 545 | DEVELOPMENT_TEAM = WQ96K2ZV89; 546 | ENABLE_BITCODE = NO; 547 | FRAMEWORK_SEARCH_PATHS = ( 548 | "$(inherited)", 549 | "$(PROJECT_DIR)/Flutter", 550 | ); 551 | INFOPLIST_FILE = Runner/Info.plist; 552 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 553 | LIBRARY_SEARCH_PATHS = ( 554 | "$(inherited)", 555 | "$(PROJECT_DIR)/Flutter", 556 | ); 557 | PRODUCT_BUNDLE_IDENTIFIER = com.example.friendlyeats; 558 | PRODUCT_NAME = Runner; 559 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 560 | SWIFT_VERSION = 5.0; 561 | VERSIONING_SYSTEM = "apple-generic"; 562 | }; 563 | name = Release; 564 | }; 565 | /* End XCBuildConfiguration section */ 566 | 567 | /* Begin XCConfigurationList section */ 568 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 97C147031CF9000F007C117D /* Debug */, 572 | 97C147041CF9000F007C117D /* Release */, 573 | 249021D3217E4FDB00AE95B9 /* Profile */, 574 | ); 575 | defaultConfigurationIsVisible = 0; 576 | defaultConfigurationName = Release; 577 | }; 578 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 579 | isa = XCConfigurationList; 580 | buildConfigurations = ( 581 | 97C147061CF9000F007C117D /* Debug */, 582 | 97C147071CF9000F007C117D /* Release */, 583 | 249021D4217E4FDB00AE95B9 /* Profile */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | /* End XCConfigurationList section */ 589 | }; 590 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 591 | } 592 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import UIKit 16 | import Flutter 17 | 18 | @UIApplicationMain 19 | @objc class AppDelegate: FlutterAppDelegate { 20 | override func application( 21 | _ application: UIApplication, 22 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 23 | ) -> Bool { 24 | GeneratedPluginRegistrant.register(with: self) 25 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/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/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 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/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "GeneratedPluginRegistrant.h" 18 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:firebase_core/firebase_core.dart'; 16 | import 'package:flutter/material.dart'; 17 | 18 | import 'src/app.dart' deferred as app; 19 | 20 | void main() async { 21 | // Initialize Firebase 22 | WidgetsFlutterBinding.ensureInitialized(); 23 | await Firebase.initializeApp(); 24 | 25 | final Future loadedLibrary = await app.loadLibrary(); 26 | runApp( 27 | FutureBuilder( 28 | future: loadedLibrary, 29 | builder: (snapshot, context) => app.FriendlyEatsApp(), 30 | ), 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/app.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | import 'home_page.dart'; 18 | import 'restaurant_page.dart'; 19 | 20 | class FriendlyEatsApp extends StatelessWidget { 21 | @override 22 | Widget build(BuildContext context) { 23 | return MaterialApp( 24 | title: 'FriendlyEats', 25 | onGenerateRoute: (settings) { 26 | switch (settings.name) { 27 | case RestaurantPage.route: 28 | final RestaurantPageArguments arguments = settings.arguments; 29 | return MaterialPageRoute( 30 | builder: (context) => RestaurantPage( 31 | restaurantId: arguments.id, 32 | )); 33 | break; 34 | default: 35 | // return MaterialPageRoute( 36 | // builder: (context) => RestaurantPage( 37 | // restaurantId: 'lV81npEeboEActMpUJjn', 38 | // )); 39 | // Everything defaults to home, but maybe we want a custom 404 here 40 | return MaterialPageRoute(builder: (context) => HomePage()); 41 | } 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/home_page.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:math'; 17 | 18 | import 'package:cloud_firestore/cloud_firestore.dart'; 19 | import 'package:firebase_auth/firebase_auth.dart'; 20 | import 'package:flutter/material.dart'; 21 | 22 | import 'restaurant_page.dart'; 23 | import 'model/data.dart' as data; 24 | import 'model/filter.dart'; 25 | import 'model/restaurant.dart'; 26 | import 'widgets/empty_list.dart'; 27 | import 'widgets/filter_bar.dart'; 28 | import 'widgets/grid.dart'; 29 | import 'widgets/dialogs/filter_select.dart'; 30 | 31 | class HomePage extends StatefulWidget { 32 | static const route = '/'; 33 | 34 | HomePage({Key key}) : super(key: key); 35 | 36 | @override 37 | _HomePageState createState() => _HomePageState(); 38 | } 39 | 40 | class _HomePageState extends State { 41 | _HomePageState() { 42 | FirebaseAuth.instance 43 | .signInAnonymously() 44 | .then((UserCredential userCredential) { 45 | _currentSubscription = 46 | data.loadAllRestaurants().listen(_updateRestaurants); 47 | }); 48 | } 49 | 50 | @override 51 | void dispose() { 52 | _currentSubscription?.cancel(); 53 | super.dispose(); 54 | } 55 | 56 | StreamSubscription _currentSubscription; 57 | bool _isLoading = true; 58 | List _restaurants = []; 59 | Filter _filter; 60 | 61 | void _updateRestaurants(QuerySnapshot snapshot) { 62 | setState(() { 63 | _isLoading = false; 64 | _restaurants = data.getRestaurantsFromQuery(snapshot); 65 | }); 66 | } 67 | 68 | Future _onAddRandomRestaurantsPressed() async { 69 | final numReviews = Random().nextInt(10) + 20; 70 | 71 | final restaurants = List.generate(numReviews, (_) => Restaurant.random()); 72 | data.addRestaurantsBatch(restaurants); 73 | } 74 | 75 | Future _onFilterBarPressed() async { 76 | final filter = await showDialog( 77 | context: context, 78 | builder: (_) => FilterSelectDialog(filter: _filter), 79 | ); 80 | if (filter != null) { 81 | await _currentSubscription?.cancel(); 82 | setState(() { 83 | _isLoading = true; 84 | _filter = filter; 85 | if (filter.isDefault) { 86 | _currentSubscription = 87 | data.loadAllRestaurants().listen(_updateRestaurants); 88 | } else { 89 | _currentSubscription = 90 | data.loadFilteredRestaurants(filter).listen(_updateRestaurants); 91 | } 92 | }); 93 | } 94 | } 95 | 96 | @override 97 | Widget build(BuildContext context) { 98 | return Scaffold( 99 | appBar: AppBar( 100 | leading: Icon(Icons.restaurant), 101 | title: Text('FriendlyEats'), 102 | bottom: PreferredSize( 103 | preferredSize: Size(320, 48), 104 | child: Padding( 105 | padding: EdgeInsets.fromLTRB(6, 0, 6, 4), 106 | child: FilterBar( 107 | filter: _filter, 108 | onPressed: _onFilterBarPressed, 109 | ), 110 | ), 111 | ), 112 | ), 113 | body: Center( 114 | child: Container( 115 | constraints: BoxConstraints(maxWidth: 1280), 116 | child: _isLoading 117 | ? CircularProgressIndicator() 118 | : _restaurants.isNotEmpty 119 | ? RestaurantGrid( 120 | restaurants: _restaurants, 121 | onRestaurantPressed: (id) { 122 | // TODO: Add deep links on web 123 | Navigator.pushNamed(context, RestaurantPage.route, 124 | arguments: RestaurantPageArguments(id: id)); 125 | }) 126 | : EmptyListView( 127 | child: Text('FriendlyEats has no restaurants yet!'), 128 | onPressed: _onAddRandomRestaurantsPressed, 129 | ), 130 | ), 131 | ), 132 | ); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /lib/src/model/data.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:cloud_firestore/cloud_firestore.dart'; 16 | 17 | import './filter.dart'; 18 | import './restaurant.dart'; 19 | import './review.dart'; 20 | 21 | // This is the file that Codelab users will primarily work on. 22 | 23 | Future addRestaurant(Restaurant restaurant) { 24 | // TODO: Complete the "Add restaurants to Firestore" step. 25 | return Future.value(); 26 | } 27 | 28 | Stream loadAllRestaurants() { 29 | // TODO: Complete the "Display data from Cloud Firestore" step. 30 | return Stream.value(null); 31 | } 32 | 33 | List getRestaurantsFromQuery(QuerySnapshot snapshot) { 34 | // TODO: Complete the "Display data from Cloud Firestore" step. 35 | return []; 36 | } 37 | 38 | Future getRestaurant(String restaurantId) { 39 | // TODO: Complete the "Get data" step. 40 | return Future.value(null); 41 | } 42 | 43 | Future addReview({String restaurantId, Review review}) { 44 | // TODO: Complete the "Write data in a transaction" step. 45 | return Future.value(); 46 | } 47 | 48 | Stream loadFilteredRestaurants(Filter filter) { 49 | // TODO: Complete the "Sorting and filtering data" step. 50 | return Stream.value(null); 51 | } 52 | 53 | void addRestaurantsBatch(List restaurants) { 54 | restaurants.forEach((Restaurant restaurant) { 55 | addRestaurant(restaurant); 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/model/filter.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | typedef FilterChangedCallback = void Function(T newValue); 16 | 17 | class Filter { 18 | final String city; 19 | final int price; 20 | final String category; 21 | final String sort; 22 | 23 | bool get isDefault { 24 | return (city == null && price == null && category == null && sort == null); 25 | } 26 | 27 | Filter({this.city, this.price, this.category, this.sort}); 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/model/restaurant.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math'; 16 | 17 | import 'package:cloud_firestore/cloud_firestore.dart'; 18 | 19 | import './values.dart'; 20 | 21 | typedef RestaurantPressedCallback = void Function(String restaurantId); 22 | 23 | typedef CloseRestaurantPressedCallback = void Function(); 24 | 25 | class Restaurant { 26 | final String id; 27 | final String name; 28 | final String category; 29 | final String city; 30 | final double avgRating; 31 | final int numRatings; 32 | final int price; 33 | final String photo; 34 | final DocumentReference reference; 35 | 36 | Restaurant._({this.name, this.category, this.city, this.price, this.photo}) 37 | : id = null, 38 | numRatings = 0, 39 | avgRating = 0, 40 | reference = null; 41 | 42 | Restaurant.fromSnapshot(DocumentSnapshot snapshot) 43 | : assert(snapshot != null), 44 | id = snapshot.id, 45 | name = snapshot.data()['name'], 46 | category = snapshot.data()['category'], 47 | city = snapshot.data()['city'], 48 | avgRating = snapshot.data()['avgRating'].toDouble(), 49 | numRatings = snapshot.data()['numRatings'], 50 | price = snapshot.data()['price'], 51 | photo = snapshot.data()['photo'], 52 | reference = snapshot.reference; 53 | 54 | factory Restaurant.random() { 55 | return Restaurant._( 56 | category: getRandomCategory(), 57 | city: getRandomCity(), 58 | name: getRandomName(), 59 | price: Random().nextInt(3) + 1, 60 | photo: getRandomPhoto(), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/model/review.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math'; 16 | 17 | import 'package:cloud_firestore/cloud_firestore.dart'; 18 | 19 | import './values.dart'; 20 | 21 | // This is called "ratings" in the backend. 22 | class Review { 23 | final String id; 24 | final String userId; 25 | final double rating; 26 | final String text; 27 | final String userName; 28 | final Timestamp timestamp; 29 | 30 | final DocumentReference reference; 31 | 32 | Review.fromSnapshot(DocumentSnapshot snapshot) 33 | : assert(snapshot != null), 34 | id = snapshot.id, 35 | rating = snapshot.data()['rating'].toDouble(), 36 | text = snapshot.data()['text'], 37 | userName = snapshot.data()['userName'], 38 | userId = snapshot.data()['userId'], 39 | timestamp = snapshot.data()['timestamp'], 40 | reference = snapshot.reference; 41 | 42 | Review.fromUserInput({this.rating, this.text, this.userName, this.userId}) 43 | : id = null, 44 | timestamp = null, 45 | reference = null; 46 | 47 | factory Review.random({String userName, String userId}) { 48 | final rating = Random().nextInt(4) + 1; 49 | final review = getRandomReviewText(rating); 50 | return Review.fromUserInput( 51 | rating: rating.toDouble(), 52 | text: review, 53 | userName: userName, 54 | userId: userId); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/model/values.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math'; 16 | 17 | final cities = [ 18 | 'Albuquerque', 19 | 'Arlington', 20 | 'Atlanta', 21 | 'Austin', 22 | 'Baltimore', 23 | 'Boston', 24 | 'Charlotte', 25 | 'Chicago', 26 | 'Cleveland', 27 | 'Colorado Springs', 28 | 'Columbus', 29 | 'Dallas', 30 | 'Denver', 31 | 'Detroit', 32 | 'El Paso', 33 | 'Fort Worth', 34 | 'Fresno', 35 | 'Houston', 36 | 'Indianapolis', 37 | 'Jacksonville', 38 | 'Kansas City', 39 | 'Las Vegas', 40 | 'Long Island', 41 | 'Los Angeles', 42 | 'Louisville', 43 | 'Memphis', 44 | 'Mesa', 45 | 'Miami', 46 | 'Milwaukee', 47 | 'Nashville', 48 | 'New York', 49 | 'Oakland', 50 | 'Oklahoma', 51 | 'Omaha', 52 | 'Philadelphia', 53 | 'Phoenix', 54 | 'Portland', 55 | 'Raleigh', 56 | 'Sacramento', 57 | 'San Antonio', 58 | 'San Diego', 59 | 'San Francisco', 60 | 'San Jose', 61 | 'Seattle', 62 | 'Tucson', 63 | 'Tulsa', 64 | 'Virginia Beach', 65 | 'Washington', 66 | ]; 67 | 68 | final categories = [ 69 | 'Brunch', 70 | 'Burgers', 71 | 'Coffee', 72 | 'Deli', 73 | 'Dim Sum', 74 | 'Indian', 75 | 'Italian', 76 | 'Mediterranean', 77 | 'Mexican', 78 | 'Pizza', 79 | 'Ramen', 80 | 'Sushi', 81 | ]; 82 | 83 | final _words = [ 84 | 'Bar', 85 | 'Deli', 86 | 'Diner', 87 | 'Fire', 88 | 'Grill', 89 | 'Drive Thru', 90 | 'Place', 91 | 'Best', 92 | 'Spot', 93 | 'Trattoria', 94 | 'Steakhouse', 95 | 'Churrasco', 96 | 'Tavern', 97 | 'Cafe', 98 | 'Pop-up', 99 | 'Yummy', 100 | 'Belly', 101 | 'Snack', 102 | 'Fast', 103 | 'Turbo', 104 | 'Hyper', 105 | 'Prime', 106 | 'Eatin\'', 107 | ]; 108 | 109 | final _reviewTextPerRating = { 110 | 1: [ 111 | 'Would never eat here again!', 112 | 'Such an awful place!', 113 | 'Not sure if they had a bad day off, but the food was very bad.' 114 | ], 115 | 2: [ 116 | 'Not my cup of tea.', 117 | 'Unlikely that we will ever come again.', 118 | 'Quite bad, but I\'ve had worse!' 119 | ], 120 | 3: [ 121 | 'Exactly okay :/', 122 | 'Unimpressed, but not disappointed!', 123 | '3 estrellas y van que arden.' 124 | ], 125 | 4: [ 126 | 'Actually pretty good, would recommend!', 127 | 'I really like this place, I come quite often!', 128 | 'A great experience, as usual!' 129 | ], 130 | 5: [ 131 | 'This is my favorite place. Literally', 132 | 'This place is ALWAYS great!', 133 | 'I recommend this to all my friends and family!' 134 | ], 135 | }; 136 | 137 | final random = Random(); 138 | 139 | String getRandomReviewText(int rating) { 140 | final reviews = _reviewTextPerRating[rating]; 141 | return reviews[random.nextInt(reviews.length)]; 142 | } 143 | 144 | String getRandomName() { 145 | final firstWord = random.nextInt(_words.length); 146 | var nextWord; 147 | do { 148 | nextWord = random.nextInt(_words.length); 149 | } while (firstWord == nextWord); 150 | return '${_words[firstWord]} ${_words[nextWord]}'; 151 | } 152 | 153 | String getRandomCategory() { 154 | return categories[random.nextInt(categories.length)]; 155 | } 156 | 157 | String getRandomCity() { 158 | return cities[random.nextInt(cities.length)]; 159 | } 160 | 161 | String getRandomPhoto() { 162 | final photoId = random.nextInt(21) + 1; 163 | return 'https://storage.googleapis.com/firestorequickstarts.appspot.com/food_$photoId.png'; 164 | } 165 | -------------------------------------------------------------------------------- /lib/src/restaurant_page.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:math'; 17 | 18 | import 'package:cloud_firestore/cloud_firestore.dart'; 19 | import 'package:firebase_auth/firebase_auth.dart'; 20 | import 'package:flutter/foundation.dart'; 21 | import 'package:flutter/material.dart'; 22 | import 'package:sliver_fab/sliver_fab.dart'; 23 | 24 | import 'widgets/empty_list.dart'; 25 | import 'model/data.dart' as data; 26 | import 'model/restaurant.dart'; 27 | import 'model/review.dart'; 28 | import 'widgets/app_bar.dart'; 29 | import 'widgets/review.dart'; 30 | import 'widgets/dialogs/review_create.dart'; 31 | 32 | class RestaurantPage extends StatefulWidget { 33 | static const route = '/restaurant'; 34 | 35 | final String _restaurantId; 36 | 37 | RestaurantPage({Key key, @required String restaurantId}) 38 | : _restaurantId = restaurantId, 39 | super(key: key); 40 | 41 | @override 42 | _RestaurantPageState createState() => 43 | _RestaurantPageState(restaurantId: _restaurantId); 44 | } 45 | 46 | class _RestaurantPageState extends State { 47 | _RestaurantPageState({@required String restaurantId}) { 48 | FirebaseAuth.instance 49 | .signInAnonymously() 50 | .then((UserCredential userCredential) { 51 | data.getRestaurant(restaurantId).then((Restaurant restaurant) { 52 | _currentReviewSubscription?.cancel(); 53 | setState(() { 54 | if (userCredential.user.displayName == null || 55 | userCredential.user.displayName.isEmpty) { 56 | _userName = 'Anonymous (${kIsWeb ? "Web" : "Mobile"})'; 57 | } else { 58 | _userName = userCredential.user.displayName; 59 | } 60 | _restaurant = restaurant; 61 | _userId = userCredential.user.uid; 62 | 63 | // Initialize the reviews snapshot... 64 | _currentReviewSubscription = _restaurant.reference 65 | .collection('ratings') 66 | .orderBy('timestamp', descending: true) 67 | .snapshots() 68 | .listen((QuerySnapshot reviewSnap) { 69 | setState(() { 70 | _isLoading = false; 71 | _reviews = reviewSnap.docs.map((DocumentSnapshot doc) { 72 | return Review.fromSnapshot(doc); 73 | }).toList(); 74 | }); 75 | }); 76 | }); 77 | }); 78 | }); 79 | } 80 | 81 | @override 82 | void dispose() { 83 | _currentReviewSubscription?.cancel(); 84 | super.dispose(); 85 | } 86 | 87 | bool _isLoading = true; 88 | StreamSubscription _currentReviewSubscription; 89 | 90 | Restaurant _restaurant; 91 | String _userId; 92 | String _userName; 93 | List _reviews = []; 94 | 95 | void _onCreateReviewPressed(BuildContext context) async { 96 | final newReview = await showDialog( 97 | context: context, 98 | builder: (_) => ReviewCreateDialog( 99 | userId: _userId, 100 | userName: _userName, 101 | ), 102 | ); 103 | if (newReview != null) { 104 | // Save the review 105 | return data.addReview( 106 | restaurantId: _restaurant.id, 107 | review: newReview, 108 | ); 109 | } 110 | } 111 | 112 | void _onAddRandomReviewsPressed() async { 113 | // Await adding a random number of random reviews 114 | final numReviews = Random().nextInt(5) + 5; 115 | for (var i = 0; i < numReviews; i++) { 116 | await data.addReview( 117 | restaurantId: _restaurant.id, 118 | review: Review.random( 119 | userId: _userId, 120 | userName: _userName, 121 | ), 122 | ); 123 | } 124 | } 125 | 126 | @override 127 | Widget build(BuildContext context) { 128 | return _isLoading 129 | ? Center(child: CircularProgressIndicator()) 130 | : Scaffold( 131 | body: Builder( 132 | builder: (context) => SliverFab( 133 | floatingWidget: FloatingActionButton( 134 | tooltip: 'Add a review', 135 | backgroundColor: Colors.amber, 136 | child: Icon(Icons.add), 137 | onPressed: () => _onCreateReviewPressed(context), 138 | ), 139 | floatingPosition: FloatingPosition(right: 16), 140 | expandedHeight: RestaurantAppBar.appBarHeight, 141 | slivers: [ 142 | RestaurantAppBar( 143 | restaurant: _restaurant, 144 | onClosePressed: () => Navigator.pop(context), 145 | ), 146 | _reviews.isNotEmpty 147 | ? SliverPadding( 148 | padding: EdgeInsets.fromLTRB(16, 24, 16, 8), 149 | sliver: SliverList( 150 | delegate: SliverChildListDelegate(_reviews 151 | .map((Review review) => 152 | RestaurantReview(review: review)) 153 | .toList()), 154 | ), 155 | ) 156 | : SliverFillRemaining( 157 | hasScrollBody: false, 158 | child: EmptyListView( 159 | child: Text('${_restaurant.name} has no reviews.'), 160 | onPressed: _onAddRandomReviewsPressed, 161 | ), 162 | ), 163 | ], 164 | ), 165 | ), 166 | ); 167 | } 168 | } 169 | 170 | class RestaurantPageArguments { 171 | final String id; 172 | 173 | RestaurantPageArguments({@required this.id}); 174 | } 175 | -------------------------------------------------------------------------------- /lib/src/widgets/app_bar.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | import '../model/restaurant.dart'; 18 | import 'stars.dart'; 19 | 20 | class RestaurantAppBar extends StatelessWidget { 21 | static final double appBarHeight = 160; 22 | 23 | RestaurantAppBar({ 24 | this.restaurant, 25 | CloseRestaurantPressedCallback onClosePressed, 26 | }) : _onPressed = onClosePressed; 27 | 28 | final Restaurant restaurant; 29 | 30 | final CloseRestaurantPressedCallback _onPressed; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return SliverAppBar( 35 | leading: IconButton( 36 | onPressed: _onPressed, 37 | icon: Icon(Icons.close), 38 | iconSize: 32, 39 | ), 40 | expandedHeight: appBarHeight, 41 | forceElevated: true, 42 | flexibleSpace: FlexibleSpaceBar( 43 | centerTitle: false, 44 | title: Wrap( 45 | children: [ 46 | Text( 47 | restaurant.name, 48 | overflow: TextOverflow.ellipsis, 49 | ), 50 | Row( 51 | crossAxisAlignment: CrossAxisAlignment.center, 52 | children: [ 53 | Container( 54 | width: 80, 55 | alignment: Alignment.bottomLeft, 56 | child: StarRating( 57 | rating: restaurant.avgRating, 58 | color: Colors.white, 59 | size: 16, 60 | ), 61 | ), 62 | Padding( 63 | padding: EdgeInsets.only(left: 6), 64 | child: Text( 65 | '\$' * restaurant.price, 66 | style: TextStyle( 67 | fontSize: Theme.of(context).textTheme.caption.fontSize), 68 | ), 69 | ), 70 | ], 71 | ), 72 | Padding( 73 | padding: EdgeInsets.only(top: 2), 74 | child: Text( 75 | '${restaurant.category} ● ${restaurant.city}', 76 | style: TextStyle( 77 | fontSize: Theme.of(context).textTheme.caption.fontSize), 78 | ), 79 | ), 80 | ], 81 | ), 82 | background: Stack( 83 | fit: StackFit.expand, 84 | children: [ 85 | Image.network( 86 | restaurant.photo, 87 | fit: BoxFit.cover, 88 | ), 89 | Container( 90 | decoration: BoxDecoration( 91 | gradient: LinearGradient( 92 | begin: Alignment.topCenter, 93 | end: Alignment.bottomCenter, 94 | colors: [ 95 | const Color(0x00000000), 96 | const Color(0xAA000000), 97 | ], 98 | ), 99 | ), 100 | ), 101 | ], 102 | ), 103 | ), 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /lib/src/widgets/card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/foundation.dart'; 16 | import 'package:flutter/material.dart'; 17 | 18 | import '../model/restaurant.dart'; 19 | import 'stars.dart'; 20 | 21 | class RestaurantCard extends StatelessWidget { 22 | RestaurantCard({ 23 | this.restaurant, 24 | @required RestaurantPressedCallback onRestaurantPressed, 25 | }) : _onPressed = onRestaurantPressed; 26 | 27 | final Restaurant restaurant; 28 | 29 | final RestaurantPressedCallback _onPressed; 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return Card( 34 | child: InkWell( 35 | onTap: () => _onPressed(restaurant.id), 36 | splashColor: Colors.blue.withAlpha(30), 37 | child: Container( 38 | height: 250, 39 | child: Column( 40 | children: [ 41 | // TODO: Make this a Hero widget so we can transition to it? 42 | Expanded( 43 | child: Container( 44 | alignment: Alignment.centerLeft, 45 | decoration: BoxDecoration( 46 | image: DecorationImage( 47 | image: NetworkImage(restaurant.photo), 48 | fit: BoxFit.cover, 49 | ), 50 | ), 51 | child: null), 52 | ), 53 | Padding( 54 | padding: EdgeInsets.all(8), 55 | child: Column( 56 | crossAxisAlignment: CrossAxisAlignment.start, 57 | mainAxisAlignment: MainAxisAlignment.end, 58 | children: [ 59 | Row( 60 | crossAxisAlignment: CrossAxisAlignment.center, 61 | children: [ 62 | Expanded( 63 | child: Text( 64 | restaurant.name, 65 | style: Theme.of(context).textTheme.headline6, 66 | ), 67 | ), 68 | Text( 69 | '\$' * restaurant.price, 70 | style: Theme.of(context).textTheme.caption, 71 | ), 72 | ], 73 | ), 74 | Container( 75 | padding: EdgeInsets.fromLTRB(0, (kIsWeb ? 0 : 2), 0, 4), 76 | alignment: Alignment.bottomLeft, 77 | child: StarRating( 78 | rating: restaurant.avgRating, 79 | ), 80 | ), 81 | Container( 82 | alignment: Alignment.bottomLeft, 83 | child: Text( 84 | '${restaurant.category} ● ${restaurant.city}', 85 | style: Theme.of(context).textTheme.caption, 86 | ), 87 | ), 88 | ], 89 | ), 90 | ), 91 | ], 92 | ), 93 | ), 94 | )); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/src/widgets/dialogs/filter_select.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math' as math; 16 | 17 | import 'package:flutter/material.dart'; 18 | 19 | import '../../model/values.dart' as hardcoded; 20 | import '../../model/filter.dart'; 21 | 22 | class FilterSelectDialog extends StatefulWidget { 23 | FilterSelectDialog({Key key, Filter filter}) 24 | : _filter = filter, 25 | super(key: key); 26 | 27 | final Filter _filter; 28 | 29 | @override 30 | _FilterSelectDialogState createState() => 31 | _FilterSelectDialogState(filter: _filter); 32 | } 33 | 34 | class _FilterSelectDialogState extends State { 35 | _FilterSelectDialogState({Filter filter}) { 36 | if (filter != null && !filter.isDefault) { 37 | _category = filter.category; 38 | _city = filter.city; 39 | _price = filter.price; 40 | _sort = filter.sort; 41 | } 42 | } 43 | 44 | String _category; 45 | String _city; 46 | int _price; 47 | String _sort; 48 | 49 | Widget _buildDropdown( 50 | List labels, 51 | List values, 52 | dynamic selected, 53 | FilterChangedCallback onChanged, 54 | ) { 55 | final items = [ 56 | for (var i = 0; i < values.length; i++) 57 | DropdownMenuItem(value: values[i], child: Text(labels[i])), 58 | ]; 59 | return DropdownButton( 60 | items: items, 61 | isExpanded: true, 62 | value: selected, 63 | onChanged: onChanged, 64 | ); 65 | } 66 | 67 | Widget _buildDropdownRow({ 68 | List values, 69 | List labels, 70 | T selected, 71 | IconData icon, 72 | FilterChangedCallback onChanged, 73 | }) { 74 | return Row( 75 | mainAxisSize: MainAxisSize.max, 76 | children: [ 77 | Icon(icon), 78 | Expanded( 79 | child: Padding( 80 | padding: EdgeInsets.fromLTRB(16, 0, 8, 0), 81 | child: _buildDropdown(labels, values, selected, onChanged), 82 | ), 83 | ), 84 | ], 85 | ); 86 | } 87 | 88 | Widget _buildCategoryDropdown({ 89 | String selected, 90 | FilterChangedCallback onChanged, 91 | }) { 92 | return _buildDropdownRow( 93 | labels: ['Any Cuisine', ...hardcoded.categories], 94 | values: [null, ...hardcoded.categories], 95 | selected: selected, 96 | icon: Icons.fastfood, 97 | onChanged: onChanged, 98 | ); 99 | } 100 | 101 | Widget _buildCityDropdown({ 102 | String selected, 103 | FilterChangedCallback onChanged, 104 | }) { 105 | return _buildDropdownRow( 106 | labels: ['Any Location', ...hardcoded.cities], 107 | values: [null, ...hardcoded.cities], 108 | selected: selected, 109 | icon: Icons.location_on, 110 | onChanged: onChanged, 111 | ); 112 | } 113 | 114 | Widget _buildPriceDropdown({ 115 | int selected, 116 | FilterChangedCallback onChanged, 117 | }) { 118 | return _buildDropdownRow( 119 | labels: ['Any Price', '\$', '\$\$', '\$\$\$', '\$\$\$\$'], 120 | values: [null, 1, 2, 3, 4], 121 | selected: selected, 122 | icon: Icons.monetization_on, 123 | onChanged: onChanged, 124 | ); 125 | } 126 | 127 | Widget _buildSortDropdown({ 128 | String selected, 129 | FilterChangedCallback onChanged, 130 | }) { 131 | return _buildDropdownRow( 132 | labels: ['Rating', 'Reviews'], 133 | values: ['avgRating', 'numRatings'], 134 | selected: selected, 135 | icon: Icons.sort, 136 | onChanged: onChanged, 137 | ); 138 | } 139 | 140 | @override 141 | Widget build(BuildContext context) { 142 | return AlertDialog( 143 | title: Row( 144 | mainAxisAlignment: MainAxisAlignment.start, 145 | children: [ 146 | Icon(Icons.filter_list), 147 | Padding( 148 | padding: EdgeInsets.fromLTRB(16, 0, 8, 0), 149 | child: Text('Filter'), 150 | ), 151 | ], 152 | ), 153 | content: Container( 154 | width: math.min(MediaQuery.of(context).size.width, 740), 155 | height: math.min(MediaQuery.of(context).size.height, 200), 156 | child: Column( 157 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 158 | children: [ 159 | _buildCategoryDropdown( 160 | selected: _category, 161 | onChanged: (String value) { 162 | setState(() { 163 | _category = value; 164 | }); 165 | }), 166 | _buildCityDropdown( 167 | selected: _city, 168 | onChanged: (String value) { 169 | setState(() { 170 | _city = value; 171 | }); 172 | }), 173 | _buildPriceDropdown( 174 | selected: _price, 175 | onChanged: (int value) { 176 | setState(() { 177 | _price = value; 178 | }); 179 | }), 180 | _buildSortDropdown( 181 | selected: _sort ?? 'avgRating', 182 | onChanged: (String value) { 183 | setState(() { 184 | _sort = value; 185 | }); 186 | }), 187 | ], 188 | ), 189 | ), 190 | actions: [ 191 | FlatButton( 192 | child: Text('CLEAR ALL'), 193 | onPressed: () => Navigator.pop(context, Filter()), 194 | ), 195 | RaisedButton( 196 | child: Text('ACCEPT'), 197 | onPressed: () => Navigator.pop( 198 | context, 199 | Filter( 200 | category: _category, 201 | city: _city, 202 | price: _price, 203 | sort: _sort, 204 | )), 205 | ), 206 | ], 207 | ); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /lib/src/widgets/dialogs/review_create.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math' as math; 16 | 17 | import 'package:flutter/material.dart'; 18 | import 'package:smooth_star_rating/smooth_star_rating.dart'; 19 | 20 | import '../../model/review.dart'; 21 | 22 | class ReviewCreateDialog extends StatefulWidget { 23 | final String userName; 24 | final String userId; 25 | 26 | ReviewCreateDialog({this.userName, this.userId, Key key}); 27 | 28 | @override 29 | _ReviewCreateDialogState createState() => _ReviewCreateDialogState(); 30 | } 31 | 32 | class _ReviewCreateDialogState extends State { 33 | double rating = 0; 34 | String review; 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | Color color = rating == 0 ? Colors.grey : Colors.amber; 39 | return AlertDialog( 40 | title: Text('Add a Review'), 41 | content: Container( 42 | width: math.min(MediaQuery.of(context).size.width, 740), 43 | height: math.min(MediaQuery.of(context).size.height, 180), 44 | child: Column( 45 | mainAxisAlignment: MainAxisAlignment.start, 46 | children: [ 47 | Container( 48 | margin: EdgeInsets.fromLTRB(0, 0, 0, 16), 49 | child: SmoothStarRating( 50 | starCount: 5, 51 | rating: rating, 52 | color: color, 53 | borderColor: Colors.grey, 54 | size: 32, 55 | onRated: (value) { 56 | if (mounted) { 57 | rating = value; 58 | } 59 | }, 60 | ), 61 | ), 62 | Expanded( 63 | child: TextField( 64 | decoration: InputDecoration.collapsed( 65 | hintText: 'Type your review here.'), 66 | keyboardType: TextInputType.multiline, 67 | maxLines: null, 68 | onChanged: (value) { 69 | if (mounted) { 70 | setState(() { 71 | review = value; 72 | }); 73 | } 74 | }, 75 | ), 76 | ), 77 | ], 78 | ), 79 | ), 80 | actions: [ 81 | FlatButton( 82 | child: Text('CANCEL'), 83 | onPressed: () => Navigator.pop(context, null), 84 | ), 85 | RaisedButton( 86 | child: Text('SAVE'), 87 | onPressed: () => Navigator.pop( 88 | context, 89 | Review.fromUserInput( 90 | rating: rating, 91 | text: review, 92 | userId: widget.userId, 93 | userName: widget.userName, 94 | ), 95 | ), 96 | ), 97 | ], 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/src/widgets/empty_list.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | typedef EmptyListActionButtonCallback = void Function(); 18 | 19 | class EmptyListView extends StatelessWidget { 20 | EmptyListView({ 21 | this.child, 22 | this.onPressed, 23 | }); 24 | 25 | final Widget child; 26 | final EmptyListActionButtonCallback onPressed; 27 | @override 28 | Widget build(BuildContext context) { 29 | final screenWidth = MediaQuery.of(context).size.width; 30 | final screenHeight = MediaQuery.of(context).size.height; 31 | var imageSize = 600.0; 32 | if (screenWidth < 640 || screenHeight < 820) { 33 | imageSize = 300; 34 | } 35 | return Center( 36 | child: Column( 37 | mainAxisSize: MainAxisSize.min, 38 | children: [ 39 | Container( 40 | width: imageSize, 41 | height: imageSize, 42 | child: Image.asset( 43 | 'assets/friendlyeater.png', 44 | ), 45 | ), 46 | child, 47 | RaisedButton(child: Text('ADD SOME'), onPressed: onPressed), 48 | ], 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/widgets/filter_bar.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | import '../model/filter.dart'; 18 | 19 | const _boldStyle = TextStyle(fontWeight: FontWeight.bold); 20 | 21 | class FilterBar extends StatelessWidget { 22 | FilterBar({@required VoidCallback onPressed, Filter filter}) 23 | : _onPressed = onPressed, 24 | _filter = filter; 25 | 26 | final VoidCallback _onPressed; 27 | final Filter _filter; 28 | 29 | List _buildCategorySpans(Filter filter) { 30 | final noneSelected = 31 | filter == null || filter.isDefault || filter.category == null; 32 | return [ 33 | if (noneSelected) TextSpan(text: 'All Restaurants', style: _boldStyle), 34 | if (!noneSelected) ...[ 35 | TextSpan(text: '${filter.category}', style: _boldStyle), 36 | TextSpan(text: ' places'), 37 | ], 38 | ]; 39 | } 40 | 41 | List _buildPriceSpans(Filter filter) { 42 | return [ 43 | if (filter.price != null) ...[ 44 | TextSpan(text: ' of '), 45 | TextSpan(text: '\$' * filter.price, style: _boldStyle), 46 | ], 47 | ]; 48 | } 49 | 50 | List _buildTitleSpans(Filter filter) { 51 | return [ 52 | ..._buildCategorySpans(filter), 53 | if (filter != null && !filter.isDefault) ..._buildPriceSpans(filter), 54 | ]; 55 | } 56 | 57 | List _buildCitySpans(Filter filter) { 58 | return [ 59 | if (filter.city != null) ...[ 60 | TextSpan(text: 'in '), 61 | TextSpan(text: '${filter.city} ', style: _boldStyle), 62 | ], 63 | ]; 64 | } 65 | 66 | List _buildSubtitleSpans(Filter filter) { 67 | final orderedByRating = 68 | filter == null || filter.sort == null || filter.sort == 'avgRating'; 69 | return [ 70 | if (filter != null) ..._buildCitySpans(filter), 71 | if (orderedByRating) TextSpan(text: 'by rating'), 72 | if (!orderedByRating) TextSpan(text: 'by # reviews'), 73 | ]; 74 | } 75 | 76 | @override 77 | Widget build(BuildContext context) { 78 | return FlatButton( 79 | color: Colors.white, 80 | padding: EdgeInsets.all(6), 81 | onPressed: _onPressed, 82 | child: Row( 83 | children: [ 84 | Icon(Icons.filter_list), 85 | Expanded( 86 | child: Padding( 87 | padding: EdgeInsets.fromLTRB(6, 0, 6, 0), 88 | child: Column( 89 | crossAxisAlignment: CrossAxisAlignment.start, 90 | children: [ 91 | RichText( 92 | overflow: TextOverflow.ellipsis, 93 | text: TextSpan( 94 | style: Theme.of(context).textTheme.bodyText2, 95 | children: _buildTitleSpans(_filter), 96 | ), 97 | ), 98 | RichText( 99 | overflow: TextOverflow.ellipsis, 100 | text: TextSpan( 101 | style: Theme.of(context).textTheme.caption, 102 | children: _buildSubtitleSpans(_filter), 103 | ), 104 | ), 105 | ], 106 | ), 107 | ), 108 | ), 109 | ], 110 | ), 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/src/widgets/grid.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:math' as math; 16 | 17 | import 'package:flutter/material.dart'; 18 | import 'package:responsive_grid/responsive_grid.dart'; 19 | 20 | import '../model/restaurant.dart'; 21 | import 'card.dart'; 22 | 23 | const double _minSpacingPx = 16; 24 | const double _cardWidth = 360; 25 | 26 | class RestaurantGrid extends StatelessWidget { 27 | RestaurantGrid({ 28 | @required RestaurantPressedCallback onRestaurantPressed, 29 | @required List restaurants, 30 | }) : _onRestaurantPressed = onRestaurantPressed, 31 | _restaurants = restaurants; 32 | 33 | final RestaurantPressedCallback _onRestaurantPressed; 34 | final List _restaurants; 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return ResponsiveGridList( 39 | // ResponsiveGridList crashes if desiredItemWidth + 2*minSpacing > Device window on Android 40 | desiredItemWidth: math.min( 41 | _cardWidth, MediaQuery.of(context).size.width - (2 * _minSpacingPx)), 42 | minSpacing: _minSpacingPx, 43 | children: _restaurants 44 | .map((restaurant) => RestaurantCard( 45 | restaurant: restaurant, 46 | onRestaurantPressed: _onRestaurantPressed, 47 | )) 48 | .toList(), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/widgets/review.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | import '../model/review.dart'; 18 | import 'stars.dart'; 19 | 20 | class RestaurantReview extends StatelessWidget { 21 | RestaurantReview({ 22 | this.review, 23 | }); 24 | 25 | final Review review; 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Center( 30 | child: Container( 31 | constraints: BoxConstraints(maxWidth: 600), 32 | padding: EdgeInsets.fromLTRB(0, 16, 0, 16), 33 | decoration: BoxDecoration( 34 | border: Border( 35 | bottom: BorderSide( 36 | color: Colors.grey, 37 | width: 1, 38 | style: BorderStyle.solid, 39 | ))), 40 | child: Column( 41 | children: [ 42 | Row( 43 | children: [ 44 | Expanded( 45 | child: Text( 46 | review.userName, 47 | style: Theme.of(context).textTheme.caption, 48 | ), 49 | ), 50 | StarRating(rating: review.rating, size: 16), 51 | ], 52 | ), 53 | Row( 54 | children: [ 55 | Expanded( 56 | child: Container( 57 | padding: EdgeInsets.fromLTRB(0, 8, 0, 0), 58 | child: Text(review.text ?? ''), 59 | ), 60 | ), 61 | ], 62 | ), 63 | ], 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/src/widgets/stars.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:smooth_star_rating/smooth_star_rating.dart'; 17 | 18 | class StarRating extends StatelessWidget { 19 | StarRating({ 20 | this.rating, 21 | this.color = Colors.amber, 22 | this.size = 24, 23 | }); 24 | 25 | final double rating; 26 | final double size; 27 | final Color color; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return SmoothStarRating( 32 | starCount: 5, 33 | allowHalfRating: true, 34 | rating: rating, 35 | color: color, 36 | borderColor: color, 37 | size: size, 38 | isReadOnly: true, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.5.0-nullsafety" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0-nullsafety" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0-nullsafety.2" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0-nullsafety" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0-nullsafety" 39 | cloud_firestore: 40 | dependency: "direct main" 41 | description: 42 | name: cloud_firestore 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.14.0+2" 46 | cloud_firestore_platform_interface: 47 | dependency: transitive 48 | description: 49 | name: cloud_firestore_platform_interface 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.0.1" 53 | cloud_firestore_web: 54 | dependency: transitive 55 | description: 56 | name: cloud_firestore_web 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.2.0+1" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.15.0-nullsafety.2" 67 | fake_async: 68 | dependency: transitive 69 | description: 70 | name: fake_async 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.1.0-nullsafety" 74 | firebase: 75 | dependency: transitive 76 | description: 77 | name: firebase 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "7.3.0" 81 | firebase_auth: 82 | dependency: "direct main" 83 | description: 84 | name: firebase_auth 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.18.0+1" 88 | firebase_auth_platform_interface: 89 | dependency: transitive 90 | description: 91 | name: firebase_auth_platform_interface 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "2.0.1" 95 | firebase_auth_web: 96 | dependency: transitive 97 | description: 98 | name: firebase_auth_web 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "0.3.0+1" 102 | firebase_core: 103 | dependency: "direct main" 104 | description: 105 | name: firebase_core 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "0.5.0" 109 | firebase_core_platform_interface: 110 | dependency: transitive 111 | description: 112 | name: firebase_core_platform_interface 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "2.0.0" 116 | firebase_core_web: 117 | dependency: transitive 118 | description: 119 | name: firebase_core_web 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "0.2.0" 123 | flutter: 124 | dependency: "direct main" 125 | description: flutter 126 | source: sdk 127 | version: "0.0.0" 128 | flutter_test: 129 | dependency: "direct dev" 130 | description: flutter 131 | source: sdk 132 | version: "0.0.0" 133 | flutter_web_plugins: 134 | dependency: transitive 135 | description: flutter 136 | source: sdk 137 | version: "0.0.0" 138 | http: 139 | dependency: transitive 140 | description: 141 | name: http 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "0.12.0+3" 145 | http_parser: 146 | dependency: transitive 147 | description: 148 | name: http_parser 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "3.1.3" 152 | intl: 153 | dependency: transitive 154 | description: 155 | name: intl 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "0.16.1" 159 | js: 160 | dependency: transitive 161 | description: 162 | name: js 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.6.1+1" 166 | matcher: 167 | dependency: transitive 168 | description: 169 | name: matcher 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "0.12.10-nullsafety" 173 | meta: 174 | dependency: transitive 175 | description: 176 | name: meta 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.3.0-nullsafety.2" 180 | path: 181 | dependency: transitive 182 | description: 183 | name: path 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "1.8.0-nullsafety" 187 | pedantic: 188 | dependency: "direct dev" 189 | description: 190 | name: pedantic 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "1.9.0" 194 | plugin_platform_interface: 195 | dependency: transitive 196 | description: 197 | name: plugin_platform_interface 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "1.0.2" 201 | quiver: 202 | dependency: transitive 203 | description: 204 | name: quiver 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "2.0.5" 208 | responsive_grid: 209 | dependency: "direct main" 210 | description: 211 | name: responsive_grid 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "1.2.1+1" 215 | sky_engine: 216 | dependency: transitive 217 | description: flutter 218 | source: sdk 219 | version: "0.0.99" 220 | sliver_fab: 221 | dependency: "direct main" 222 | description: 223 | name: sliver_fab 224 | url: "https://pub.dartlang.org" 225 | source: hosted 226 | version: "1.0.0" 227 | smooth_star_rating: 228 | dependency: "direct main" 229 | description: 230 | name: smooth_star_rating 231 | url: "https://pub.dartlang.org" 232 | source: hosted 233 | version: "1.1.1" 234 | source_span: 235 | dependency: transitive 236 | description: 237 | name: source_span 238 | url: "https://pub.dartlang.org" 239 | source: hosted 240 | version: "1.8.0-nullsafety" 241 | stack_trace: 242 | dependency: transitive 243 | description: 244 | name: stack_trace 245 | url: "https://pub.dartlang.org" 246 | source: hosted 247 | version: "1.10.0-nullsafety" 248 | stream_channel: 249 | dependency: transitive 250 | description: 251 | name: stream_channel 252 | url: "https://pub.dartlang.org" 253 | source: hosted 254 | version: "2.1.0-nullsafety" 255 | string_scanner: 256 | dependency: transitive 257 | description: 258 | name: string_scanner 259 | url: "https://pub.dartlang.org" 260 | source: hosted 261 | version: "1.1.0-nullsafety" 262 | term_glyph: 263 | dependency: transitive 264 | description: 265 | name: term_glyph 266 | url: "https://pub.dartlang.org" 267 | source: hosted 268 | version: "1.2.0-nullsafety" 269 | test_api: 270 | dependency: transitive 271 | description: 272 | name: test_api 273 | url: "https://pub.dartlang.org" 274 | source: hosted 275 | version: "0.2.19-nullsafety" 276 | typed_data: 277 | dependency: transitive 278 | description: 279 | name: typed_data 280 | url: "https://pub.dartlang.org" 281 | source: hosted 282 | version: "1.3.0-nullsafety.2" 283 | vector_math: 284 | dependency: transitive 285 | description: 286 | name: vector_math 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "2.1.0-nullsafety.2" 290 | sdks: 291 | dart: ">=2.10.0-0.0.dev <2.10.0" 292 | flutter: ">=1.12.13+hotfix.5 <2.0.0" 293 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: friendlyeats 16 | description: A new Flutter project. 17 | 18 | # version: 1.0.0 19 | publish_to: none 20 | 21 | environment: 22 | sdk: ">=2.7.0 <3.0.0" 23 | 24 | dependencies: 25 | firebase_core: ^0.5.0 26 | firebase_auth: ^0.18.0+1 27 | cloud_firestore: ^0.14.0+2 28 | responsive_grid: ^1.2.1+1 29 | smooth_star_rating: ^1.1.1 30 | sliver_fab: ^1.0.0 31 | flutter: 32 | sdk: flutter 33 | 34 | dev_dependencies: 35 | pedantic: ^1.9.0 36 | flutter_test: 37 | sdk: flutter 38 | 39 | 40 | # For information on the generic Dart part of this file, see the 41 | # following page: https://dart.dev/tools/pub/pubspec 42 | 43 | # The following section is specific to Flutter. 44 | flutter: 45 | # The following line ensures that the Material Icons font is 46 | # included with your application, so that you can use the icons in 47 | # the material Icons class. 48 | uses-material-design: true 49 | 50 | # For details regarding assets, see 51 | # https://flutter.dev/assets-and-images 52 | assets: 53 | - assets/friendlyeater.png 54 | 55 | # To add custom fonts to your application, add a fonts section here, 56 | # in this "flutter" section. Each entry in this list should have a 57 | # "family" key with the font family name, and a "fonts" key with a 58 | # list giving the asset and other descriptors for the font. For 59 | # example: 60 | # fonts: 61 | # - family: Schyler 62 | # fonts: 63 | # - asset: fonts/Schyler-Regular.ttf 64 | # - asset: fonts/Schyler-Italic.ttf 65 | # style: italic 66 | # - family: Trajan Pro 67 | # fonts: 68 | # - asset: fonts/TrajanPro.ttf 69 | # - asset: fonts/TrajanPro_Bold.ttf 70 | # weight: 700 71 | # 72 | # For details regarding fonts from package dependencies, 73 | # see https://flutter.dev/custom-fonts/#from-packages 74 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This is a basic Flutter widget test. 16 | // 17 | // To perform an interaction with a widget in your test, use the WidgetTester 18 | // utility that Flutter provides. For example, you can send tap and scroll 19 | // gestures. You can also use WidgetTester to find child widgets in the widget 20 | // tree, read text, and verify that the values of widget properties are correct. 21 | 22 | import 'package:flutter/material.dart'; 23 | import 'package:flutter_test/flutter_test.dart'; 24 | 25 | import 'package:friendlyeats/src/app.dart'; 26 | 27 | void main() { 28 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 29 | // Build our app and trigger a frame. 30 | await tester.pumpWidget(FriendlyEatsApp()); 31 | 32 | // Verify that our counter starts at 0. 33 | expect(find.text('0'), findsOneWidget); 34 | expect(find.text('1'), findsNothing); 35 | 36 | // Tap the '+' icon and trigger a frame. 37 | await tester.tap(find.byIcon(Icons.add)); 38 | await tester.pump(); 39 | 40 | // Verify that our counter has incremented. 41 | expect(find.text('0'), findsNothing); 42 | expect(find.text('1'), findsOneWidget); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/codelab-friendlyeats-flutter/6f7603c33f2ef0f7e37ff1730991e1982327aa6f/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | friendlyeats 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 61 | 62 | 63 | 66 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "friendlyeats", 3 | "short_name": "friendlyeats", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------