├── .gitignore ├── .idx └── dev.nix ├── .metadata ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_draw_it_sample │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── 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-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── lib └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /.idx/dev.nix: -------------------------------------------------------------------------------- 1 | # To learn more about how to use Nix to configure your environment 2 | # see: https://developers.google.com/idx/guides/customize-idx-env 3 | { pkgs, ... }: { 4 | # Which nixpkgs channel to use. 5 | channel = "stable-23.11"; # or "unstable" 6 | # Use https://search.nixos.org/packages to find packages 7 | packages = [ 8 | pkgs.nodePackages.firebase-tools 9 | pkgs.jdk17 10 | pkgs.unzip 11 | ]; 12 | # Sets environment variables in the workspace 13 | env = {}; 14 | idx = { 15 | # Search for the extensions you want on https://open-vsx.org/ and use "publisher.id" 16 | extensions = [ 17 | "Dart-Code.flutter" 18 | "Dart-Code.dart-code" 19 | ]; 20 | workspace = { 21 | # Runs when a workspace is first created with this `dev.nix` file 22 | onCreate = { 23 | build-flutter = '' 24 | cd /home/user/myapp/android 25 | ./gradlew \ 26 | --parallel \ 27 | -Pverbose=true \ 28 | -Ptarget-platform=android-x86 \ 29 | -Ptarget=/home/user/myapp/lib/main.dart \ 30 | -Pbase-application-name=android.app.Application \ 31 | -Pdart-defines=RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC85NzU1MDkwN2I3MGY0ZjNiMzI4YjZjMTYwMGRmMjFmYWMxYTE4ODlhLw== \ 32 | -Pdart-obfuscation=false \ 33 | -Ptrack-widget-creation=true \ 34 | -Ptree-shake-icons=false \ 35 | -Pfilesystem-scheme=org-dartlang-root \ 36 | assembleDebug 37 | 38 | # TODO: Execute web build in debug mode. 39 | # flutter run does this transparently either way 40 | # https://github.com/flutter/flutter/issues/96283#issuecomment-1144750411 41 | # flutter build web --profile --dart-define=Dart2jsOptimization=O0 42 | adb -s localhost:5555 wait-for-device 43 | ''; 44 | }; 45 | 46 | # To run something each time the workspace is (re)started, use the `onStart` hook 47 | }; 48 | # Enable previews and customize configuration 49 | previews = { 50 | enable = true; 51 | previews = { 52 | web = { 53 | command = ["flutter" "run" "--machine" "-d" "web-server" "--web-hostname" "0.0.0.0" "--web-port" "$PORT"]; 54 | manager = "flutter"; 55 | }; 56 | android = { 57 | command = ["flutter" "run" "--machine" "-d" "android" "-d" "localhost:5555"]; 58 | manager = "flutter"; 59 | }; 60 | }; 61 | }; 62 | }; 63 | } -------------------------------------------------------------------------------- /.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: "300451adae589accbece3490f4396f10bdf15e6e" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 17 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 18 | - platform: android 19 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 20 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 21 | - platform: ios 22 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 23 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 24 | - platform: linux 25 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 26 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 27 | - platform: macos 28 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 29 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 30 | - platform: web 31 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 32 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 33 | - platform: windows 34 | create_revision: 300451adae589accbece3490f4396f10bdf15e6e 35 | base_revision: 300451adae589accbece3490f4396f10bdf15e6e 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | This project is not accepting pull requests at this time. 4 | 5 | Feel free to fork this repository if you wish to make changes. 6 | -------------------------------------------------------------------------------- /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. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Draw-It Sample 2 | 3 | 4 | 5 | 8 | 11 | Open in IDX 15 | 16 | 17 | 18 | An open source sample for Flutter and Gemini that uses multimodal 19 | prompting to compare an image and word to see if they match. 20 | 21 | ## Getting Started 22 | 23 | To use this sample, you'll need a Gemini API key. You can find instructions 24 | for generating one at https://ai.google.dev/. 25 | 26 | Before running the project locally, recreate its platform-specific subprojects 27 | with this command: 28 | 29 | ```bash 30 | flutter create --project-name flutter_draw_it_sample . 31 | ``` 32 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | include: package:flutter_lints/flutter.yaml 16 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | def localProperties = new Properties() 9 | def localPropertiesFile = rootProject.file("local.properties") 10 | if (localPropertiesFile.exists()) { 11 | localPropertiesFile.withReader("UTF-8") { reader -> 12 | localProperties.load(reader) 13 | } 14 | } 15 | 16 | def flutterVersionCode = localProperties.getProperty("flutter.versionCode") 17 | if (flutterVersionCode == null) { 18 | flutterVersionCode = "1" 19 | } 20 | 21 | def flutterVersionName = localProperties.getProperty("flutter.versionName") 22 | if (flutterVersionName == null) { 23 | flutterVersionName = "1.0" 24 | } 25 | 26 | android { 27 | namespace = "com.example.flutter_draw_it_sample" 28 | compileSdk = flutter.compileSdkVersion 29 | ndkVersion = flutter.ndkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility = JavaVersion.VERSION_1_8 33 | targetCompatibility = JavaVersion.VERSION_1_8 34 | } 35 | 36 | defaultConfig { 37 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 38 | applicationId = "com.example.flutter_draw_it_sample" 39 | // You can update the following values to match your application needs. 40 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 41 | minSdk = flutter.minSdkVersion 42 | targetSdk = flutter.targetSdkVersion 43 | versionCode = flutterVersionCode.toInteger() 44 | versionName = flutterVersionName 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig = signingConfigs.debug 52 | } 53 | } 54 | } 55 | 56 | flutter { 57 | source = "../.." 58 | } 59 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_draw_it_sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_draw_it_sample 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-gemini/flutter-draw-it-sample/5f8143c96d32786f4493bbbafb5aa310d0419a9c/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-gemini/flutter-draw-it-sample/5f8143c96d32786f4493bbbafb5aa310d0419a9c/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-gemini/flutter-draw-it-sample/5f8143c96d32786f4493bbbafb5aa310d0419a9c/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-gemini/flutter-draw-it-sample/5f8143c96d32786f4493bbbafb5aa310d0419a9c/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-gemini/flutter-draw-it-sample/5f8143c96d32786f4493bbbafb5aa310d0419a9c/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2024 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 | // https://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:ui' as ui; 16 | import 'dart:math' as math; 17 | 18 | import 'package:flutter/foundation.dart'; 19 | import 'package:flutter/material.dart'; 20 | import 'package:flutter/rendering.dart'; 21 | import 'package:google_generative_ai/google_generative_ai.dart'; 22 | import 'package:url_launcher/link.dart'; 23 | 24 | final wordList = ['STAR', 'HAPPY FACE', 'MOON', 'ARROW', 'DIAMOND', 'SUN']; 25 | 26 | void main() { 27 | runApp(const GenerativeAISample()); 28 | } 29 | 30 | class GenerativeAISample extends StatelessWidget { 31 | const GenerativeAISample({super.key}); 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return MaterialApp( 36 | debugShowCheckedModeBanner: false, 37 | title: 'Gemini Picture Game', 38 | theme: ThemeData( 39 | brightness: Brightness.dark, 40 | ), 41 | home: const ChatScreen(title: 'Gemini Picture Game'), 42 | ); 43 | } 44 | } 45 | 46 | class ChatScreen extends StatefulWidget { 47 | const ChatScreen({super.key, required this.title}); 48 | 49 | final String title; 50 | 51 | @override 52 | State createState() => _ChatScreenState(); 53 | } 54 | 55 | class _ChatScreenState extends State { 56 | String? apiKey; 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | return Scaffold( 61 | appBar: AppBar( 62 | title: Text(widget.title), 63 | ), 64 | body: switch (apiKey) { 65 | final providedKey? => ChatWidget(apiKey: providedKey), 66 | _ => ApiKeyWidget(onSubmitted: (key) { 67 | setState(() => apiKey = key); 68 | }), 69 | }, 70 | ); 71 | } 72 | } 73 | 74 | class ApiKeyWidget extends StatelessWidget { 75 | ApiKeyWidget({required this.onSubmitted, super.key}); 76 | 77 | final ValueChanged onSubmitted; 78 | final TextEditingController _textController = TextEditingController(); 79 | 80 | @override 81 | Widget build(BuildContext context) { 82 | return Scaffold( 83 | body: Padding( 84 | padding: const EdgeInsets.all(8.0), 85 | child: Column( 86 | mainAxisSize: MainAxisSize.min, 87 | children: [ 88 | const Text( 89 | 'To use the Gemini API, you\'ll need an API key. ' 90 | 'If you don\'t already have one, ' 91 | 'create a key in Google AI Studio.', 92 | ), 93 | const SizedBox(height: 8), 94 | Link( 95 | uri: Uri.https('aistudio.google.com', '/app/apikey'), 96 | target: LinkTarget.blank, 97 | builder: (context, followLink) => TextButton( 98 | onPressed: followLink, 99 | child: const Text('Get an API Key'), 100 | ), 101 | ), 102 | const SizedBox(height: 8), 103 | Padding( 104 | padding: const EdgeInsets.symmetric(horizontal: 32), 105 | child: Row( 106 | children: [ 107 | Expanded( 108 | child: TextField( 109 | decoration: 110 | textFieldDecoration(context, 'Enter your API key'), 111 | controller: _textController, 112 | onSubmitted: (value) { 113 | onSubmitted(value); 114 | }, 115 | ), 116 | ), 117 | const SizedBox(height: 8), 118 | TextButton( 119 | onPressed: () { 120 | onSubmitted(_textController.value.text); 121 | }, 122 | child: const Text('Submit'), 123 | ), 124 | ], 125 | ), 126 | ), 127 | ], 128 | ), 129 | ), 130 | ); 131 | } 132 | } 133 | 134 | class ChatWidget extends StatefulWidget { 135 | const ChatWidget({required this.apiKey, super.key}); 136 | 137 | final String apiKey; 138 | 139 | @override 140 | State createState() => _ChatWidgetState(); 141 | } 142 | 143 | class _ChatWidgetState extends State { 144 | final dots = []; 145 | final paintKey = GlobalKey(); 146 | late final IdentificationService _service; 147 | Future? idResult; 148 | final _rng = math.Random(); 149 | String secretWord = 'STAR'; 150 | 151 | @override 152 | void initState() { 153 | super.initState(); 154 | _service = IdentificationService(widget.apiKey); 155 | } 156 | 157 | Widget _buildIdButton(bool enabled) { 158 | return ElevatedButton( 159 | onPressed: !enabled 160 | ? null 161 | : () async { 162 | setState(() => idResult = null); 163 | final bytes = await _captureWidget(); 164 | setState(() { 165 | idResult = _service.getId(bytes, secretWord); 166 | }); 167 | }, 168 | child: const Text('Identify'), 169 | ); 170 | } 171 | 172 | @override 173 | Widget build(BuildContext context) { 174 | final theme = Theme.of(context); 175 | 176 | return SizedBox.expand( 177 | child: SingleChildScrollView( 178 | child: Column( 179 | mainAxisAlignment: MainAxisAlignment.center, 180 | crossAxisAlignment: CrossAxisAlignment.center, 181 | children: [ 182 | const Padding( 183 | padding: EdgeInsets.symmetric(vertical: 16, horizontal: 64), 184 | child: Text('Click/tap and drag in the rectangle below to make an' 185 | ' image, and then hit the "Identify" button to send that' 186 | ' image to the Gemini API. The multimodal prompt will ask the' 187 | ' model to determine if the image and secret word are a' 188 | ' match!'), 189 | ), 190 | Row( 191 | mainAxisSize: MainAxisSize.min, 192 | children: [ 193 | Text( 194 | 'Secret word: $secretWord', 195 | style: theme.textTheme.titleMedium, 196 | ), 197 | IconButton( 198 | onPressed: () => setState(() { 199 | secretWord = wordList[_rng.nextInt(wordList.length)]; 200 | }), 201 | icon: const Icon(Icons.refresh), 202 | ) 203 | ], 204 | ), 205 | Container( 206 | width: 400, 207 | height: 300, 208 | decoration: BoxDecoration( 209 | color: theme.colorScheme.primaryContainer, 210 | borderRadius: BorderRadius.circular(5), 211 | border: Border.all( 212 | color: theme.colorScheme.outline, 213 | style: BorderStyle.solid, 214 | width: 1.0, 215 | ), 216 | ), 217 | child: RepaintBoundary( 218 | key: paintKey, 219 | child: Stack( 220 | children: [ 221 | Positioned.fill( 222 | child: GestureDetector( 223 | onPanUpdate: (details) { 224 | setState(() { 225 | dots.add(details.localPosition); 226 | }); 227 | }, 228 | ), 229 | ), 230 | for (final dot in dots) 231 | Positioned( 232 | left: dot.dx, 233 | top: dot.dy, 234 | child: Container( 235 | width: 5, 236 | height: 5, 237 | color: theme.colorScheme.onPrimaryContainer, 238 | ), 239 | ), 240 | ], 241 | ), 242 | ), 243 | ), 244 | const SizedBox(height: 32), 245 | Row( 246 | mainAxisSize: MainAxisSize.min, 247 | children: [ 248 | if (idResult != null) 249 | FutureBuilder( 250 | future: idResult, 251 | builder: (context, snapshot) { 252 | return _buildIdButton(snapshot.hasData); 253 | }, 254 | ) 255 | else 256 | _buildIdButton(true), 257 | const SizedBox(width: 32), 258 | ElevatedButton( 259 | onPressed: () => setState(() { 260 | dots.clear(); 261 | }), 262 | child: const Text('Clear'), 263 | ), 264 | ], 265 | ), 266 | if (idResult != null) 267 | FutureBuilder( 268 | future: idResult, 269 | builder: (context, snapshot) { 270 | if (snapshot.data == true) { 271 | return const StatusWidget('Correct!'); 272 | } else if (snapshot.data == false) { 273 | return const StatusWidget('Not a match.'); 274 | } else { 275 | return const StatusWidget('Thinking...'); 276 | } 277 | }, 278 | ) 279 | else 280 | const StatusWidget(''), 281 | const SizedBox(height: 100), 282 | ], 283 | ), 284 | ), 285 | ); 286 | } 287 | 288 | Future _captureWidget() async { 289 | final RenderRepaintBoundary boundary = 290 | paintKey.currentContext!.findRenderObject() as RenderRepaintBoundary; 291 | final ui.Image image = await boundary.toImage(); 292 | final ByteData byteData = 293 | (await image.toByteData(format: ui.ImageByteFormat.png))!; 294 | final Uint8List pngBytes = byteData.buffer.asUint8List(); 295 | return pngBytes; 296 | } 297 | } 298 | 299 | class StatusWidget extends StatelessWidget { 300 | final String status; 301 | 302 | const StatusWidget(this.status, {super.key}); 303 | 304 | @override 305 | Widget build(BuildContext context) { 306 | final theme = Theme.of(context); 307 | 308 | return SizedBox( 309 | height: 100, 310 | child: Center( 311 | child: Text( 312 | status, 313 | style: theme.textTheme.titleLarge?.copyWith( 314 | color: theme.colorScheme.tertiary, 315 | ), 316 | ), 317 | ), 318 | ); 319 | } 320 | } 321 | 322 | InputDecoration textFieldDecoration(BuildContext context, String hintText) => 323 | InputDecoration( 324 | contentPadding: const EdgeInsets.all(15), 325 | hintText: hintText, 326 | border: OutlineInputBorder( 327 | borderRadius: const BorderRadius.all( 328 | Radius.circular(14), 329 | ), 330 | borderSide: BorderSide( 331 | color: Theme.of(context).colorScheme.secondary, 332 | ), 333 | ), 334 | focusedBorder: OutlineInputBorder( 335 | borderRadius: const BorderRadius.all( 336 | Radius.circular(14), 337 | ), 338 | borderSide: BorderSide( 339 | color: Theme.of(context).colorScheme.secondary, 340 | ), 341 | ), 342 | ); 343 | 344 | class IdentificationService { 345 | final String apiKey; 346 | 347 | late final GenerativeModel model; 348 | 349 | final generationConfig = GenerationConfig( 350 | temperature: 0.4, 351 | topK: 32, 352 | topP: 1, 353 | maxOutputTokens: 4096, 354 | ); 355 | 356 | final safetySettings = [ 357 | SafetySetting(HarmCategory.harassment, HarmBlockThreshold.medium), 358 | SafetySetting(HarmCategory.hateSpeech, HarmBlockThreshold.medium), 359 | SafetySetting(HarmCategory.sexuallyExplicit, HarmBlockThreshold.medium), 360 | SafetySetting(HarmCategory.dangerousContent, HarmBlockThreshold.medium), 361 | ]; 362 | 363 | IdentificationService(this.apiKey) { 364 | model = GenerativeModel(model: 'gemini-pro-vision', apiKey: apiKey); 365 | } 366 | 367 | Future getId(Uint8List pngBytes, String symbolName) async { 368 | final prompt = [ 369 | Content.multi([ 370 | DataPart('image/jpeg', pngBytes), 371 | TextPart('Does this image contain a $symbolName? Answer "yes" or' 372 | ' "no" with no additional text.'), 373 | ]), 374 | ]; 375 | 376 | try { 377 | final response = await model.generateContent( 378 | prompt, 379 | safetySettings: safetySettings, 380 | generationConfig: generationConfig, 381 | ); 382 | if (response.text?.toLowerCase().contains('yes') ?? false) { 383 | return true; 384 | } 385 | } on GenerativeAIException { 386 | return false; 387 | } 388 | 389 | return false; 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /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 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.8" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | ffi: 61 | dependency: transitive 62 | description: 63 | name: ffi 64 | sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "2.1.3" 68 | flutter: 69 | dependency: "direct main" 70 | description: flutter 71 | source: sdk 72 | version: "0.0.0" 73 | flutter_lints: 74 | dependency: "direct dev" 75 | description: 76 | name: flutter_lints 77 | sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" 78 | url: "https://pub.dev" 79 | source: hosted 80 | version: "3.0.2" 81 | flutter_test: 82 | dependency: "direct dev" 83 | description: flutter 84 | source: sdk 85 | version: "0.0.0" 86 | flutter_web_plugins: 87 | dependency: transitive 88 | description: flutter 89 | source: sdk 90 | version: "0.0.0" 91 | google_generative_ai: 92 | dependency: "direct main" 93 | description: 94 | name: google_generative_ai 95 | sha256: f666a8c09225630a9ab366296407b38c6dab87ba7b1bce15a7db35e9411c17d3 96 | url: "https://pub.dev" 97 | source: hosted 98 | version: "0.2.3" 99 | http: 100 | dependency: transitive 101 | description: 102 | name: http 103 | sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 104 | url: "https://pub.dev" 105 | source: hosted 106 | version: "1.2.2" 107 | http_parser: 108 | dependency: transitive 109 | description: 110 | name: http_parser 111 | sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "4.1.1" 115 | leak_tracker: 116 | dependency: transitive 117 | description: 118 | name: leak_tracker 119 | sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "10.0.7" 123 | leak_tracker_flutter_testing: 124 | dependency: transitive 125 | description: 126 | name: leak_tracker_flutter_testing 127 | sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "3.0.8" 131 | leak_tracker_testing: 132 | dependency: transitive 133 | description: 134 | name: leak_tracker_testing 135 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "3.0.1" 139 | lints: 140 | dependency: transitive 141 | description: 142 | name: lints 143 | sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "3.0.0" 147 | matcher: 148 | dependency: transitive 149 | description: 150 | name: matcher 151 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "0.12.16+1" 155 | material_color_utilities: 156 | dependency: transitive 157 | description: 158 | name: material_color_utilities 159 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "0.11.1" 163 | meta: 164 | dependency: transitive 165 | description: 166 | name: meta 167 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "1.15.0" 171 | path: 172 | dependency: "direct main" 173 | description: 174 | name: path 175 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "1.9.0" 179 | path_provider: 180 | dependency: "direct main" 181 | description: 182 | name: path_provider 183 | sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "2.1.4" 187 | path_provider_android: 188 | dependency: transitive 189 | description: 190 | name: path_provider_android 191 | sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "2.2.12" 195 | path_provider_foundation: 196 | dependency: transitive 197 | description: 198 | name: path_provider_foundation 199 | sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "2.4.0" 203 | path_provider_linux: 204 | dependency: transitive 205 | description: 206 | name: path_provider_linux 207 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "2.2.1" 211 | path_provider_platform_interface: 212 | dependency: transitive 213 | description: 214 | name: path_provider_platform_interface 215 | sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" 216 | url: "https://pub.dev" 217 | source: hosted 218 | version: "2.1.2" 219 | path_provider_windows: 220 | dependency: transitive 221 | description: 222 | name: path_provider_windows 223 | sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 224 | url: "https://pub.dev" 225 | source: hosted 226 | version: "2.3.0" 227 | platform: 228 | dependency: transitive 229 | description: 230 | name: platform 231 | sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" 232 | url: "https://pub.dev" 233 | source: hosted 234 | version: "3.1.6" 235 | plugin_platform_interface: 236 | dependency: transitive 237 | description: 238 | name: plugin_platform_interface 239 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 240 | url: "https://pub.dev" 241 | source: hosted 242 | version: "2.1.8" 243 | sky_engine: 244 | dependency: transitive 245 | description: flutter 246 | source: sdk 247 | version: "0.0.0" 248 | source_span: 249 | dependency: transitive 250 | description: 251 | name: source_span 252 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 253 | url: "https://pub.dev" 254 | source: hosted 255 | version: "1.10.0" 256 | stack_trace: 257 | dependency: transitive 258 | description: 259 | name: stack_trace 260 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 261 | url: "https://pub.dev" 262 | source: hosted 263 | version: "1.11.1" 264 | stream_channel: 265 | dependency: transitive 266 | description: 267 | name: stream_channel 268 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 269 | url: "https://pub.dev" 270 | source: hosted 271 | version: "2.1.2" 272 | string_scanner: 273 | dependency: transitive 274 | description: 275 | name: string_scanner 276 | sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" 277 | url: "https://pub.dev" 278 | source: hosted 279 | version: "1.3.0" 280 | term_glyph: 281 | dependency: transitive 282 | description: 283 | name: term_glyph 284 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 285 | url: "https://pub.dev" 286 | source: hosted 287 | version: "1.2.1" 288 | test_api: 289 | dependency: transitive 290 | description: 291 | name: test_api 292 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 293 | url: "https://pub.dev" 294 | source: hosted 295 | version: "0.7.3" 296 | typed_data: 297 | dependency: transitive 298 | description: 299 | name: typed_data 300 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 301 | url: "https://pub.dev" 302 | source: hosted 303 | version: "1.4.0" 304 | url_launcher: 305 | dependency: "direct main" 306 | description: 307 | name: url_launcher 308 | sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" 309 | url: "https://pub.dev" 310 | source: hosted 311 | version: "6.3.1" 312 | url_launcher_android: 313 | dependency: transitive 314 | description: 315 | name: url_launcher_android 316 | sha256: "8fc3bae0b68c02c47c5c86fa8bfa74471d42687b0eded01b78de87872db745e2" 317 | url: "https://pub.dev" 318 | source: hosted 319 | version: "6.3.12" 320 | url_launcher_ios: 321 | dependency: transitive 322 | description: 323 | name: url_launcher_ios 324 | sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e 325 | url: "https://pub.dev" 326 | source: hosted 327 | version: "6.3.1" 328 | url_launcher_linux: 329 | dependency: transitive 330 | description: 331 | name: url_launcher_linux 332 | sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af 333 | url: "https://pub.dev" 334 | source: hosted 335 | version: "3.2.0" 336 | url_launcher_macos: 337 | dependency: transitive 338 | description: 339 | name: url_launcher_macos 340 | sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" 341 | url: "https://pub.dev" 342 | source: hosted 343 | version: "3.2.1" 344 | url_launcher_platform_interface: 345 | dependency: transitive 346 | description: 347 | name: url_launcher_platform_interface 348 | sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" 349 | url: "https://pub.dev" 350 | source: hosted 351 | version: "2.3.2" 352 | url_launcher_web: 353 | dependency: transitive 354 | description: 355 | name: url_launcher_web 356 | sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" 357 | url: "https://pub.dev" 358 | source: hosted 359 | version: "2.3.3" 360 | url_launcher_windows: 361 | dependency: transitive 362 | description: 363 | name: url_launcher_windows 364 | sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" 365 | url: "https://pub.dev" 366 | source: hosted 367 | version: "3.1.3" 368 | vector_math: 369 | dependency: transitive 370 | description: 371 | name: vector_math 372 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 373 | url: "https://pub.dev" 374 | source: hosted 375 | version: "2.1.4" 376 | vm_service: 377 | dependency: transitive 378 | description: 379 | name: vm_service 380 | sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" 381 | url: "https://pub.dev" 382 | source: hosted 383 | version: "14.2.5" 384 | web: 385 | dependency: transitive 386 | description: 387 | name: web 388 | sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb 389 | url: "https://pub.dev" 390 | source: hosted 391 | version: "1.1.0" 392 | xdg_directories: 393 | dependency: transitive 394 | description: 395 | name: xdg_directories 396 | sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" 397 | url: "https://pub.dev" 398 | source: hosted 399 | version: "1.1.0" 400 | sdks: 401 | dart: ">=3.5.0 <4.0.0" 402 | flutter: ">=3.24.0" 403 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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: flutter_draw_it_sample 16 | description: "A new Flutter project." 17 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 18 | 19 | version: 1.0.0+1 20 | 21 | environment: 22 | sdk: '>=3.3.3 <4.0.0' 23 | 24 | dependencies: 25 | flutter: 26 | sdk: flutter 27 | google_generative_ai: ^0.2.3 28 | path: ^1.9.0 29 | path_provider: ^2.1.3 30 | url_launcher: ^6.2.5 31 | 32 | cupertino_icons: ^1.0.6 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | 38 | flutter_lints: ^3.0.0 39 | 40 | flutter: 41 | 42 | uses-material-design: true -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2024 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 | // https://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_test/flutter_test.dart'; 16 | 17 | void main() { 18 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); 19 | } 20 | --------------------------------------------------------------------------------