├── .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 |
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 |
--------------------------------------------------------------------------------