├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── google-services.json │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── flutter │ │ │ │ └── plugins │ │ │ │ └── GeneratedPluginRegistrant.java │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── my_project │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── audios │ └── favicon.png ├── fonts │ ├── Poppins-Regular.ttf │ ├── Poppins-SemiBold.ttf │ └── favicon.png ├── images │ ├── ai_spy_logo.png │ ├── app_launcher_icon.png │ ├── codewords_game_cover.png │ ├── favicon.png │ └── spy_logo.png ├── lottie_animations │ └── favicon.png ├── pdfs │ └── favicon.png ├── rive_animations │ └── favicon.png └── videos │ └── favicon.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── ImageNotification │ ├── Info.plist │ └── NotificationService.swift ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ ├── GoogleService-Info.plist │ ├── Info.plist │ ├── Runner-Bridging-Header.h │ └── Runner.entitlements ├── lib ├── app_state.dart ├── auth │ ├── auth_manager.dart │ ├── base_auth_user_provider.dart │ └── firebase_auth │ │ ├── anonymous_auth.dart │ │ ├── apple_auth.dart │ │ ├── auth_util.dart │ │ ├── email_auth.dart │ │ ├── firebase_auth_manager.dart │ │ ├── firebase_user_provider.dart │ │ ├── google_auth.dart │ │ └── jwt_token_auth.dart ├── backend │ ├── api_requests │ │ ├── api_calls.dart │ │ └── api_manager.dart │ ├── backend.dart │ ├── cloud_functions │ │ └── cloud_functions.dart │ ├── firebase │ │ └── firebase_config.dart │ ├── firebase_analytics │ │ └── analytics.dart │ └── schema │ │ ├── firestore.indexes.json │ │ ├── firestore.rules │ │ ├── index.dart │ │ ├── players_record.dart │ │ ├── room_record.dart │ │ ├── structs │ │ ├── clue_data_struct.dart │ │ └── index.dart │ │ ├── users_record.dart │ │ └── util │ │ ├── firestore_util.dart │ │ └── schema_util.dart ├── components │ ├── game_mode_dialog │ │ ├── game_mode_dialog_model.dart │ │ └── game_mode_dialog_widget.dart │ ├── join_game │ │ ├── join_game_model.dart │ │ └── join_game_widget.dart │ ├── loading_dialog │ │ ├── loading_dialog_model.dart │ │ └── loading_dialog_widget.dart │ └── loading_widget │ │ ├── loading_widget_model.dart │ │ └── loading_widget_widget.dart ├── custom_code │ ├── actions │ │ ├── calculate_words_left.dart │ │ ├── declare_winner.dart │ │ ├── generate_board_words.dart │ │ ├── get_word_color.dart │ │ ├── index.dart │ │ ├── init_words.dart │ │ └── word_tapped.dart │ └── widgets │ │ ├── circular_indicator.dart │ │ ├── confetti_overlay.dart │ │ └── index.dart ├── flutter_flow │ ├── custom_functions.dart │ ├── flutter_flow_animations.dart │ ├── flutter_flow_icon_button.dart │ ├── flutter_flow_model.dart │ ├── flutter_flow_theme.dart │ ├── flutter_flow_util.dart │ ├── flutter_flow_widgets.dart │ ├── form_field_controller.dart │ ├── instant_timer.dart │ ├── internationalization.dart │ ├── lat_lng.dart │ ├── nav │ │ ├── nav.dart │ │ └── serialization_util.dart │ ├── place.dart │ └── uploaded_file.dart ├── index.dart ├── main.dart └── pages │ ├── celebrate_pages │ ├── blue_celebrate_page │ │ ├── blue_celebrate_page_model.dart │ │ └── blue_celebrate_page_widget.dart │ └── red_celebrate_page │ │ ├── red_celebrate_page_model.dart │ │ └── red_celebrate_page_widget.dart │ ├── create_join_screen │ ├── create_join_screen_model.dart │ └── create_join_screen_widget.dart │ ├── game_pages │ ├── field_operatives_view │ │ ├── field_operatives_view_model.dart │ │ └── field_operatives_view_widget.dart │ └── spy_view │ │ ├── spy_view_model.dart │ │ └── spy_view_widget.dart │ ├── joining_pages │ ├── host_page │ │ ├── host_page_model.dart │ │ └── host_page_widget.dart │ └── player_page │ │ ├── player_page_model.dart │ │ └── player_page_widget.dart │ └── start_screen │ ├── start_screen_model.dart │ └── start_screen_widget.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshots ├── codewords_ai_mode.png ├── codewords_screens.png ├── codewords_screens_2_rows.png └── codewords_screens_new.png ├── test └── widget_test.dart └── web ├── codewords_game_cover.png ├── favicon.png ├── favicon_codewords.png ├── icons ├── Icon-192.png ├── Icon-512.png └── app_launcher_icon.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Firebase – this is necessary if you use Firebase since it could otherwise 35 | # lead to leaking of private certificates to your repository, which is no bueno. 36 | .firebase/ 37 | 38 | # Web related 39 | lib/generated_plugin_registrant.dart 40 | 41 | # Symbolication related 42 | app.*.symbols 43 | 44 | # Obfuscation related 45 | app.*.map.json 46 | 47 | # Android Studio will place build artifacts here 48 | /android/app/debug 49 | /android/app/profile 50 | /android/app/release 51 | .vscode/settings.json 52 | -------------------------------------------------------------------------------- /.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: 4d7946a68d26794349189cf21b3f68cc6fe61dcb 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Souvik Biswas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codewords 2 | 3 | The famous [Codenames](https://en.wikipedia.org/wiki/Codenames_(board_game)) game created using [FlutterFlow](https://flutterflow.io/). The app is responsive and adapts to both mobile and desktop screen sizes. 4 | 5 | **Start playing [HERE](https://codewords.flutterflow.app)!** 6 | 7 | > It's recommended to have at least 6 players (Players: 4-8+). 8 | 9 | ![Codewords screens](screenshots/codewords_screens_new.png) 10 | 11 | ## New: AI Mode 12 | 13 | You can now use **AI-based Spymasters** while playing Codewords. That means Codewords is now fun even with less people, as low as just 2 players (one Operative in each team). 14 | 15 | > AI Spymasters are powered by [GPT 4](https://openai.com/product/gpt-4). 16 | 17 | ![Codewords AI Spymaster](screenshots/codewords_ai_mode.png) 18 | 19 | ## License 20 | 21 | Copyright (c) 2023 Souvik Biswas 22 | 23 | Permission is hereby granted, free of charge, to any person obtaining a copy 24 | of this software and associated documentation files (the "Software"), to deal 25 | in the Software without restriction, including without limitation the rights 26 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 27 | copies of the Software, and to permit persons to whom the Software is 28 | furnished to do so, subject to the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be included in all 31 | copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 39 | SOFTWARE. 40 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | apply plugin: 'com.google.gms.google-services' // Google Services plugin 28 | 29 | 30 | def keystoreProperties = new Properties() 31 | def keystorePropertiesFile = rootProject.file('key.properties') 32 | if (keystorePropertiesFile.exists()) { 33 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 34 | } 35 | 36 | android { 37 | compileSdkVersion 33 38 | 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | lintOptions { 45 | disable 'InvalidPackage' 46 | checkReleaseBuilds false 47 | } 48 | 49 | defaultConfig { 50 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 51 | applicationId "io.flutterflow.codewords" 52 | minSdkVersion 21 53 | targetSdkVersion 33 54 | versionCode flutterVersionCode.toInteger() 55 | versionName flutterVersionName 56 | } 57 | 58 | signingConfigs { 59 | release { 60 | keyAlias keystoreProperties['keyAlias'] 61 | keyPassword keystoreProperties['keyPassword'] 62 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null 63 | storePassword keystoreProperties['storePassword'] 64 | } 65 | } 66 | 67 | buildTypes { 68 | release { 69 | // TODO: Add your own signing config for the release build. 70 | // Signing with the debug keys for now, so `flutter run --release` works. 71 | signingConfig signingConfigs.debug 72 | } 73 | } 74 | } 75 | 76 | flutter { 77 | source '../..' 78 | } 79 | 80 | dependencies { 81 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 82 | } 83 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "82596644495", 4 | "project_id": "codewords-82f6e", 5 | "storage_bucket": "codewords-82f6e.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:82596644495:android:f8a5277f363b99d26f92fa", 11 | "android_client_info": { 12 | "package_name": "io.flutterflow.codewords" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "82596644495-ff8flnqmaofrkdkloeore6mktccf5ega.apps.googleusercontent.com", 18 | "client_type": 1, 19 | "android_info": { 20 | "package_name": "io.flutterflow.codewords", 21 | "certificate_hash": "9bbb3186b2189ef16d8f272bdab59362c395cbb4" 22 | } 23 | }, 24 | { 25 | "client_id": "82596644495-ldllvd1bg9dsnlpggkq6i7aqmi08pmhe.apps.googleusercontent.com", 26 | "client_type": 3 27 | } 28 | ], 29 | "api_key": [ 30 | { 31 | "current_key": "AIzaSyAUDQFSetq1-vGQUEXmKcsl6LZGdMQrDpw" 32 | } 33 | ], 34 | "services": { 35 | "appinvite_service": { 36 | "other_platform_oauth_client": [ 37 | { 38 | "client_id": "82596644495-ldllvd1bg9dsnlpggkq6i7aqmi08pmhe.apps.googleusercontent.com", 39 | "client_type": 3 40 | }, 41 | { 42 | "client_id": "82596644495-811s84aecqhpvrc12livlarnr5u43ce3.apps.googleusercontent.com", 43 | "client_type": 2, 44 | "ios_info": { 45 | "bundle_id": "io.flutterflow.codewords" 46 | } 47 | } 48 | ] 49 | } 50 | } 51 | } 52 | ], 53 | "configuration_version": "1" 54 | } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 12 | 13 | 21 | 25 | 29 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import androidx.annotation.Keep; 4 | import androidx.annotation.NonNull; 5 | import io.flutter.Log; 6 | 7 | import io.flutter.embedding.engine.FlutterEngine; 8 | 9 | /** 10 | * Generated file. Do not edit. 11 | * This file is generated by the Flutter tool based on the 12 | * plugins that support the Android platform. 13 | */ 14 | @Keep 15 | public final class GeneratedPluginRegistrant { 16 | private static final String TAG = "GeneratedPluginRegistrant"; 17 | public static void registerWith(@NonNull FlutterEngine flutterEngine) { 18 | try { 19 | flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.firestore.FlutterFirebaseFirestorePlugin()); 20 | } catch(Exception e) { 21 | Log.e(TAG, "Error registering plugin cloud_firestore, io.flutter.plugins.firebase.firestore.FlutterFirebaseFirestorePlugin", e); 22 | } 23 | try { 24 | flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.functions.FlutterFirebaseFunctionsPlugin()); 25 | } catch(Exception e) { 26 | Log.e(TAG, "Error registering plugin cloud_functions, io.flutter.plugins.firebase.functions.FlutterFirebaseFunctionsPlugin", e); 27 | } 28 | try { 29 | flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.analytics.FlutterFirebaseAnalyticsPlugin()); 30 | } catch(Exception e) { 31 | Log.e(TAG, "Error registering plugin firebase_analytics, io.flutter.plugins.firebase.analytics.FlutterFirebaseAnalyticsPlugin", e); 32 | } 33 | try { 34 | flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin()); 35 | } catch(Exception e) { 36 | Log.e(TAG, "Error registering plugin firebase_auth, io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin", e); 37 | } 38 | try { 39 | flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin()); 40 | } catch(Exception e) { 41 | Log.e(TAG, "Error registering plugin firebase_core, io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin", e); 42 | } 43 | try { 44 | flutterEngine.getPlugins().add(new io.flutter.plugins.googlesignin.GoogleSignInPlugin()); 45 | } catch(Exception e) { 46 | Log.e(TAG, "Error registering plugin google_sign_in_android, io.flutter.plugins.googlesignin.GoogleSignInPlugin", e); 47 | } 48 | try { 49 | flutterEngine.getPlugins().add(new io.flutter.plugins.pathprovider.PathProviderPlugin()); 50 | } catch(Exception e) { 51 | Log.e(TAG, "Error registering plugin path_provider_android, io.flutter.plugins.pathprovider.PathProviderPlugin", e); 52 | } 53 | try { 54 | flutterEngine.getPlugins().add(new io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin()); 55 | } catch(Exception e) { 56 | Log.e(TAG, "Error registering plugin shared_preferences_android, io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin", e); 57 | } 58 | try { 59 | flutterEngine.getPlugins().add(new com.aboutyou.dart_packages.sign_in_with_apple.SignInWithApplePlugin()); 60 | } catch(Exception e) { 61 | Log.e(TAG, "Error registering plugin sign_in_with_apple, com.aboutyou.dart_packages.sign_in_with_apple.SignInWithApplePlugin", e); 62 | } 63 | try { 64 | flutterEngine.getPlugins().add(new com.tekartik.sqflite.SqflitePlugin()); 65 | } catch(Exception e) { 66 | Log.e(TAG, "Error registering plugin sqflite, com.tekartik.sqflite.SqflitePlugin", e); 67 | } 68 | try { 69 | flutterEngine.getPlugins().add(new io.flutter.plugins.urllauncher.UrlLauncherPlugin()); 70 | } catch(Exception e) { 71 | Log.e(TAG, "Error registering plugin url_launcher_android, io.flutter.plugins.urllauncher.UrlLauncherPlugin", e); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/my_project/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package io.flutterflow.codewords 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/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/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Codewords 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.8' // Google Services plugin 12 | 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | mavenCentral() 20 | } 21 | } 22 | 23 | rootProject.buildDir = '../build' 24 | subprojects { 25 | project.buildDir = "${rootProject.buildDir}/${project.name}" 26 | } 27 | subprojects { 28 | project.evaluationDependsOn(':app') 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4608m 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | 13 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 14 | 15 | def plugins = new Properties() 16 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 17 | if (pluginsFile.exists()) { 18 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 19 | } 20 | 21 | plugins.each { name, path -> 22 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 23 | include ":$name" 24 | project(":$name").projectDir = pluginDirectory 25 | } -------------------------------------------------------------------------------- /assets/audios/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/audios/favicon.png -------------------------------------------------------------------------------- /assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/fonts/favicon.png -------------------------------------------------------------------------------- /assets/images/ai_spy_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/images/ai_spy_logo.png -------------------------------------------------------------------------------- /assets/images/app_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/images/app_launcher_icon.png -------------------------------------------------------------------------------- /assets/images/codewords_game_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/images/codewords_game_cover.png -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/spy_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/images/spy_logo.png -------------------------------------------------------------------------------- /assets/lottie_animations/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/lottie_animations/favicon.png -------------------------------------------------------------------------------- /assets/pdfs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/pdfs/favicon.png -------------------------------------------------------------------------------- /assets/rive_animations/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/rive_animations/favicon.png -------------------------------------------------------------------------------- /assets/videos/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/assets/videos/favicon.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | build/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 13.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/ImageNotification/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | ImageNotification 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.usernotifications.service 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).NotificationService 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ios/ImageNotification/NotificationService.swift: -------------------------------------------------------------------------------- 1 | import FirebaseMessaging 2 | import UserNotifications 3 | 4 | class NotificationService: UNNotificationServiceExtension { 5 | 6 | var contentHandler: ((UNNotificationContent) -> Void)? 7 | var bestAttemptContent: UNMutableNotificationContent? 8 | 9 | override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { 10 | self.contentHandler = contentHandler 11 | bestAttemptContent = request.content 12 | .mutableCopy() as? UNMutableNotificationContent 13 | guard let bestAttemptContent = bestAttemptContent else { return } 14 | FIRMessagingExtensionHelper().populateNotificationContent( 15 | bestAttemptContent, 16 | withContentHandler: contentHandler) 17 | } 18 | 19 | override func serviceExtensionTimeWillExpire() { 20 | // Called just before the extension will be terminated by the system. 21 | // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. 22 | if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { 23 | contentHandler(bestAttemptContent) 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | $FirebaseAnalyticsWithoutAdIdSupport = true 2 | # Uncomment this line to define a global platform for your project 3 | platform :ios, '13.0' 4 | 5 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 6 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 7 | 8 | project 'Runner', { 9 | 'Debug' => :debug, 10 | 'Profile' => :release, 11 | 'Release' => :release, 12 | } 13 | 14 | def flutter_root 15 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 16 | unless File.exist?(generated_xcode_build_settings_path) 17 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 18 | end 19 | 20 | File.foreach(generated_xcode_build_settings_path) do |line| 21 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 22 | return matches[1].strip if matches 23 | end 24 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 25 | end 26 | 27 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 28 | 29 | flutter_ios_podfile_setup 30 | 31 | target 'Runner' do 32 | use_frameworks! 33 | use_modular_headers! 34 | 35 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 36 | end 37 | 38 | post_install do |installer| 39 | installer.pods_project.targets.each do |target| 40 | flutter_additional_ios_build_settings(target) 41 | target.build_configurations.each do |config| 42 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' 43 | 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | import Flutter 4 | 5 | @UIApplicationMain 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | GeneratedPluginRegistrant.register(with: self) 12 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GeneratedPluginRegistrant_h 8 | #define GeneratedPluginRegistrant_h 9 | 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface GeneratedPluginRegistrant : NSObject 15 | + (void)registerWithRegistry:(NSObject*)registry; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | #endif /* GeneratedPluginRegistrant_h */ 20 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #import "GeneratedPluginRegistrant.h" 8 | 9 | #if __has_include() 10 | #import 11 | #else 12 | @import cloud_firestore; 13 | #endif 14 | 15 | #if __has_include() 16 | #import 17 | #else 18 | @import cloud_functions; 19 | #endif 20 | 21 | #if __has_include() 22 | #import 23 | #else 24 | @import firebase_analytics; 25 | #endif 26 | 27 | #if __has_include() 28 | #import 29 | #else 30 | @import firebase_auth; 31 | #endif 32 | 33 | #if __has_include() 34 | #import 35 | #else 36 | @import firebase_core; 37 | #endif 38 | 39 | #if __has_include() 40 | #import 41 | #else 42 | @import google_sign_in_ios; 43 | #endif 44 | 45 | #if __has_include() 46 | #import 47 | #else 48 | @import path_provider_foundation; 49 | #endif 50 | 51 | #if __has_include() 52 | #import 53 | #else 54 | @import shared_preferences_ios; 55 | #endif 56 | 57 | #if __has_include() 58 | #import 59 | #else 60 | @import sign_in_with_apple; 61 | #endif 62 | 63 | #if __has_include() 64 | #import 65 | #else 66 | @import sqflite; 67 | #endif 68 | 69 | #if __has_include() 70 | #import 71 | #else 72 | @import url_launcher_ios; 73 | #endif 74 | 75 | @implementation GeneratedPluginRegistrant 76 | 77 | + (void)registerWithRegistry:(NSObject*)registry { 78 | [FLTFirebaseFirestorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseFirestorePlugin"]]; 79 | [FLTFirebaseFunctionsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseFunctionsPlugin"]]; 80 | [FLTFirebaseAnalyticsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAnalyticsPlugin"]]; 81 | [FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]]; 82 | [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; 83 | [FLTGoogleSignInPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTGoogleSignInPlugin"]]; 84 | [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; 85 | [FLTSharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTSharedPreferencesPlugin"]]; 86 | [SignInWithApplePlugin registerWithRegistrar:[registry registrarForPlugin:@"SignInWithApplePlugin"]]; 87 | [SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]]; 88 | [FLTURLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTURLLauncherPlugin"]]; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CLIENT_ID 6 | 82596644495-811s84aecqhpvrc12livlarnr5u43ce3.apps.googleusercontent.com 7 | REVERSED_CLIENT_ID 8 | com.googleusercontent.apps.82596644495-811s84aecqhpvrc12livlarnr5u43ce3 9 | ANDROID_CLIENT_ID 10 | 82596644495-ff8flnqmaofrkdkloeore6mktccf5ega.apps.googleusercontent.com 11 | API_KEY 12 | AIzaSyBCavNfJRoE1i0UxqNsD2OFy7pqg729tfE 13 | GCM_SENDER_ID 14 | 82596644495 15 | PLIST_VERSION 16 | 1 17 | BUNDLE_ID 18 | io.flutterflow.codewords 19 | PROJECT_ID 20 | codewords-82f6e 21 | STORAGE_BUCKET 22 | codewords-82f6e.appspot.com 23 | IS_ADS_ENABLED 24 | 25 | IS_ANALYTICS_ENABLED 26 | 27 | IS_APPINVITE_ENABLED 28 | 29 | IS_GCM_ENABLED 30 | 31 | IS_SIGNIN_ENABLED 32 | 33 | GOOGLE_APP_ID 34 | 1:82596644495:ios:7ea8fe80727224a16f92fa 35 | 36 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Codewords 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | Codewords 17 | CFBundlePackageType 18 | APPL 19 | 20 | CFBundleShortVersionString 21 | $(FLUTTER_BUILD_NAME) 22 | CFBundleSignature 23 | ???? 24 | CFBundleURLTypes 25 | 26 | 27 | CFBundleTypeRole 28 | Editor 29 | CFBundleURLSchemes 30 | 31 | com.googleusercontent.apps.82596644495-811s84aecqhpvrc12livlarnr5u43ce3 32 | 33 | 34 | 35 | 36 | 37 | CFBundleTypeRole 38 | Editor 39 | CFBundleURLName 40 | codewords.com 41 | CFBundleURLSchemes 42 | 43 | codewords 44 | 45 | 46 | 47 | FlutterDeepLinkingEnabled 48 | 49 | 50 | 51 | CFBundleVersion 52 | $(FLUTTER_BUILD_NUMBER) 53 | LSRequiresIPhoneOS 54 | 55 | 56 | 57 | 58 | 59 | 60 | UILaunchStoryboardName 61 | LaunchScreen 62 | UIMainStoryboardFile 63 | Main 64 | UISupportedInterfaceOrientations 65 | 66 | UIInterfaceOrientationPortrait 67 | UIInterfaceOrientationLandscapeLeft 68 | UIInterfaceOrientationLandscapeRight 69 | 70 | UISupportedInterfaceOrientations~ipad 71 | 72 | UIInterfaceOrientationPortrait 73 | UIInterfaceOrientationPortraitUpsideDown 74 | UIInterfaceOrientationLandscapeLeft 75 | UIInterfaceOrientationLandscapeRight 76 | 77 | UIViewControllerBasedStatusBarAppearance 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/app_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import 'backend/api_requests/api_manager.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | import 'flutter_flow/flutter_flow_util.dart'; 7 | 8 | class FFAppState extends ChangeNotifier { 9 | static final FFAppState _instance = FFAppState._internal(); 10 | 11 | factory FFAppState() { 12 | return _instance; 13 | } 14 | 15 | FFAppState._internal(); 16 | 17 | Future initializePersistedState() async {} 18 | 19 | void update(VoidCallback callback) { 20 | callback(); 21 | notifyListeners(); 22 | } 23 | 24 | List _words = []; 25 | List get words => _words; 26 | set words(List _value) { 27 | _words = _value; 28 | } 29 | 30 | void addToWords(String _value) { 31 | _words.add(_value); 32 | } 33 | 34 | void removeFromWords(String _value) { 35 | _words.remove(_value); 36 | } 37 | 38 | void removeAtIndexFromWords(int _index) { 39 | _words.removeAt(_index); 40 | } 41 | 42 | void updateWordsAtIndex( 43 | int _index, 44 | Function(String) updateFn, 45 | ) { 46 | updateFn(_words[_index]); 47 | } 48 | 49 | bool _isVerifyPressed = false; 50 | bool get isVerifyPressed => _isVerifyPressed; 51 | set isVerifyPressed(bool _value) { 52 | _isVerifyPressed = _value; 53 | } 54 | 55 | bool _isJoinning = false; 56 | bool get isJoinning => _isJoinning; 57 | set isJoinning(bool _value) { 58 | _isJoinning = _value; 59 | } 60 | 61 | String _apiKey = 'YOUR_OPENAI_KEY_HERE'; 62 | String get apiKey => _apiKey; 63 | set apiKey(String _value) { 64 | _apiKey = _value; 65 | } 66 | 67 | String _modelName = 'gpt-4'; 68 | String get modelName => _modelName; 69 | set modelName(String _value) { 70 | _modelName = _value; 71 | } 72 | } 73 | 74 | LatLng? _latLngFromString(String? val) { 75 | if (val == null) { 76 | return null; 77 | } 78 | final split = val.split(','); 79 | final lat = double.parse(split.first); 80 | final lng = double.parse(split.last); 81 | return LatLng(lat, lng); 82 | } 83 | 84 | void _safeInit(Function() initializeField) { 85 | try { 86 | initializeField(); 87 | } catch (_) {} 88 | } 89 | 90 | Future _safeInitAsync(Function() initializeField) async { 91 | try { 92 | await initializeField(); 93 | } catch (_) {} 94 | } 95 | -------------------------------------------------------------------------------- /lib/auth/auth_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'base_auth_user_provider.dart'; 4 | 5 | abstract class AuthManager { 6 | Future signOut(); 7 | Future deleteUser(BuildContext context); 8 | Future resetPassword({required String email, required BuildContext context}); 9 | Future sendEmailVerification() async => currentUser?.sendEmailVerification(); 10 | } 11 | 12 | mixin EmailSignInManager on AuthManager { 13 | Future signInWithEmail( 14 | BuildContext context, 15 | String email, 16 | String password, 17 | ); 18 | 19 | Future createAccountWithEmail( 20 | BuildContext context, 21 | String email, 22 | String password, 23 | ); 24 | } 25 | 26 | mixin AnonymousSignInManager on AuthManager { 27 | Future signInAnonymously(BuildContext context); 28 | } 29 | 30 | mixin AppleSignInManager on AuthManager { 31 | Future signInWithApple(BuildContext context); 32 | } 33 | 34 | mixin GoogleSignInManager on AuthManager { 35 | Future signInWithGoogle(BuildContext context); 36 | } 37 | 38 | mixin JwtSignInManager on AuthManager { 39 | Future signInWithJwtToken( 40 | BuildContext context, 41 | String jwtToken, 42 | ); 43 | } 44 | 45 | mixin PhoneSignInManager on AuthManager { 46 | Future beginPhoneAuth({ 47 | required BuildContext context, 48 | required String phoneNumber, 49 | required void Function(BuildContext) onCodeSent, 50 | }); 51 | 52 | Future verifySmsCode({ 53 | required BuildContext context, 54 | required String smsCode, 55 | }); 56 | } 57 | 58 | mixin FacebookSignInManager on AuthManager { 59 | Future signInWithFacebook(BuildContext context); 60 | } 61 | 62 | mixin MicrosoftSignInManager on AuthManager { 63 | Future signInWithMicrosoft( 64 | BuildContext context, 65 | List scopes, 66 | String tenantId, 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /lib/auth/base_auth_user_provider.dart: -------------------------------------------------------------------------------- 1 | class AuthUserInfo { 2 | const AuthUserInfo({ 3 | this.uid, 4 | this.email, 5 | this.displayName, 6 | this.photoUrl, 7 | this.phoneNumber, 8 | }); 9 | 10 | final String? uid; 11 | final String? email; 12 | final String? displayName; 13 | final String? photoUrl; 14 | final String? phoneNumber; 15 | } 16 | 17 | abstract class BaseAuthUser { 18 | bool get loggedIn; 19 | bool get emailVerified; 20 | 21 | AuthUserInfo get authUserInfo; 22 | 23 | Future? delete(); 24 | Future? sendEmailVerification(); 25 | 26 | String? get uid => authUserInfo.uid; 27 | String? get email => authUserInfo.email; 28 | String? get displayName => authUserInfo.displayName; 29 | String? get photoUrl => authUserInfo.photoUrl; 30 | String? get phoneNumber => authUserInfo.phoneNumber; 31 | } 32 | 33 | BaseAuthUser? currentUser; 34 | bool get loggedIn => currentUser?.loggedIn ?? false; 35 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/anonymous_auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | 3 | Future anonymousSignInFunc() => 4 | FirebaseAuth.instance.signInAnonymously(); 5 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/apple_auth.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | 4 | import 'package:crypto/crypto.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | import 'package:sign_in_with_apple/sign_in_with_apple.dart'; 8 | 9 | /// Generates a cryptographically secure random nonce, to be included in a 10 | /// credential request. 11 | String generateNonce([int length = 32]) { 12 | final charset = 13 | '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; 14 | final random = Random.secure(); 15 | return List.generate(length, (_) => charset[random.nextInt(charset.length)]) 16 | .join(); 17 | } 18 | 19 | /// Returns the sha256 hash of [input] in hex notation. 20 | String sha256ofString(String input) { 21 | final bytes = utf8.encode(input); 22 | final digest = sha256.convert(bytes); 23 | return digest.toString(); 24 | } 25 | 26 | Future appleSignIn() async { 27 | if (kIsWeb) { 28 | final provider = OAuthProvider("apple.com") 29 | ..addScope('email') 30 | ..addScope('name'); 31 | 32 | // Sign in the user with Firebase. 33 | return await FirebaseAuth.instance.signInWithPopup(provider); 34 | } 35 | // To prevent replay attacks with the credential returned from Apple, we 36 | // include a nonce in the credential request. When signing in in with 37 | // Firebase, the nonce in the id token returned by Apple, is expected to 38 | // match the sha256 hash of `rawNonce`. 39 | final rawNonce = generateNonce(); 40 | final nonce = sha256ofString(rawNonce); 41 | 42 | // Request credential for the currently signed in Apple account. 43 | final appleCredential = await SignInWithApple.getAppleIDCredential( 44 | scopes: [ 45 | AppleIDAuthorizationScopes.email, 46 | AppleIDAuthorizationScopes.fullName, 47 | ], 48 | nonce: nonce, 49 | ); 50 | 51 | // Create an `OAuthCredential` from the credential returned by Apple. 52 | final oauthCredential = OAuthProvider("apple.com").credential( 53 | idToken: appleCredential.identityToken, 54 | rawNonce: rawNonce, 55 | ); 56 | 57 | // Sign in the user with Firebase. If the nonce we generated earlier does 58 | // not match the nonce in `appleCredential.identityToken`, sign in will fail. 59 | return await FirebaseAuth.instance.signInWithCredential(oauthCredential); 60 | } 61 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/auth_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart' show kIsWeb; 4 | import 'package:firebase_auth/firebase_auth.dart'; 5 | import 'package:flutter/material.dart'; 6 | import '../auth_manager.dart'; 7 | import '../base_auth_user_provider.dart'; 8 | import '../../flutter_flow/flutter_flow_util.dart'; 9 | 10 | import '/backend/backend.dart'; 11 | import 'package:cloud_firestore/cloud_firestore.dart'; 12 | import 'package:stream_transform/stream_transform.dart'; 13 | import 'firebase_auth_manager.dart'; 14 | 15 | export 'firebase_auth_manager.dart'; 16 | 17 | final _authManager = FirebaseAuthManager(); 18 | FirebaseAuthManager get authManager => _authManager; 19 | 20 | String get currentUserEmail => 21 | currentUserDocument?.email ?? currentUser?.email ?? ''; 22 | 23 | String get currentUserUid => currentUser?.uid ?? ''; 24 | 25 | String get currentUserDisplayName => 26 | currentUserDocument?.displayName ?? currentUser?.displayName ?? ''; 27 | 28 | String get currentUserPhoto => 29 | currentUserDocument?.photoUrl ?? currentUser?.photoUrl ?? ''; 30 | 31 | String get currentPhoneNumber => 32 | currentUserDocument?.phoneNumber ?? currentUser?.phoneNumber ?? ''; 33 | 34 | String get currentJwtToken => _currentJwtToken ?? ''; 35 | 36 | bool get currentUserEmailVerified => currentUser?.emailVerified ?? false; 37 | 38 | /// Create a Stream that listens to the current user's JWT Token, since Firebase 39 | /// generates a new token every hour. 40 | String? _currentJwtToken; 41 | final jwtTokenStream = FirebaseAuth.instance 42 | .idTokenChanges() 43 | .map((user) async => _currentJwtToken = await user?.getIdToken()) 44 | .asBroadcastStream(); 45 | 46 | DocumentReference? get currentUserReference => 47 | loggedIn ? UsersRecord.collection.doc(currentUser!.uid) : null; 48 | 49 | UsersRecord? currentUserDocument; 50 | final authenticatedUserStream = FirebaseAuth.instance 51 | .authStateChanges() 52 | .map((user) => user?.uid ?? '') 53 | .switchMap( 54 | (uid) => uid.isEmpty 55 | ? Stream.value(null) 56 | : UsersRecord.getDocument(UsersRecord.collection.doc(uid)) 57 | .handleError((_) {}), 58 | ) 59 | .map((user) => currentUserDocument = user) 60 | .asBroadcastStream(); 61 | 62 | class AuthUserStreamWidget extends StatelessWidget { 63 | const AuthUserStreamWidget({Key? key, required this.builder}) 64 | : super(key: key); 65 | 66 | final WidgetBuilder builder; 67 | 68 | @override 69 | Widget build(BuildContext context) => StreamBuilder( 70 | stream: authenticatedUserStream, 71 | builder: (context, _) => builder(context), 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/email_auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | 3 | Future emailSignInFunc( 4 | String email, 5 | String password, 6 | ) => 7 | FirebaseAuth.instance 8 | .signInWithEmailAndPassword(email: email.trim(), password: password); 9 | 10 | Future emailCreateAccountFunc( 11 | String email, 12 | String password, 13 | ) => 14 | FirebaseAuth.instance.createUserWithEmailAndPassword( 15 | email: email.trim(), 16 | password: password, 17 | ); 18 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/firebase_user_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:rxdart/rxdart.dart'; 3 | 4 | import '../base_auth_user_provider.dart'; 5 | 6 | export '../base_auth_user_provider.dart'; 7 | 8 | class CodewordsFirebaseUser extends BaseAuthUser { 9 | CodewordsFirebaseUser(this.user); 10 | User? user; 11 | bool get loggedIn => user != null; 12 | 13 | @override 14 | AuthUserInfo get authUserInfo => AuthUserInfo( 15 | uid: user?.uid, 16 | email: user?.email, 17 | displayName: user?.displayName, 18 | photoUrl: user?.photoURL, 19 | phoneNumber: user?.phoneNumber, 20 | ); 21 | 22 | @override 23 | Future? delete() => user?.delete(); 24 | 25 | @override 26 | Future? sendEmailVerification() => user?.sendEmailVerification(); 27 | 28 | @override 29 | bool get emailVerified { 30 | // Reloads the user when checking in order to get the most up to date 31 | // email verified status. 32 | if (loggedIn && !user!.emailVerified) { 33 | FirebaseAuth.instance.currentUser 34 | ?.reload() 35 | .then((_) => user = FirebaseAuth.instance.currentUser); 36 | } 37 | return user?.emailVerified ?? false; 38 | } 39 | 40 | static BaseAuthUser fromUserCredential(UserCredential userCredential) => 41 | fromFirebaseUser(userCredential.user); 42 | static BaseAuthUser fromFirebaseUser(User? user) => 43 | CodewordsFirebaseUser(user); 44 | } 45 | 46 | Stream codewordsFirebaseUserStream() => FirebaseAuth.instance 47 | .authStateChanges() 48 | .debounce((user) => user == null && !loggedIn 49 | ? TimerStream(true, const Duration(seconds: 1)) 50 | : Stream.value(user)) 51 | .map( 52 | (user) { 53 | currentUser = CodewordsFirebaseUser(user); 54 | return currentUser!; 55 | }, 56 | ); 57 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/google_auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:google_sign_in/google_sign_in.dart'; 4 | 5 | final _googleSignIn = GoogleSignIn(); 6 | 7 | Future googleSignInFunc() async { 8 | if (kIsWeb) { 9 | // Once signed in, return the UserCredential 10 | return await FirebaseAuth.instance.signInWithPopup(GoogleAuthProvider()); 11 | } 12 | 13 | await signOutWithGoogle().catchError((_) => null); 14 | final auth = await (await _googleSignIn.signIn())?.authentication; 15 | if (auth == null) { 16 | return null; 17 | } 18 | final credential = GoogleAuthProvider.credential( 19 | idToken: auth.idToken, accessToken: auth.accessToken); 20 | return FirebaseAuth.instance.signInWithCredential(credential); 21 | } 22 | 23 | Future signOutWithGoogle() => _googleSignIn.signOut(); 24 | -------------------------------------------------------------------------------- /lib/auth/firebase_auth/jwt_token_auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | 3 | Future jwtTokenSignIn(String jwtToken) => 4 | FirebaseAuth.instance.signInWithCustomToken(jwtToken); 5 | -------------------------------------------------------------------------------- /lib/backend/api_requests/api_calls.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import '../../flutter_flow/flutter_flow_util.dart'; 5 | import '../cloud_functions/cloud_functions.dart'; 6 | 7 | import 'api_manager.dart'; 8 | 9 | export 'api_manager.dart' show ApiCallResponse; 10 | 11 | const _kPrivateApiFunctionName = 'ffPrivateApiCall'; 12 | 13 | /// Start AI Spymaster Group Code 14 | 15 | class AISpymasterGroup { 16 | static GetClueCall getClueCall = GetClueCall(); 17 | } 18 | 19 | class GetClueCall { 20 | Future call({ 21 | String? apiKey = '', 22 | String? systemPrompt = '', 23 | String? userPrompt = '', 24 | String? modelName = '', 25 | }) async { 26 | final response = await makeCloudCall( 27 | _kPrivateApiFunctionName, 28 | { 29 | 'callName': 'GetClueCall', 30 | 'variables': { 31 | 'apiKey': apiKey, 32 | 'systemPrompt': systemPrompt, 33 | 'userPrompt': userPrompt, 34 | 'modelName': modelName, 35 | }, 36 | }, 37 | ); 38 | return ApiCallResponse.fromCloudCallResponse(response); 39 | } 40 | 41 | dynamic rawClue(dynamic response) => getJsonField( 42 | response, 43 | r'''$.choices[0].message.content''', 44 | ); 45 | } 46 | 47 | /// End AI Spymaster Group Code 48 | 49 | class ApiPagingParams { 50 | int nextPageNumber = 0; 51 | int numItems = 0; 52 | dynamic lastResponse; 53 | 54 | ApiPagingParams({ 55 | required this.nextPageNumber, 56 | required this.numItems, 57 | required this.lastResponse, 58 | }); 59 | 60 | @override 61 | String toString() => 62 | 'PagingParams(nextPageNumber: $nextPageNumber, numItems: $numItems, lastResponse: $lastResponse,)'; 63 | } 64 | 65 | String _serializeList(List? list) { 66 | list ??= []; 67 | try { 68 | return json.encode(list); 69 | } catch (_) { 70 | return '[]'; 71 | } 72 | } 73 | 74 | String _serializeJson(dynamic jsonVar) { 75 | jsonVar ??= {}; 76 | try { 77 | return json.encode(jsonVar); 78 | } catch (_) { 79 | return '{}'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/backend/cloud_functions/cloud_functions.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_functions/cloud_functions.dart'; 2 | 3 | Future> makeCloudCall( 4 | String callName, 5 | Map input, 6 | ) async { 7 | try { 8 | final response = await FirebaseFunctions.instance 9 | .httpsCallable(callName, options: HttpsCallableOptions()) 10 | .call(input); 11 | return response.data is Map 12 | ? Map.from(response.data as Map) 13 | : {}; 14 | } on FirebaseFunctionsException catch (e) { 15 | if (e is FirebaseFunctionsException) { 16 | print( 17 | 'Cloud call error!\n' 18 | 'Code: ${e.code}\n' 19 | 'Details: ${e.details}\n' 20 | 'Message: ${e.message}', 21 | ); 22 | } else { 23 | print('Cloud call error: $e'); 24 | } 25 | return {}; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/backend/firebase/firebase_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | Future initFirebase() async { 5 | if (kIsWeb) { 6 | await Firebase.initializeApp( 7 | options: FirebaseOptions( 8 | apiKey: "AIzaSyDf8PKUHZ0-c84WoFzAn-Qn7Eu6KshWH8E", 9 | authDomain: "codewords-82f6e.firebaseapp.com", 10 | projectId: "codewords-82f6e", 11 | storageBucket: "codewords-82f6e.appspot.com", 12 | messagingSenderId: "82596644495", 13 | appId: "1:82596644495:web:0e1ab5462831bbfc6f92fa")); 14 | } else { 15 | await Firebase.initializeApp(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/backend/firebase_analytics/analytics.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:firebase_analytics/firebase_analytics.dart'; 4 | import '../../auth/firebase_auth/auth_util.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | 7 | const kMaxEventNameLength = 40; 8 | const kMaxParameterLength = 100; 9 | 10 | void logFirebaseEvent(String eventName, {Map? parameters}) { 11 | // https://firebase.google.com/docs/reference/cpp/group/event-names 12 | assert(eventName.length <= kMaxEventNameLength); 13 | 14 | parameters ??= {}; 15 | parameters.putIfAbsent( 16 | 'user', () => currentUserUid.isEmpty ? currentUserUid : 'unset'); 17 | parameters.removeWhere((k, v) => k == null || v == null); 18 | final params = parameters.map((k, v) => MapEntry(k!, v)); 19 | 20 | // FB Analytics allows num values but others need to be converted to strings 21 | // and cannot be more than 100 characters. 22 | for (final entry in params.entries) { 23 | if (entry.value is! num) { 24 | var valStr = entry.value.toString(); 25 | if (valStr.length > kMaxParameterLength) { 26 | valStr = valStr.substring(0, min(valStr.length, kMaxParameterLength)); 27 | } 28 | params[entry.key] = valStr; 29 | } 30 | } 31 | 32 | FirebaseAnalytics.instance.logEvent(name: eventName, parameters: params); 33 | } 34 | 35 | void logFirebaseAuthEvent(User? user, String method) { 36 | final isSignup = user!.metadata.creationTime == user.metadata.lastSignInTime; 37 | final authEvent = isSignup ? 'sign_up' : 'login'; 38 | logFirebaseEvent(authEvent, parameters: {'method': method}); 39 | } 40 | -------------------------------------------------------------------------------- /lib/backend/schema/firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [] 3 | } -------------------------------------------------------------------------------- /lib/backend/schema/firestore.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | service cloud.firestore { 3 | match /databases/{database}/documents { 4 | match /room/{document} { 5 | allow create: if request.auth != null; 6 | allow read: if request.auth != null; 7 | allow write: if request.auth != null; 8 | allow delete: if request.auth != null; 9 | } 10 | 11 | match /room/{parent}/players/{document} { 12 | allow create: if request.auth != null; 13 | allow read: if request.auth != null; 14 | allow write: if request.auth != null; 15 | allow delete: if request.auth != null; 16 | } 17 | 18 | match /{path=**}/players/{document} { 19 | allow read: if request.auth != null; 20 | } 21 | 22 | 23 | match /users/{document} { 24 | allow create: if request.auth.uid == document; 25 | allow read: if true; 26 | allow write: if request.auth.uid == document; 27 | allow delete: if false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/backend/schema/index.dart: -------------------------------------------------------------------------------- 1 | export 'package:cloud_firestore/cloud_firestore.dart'; 2 | export 'package:flutter/material.dart' show Color, Colors; 3 | export '/flutter_flow/lat_lng.dart'; 4 | 5 | export 'structs/index.dart'; 6 | -------------------------------------------------------------------------------- /lib/backend/schema/players_record.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import '/backend/schema/util/firestore_util.dart'; 4 | import '/backend/schema/util/schema_util.dart'; 5 | 6 | import 'index.dart'; 7 | import '/flutter_flow/flutter_flow_util.dart'; 8 | 9 | class PlayersRecord extends FirestoreRecord { 10 | PlayersRecord._( 11 | DocumentReference reference, 12 | Map data, 13 | ) : super(reference, data) { 14 | _initializeFields(); 15 | } 16 | 17 | // "name" field. 18 | String? _name; 19 | String get name => _name ?? ''; 20 | bool hasName() => _name != null; 21 | 22 | // "is_team_selected" field. 23 | bool? _isTeamSelected; 24 | bool get isTeamSelected => _isTeamSelected ?? false; 25 | bool hasIsTeamSelected() => _isTeamSelected != null; 26 | 27 | // "is_blue" field. 28 | bool? _isBlue; 29 | bool get isBlue => _isBlue ?? false; 30 | bool hasIsBlue() => _isBlue != null; 31 | 32 | // "is_spymaster" field. 33 | bool? _isSpymaster; 34 | bool get isSpymaster => _isSpymaster ?? false; 35 | bool hasIsSpymaster() => _isSpymaster != null; 36 | 37 | // "uid" field. 38 | String? _uid; 39 | String get uid => _uid ?? ''; 40 | bool hasUid() => _uid != null; 41 | 42 | DocumentReference get parentReference => reference.parent.parent!; 43 | 44 | void _initializeFields() { 45 | _name = snapshotData['name'] as String?; 46 | _isTeamSelected = snapshotData['is_team_selected'] as bool?; 47 | _isBlue = snapshotData['is_blue'] as bool?; 48 | _isSpymaster = snapshotData['is_spymaster'] as bool?; 49 | _uid = snapshotData['uid'] as String?; 50 | } 51 | 52 | static Query> collection([DocumentReference? parent]) => 53 | parent != null 54 | ? parent.collection('players') 55 | : FirebaseFirestore.instance.collectionGroup('players'); 56 | 57 | static DocumentReference createDoc(DocumentReference parent) => 58 | parent.collection('players').doc(); 59 | 60 | static Stream getDocument(DocumentReference ref) => 61 | ref.snapshots().map((s) => PlayersRecord.fromSnapshot(s)); 62 | 63 | static Future getDocumentOnce(DocumentReference ref) => 64 | ref.get().then((s) => PlayersRecord.fromSnapshot(s)); 65 | 66 | static PlayersRecord fromSnapshot(DocumentSnapshot snapshot) => 67 | PlayersRecord._( 68 | snapshot.reference, 69 | mapFromFirestore(snapshot.data() as Map), 70 | ); 71 | 72 | static PlayersRecord getDocumentFromData( 73 | Map data, 74 | DocumentReference reference, 75 | ) => 76 | PlayersRecord._(reference, mapFromFirestore(data)); 77 | 78 | @override 79 | String toString() => 80 | 'PlayersRecord(reference: ${reference.path}, data: $snapshotData)'; 81 | } 82 | 83 | Map createPlayersRecordData({ 84 | String? name, 85 | bool? isTeamSelected, 86 | bool? isBlue, 87 | bool? isSpymaster, 88 | String? uid, 89 | }) { 90 | final firestoreData = mapToFirestore( 91 | { 92 | 'name': name, 93 | 'is_team_selected': isTeamSelected, 94 | 'is_blue': isBlue, 95 | 'is_spymaster': isSpymaster, 96 | 'uid': uid, 97 | }.withoutNulls, 98 | ); 99 | 100 | return firestoreData; 101 | } 102 | -------------------------------------------------------------------------------- /lib/backend/schema/room_record.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import '/backend/schema/util/firestore_util.dart'; 4 | import '/backend/schema/util/schema_util.dart'; 5 | 6 | import 'index.dart'; 7 | import '/flutter_flow/flutter_flow_util.dart'; 8 | 9 | class RoomRecord extends FirestoreRecord { 10 | RoomRecord._( 11 | DocumentReference reference, 12 | Map data, 13 | ) : super(reference, data) { 14 | _initializeFields(); 15 | } 16 | 17 | // "code" field. 18 | int? _code; 19 | int get code => _code ?? 0; 20 | bool hasCode() => _code != null; 21 | 22 | // "host" field. 23 | String? _host; 24 | String get host => _host ?? ''; 25 | bool hasHost() => _host != null; 26 | 27 | // "words" field. 28 | List? _words; 29 | List get words => _words ?? const []; 30 | bool hasWords() => _words != null; 31 | 32 | // "is_started" field. 33 | bool? _isStarted; 34 | bool get isStarted => _isStarted ?? false; 35 | bool hasIsStarted() => _isStarted != null; 36 | 37 | // "is_red_guessing" field. 38 | bool? _isRedGuessing; 39 | bool get isRedGuessing => _isRedGuessing ?? false; 40 | bool hasIsRedGuessing() => _isRedGuessing != null; 41 | 42 | // "is_blue_guessing" field. 43 | bool? _isBlueGuessing; 44 | bool get isBlueGuessing => _isBlueGuessing ?? false; 45 | bool hasIsBlueGuessing() => _isBlueGuessing != null; 46 | 47 | // "redWordsLeft" field. 48 | int? _redWordsLeft; 49 | int get redWordsLeft => _redWordsLeft ?? 0; 50 | bool hasRedWordsLeft() => _redWordsLeft != null; 51 | 52 | // "blueWordsLeft" field. 53 | int? _blueWordsLeft; 54 | int get blueWordsLeft => _blueWordsLeft ?? 0; 55 | bool hasBlueWordsLeft() => _blueWordsLeft != null; 56 | 57 | // "is_red_winner" field. 58 | bool? _isRedWinner; 59 | bool get isRedWinner => _isRedWinner ?? false; 60 | bool hasIsRedWinner() => _isRedWinner != null; 61 | 62 | // "is_blue_winner" field. 63 | bool? _isBlueWinner; 64 | bool get isBlueWinner => _isBlueWinner ?? false; 65 | bool hasIsBlueWinner() => _isBlueWinner != null; 66 | 67 | // "is_ai_spymaster" field. 68 | bool? _isAiSpymaster; 69 | bool get isAiSpymaster => _isAiSpymaster ?? false; 70 | bool hasIsAiSpymaster() => _isAiSpymaster != null; 71 | 72 | // "created_at" field. 73 | DateTime? _createdAt; 74 | DateTime? get createdAt => _createdAt; 75 | bool hasCreatedAt() => _createdAt != null; 76 | 77 | // "current_turn" field. 78 | int? _currentTurn; 79 | int get currentTurn => _currentTurn ?? 0; 80 | bool hasCurrentTurn() => _currentTurn != null; 81 | 82 | // "clues" field. 83 | List? _clues; 84 | List get clues => _clues ?? const []; 85 | bool hasClues() => _clues != null; 86 | 87 | void _initializeFields() { 88 | _code = snapshotData['code'] as int?; 89 | _host = snapshotData['host'] as String?; 90 | _words = getDataList(snapshotData['words']); 91 | _isStarted = snapshotData['is_started'] as bool?; 92 | _isRedGuessing = snapshotData['is_red_guessing'] as bool?; 93 | _isBlueGuessing = snapshotData['is_blue_guessing'] as bool?; 94 | _redWordsLeft = snapshotData['redWordsLeft'] as int?; 95 | _blueWordsLeft = snapshotData['blueWordsLeft'] as int?; 96 | _isRedWinner = snapshotData['is_red_winner'] as bool?; 97 | _isBlueWinner = snapshotData['is_blue_winner'] as bool?; 98 | _isAiSpymaster = snapshotData['is_ai_spymaster'] as bool?; 99 | _createdAt = snapshotData['created_at'] as DateTime?; 100 | _currentTurn = snapshotData['current_turn'] as int?; 101 | _clues = getStructList( 102 | snapshotData['clues'], 103 | ClueDataStruct.fromMap, 104 | ); 105 | } 106 | 107 | static CollectionReference get collection => 108 | FirebaseFirestore.instance.collection('room'); 109 | 110 | static Stream getDocument(DocumentReference ref) => 111 | ref.snapshots().map((s) => RoomRecord.fromSnapshot(s)); 112 | 113 | static Future getDocumentOnce(DocumentReference ref) => 114 | ref.get().then((s) => RoomRecord.fromSnapshot(s)); 115 | 116 | static RoomRecord fromSnapshot(DocumentSnapshot snapshot) => RoomRecord._( 117 | snapshot.reference, 118 | mapFromFirestore(snapshot.data() as Map), 119 | ); 120 | 121 | static RoomRecord getDocumentFromData( 122 | Map data, 123 | DocumentReference reference, 124 | ) => 125 | RoomRecord._(reference, mapFromFirestore(data)); 126 | 127 | @override 128 | String toString() => 129 | 'RoomRecord(reference: ${reference.path}, data: $snapshotData)'; 130 | } 131 | 132 | Map createRoomRecordData({ 133 | int? code, 134 | String? host, 135 | bool? isStarted, 136 | bool? isRedGuessing, 137 | bool? isBlueGuessing, 138 | int? redWordsLeft, 139 | int? blueWordsLeft, 140 | bool? isRedWinner, 141 | bool? isBlueWinner, 142 | bool? isAiSpymaster, 143 | DateTime? createdAt, 144 | int? currentTurn, 145 | }) { 146 | final firestoreData = mapToFirestore( 147 | { 148 | 'code': code, 149 | 'host': host, 150 | 'is_started': isStarted, 151 | 'is_red_guessing': isRedGuessing, 152 | 'is_blue_guessing': isBlueGuessing, 153 | 'redWordsLeft': redWordsLeft, 154 | 'blueWordsLeft': blueWordsLeft, 155 | 'is_red_winner': isRedWinner, 156 | 'is_blue_winner': isBlueWinner, 157 | 'is_ai_spymaster': isAiSpymaster, 158 | 'created_at': createdAt, 159 | 'current_turn': currentTurn, 160 | }.withoutNulls, 161 | ); 162 | 163 | return firestoreData; 164 | } 165 | -------------------------------------------------------------------------------- /lib/backend/schema/structs/clue_data_struct.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: unnecessary_getters_setters 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | 4 | import '/backend/schema/util/firestore_util.dart'; 5 | import '/backend/schema/util/schema_util.dart'; 6 | 7 | import 'index.dart'; 8 | import '/flutter_flow/flutter_flow_util.dart'; 9 | 10 | class ClueDataStruct extends FFFirebaseStruct { 11 | ClueDataStruct({ 12 | String? clue, 13 | int? turn, 14 | bool? isForBlue, 15 | FirestoreUtilData firestoreUtilData = const FirestoreUtilData(), 16 | }) : _clue = clue, 17 | _turn = turn, 18 | _isForBlue = isForBlue, 19 | super(firestoreUtilData); 20 | 21 | // "clue" field. 22 | String? _clue; 23 | String get clue => _clue ?? ''; 24 | set clue(String? val) => _clue = val; 25 | bool hasClue() => _clue != null; 26 | 27 | // "turn" field. 28 | int? _turn; 29 | int get turn => _turn ?? 0; 30 | set turn(int? val) => _turn = val; 31 | void incrementTurn(int amount) => _turn = turn + amount; 32 | bool hasTurn() => _turn != null; 33 | 34 | // "is_for_blue" field. 35 | bool? _isForBlue; 36 | bool get isForBlue => _isForBlue ?? false; 37 | set isForBlue(bool? val) => _isForBlue = val; 38 | bool hasIsForBlue() => _isForBlue != null; 39 | 40 | static ClueDataStruct fromMap(Map data) => ClueDataStruct( 41 | clue: data['clue'] as String?, 42 | turn: data['turn'] as int?, 43 | isForBlue: data['is_for_blue'] as bool?, 44 | ); 45 | 46 | static ClueDataStruct? maybeFromMap(dynamic data) => 47 | data is Map ? ClueDataStruct.fromMap(data) : null; 48 | 49 | Map toMap() => { 50 | 'clue': _clue, 51 | 'turn': _turn, 52 | 'is_for_blue': _isForBlue, 53 | }.withoutNulls; 54 | 55 | @override 56 | Map toSerializableMap() => { 57 | 'clue': serializeParam( 58 | _clue, 59 | ParamType.String, 60 | ), 61 | 'turn': serializeParam( 62 | _turn, 63 | ParamType.int, 64 | ), 65 | 'is_for_blue': serializeParam( 66 | _isForBlue, 67 | ParamType.bool, 68 | ), 69 | }.withoutNulls; 70 | 71 | static ClueDataStruct fromSerializableMap(Map data) => 72 | ClueDataStruct( 73 | clue: deserializeParam( 74 | data['clue'], 75 | ParamType.String, 76 | false, 77 | ), 78 | turn: deserializeParam( 79 | data['turn'], 80 | ParamType.int, 81 | false, 82 | ), 83 | isForBlue: deserializeParam( 84 | data['is_for_blue'], 85 | ParamType.bool, 86 | false, 87 | ), 88 | ); 89 | 90 | @override 91 | String toString() => 'ClueDataStruct(${toMap()})'; 92 | } 93 | 94 | ClueDataStruct createClueDataStruct({ 95 | String? clue, 96 | int? turn, 97 | bool? isForBlue, 98 | Map fieldValues = const {}, 99 | bool clearUnsetFields = true, 100 | bool create = false, 101 | bool delete = false, 102 | }) => 103 | ClueDataStruct( 104 | clue: clue, 105 | turn: turn, 106 | isForBlue: isForBlue, 107 | firestoreUtilData: FirestoreUtilData( 108 | clearUnsetFields: clearUnsetFields, 109 | create: create, 110 | delete: delete, 111 | fieldValues: fieldValues, 112 | ), 113 | ); 114 | 115 | ClueDataStruct? updateClueDataStruct( 116 | ClueDataStruct? clueData, { 117 | bool clearUnsetFields = true, 118 | }) => 119 | clueData 120 | ?..firestoreUtilData = 121 | FirestoreUtilData(clearUnsetFields: clearUnsetFields); 122 | 123 | void addClueDataStructData( 124 | Map firestoreData, 125 | ClueDataStruct? clueData, 126 | String fieldName, [ 127 | bool forFieldValue = false, 128 | ]) { 129 | firestoreData.remove(fieldName); 130 | if (clueData == null) { 131 | return; 132 | } 133 | if (clueData.firestoreUtilData.delete) { 134 | firestoreData[fieldName] = FieldValue.delete(); 135 | return; 136 | } 137 | if (!forFieldValue && clueData.firestoreUtilData.clearUnsetFields) { 138 | firestoreData[fieldName] = {}; 139 | } 140 | final clueDataData = getClueDataFirestoreData(clueData, forFieldValue); 141 | final nestedData = clueDataData.map((k, v) => MapEntry('$fieldName.$k', v)); 142 | 143 | final create = clueData.firestoreUtilData.create; 144 | firestoreData.addAll(create ? mergeNestedFields(nestedData) : nestedData); 145 | } 146 | 147 | Map getClueDataFirestoreData( 148 | ClueDataStruct? clueData, [ 149 | bool forFieldValue = false, 150 | ]) { 151 | if (clueData == null) { 152 | return {}; 153 | } 154 | final firestoreData = mapToFirestore(clueData.toMap()); 155 | 156 | // Add any Firestore field values 157 | clueData.firestoreUtilData.fieldValues 158 | .forEach((k, v) => firestoreData[k] = v); 159 | 160 | return forFieldValue ? mergeNestedFields(firestoreData) : firestoreData; 161 | } 162 | 163 | List> getClueDataListFirestoreData( 164 | List? clueDatas, 165 | ) => 166 | clueDatas?.map((e) => getClueDataFirestoreData(e, true)).toList() ?? []; 167 | -------------------------------------------------------------------------------- /lib/backend/schema/structs/index.dart: -------------------------------------------------------------------------------- 1 | export '/backend/schema/util/schema_util.dart'; 2 | 3 | export 'clue_data_struct.dart'; 4 | -------------------------------------------------------------------------------- /lib/backend/schema/users_record.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import '/backend/schema/util/firestore_util.dart'; 4 | import '/backend/schema/util/schema_util.dart'; 5 | 6 | import 'index.dart'; 7 | import '/flutter_flow/flutter_flow_util.dart'; 8 | 9 | class UsersRecord extends FirestoreRecord { 10 | UsersRecord._( 11 | DocumentReference reference, 12 | Map data, 13 | ) : super(reference, data) { 14 | _initializeFields(); 15 | } 16 | 17 | // "email" field. 18 | String? _email; 19 | String get email => _email ?? ''; 20 | bool hasEmail() => _email != null; 21 | 22 | // "display_name" field. 23 | String? _displayName; 24 | String get displayName => _displayName ?? ''; 25 | bool hasDisplayName() => _displayName != null; 26 | 27 | // "photo_url" field. 28 | String? _photoUrl; 29 | String get photoUrl => _photoUrl ?? ''; 30 | bool hasPhotoUrl() => _photoUrl != null; 31 | 32 | // "uid" field. 33 | String? _uid; 34 | String get uid => _uid ?? ''; 35 | bool hasUid() => _uid != null; 36 | 37 | // "created_time" field. 38 | DateTime? _createdTime; 39 | DateTime? get createdTime => _createdTime; 40 | bool hasCreatedTime() => _createdTime != null; 41 | 42 | // "phone_number" field. 43 | String? _phoneNumber; 44 | String get phoneNumber => _phoneNumber ?? ''; 45 | bool hasPhoneNumber() => _phoneNumber != null; 46 | 47 | void _initializeFields() { 48 | _email = snapshotData['email'] as String?; 49 | _displayName = snapshotData['display_name'] as String?; 50 | _photoUrl = snapshotData['photo_url'] as String?; 51 | _uid = snapshotData['uid'] as String?; 52 | _createdTime = snapshotData['created_time'] as DateTime?; 53 | _phoneNumber = snapshotData['phone_number'] as String?; 54 | } 55 | 56 | static CollectionReference get collection => 57 | FirebaseFirestore.instance.collection('users'); 58 | 59 | static Stream getDocument(DocumentReference ref) => 60 | ref.snapshots().map((s) => UsersRecord.fromSnapshot(s)); 61 | 62 | static Future getDocumentOnce(DocumentReference ref) => 63 | ref.get().then((s) => UsersRecord.fromSnapshot(s)); 64 | 65 | static UsersRecord fromSnapshot(DocumentSnapshot snapshot) => UsersRecord._( 66 | snapshot.reference, 67 | mapFromFirestore(snapshot.data() as Map), 68 | ); 69 | 70 | static UsersRecord getDocumentFromData( 71 | Map data, 72 | DocumentReference reference, 73 | ) => 74 | UsersRecord._(reference, mapFromFirestore(data)); 75 | 76 | @override 77 | String toString() => 78 | 'UsersRecord(reference: ${reference.path}, data: $snapshotData)'; 79 | } 80 | 81 | Map createUsersRecordData({ 82 | String? email, 83 | String? displayName, 84 | String? photoUrl, 85 | String? uid, 86 | DateTime? createdTime, 87 | String? phoneNumber, 88 | }) { 89 | final firestoreData = mapToFirestore( 90 | { 91 | 'email': email, 92 | 'display_name': displayName, 93 | 'photo_url': photoUrl, 94 | 'uid': uid, 95 | 'created_time': createdTime, 96 | 'phone_number': phoneNumber, 97 | }.withoutNulls, 98 | ); 99 | 100 | return firestoreData; 101 | } 102 | -------------------------------------------------------------------------------- /lib/backend/schema/util/firestore_util.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:from_css_color/from_css_color.dart'; 4 | 5 | import '/backend/schema/util/schema_util.dart'; 6 | import '/flutter_flow/flutter_flow_util.dart'; 7 | 8 | typedef RecordBuilder = T Function(DocumentSnapshot snapshot); 9 | 10 | abstract class FirestoreRecord { 11 | FirestoreRecord(this.reference, this.snapshotData); 12 | Map snapshotData; 13 | DocumentReference reference; 14 | } 15 | 16 | abstract class FFFirebaseStruct extends BaseStruct { 17 | FFFirebaseStruct(this.firestoreUtilData); 18 | 19 | /// Utility class for Firestore updates 20 | FirestoreUtilData firestoreUtilData = FirestoreUtilData(); 21 | } 22 | 23 | class FirestoreUtilData { 24 | const FirestoreUtilData({ 25 | this.fieldValues = const {}, 26 | this.clearUnsetFields = true, 27 | this.create = false, 28 | this.delete = false, 29 | }); 30 | final Map fieldValues; 31 | final bool clearUnsetFields; 32 | final bool create; 33 | final bool delete; 34 | static String get name => 'firestoreUtilData'; 35 | } 36 | 37 | Map mapFromFirestore(Map data) => 38 | mergeNestedFields(data) 39 | .where((k, _) => k != FirestoreUtilData.name) 40 | .map((key, value) { 41 | // Handle Timestamp 42 | if (value is Timestamp) { 43 | value = value.toDate(); 44 | } 45 | // Handle list of Timestamp 46 | if (value is Iterable && value.isNotEmpty && value.first is Timestamp) { 47 | value = value.map((v) => (v as Timestamp).toDate()).toList(); 48 | } 49 | // Handle GeoPoint 50 | if (value is GeoPoint) { 51 | value = value.toLatLng(); 52 | } 53 | // Handle list of GeoPoint 54 | if (value is Iterable && value.isNotEmpty && value.first is GeoPoint) { 55 | value = value.map((v) => (v as GeoPoint).toLatLng()).toList(); 56 | } 57 | // Handle nested data. 58 | if (value is Map) { 59 | value = mapFromFirestore(value as Map); 60 | } 61 | // Handle list of nested data. 62 | if (value is Iterable && value.isNotEmpty && value.first is Map) { 63 | value = value 64 | .map((v) => mapFromFirestore(v as Map)) 65 | .toList(); 66 | } 67 | return MapEntry(key, value); 68 | }); 69 | 70 | Map mapToFirestore(Map data) => 71 | data.where((k, v) => k != FirestoreUtilData.name).map((key, value) { 72 | // Handle GeoPoint 73 | if (value is LatLng) { 74 | value = value.toGeoPoint(); 75 | } 76 | // Handle list of GeoPoint 77 | if (value is Iterable && value.isNotEmpty && value.first is LatLng) { 78 | value = value.map((v) => (v as LatLng).toGeoPoint()).toList(); 79 | } 80 | // Handle Color 81 | if (value is Color) { 82 | value = value.toCssString(); 83 | } 84 | // Handle list of Color 85 | if (value is Iterable && value.isNotEmpty && value.first is Color) { 86 | value = value.map((v) => (v as Color).toCssString()).toList(); 87 | } 88 | // Handle nested data. 89 | if (value is Map) { 90 | value = mapFromFirestore(value as Map); 91 | } 92 | // Handle list of nested data. 93 | if (value is Iterable && value.isNotEmpty && value.first is Map) { 94 | value = value 95 | .map((v) => mapFromFirestore(v as Map)) 96 | .toList(); 97 | } 98 | return MapEntry(key, value); 99 | }); 100 | 101 | List? convertToGeoPointList(List? list) => 102 | list?.map((e) => e.toGeoPoint()).toList(); 103 | 104 | extension GeoPointExtension on LatLng { 105 | GeoPoint toGeoPoint() => GeoPoint(latitude, longitude); 106 | } 107 | 108 | extension LatLngExtension on GeoPoint { 109 | LatLng toLatLng() => LatLng(latitude, longitude); 110 | } 111 | 112 | DocumentReference toRef(String ref) => FirebaseFirestore.instance.doc(ref); 113 | 114 | T? safeGet(T Function() func, [Function(dynamic)? reportError]) { 115 | try { 116 | return func(); 117 | } catch (e) { 118 | reportError?.call(e); 119 | } 120 | return null; 121 | } 122 | 123 | Map mergeNestedFields(Map data) { 124 | final nestedData = data.where((k, _) => k.contains('.')); 125 | final fieldNames = nestedData.keys.map((k) => k.split('.').first).toSet(); 126 | // Remove nested values (e.g. 'foo.bar') and merge them into a map. 127 | data.removeWhere((k, _) => k.contains('.')); 128 | fieldNames.forEach((name) { 129 | final mergedValues = mergeNestedFields( 130 | nestedData 131 | .where((k, _) => k.split('.').first == name) 132 | .map((k, v) => MapEntry(k.split('.').skip(1).join('.'), v)), 133 | ); 134 | final existingValue = data[name]; 135 | data[name] = { 136 | if (existingValue != null && existingValue is Map) 137 | ...existingValue as Map, 138 | ...mergedValues, 139 | }; 140 | }); 141 | // Merge any nested maps inside any of the fields as well. 142 | data.where((_, v) => v is Map).forEach((k, v) { 143 | data[k] = mergeNestedFields(v as Map); 144 | }); 145 | 146 | return data; 147 | } 148 | 149 | extension _WhereMapExtension on Map { 150 | Map where(bool Function(K, V) test) => 151 | Map.fromEntries(entries.where((e) => test(e.key, e.value))); 152 | } 153 | -------------------------------------------------------------------------------- /lib/backend/schema/util/schema_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:from_css_color/from_css_color.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | 7 | export 'package:flutter/material.dart' show Color, Colors; 8 | export 'package:from_css_color/from_css_color.dart'; 9 | 10 | typedef StructBuilder = T Function(Map data); 11 | 12 | abstract class BaseStruct { 13 | Map toSerializableMap(); 14 | String serialize() => json.encode(toSerializableMap()); 15 | } 16 | 17 | List? getStructList( 18 | dynamic value, 19 | StructBuilder structBuilder, 20 | ) => 21 | value is! List 22 | ? null 23 | : value 24 | .where((e) => e is Map) 25 | .map((e) => structBuilder(e as Map)) 26 | .toList(); 27 | 28 | Color? getSchemaColor(dynamic value) => value is String 29 | ? fromCssColor(value) 30 | : value is Color 31 | ? value 32 | : null; 33 | 34 | List? getColorsList(dynamic value) => 35 | value is! List ? null : value.map(getSchemaColor).withoutNulls; 36 | 37 | List? getDataList(dynamic value) => 38 | value is! List ? null : value.map((e) => castToType(e)!).toList(); 39 | 40 | T? castToType(dynamic value) { 41 | if (value == null) { 42 | return null; 43 | } 44 | switch (T) { 45 | case double: 46 | return value.toDouble() as T; 47 | default: 48 | return value as T; 49 | } 50 | } 51 | 52 | extension MapDataExtensions on Map { 53 | Map get withoutNulls => Map.fromEntries( 54 | entries 55 | .where((e) => e.value != null) 56 | .map((e) => MapEntry(e.key, e.value!)), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /lib/components/game_mode_dialog/game_mode_dialog_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/flutter_flow/flutter_flow_theme.dart'; 4 | import '/flutter_flow/flutter_flow_util.dart'; 5 | import '/custom_code/widgets/index.dart' as custom_widgets; 6 | import '/flutter_flow/custom_functions.dart' as functions; 7 | import 'package:auto_size_text/auto_size_text.dart'; 8 | import 'package:cloud_firestore/cloud_firestore.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:google_fonts/google_fonts.dart'; 11 | import 'package:provider/provider.dart'; 12 | 13 | class GameModeDialogModel extends FlutterFlowModel { 14 | /// Local state fields for this component. 15 | 16 | bool isCreating = false; 17 | 18 | /// State fields for stateful widgets in this component. 19 | 20 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 21 | RoomRecord? roomDetails; 22 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 23 | PlayersRecord? playerDocument; 24 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 25 | RoomRecord? roomDetailsAI; 26 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 27 | PlayersRecord? playerDocumentUser; 28 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 29 | PlayersRecord? spymasterBlueAI; 30 | // Stores action output result for [Backend Call - Create Document] action in Container widget. 31 | PlayersRecord? spymasterRedAI; 32 | 33 | /// Initialization and disposal methods. 34 | 35 | void initState(BuildContext context) {} 36 | 37 | void dispose() {} 38 | 39 | /// Additional helper methods are added here. 40 | 41 | } 42 | -------------------------------------------------------------------------------- /lib/components/join_game/join_game_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/flutter_flow/flutter_flow_theme.dart'; 4 | import '/flutter_flow/flutter_flow_util.dart'; 5 | import '/flutter_flow/flutter_flow_widgets.dart'; 6 | import 'dart:async'; 7 | import 'package:cloud_firestore/cloud_firestore.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:google_fonts/google_fonts.dart'; 10 | import 'package:provider/provider.dart'; 11 | 12 | class JoinGameModel extends FlutterFlowModel { 13 | /// State fields for stateful widgets in this component. 14 | 15 | // State field(s) for TextField widget. 16 | TextEditingController? textController; 17 | String? Function(BuildContext, String?)? textControllerValidator; 18 | Completer>? firestoreRequestCompleter; 19 | // Stores action output result for [Backend Call - Create Document] action in Button widget. 20 | PlayersRecord? playerDocument; 21 | 22 | /// Initialization and disposal methods. 23 | 24 | void initState(BuildContext context) {} 25 | 26 | void dispose() { 27 | textController?.dispose(); 28 | } 29 | 30 | /// Additional helper methods are added here. 31 | 32 | Future waitForFirestoreRequestCompleted({ 33 | double minWait = 0, 34 | double maxWait = double.infinity, 35 | }) async { 36 | final stopwatch = Stopwatch()..start(); 37 | while (true) { 38 | await Future.delayed(Duration(milliseconds: 50)); 39 | final timeElapsed = stopwatch.elapsedMilliseconds; 40 | final requestComplete = firestoreRequestCompleter?.isCompleted ?? false; 41 | if (timeElapsed > maxWait || (requestComplete && timeElapsed > minWait)) { 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/components/loading_dialog/loading_dialog_model.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/custom_code/widgets/index.dart' as custom_widgets; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class LoadingDialogModel extends FlutterFlowModel { 9 | /// Initialization and disposal methods. 10 | 11 | void initState(BuildContext context) {} 12 | 13 | void dispose() {} 14 | 15 | /// Additional helper methods are added here. 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib/components/loading_dialog/loading_dialog_widget.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/custom_code/widgets/index.dart' as custom_widgets; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'loading_dialog_model.dart'; 8 | export 'loading_dialog_model.dart'; 9 | 10 | class LoadingDialogWidget extends StatefulWidget { 11 | const LoadingDialogWidget({Key? key}) : super(key: key); 12 | 13 | @override 14 | _LoadingDialogWidgetState createState() => _LoadingDialogWidgetState(); 15 | } 16 | 17 | class _LoadingDialogWidgetState extends State { 18 | late LoadingDialogModel _model; 19 | 20 | @override 21 | void setState(VoidCallback callback) { 22 | super.setState(callback); 23 | _model.onUpdate(); 24 | } 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _model = createModel(context, () => LoadingDialogModel()); 30 | 31 | WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); 32 | } 33 | 34 | @override 35 | void dispose() { 36 | _model.maybeDispose(); 37 | 38 | super.dispose(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | context.watch(); 44 | 45 | return Padding( 46 | padding: EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0), 47 | child: Material( 48 | color: Colors.transparent, 49 | elevation: 4.0, 50 | shape: RoundedRectangleBorder( 51 | borderRadius: BorderRadius.circular(12.0), 52 | ), 53 | child: Container( 54 | width: 600.0, 55 | height: 160.0, 56 | constraints: BoxConstraints( 57 | maxWidth: 600.0, 58 | ), 59 | decoration: BoxDecoration( 60 | color: FlutterFlowTheme.of(context).secondaryBackground, 61 | borderRadius: BorderRadius.circular(12.0), 62 | ), 63 | child: Row( 64 | mainAxisSize: MainAxisSize.min, 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | children: [ 67 | Container( 68 | width: 50.0, 69 | height: 50.0, 70 | child: custom_widgets.CircularIndicator( 71 | width: 50.0, 72 | height: 50.0, 73 | color: FlutterFlowTheme.of(context).primary, 74 | thickness: 4.0, 75 | ), 76 | ), 77 | ], 78 | ), 79 | ), 80 | ), 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/components/loading_widget/loading_widget_model.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/custom_code/widgets/index.dart' as custom_widgets; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class LoadingWidgetModel extends FlutterFlowModel { 9 | /// Initialization and disposal methods. 10 | 11 | void initState(BuildContext context) {} 12 | 13 | void dispose() {} 14 | 15 | /// Additional helper methods are added here. 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib/components/loading_widget/loading_widget_widget.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/custom_code/widgets/index.dart' as custom_widgets; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'loading_widget_model.dart'; 8 | export 'loading_widget_model.dart'; 9 | 10 | class LoadingWidgetWidget extends StatefulWidget { 11 | const LoadingWidgetWidget({Key? key}) : super(key: key); 12 | 13 | @override 14 | _LoadingWidgetWidgetState createState() => _LoadingWidgetWidgetState(); 15 | } 16 | 17 | class _LoadingWidgetWidgetState extends State { 18 | late LoadingWidgetModel _model; 19 | 20 | @override 21 | void setState(VoidCallback callback) { 22 | super.setState(callback); 23 | _model.onUpdate(); 24 | } 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _model = createModel(context, () => LoadingWidgetModel()); 30 | 31 | WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); 32 | } 33 | 34 | @override 35 | void dispose() { 36 | _model.maybeDispose(); 37 | 38 | super.dispose(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | context.watch(); 44 | 45 | return Container( 46 | width: 600.0, 47 | height: 160.0, 48 | constraints: BoxConstraints( 49 | maxWidth: 600.0, 50 | ), 51 | decoration: BoxDecoration( 52 | color: FlutterFlowTheme.of(context).secondaryBackground, 53 | borderRadius: BorderRadius.circular(12.0), 54 | ), 55 | child: Row( 56 | mainAxisSize: MainAxisSize.min, 57 | mainAxisAlignment: MainAxisAlignment.center, 58 | children: [ 59 | Container( 60 | width: 50.0, 61 | height: 50.0, 62 | child: custom_widgets.CircularIndicator( 63 | width: 50.0, 64 | height: 50.0, 65 | color: FlutterFlowTheme.of(context).primary, 66 | thickness: 4.0, 67 | ), 68 | ), 69 | ], 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/custom_code/actions/calculate_words_left.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | dynamic calculateWordsLeft(List rawWords) { 13 | int redWordsLeft = 0; 14 | int blueWordsLeft = 0; 15 | 16 | for (int i = 0; i < rawWords.length; i++) { 17 | final json = separateWordDetails(rawWords[i]); 18 | final color = json['color']; 19 | final isGuessed = json['is_guessed']; 20 | 21 | if (isGuessed == 'f' && color == 'r') { 22 | redWordsLeft++; 23 | } else if (isGuessed == 'f' && color == 'b') { 24 | blueWordsLeft++; 25 | } 26 | } 27 | 28 | return { 29 | 'red': redWordsLeft, 30 | 'blue': blueWordsLeft, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /lib/custom_code/actions/declare_winner.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | String declareWinner(int /*?*/ redWordsLeft, int /*?*/ blueWordsLeft) { 13 | if (redWordsLeft == 0) { 14 | return 'r'; 15 | } else if (blueWordsLeft == 0) { 16 | return 'b'; 17 | } else { 18 | return 'n'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/custom_code/actions/generate_board_words.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | List generateBoardWords(List /*?*/ totalWordList) { 13 | // generate list of 25 unique words from list 14 | // format: 15 | // word # color(b/r/n) # is_guessed(t/f) 16 | // example: 17 | // "animal#b#t" ==> animal b t 18 | // 19 | totalWordList.shuffle(); 20 | final uniqueWords = totalWordList.sublist(0, 25); 21 | final wordColors = [ 22 | 'b', 23 | 'b', 24 | 'b', 25 | 'b', 26 | 'b', 27 | 'b', 28 | 'b', 29 | 'b', 30 | 'b', 31 | 'r', 32 | 'r', 33 | 'r', 34 | 'r', 35 | 'r', 36 | 'r', 37 | 'r', 38 | 'r', 39 | 'n', 40 | 'n', 41 | 'n', 42 | 'n', 43 | 'n', 44 | 'n', 45 | 'n', 46 | 'n', 47 | ]; 48 | wordColors.shuffle(); 49 | uniqueWords.asMap().forEach((index, word) => uniqueWords[index] = 50 | uniqueWords[index] + '#' + wordColors[index] + '#' + 'f'); 51 | return uniqueWords; 52 | } 53 | -------------------------------------------------------------------------------- /lib/custom_code/actions/get_word_color.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | String getWordColor(int index, List words) { 13 | final selectedWord = words[index]; 14 | final wordColor = selectedWord.split('#')[1]; 15 | return wordColor; 16 | } 17 | -------------------------------------------------------------------------------- /lib/custom_code/actions/index.dart: -------------------------------------------------------------------------------- 1 | export 'init_words.dart' show initWords; 2 | export 'generate_board_words.dart' show generateBoardWords; 3 | export 'word_tapped.dart' show wordTapped; 4 | export 'get_word_color.dart' show getWordColor; 5 | export 'calculate_words_left.dart' show calculateWordsLeft; 6 | export 'declare_winner.dart' show declareWinner; 7 | -------------------------------------------------------------------------------- /lib/custom_code/actions/init_words.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | initWords() { 13 | FFAppState().words = [ 14 | 'Africa', 15 | 'Agent', 16 | 'Air', 17 | 'Alien', 18 | 'Alps', 19 | 'Amazon', 20 | 'Ambulance', 21 | 'America', 22 | 'Angel', 23 | 'Antarctica', 24 | 'Apple', 25 | 'Arm', 26 | 'Atlantis', 27 | 'Australia', 28 | 'Aztec', 29 | 'Back', 30 | 'Ball', 31 | 'Band', 32 | 'Bank', 33 | 'Bar', 34 | 'Bark', 35 | 'Bat', 36 | 'Battery', 37 | 'Beach', 38 | 'Bear', 39 | 'Beat', 40 | 'Bed', 41 | 'Beijing', 42 | 'Bell', 43 | 'Belt', 44 | 'Berlin', 45 | 'Bermuda', 46 | 'Berry', 47 | 'Bill', 48 | 'Block', 49 | 'Board', 50 | 'Bolt', 51 | 'Bomb', 52 | 'Bond', 53 | 'Boom', 54 | 'Boot', 55 | 'Bottle', 56 | 'Bow', 57 | 'Box', 58 | 'Bridge', 59 | 'Brush', 60 | 'Buck', 61 | 'Buffalo', 62 | 'Bug', 63 | 'Bugle', 64 | 'Button', 65 | 'Calf', 66 | 'Canada', 67 | 'Cap', 68 | 'Capital', 69 | 'Car', 70 | 'Card', 71 | 'Carrot', 72 | 'Casino', 73 | 'Cast', 74 | 'Cat', 75 | 'Cell', 76 | 'Centaur', 77 | 'Center', 78 | 'Chair', 79 | 'Change', 80 | 'Charge', 81 | 'Check', 82 | 'Chest', 83 | 'Chick', 84 | 'China', 85 | 'Chocolate', 86 | 'Church', 87 | 'Circle', 88 | 'Cliff', 89 | 'Cloak', 90 | 'Club', 91 | 'Code', 92 | 'Cold', 93 | 'Comic', 94 | 'Compound', 95 | 'Concert', 96 | 'Conductor', 97 | 'Contract', 98 | 'Cook', 99 | 'Copper', 100 | 'Cotton', 101 | 'Court', 102 | 'Cover', 103 | 'Crane', 104 | 'Crash', 105 | 'Cricket', 106 | 'Cross', 107 | 'Crown', 108 | 'Cycle', 109 | 'Czech', 110 | 'Dance', 111 | 'Date', 112 | 'Day', 113 | 'Death', 114 | 'Deck', 115 | 'Degree', 116 | 'Diamond', 117 | 'Dice', 118 | 'Dinosaur', 119 | 'Disease', 120 | 'Doctor', 121 | 'Dog', 122 | 'Draft', 123 | 'Dragon', 124 | 'Dress', 125 | 'Drill', 126 | 'Drop', 127 | 'Duck', 128 | 'Dwarf', 129 | 'Eagle', 130 | 'Egypt', 131 | 'Embassy', 132 | 'Engine', 133 | 'England', 134 | 'Europe', 135 | 'Eye', 136 | 'Face', 137 | 'Fair', 138 | 'Fall', 139 | 'Fan', 140 | 'Fence', 141 | 'Field', 142 | 'Fighter', 143 | 'Figure', 144 | 'File', 145 | 'Film', 146 | 'Fire', 147 | 'Fish', 148 | 'Flute', 149 | 'Fly', 150 | 'Foot', 151 | 'Force', 152 | 'Forest', 153 | 'Fork', 154 | 'France', 155 | 'Game', 156 | 'Gas', 157 | 'Genius', 158 | 'Germany', 159 | 'Ghost', 160 | 'Giant', 161 | 'Glass', 162 | 'Glove', 163 | 'Gold', 164 | 'Grace', 165 | 'Grass', 166 | 'Greece', 167 | 'Green', 168 | 'Ground', 169 | 'Ham', 170 | 'Hand', 171 | 'Hawk', 172 | 'Head', 173 | 'Heart', 174 | 'Helicopter', 175 | 'Himalayas', 176 | 'Hole', 177 | 'Hollywood', 178 | 'Honey', 179 | 'Hood', 180 | 'Hook', 181 | 'Horn', 182 | 'Horse', 183 | 'Horseshoe', 184 | 'Hospital', 185 | 'Hotel', 186 | 'Ice', 187 | 'Ice cream', 188 | 'India', 189 | 'Iron', 190 | 'Ivory', 191 | 'Jack', 192 | 'Jam', 193 | 'Jet', 194 | 'Jupiter', 195 | 'Kangaroo', 196 | 'Ketchup', 197 | 'Key', 198 | 'Kid', 199 | 'King', 200 | 'Kiwi', 201 | 'Knife', 202 | 'Knight', 203 | 'Lab', 204 | 'Lap', 205 | 'Laser', 206 | 'Lawyer', 207 | 'Lead', 208 | 'Lemon', 209 | 'Leprechaun', 210 | 'Life', 211 | 'Light', 212 | 'Limousine', 213 | 'Line', 214 | 'Link', 215 | 'Lion', 216 | 'Litter', 217 | 'Loch ness', 218 | 'Lock', 219 | 'Log', 220 | 'London', 221 | 'Luck', 222 | 'Mail', 223 | 'Mammoth', 224 | 'Maple', 225 | 'Marble', 226 | 'March', 227 | 'Mass', 228 | 'Match', 229 | 'Mercury', 230 | 'Mexico', 231 | 'Microscope', 232 | 'Millionaire', 233 | 'Mine', 234 | 'Mint', 235 | 'Missile', 236 | 'Model', 237 | 'Mole', 238 | 'Moon', 239 | 'Moscow', 240 | 'Mount', 241 | 'Mouse', 242 | 'Mouth', 243 | 'Mug', 244 | 'Nail', 245 | 'Needle', 246 | 'Net', 247 | 'New york', 248 | 'Night', 249 | 'Ninja', 250 | 'Note', 251 | 'Novel', 252 | 'Nurse', 253 | 'Nut', 254 | 'Octopus', 255 | 'Oil', 256 | 'Olive', 257 | 'Olympus', 258 | 'Opera', 259 | 'Orange', 260 | 'Organ', 261 | 'Palm', 262 | 'Pan', 263 | 'Pants', 264 | 'Paper', 265 | 'Parachute', 266 | 'Park', 267 | 'Part', 268 | 'Pass', 269 | 'Paste', 270 | 'Penguin', 271 | 'Phoenix', 272 | 'Piano', 273 | 'Pie', 274 | 'Pilot', 275 | 'Pin', 276 | 'Pipe', 277 | 'Pirate', 278 | 'Pistol', 279 | 'Pit', 280 | 'Pitch', 281 | 'Plane', 282 | 'Plastic', 283 | 'Plate', 284 | 'Platypus', 285 | 'Play', 286 | 'Plot', 287 | 'Point', 288 | 'Poison', 289 | 'Pole', 290 | 'Police', 291 | 'Pool', 292 | 'Port', 293 | 'Post', 294 | 'Pound', 295 | 'Press', 296 | 'Princess', 297 | 'Pumpkin', 298 | 'Pupil', 299 | 'Pyramid', 300 | 'Queen', 301 | 'Rabbit', 302 | 'Racket', 303 | 'Ray', 304 | 'Revolution', 305 | 'Ring', 306 | 'Robin', 307 | 'Robot', 308 | 'Rock', 309 | 'Rome', 310 | 'Root', 311 | 'Rose', 312 | 'Roulette', 313 | 'Round', 314 | 'Row', 315 | 'Ruler', 316 | 'Satellite', 317 | 'Saturn', 318 | 'Scale', 319 | 'School', 320 | 'Scientist', 321 | 'Scorpion', 322 | 'Screen', 323 | 'Scuba diver', 324 | 'Seal', 325 | 'Server', 326 | 'Shadow', 327 | 'Shakespeare', 328 | 'Shark', 329 | 'Ship', 330 | 'Shoe', 331 | 'Shop', 332 | 'Shot', 333 | 'Sink', 334 | 'Skyscraper', 335 | 'Slip', 336 | 'Slug', 337 | 'Smuggler', 338 | 'Snow', 339 | 'Snowman', 340 | 'Sock', 341 | 'Soldier', 342 | 'Soul', 343 | 'Sound', 344 | 'Space', 345 | 'Spell', 346 | 'Spider', 347 | 'Spike', 348 | 'Spine', 349 | 'Spot', 350 | 'Spring', 351 | 'Spy', 352 | 'Square', 353 | 'Stadium', 354 | 'Staff', 355 | 'Star', 356 | 'State', 357 | 'Stick', 358 | 'Stock', 359 | 'Straw', 360 | 'Stream', 361 | 'Strike', 362 | 'String', 363 | 'Sub', 364 | 'Suit', 365 | 'Superhero', 366 | 'Swing', 367 | 'Switch', 368 | 'Table', 369 | 'Tablet', 370 | 'Tag', 371 | 'Tail', 372 | 'Tap', 373 | 'Teacher', 374 | 'Telescope', 375 | 'Temple', 376 | 'Theater', 377 | 'Thief', 378 | 'Thumb', 379 | 'Tick', 380 | 'Tie', 381 | 'Time', 382 | 'Tokyo', 383 | 'Tooth', 384 | 'Torch', 385 | 'Tower', 386 | 'Track', 387 | 'Train', 388 | 'Triangle', 389 | 'Trip', 390 | 'Trunk', 391 | 'Tube', 392 | 'Turkey', 393 | 'Undertaker', 394 | 'Unicorn', 395 | 'Vacuum', 396 | 'Van', 397 | 'Vet', 398 | 'Wake', 399 | 'Wall', 400 | 'War', 401 | 'Washer', 402 | 'Washington', 403 | 'Watch', 404 | 'Water', 405 | 'Wave', 406 | 'Web', 407 | 'Well', 408 | 'Whale', 409 | 'Whip', 410 | 'Wind', 411 | 'Witch', 412 | 'Worm', 413 | 'Yard', 414 | ]; 415 | } 416 | -------------------------------------------------------------------------------- /lib/custom_code/actions/word_tapped.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom actions 7 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 8 | import 'package:flutter/material.dart'; 9 | // Begin custom action code 10 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 11 | 12 | List wordTapped(int index, List words) { 13 | final selectedWord = words[index]; 14 | final updatedWord = selectedWord.substring(0, selectedWord.length - 1) + 't'; 15 | words[index] = updatedWord; 16 | return words; 17 | } 18 | -------------------------------------------------------------------------------- /lib/custom_code/widgets/circular_indicator.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom widgets 7 | import '/custom_code/actions/index.dart'; // Imports custom actions 8 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 9 | import 'package:flutter/material.dart'; 10 | // Begin custom widget code 11 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 12 | 13 | class CircularIndicator extends StatefulWidget { 14 | const CircularIndicator({ 15 | Key? key, 16 | this.width, 17 | this.height, 18 | required this.color, 19 | required this.thickness, 20 | }) : super(key: key); 21 | 22 | final double? width; 23 | final double? height; 24 | final Color color; 25 | final double thickness; 26 | 27 | @override 28 | _CircularIndicatorState createState() => _CircularIndicatorState(); 29 | } 30 | 31 | class _CircularIndicatorState extends State { 32 | @override 33 | Widget build(BuildContext context) { 34 | return Container( 35 | width: widget.width, 36 | height: widget.height, 37 | child: Padding( 38 | padding: const EdgeInsets.all(2.0), 39 | child: CircularProgressIndicator( 40 | valueColor: AlwaysStoppedAnimation(widget.color), 41 | strokeWidth: widget.thickness, 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/custom_code/widgets/confetti_overlay.dart: -------------------------------------------------------------------------------- 1 | // Automatic FlutterFlow imports 2 | import '/backend/backend.dart'; 3 | import '/backend/schema/structs/index.dart'; 4 | import '/flutter_flow/flutter_flow_theme.dart'; 5 | import '/flutter_flow/flutter_flow_util.dart'; 6 | import 'index.dart'; // Imports other custom widgets 7 | import '/custom_code/actions/index.dart'; // Imports custom actions 8 | import '/flutter_flow/custom_functions.dart'; // Imports custom functions 9 | import 'package:flutter/material.dart'; 10 | // Begin custom widget code 11 | // DO NOT REMOVE OR MODIFY THE CODE ABOVE! 12 | 13 | import 'package:confetti/confetti.dart'; 14 | import 'dart:math' as math; 15 | 16 | class ConfettiOverlay extends StatefulWidget { 17 | const ConfettiOverlay({ 18 | Key? key, 19 | this.width, 20 | this.height, 21 | }) : super(key: key); 22 | 23 | final double? width; 24 | final double? height; 25 | 26 | @override 27 | _ConfettiOverlayState createState() => _ConfettiOverlayState(); 28 | } 29 | 30 | class _ConfettiOverlayState extends State { 31 | late final ConfettiController _topController; 32 | 33 | @override 34 | void initState() { 35 | super.initState(); 36 | 37 | _topController = ConfettiController(duration: const Duration(seconds: 5)); 38 | _topController.play(); 39 | } 40 | 41 | @override 42 | void dispose() { 43 | _topController.dispose(); 44 | super.dispose(); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Align( 50 | alignment: Alignment.topCenter, 51 | child: ConfettiWidget( 52 | confettiController: _topController, 53 | blastDirection: math.pi / 2, 54 | maxBlastForce: 4, 55 | minBlastForce: 1, 56 | emissionFrequency: 0.01, 57 | numberOfParticles: 20, 58 | gravity: 0.6, 59 | shouldLoop: true, 60 | colors: const [ 61 | Colors.white, 62 | Colors.yellow, 63 | ], 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/custom_code/widgets/index.dart: -------------------------------------------------------------------------------- 1 | export 'confetti_overlay.dart' show ConfettiOverlay; 2 | export 'circular_indicator.dart' show CircularIndicator; 3 | -------------------------------------------------------------------------------- /lib/flutter_flow/custom_functions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math' as math; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | import 'package:intl/intl.dart'; 7 | import 'package:timeago/timeago.dart' as timeago; 8 | import 'lat_lng.dart'; 9 | import 'place.dart'; 10 | import '/backend/backend.dart'; 11 | import 'package:cloud_firestore/cloud_firestore.dart'; 12 | import '/backend/schema/structs/index.dart'; 13 | import '/auth/firebase_auth/auth_util.dart'; 14 | 15 | int generateRoomCode() { 16 | math.Random rdm = math.Random(); 17 | int ranRoomCode = rdm.nextInt(9000) + 1000; 18 | return ranRoomCode; 19 | } 20 | 21 | dynamic separateWordDetails(String combinedWord) { 22 | final parts = combinedWord.split('#'); 23 | 24 | final word = parts[0]; 25 | final color = parts[1]; 26 | final isGuessed = parts[2]; 27 | 28 | final json = { 29 | 'word': word, 30 | 'color': color, 31 | 'is_guessed': isGuessed, 32 | }; 33 | 34 | return json; 35 | } 36 | 37 | bool isBlueVisible( 38 | String color, 39 | String isGuessed, 40 | ) { 41 | if (color == 'b' && isGuessed == 't') { 42 | return true; 43 | } else { 44 | return false; 45 | } 46 | } 47 | 48 | bool isBlueVisibleSpy(String color) { 49 | return color == 'b'; 50 | } 51 | 52 | bool isRedVisible( 53 | String color, 54 | String isGuessed, 55 | ) { 56 | if (color == 'r' && isGuessed == 't') { 57 | return true; 58 | } else { 59 | return false; 60 | } 61 | } 62 | 63 | bool isRedVisibleSpy(String color) { 64 | return color == 'r'; 65 | } 66 | 67 | bool isNeutralVisible( 68 | String color, 69 | String isGuessed, 70 | ) { 71 | if (color == 'n' && isGuessed == 't') { 72 | return true; 73 | } else { 74 | return false; 75 | } 76 | } 77 | 78 | bool isNeutralVisibleSpy(String color) { 79 | return color == 'n'; 80 | } 81 | 82 | bool isGuessed(String isGuessedString) { 83 | if (isGuessedString == 't') { 84 | return true; 85 | } else { 86 | return false; 87 | } 88 | } 89 | 90 | bool shouldBlock( 91 | bool isBlue, 92 | bool isRedGuessing, 93 | bool isBlueGuessing, 94 | ) { 95 | if (isBlue && isBlueGuessing) { 96 | return true; 97 | } else if (!isBlue && isRedGuessing) { 98 | return true; 99 | } else { 100 | return false; 101 | } 102 | } 103 | 104 | bool shouldShowEndTurn( 105 | bool isBlue, 106 | bool isRedGuessing, 107 | bool isBlueGuessing, 108 | bool isSpy, 109 | ) { 110 | if (isBlue && isBlueGuessing && !isSpy) { 111 | return true; 112 | } else if (!isBlue && isRedGuessing && !isSpy) { 113 | return true; 114 | } else { 115 | return false; 116 | } 117 | } 118 | 119 | bool shouldShowSpyView( 120 | bool isSpy, 121 | bool isSpyViewOn, 122 | ) { 123 | if (isSpy && isSpyViewOn) { 124 | return true; 125 | } else { 126 | return false; 127 | } 128 | } 129 | 130 | String retrieveSelectedWordInfo( 131 | List words, 132 | int index, 133 | ) { 134 | return words[index]; 135 | } 136 | 137 | bool isCurrentTeamsTurn( 138 | bool isBlueTeam, 139 | bool isBlueGuessing, 140 | ) { 141 | if ((isBlueTeam && isBlueGuessing) || (!isBlueTeam && !isBlueGuessing)) { 142 | return true; 143 | } 144 | 145 | return false; 146 | } 147 | 148 | String createAISystemPrompt( 149 | List allWords, 150 | bool isBlue, 151 | ) { 152 | final teamColor = isBlue ? 'Blue' : 'Red'; 153 | 154 | final words = allWords 155 | .map((word) => separateWordDetails(word)['word'] as String) 156 | .toList() 157 | .join(', '); 158 | 159 | final blueWords = allWords 160 | .where((word) => separateWordDetails(word)['color'] == 'b') 161 | .map((filteredWords) => 162 | separateWordDetails(filteredWords)['word'] as String) 163 | .toList() 164 | .join(', '); 165 | 166 | final redWords = allWords 167 | .where((word) => separateWordDetails(word)['color'] == 'r') 168 | .map((filteredWords) => 169 | separateWordDetails(filteredWords)['word'] as String) 170 | .toList() 171 | .join(', '); 172 | 173 | final systemPrompt = 174 | '''You are the AI Spymaster for the $teamColor team of the Codenames game. 175 | 176 | The Board contains these words: $words. 177 | 178 | Among these words, those belonging to the Blue team are: $blueWords. 179 | 180 | Words belonging to the Red team are: $redWords. 181 | 182 | The rest of the words are neutral. There is no assassin in this game. 183 | 184 | You will be given the words that are already guessed in this format: 185 | 186 | Guessed: Sink, Poison, Queen 187 | 188 | You will reply with a one-word clue for the $teamColor team along with the number of words to guess in this format: [word, number]. Examples: 189 | 190 | Clue: Basin, 2 191 | 192 | Clue: Law, 1 193 | 194 | Clue: King, 0 195 | 196 | Some rules are as follows: 197 | 198 | - You can give only one clue at a time. 199 | 200 | - The word portion of a clue must be either a single word or a proper noun (which can be longer than one word). 201 | 202 | - The clue word must be based on the meaning of one or more words on the board belonging to your team. 203 | 204 | - You can't use any word that's present on the board. 205 | 206 | - Clue number can be between 0-9. 207 | 208 | - The number given with each clue generally represents the number of words to which the clue word applies. The clue number is important because the field operatives can guess up to that number plus words left to guess in their previous turns. 209 | 210 | - The clue number can also be zero, which perhaps could be used to send information about which words are not yours. If the clue number is zero, the field operatives can guess an unlimited number of times, as long as they continue to guess words that belong to their team. 211 | 212 | - Spymaster's target is to help its field operatives to guess all the words belonging to their team without choosing the other team's or neutral words. 213 | 214 | - The game ends when all words of a team are guessed correctly and that team becomes the winner. 215 | 216 | - You need to give clues until there is 0 words left in a team. 217 | '''; 218 | return jsonEncode(systemPrompt).substring(1, systemPrompt.length - 1); 219 | } 220 | 221 | String getClue(String rawClue) { 222 | return rawClue.split('Clue: ')[0]; 223 | } 224 | 225 | String createAIUserPrompt(List allWords) { 226 | final guessedWords = allWords 227 | .where( 228 | (word) => separateWordDetails(word)['is_guessed'] == 't', 229 | ) 230 | .map( 231 | (filteredWords) => separateWordDetails(filteredWords)['word'] as String, 232 | ) 233 | .toList(); 234 | 235 | return 'Guessed: ' + guessedWords.join(', '); 236 | } 237 | -------------------------------------------------------------------------------- /lib/flutter_flow/flutter_flow_animations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_animate/flutter_animate.dart'; 3 | 4 | enum AnimationTrigger { 5 | onPageLoad, 6 | onActionTrigger, 7 | } 8 | 9 | class AnimationInfo { 10 | AnimationInfo({ 11 | required this.trigger, 12 | required this.effects, 13 | this.loop = false, 14 | this.reverse = false, 15 | this.applyInitialState = true, 16 | }); 17 | final AnimationTrigger trigger; 18 | final List> effects; 19 | final bool applyInitialState; 20 | final bool loop; 21 | final bool reverse; 22 | late AnimationController controller; 23 | } 24 | 25 | void createAnimation(AnimationInfo animation, TickerProvider vsync) { 26 | final newController = AnimationController(vsync: vsync); 27 | animation.controller = newController; 28 | } 29 | 30 | void setupAnimations(Iterable animations, TickerProvider vsync) { 31 | animations.forEach((animation) => createAnimation(animation, vsync)); 32 | } 33 | 34 | extension AnimatedWidgetExtension on Widget { 35 | Widget animateOnPageLoad(AnimationInfo animationInfo) => Animate( 36 | effects: animationInfo.effects, 37 | child: this, 38 | onPlay: (controller) => animationInfo.loop 39 | ? controller.repeat(reverse: animationInfo.reverse) 40 | : null, 41 | onComplete: (controller) => !animationInfo.loop && animationInfo.reverse 42 | ? controller.reverse() 43 | : null); 44 | 45 | Widget animateOnActionTrigger( 46 | AnimationInfo animationInfo, { 47 | bool hasBeenTriggered = false, 48 | }) => 49 | hasBeenTriggered || animationInfo.applyInitialState 50 | ? Animate( 51 | controller: animationInfo.controller, 52 | autoPlay: false, 53 | effects: animationInfo.effects, 54 | child: this) 55 | : this; 56 | } 57 | 58 | class TiltEffect extends Effect { 59 | const TiltEffect({ 60 | Duration? delay, 61 | Duration? duration, 62 | Curve? curve, 63 | Offset? begin, 64 | Offset? end, 65 | }) : super( 66 | delay: delay, 67 | duration: duration, 68 | curve: curve, 69 | begin: begin ?? const Offset(0.0, 0.0), 70 | end: end ?? const Offset(0.0, 0.0), 71 | ); 72 | 73 | @override 74 | Widget build( 75 | BuildContext context, 76 | Widget child, 77 | AnimationController controller, 78 | EffectEntry entry, 79 | ) { 80 | Animation animation = buildAnimation(controller, entry); 81 | return getOptimizedBuilder( 82 | animation: animation, 83 | builder: (_, __) => Transform( 84 | transform: Matrix4.identity() 85 | ..setEntry(3, 2, 0.001) 86 | ..rotateX(animation.value.dx) 87 | ..rotateY(animation.value.dy), 88 | alignment: Alignment.center, 89 | child: child, 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/flutter_flow/flutter_flow_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | 4 | class FlutterFlowIconButton extends StatefulWidget { 5 | const FlutterFlowIconButton({ 6 | Key? key, 7 | required this.icon, 8 | this.borderColor, 9 | this.borderRadius, 10 | this.borderWidth, 11 | this.buttonSize, 12 | this.fillColor, 13 | this.disabledColor, 14 | this.disabledIconColor, 15 | this.hoverColor, 16 | this.hoverIconColor, 17 | this.onPressed, 18 | this.showLoadingIndicator = false, 19 | }) : super(key: key); 20 | 21 | final Widget icon; 22 | final double? borderRadius; 23 | final double? buttonSize; 24 | final Color? fillColor; 25 | final Color? disabledColor; 26 | final Color? disabledIconColor; 27 | final Color? hoverColor; 28 | final Color? hoverIconColor; 29 | final Color? borderColor; 30 | final double? borderWidth; 31 | final bool showLoadingIndicator; 32 | final Function()? onPressed; 33 | 34 | @override 35 | State createState() => _FlutterFlowIconButtonState(); 36 | } 37 | 38 | class _FlutterFlowIconButtonState extends State { 39 | bool loading = false; 40 | late double? iconSize; 41 | late Color? iconColor; 42 | late Widget effectiveIcon; 43 | 44 | @override 45 | void initState() { 46 | super.initState(); 47 | _updateIcon(); 48 | } 49 | 50 | @override 51 | void didUpdateWidget(FlutterFlowIconButton oldWidget) { 52 | super.didUpdateWidget(oldWidget); 53 | _updateIcon(); 54 | } 55 | 56 | void _updateIcon() { 57 | final isFontAwesome = widget.icon is FaIcon; 58 | if (isFontAwesome) { 59 | FaIcon icon = widget.icon as FaIcon; 60 | effectiveIcon = FaIcon( 61 | icon.icon, 62 | size: icon.size, 63 | ); 64 | iconSize = icon.size; 65 | iconColor = icon.color; 66 | } else { 67 | Icon icon = widget.icon as Icon; 68 | effectiveIcon = Icon( 69 | icon.icon, 70 | size: icon.size, 71 | ); 72 | iconSize = icon.size; 73 | iconColor = icon.color; 74 | } 75 | } 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | ButtonStyle style = ButtonStyle( 80 | shape: MaterialStateProperty.resolveWith( 81 | (states) { 82 | return RoundedRectangleBorder( 83 | borderRadius: BorderRadius.circular(widget.borderRadius ?? 0), 84 | side: BorderSide( 85 | color: widget.borderColor ?? Colors.transparent, 86 | width: widget.borderWidth ?? 0, 87 | ), 88 | ); 89 | }, 90 | ), 91 | iconColor: MaterialStateProperty.resolveWith( 92 | (states) { 93 | if (states.contains(MaterialState.disabled) && 94 | widget.disabledIconColor != null) { 95 | return widget.disabledIconColor; 96 | } 97 | if (states.contains(MaterialState.hovered) && 98 | widget.hoverIconColor != null) { 99 | return widget.hoverIconColor; 100 | } 101 | return iconColor; 102 | }, 103 | ), 104 | backgroundColor: MaterialStateProperty.resolveWith( 105 | (states) { 106 | if (states.contains(MaterialState.disabled) && 107 | widget.disabledColor != null) { 108 | return widget.disabledColor; 109 | } 110 | if (states.contains(MaterialState.hovered) && 111 | widget.hoverColor != null) { 112 | return widget.hoverColor; 113 | } 114 | 115 | return widget.fillColor; 116 | }, 117 | ), 118 | ); 119 | 120 | return SizedBox( 121 | width: widget.buttonSize, 122 | height: widget.buttonSize, 123 | child: Theme( 124 | data: Theme.of(context).copyWith(useMaterial3: true), 125 | child: IgnorePointer( 126 | ignoring: (widget.showLoadingIndicator && loading), 127 | child: IconButton( 128 | icon: (widget.showLoadingIndicator && loading) 129 | ? Container( 130 | width: iconSize, 131 | height: iconSize, 132 | child: CircularProgressIndicator( 133 | valueColor: AlwaysStoppedAnimation( 134 | iconColor ?? Colors.white, 135 | ), 136 | ), 137 | ) 138 | : effectiveIcon, 139 | onPressed: widget.onPressed == null 140 | ? null 141 | : () async { 142 | if (loading) { 143 | return; 144 | } 145 | setState(() => loading = true); 146 | try { 147 | await widget.onPressed!(); 148 | } finally { 149 | if (mounted) { 150 | setState(() => loading = false); 151 | } 152 | } 153 | }, 154 | splashRadius: widget.buttonSize, 155 | style: style, 156 | ), 157 | ), 158 | ), 159 | ); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /lib/flutter_flow/flutter_flow_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/scheduler.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | Widget wrapWithModel({ 7 | required T model, 8 | required Widget child, 9 | required VoidCallback updateCallback, 10 | bool updateOnChange = false, 11 | }) { 12 | // Set the component to optionally update the page on updates. 13 | model.setOnUpdate( 14 | onUpdate: updateCallback, 15 | updateOnChange: updateOnChange, 16 | ); 17 | // Models for components within a page will be disposed by the page's model, 18 | // so we don't want the component widget to dispose them until the page is 19 | // itself disposed. 20 | model.disposeOnWidgetDisposal = false; 21 | // Wrap in a Provider so that the model can be accessed by the component. 22 | return Provider.value( 23 | value: model, 24 | child: child, 25 | ); 26 | } 27 | 28 | T createModel( 29 | BuildContext context, 30 | T Function() defaultBuilder, 31 | ) { 32 | final model = context.read() ?? defaultBuilder(); 33 | model._init(context); 34 | return model; 35 | } 36 | 37 | abstract class FlutterFlowModel { 38 | // Initialization methods 39 | bool _isInitialized = false; 40 | void initState(BuildContext context); 41 | void _init(BuildContext context) { 42 | if (!_isInitialized) { 43 | initState(context); 44 | _isInitialized = true; 45 | } 46 | } 47 | 48 | // Dispose methods 49 | // Whether to dispose this model when the corresponding widget is 50 | // disposed. By default this is true for pages and false for components, 51 | // as page/component models handle the disposal of their children. 52 | bool disposeOnWidgetDisposal = true; 53 | void dispose(); 54 | void maybeDispose() { 55 | if (disposeOnWidgetDisposal) { 56 | dispose(); 57 | } 58 | } 59 | 60 | // Whether to update the containing page / component on updates. 61 | bool updateOnChange = false; 62 | // Function to call when the model receives an update. 63 | VoidCallback _updateCallback = () {}; 64 | void onUpdate() => updateOnChange ? _updateCallback() : () {}; 65 | FlutterFlowModel setOnUpdate({ 66 | bool updateOnChange = false, 67 | required VoidCallback onUpdate, 68 | }) => 69 | this 70 | .._updateCallback = onUpdate 71 | ..updateOnChange = updateOnChange; 72 | // Update the containing page when this model received an update. 73 | void updatePage(VoidCallback callback) { 74 | callback(); 75 | _updateCallback(); 76 | } 77 | } 78 | 79 | class FlutterFlowDynamicModels { 80 | FlutterFlowDynamicModels(this.defaultBuilder); 81 | 82 | final T Function() defaultBuilder; 83 | final Map _childrenModels = {}; 84 | final Map _childrenIndexes = {}; 85 | Set? _activeKeys; 86 | 87 | T getModel(String uniqueKey, int index) { 88 | _updateActiveKeys(uniqueKey); 89 | _childrenIndexes[uniqueKey] = index; 90 | return _childrenModels[uniqueKey] ??= defaultBuilder(); 91 | } 92 | 93 | List getValues(S? Function(T) getValue) { 94 | return _childrenIndexes.entries 95 | // Sort keys by index. 96 | .sorted((a, b) => a.value.compareTo(b.value)) 97 | .where((e) => _childrenModels[e.key] != null) 98 | // Map each model to the desired value and return as list. In order 99 | // to preserve index order, rather than removing null values we provide 100 | // default values (for types with reasonable defaults). 101 | .map((e) => getValue(_childrenModels[e.key]!) ?? _getDefaultValue()!) 102 | .toList(); 103 | } 104 | 105 | S? getValueAtIndex(int index, S? Function(T) getValue) { 106 | final uniqueKey = 107 | _childrenIndexes.entries.firstWhereOrNull((e) => e.value == index)?.key; 108 | return getValueForKey(uniqueKey, getValue); 109 | } 110 | 111 | S? getValueForKey(String? uniqueKey, S? Function(T) getValue) { 112 | final model = _childrenModels[uniqueKey]; 113 | return model != null ? getValue(model) : null; 114 | } 115 | 116 | void dispose() => _childrenModels.values.forEach((model) => model.dispose()); 117 | 118 | void _updateActiveKeys(String uniqueKey) { 119 | final shouldResetActiveKeys = _activeKeys == null; 120 | _activeKeys ??= {}; 121 | _activeKeys!.add(uniqueKey); 122 | 123 | if (shouldResetActiveKeys) { 124 | // Add a post-frame callback to remove and dispose of unused models after 125 | // we're done building, then reset `_activeKeys` to null so we know to do 126 | // this again next build. 127 | SchedulerBinding.instance.addPostFrameCallback((_) { 128 | _childrenIndexes.removeWhere((k, _) => !_activeKeys!.contains(k)); 129 | _childrenModels.keys 130 | .toSet() 131 | .difference(_activeKeys!) 132 | // Remove and dispose of unused models since they are not being used 133 | // elsewhere and would not otherwise be disposed. 134 | .forEach((k) => _childrenModels.remove(k)?.dispose()); 135 | _activeKeys = null; 136 | }); 137 | } 138 | } 139 | } 140 | 141 | T? _getDefaultValue() { 142 | switch (T) { 143 | case int: 144 | return 0 as T; 145 | case double: 146 | return 0.0 as T; 147 | case String: 148 | return '' as T; 149 | case bool: 150 | return false as T; 151 | default: 152 | return null as T; 153 | } 154 | } 155 | 156 | extension TextValidationExtensions on String? Function(BuildContext, String?)? { 157 | String? Function(String?)? asValidator(BuildContext context) => 158 | this != null ? (val) => this!(context, val) : null; 159 | } 160 | -------------------------------------------------------------------------------- /lib/flutter_flow/flutter_flow_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:auto_size_text/auto_size_text.dart'; 4 | 5 | class FFButtonOptions { 6 | const FFButtonOptions({ 7 | this.textStyle, 8 | this.elevation, 9 | this.height, 10 | this.width, 11 | this.padding, 12 | this.color, 13 | this.disabledColor, 14 | this.disabledTextColor, 15 | this.splashColor, 16 | this.iconSize, 17 | this.iconColor, 18 | this.iconPadding, 19 | this.borderRadius, 20 | this.borderSide, 21 | this.hoverColor, 22 | this.hoverBorderSide, 23 | this.hoverTextColor, 24 | this.hoverElevation, 25 | }); 26 | 27 | final TextStyle? textStyle; 28 | final double? elevation; 29 | final double? height; 30 | final double? width; 31 | final EdgeInsetsGeometry? padding; 32 | final Color? color; 33 | final Color? disabledColor; 34 | final Color? disabledTextColor; 35 | final Color? splashColor; 36 | final double? iconSize; 37 | final Color? iconColor; 38 | final EdgeInsetsGeometry? iconPadding; 39 | final BorderRadius? borderRadius; 40 | final BorderSide? borderSide; 41 | final Color? hoverColor; 42 | final BorderSide? hoverBorderSide; 43 | final Color? hoverTextColor; 44 | final double? hoverElevation; 45 | } 46 | 47 | class FFButtonWidget extends StatefulWidget { 48 | const FFButtonWidget({ 49 | Key? key, 50 | required this.text, 51 | required this.onPressed, 52 | this.icon, 53 | this.iconData, 54 | required this.options, 55 | this.showLoadingIndicator = true, 56 | }) : super(key: key); 57 | 58 | final String text; 59 | final Widget? icon; 60 | final IconData? iconData; 61 | final Function()? onPressed; 62 | final FFButtonOptions options; 63 | final bool showLoadingIndicator; 64 | 65 | @override 66 | State createState() => _FFButtonWidgetState(); 67 | } 68 | 69 | class _FFButtonWidgetState extends State { 70 | bool loading = false; 71 | 72 | @override 73 | Widget build(BuildContext context) { 74 | Widget textWidget = loading 75 | ? Center( 76 | child: Container( 77 | width: 23, 78 | height: 23, 79 | child: CircularProgressIndicator( 80 | valueColor: AlwaysStoppedAnimation( 81 | widget.options.textStyle!.color ?? Colors.white, 82 | ), 83 | ), 84 | ), 85 | ) 86 | : AutoSizeText( 87 | widget.text, 88 | style: widget.options.textStyle?.withoutColor(), 89 | maxLines: 1, 90 | overflow: TextOverflow.ellipsis, 91 | ); 92 | 93 | final onPressed = widget.onPressed != null 94 | ? (widget.showLoadingIndicator 95 | ? () async { 96 | if (loading) { 97 | return; 98 | } 99 | setState(() => loading = true); 100 | try { 101 | await widget.onPressed!(); 102 | } finally { 103 | if (mounted) { 104 | setState(() => loading = false); 105 | } 106 | } 107 | } 108 | : () => widget.onPressed!()) 109 | : null; 110 | 111 | ButtonStyle style = ButtonStyle( 112 | shape: MaterialStateProperty.resolveWith( 113 | (states) { 114 | if (states.contains(MaterialState.hovered) && 115 | widget.options.hoverBorderSide != null) { 116 | return RoundedRectangleBorder( 117 | borderRadius: 118 | widget.options.borderRadius ?? BorderRadius.circular(8), 119 | side: widget.options.hoverBorderSide!, 120 | ); 121 | } 122 | return RoundedRectangleBorder( 123 | borderRadius: 124 | widget.options.borderRadius ?? BorderRadius.circular(8), 125 | side: widget.options.borderSide ?? BorderSide.none, 126 | ); 127 | }, 128 | ), 129 | foregroundColor: MaterialStateProperty.resolveWith( 130 | (states) { 131 | if (states.contains(MaterialState.disabled) && 132 | widget.options.disabledTextColor != null) { 133 | return widget.options.disabledTextColor; 134 | } 135 | if (states.contains(MaterialState.hovered) && 136 | widget.options.hoverTextColor != null) { 137 | return widget.options.hoverTextColor; 138 | } 139 | return widget.options.textStyle?.color; 140 | }, 141 | ), 142 | backgroundColor: MaterialStateProperty.resolveWith( 143 | (states) { 144 | if (states.contains(MaterialState.disabled) && 145 | widget.options.disabledColor != null) { 146 | return widget.options.disabledColor; 147 | } 148 | if (states.contains(MaterialState.hovered) && 149 | widget.options.hoverColor != null) { 150 | return widget.options.hoverColor; 151 | } 152 | return widget.options.color; 153 | }, 154 | ), 155 | overlayColor: MaterialStateProperty.resolveWith((states) { 156 | if (states.contains(MaterialState.pressed)) { 157 | return widget.options.splashColor; 158 | } 159 | return null; 160 | }), 161 | padding: MaterialStateProperty.all(widget.options.padding ?? 162 | const EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0)), 163 | elevation: MaterialStateProperty.resolveWith( 164 | (states) { 165 | if (states.contains(MaterialState.hovered) && 166 | widget.options.hoverElevation != null) { 167 | return widget.options.hoverElevation!; 168 | } 169 | return widget.options.elevation; 170 | }, 171 | ), 172 | ); 173 | 174 | if (widget.icon != null || widget.iconData != null) { 175 | return Container( 176 | height: widget.options.height, 177 | width: widget.options.width, 178 | child: ElevatedButton.icon( 179 | icon: Padding( 180 | padding: widget.options.iconPadding ?? EdgeInsets.zero, 181 | child: widget.icon ?? 182 | FaIcon( 183 | widget.iconData, 184 | size: widget.options.iconSize, 185 | color: widget.options.iconColor ?? 186 | widget.options.textStyle!.color, 187 | ), 188 | ), 189 | label: textWidget, 190 | onPressed: onPressed, 191 | style: style, 192 | ), 193 | ); 194 | } 195 | 196 | return Container( 197 | height: widget.options.height, 198 | width: widget.options.width, 199 | child: ElevatedButton( 200 | onPressed: onPressed, 201 | style: style, 202 | child: textWidget, 203 | ), 204 | ); 205 | } 206 | } 207 | 208 | extension _WithoutColorExtension on TextStyle { 209 | TextStyle withoutColor() => TextStyle( 210 | inherit: inherit, 211 | color: null, 212 | backgroundColor: backgroundColor, 213 | fontSize: fontSize, 214 | fontWeight: fontWeight, 215 | fontStyle: fontStyle, 216 | letterSpacing: letterSpacing, 217 | wordSpacing: wordSpacing, 218 | textBaseline: textBaseline, 219 | height: height, 220 | leadingDistribution: leadingDistribution, 221 | locale: locale, 222 | foreground: foreground, 223 | background: background, 224 | shadows: shadows, 225 | fontFeatures: fontFeatures, 226 | decoration: decoration, 227 | decorationColor: decorationColor, 228 | decorationStyle: decorationStyle, 229 | decorationThickness: decorationThickness, 230 | debugLabel: debugLabel, 231 | fontFamily: fontFamily, 232 | fontFamilyFallback: fontFamilyFallback, 233 | // The _package field is private so unfortunately we can't set it here, 234 | // but it's almost always unset anyway. 235 | // package: _package, 236 | overflow: overflow, 237 | ); 238 | } 239 | -------------------------------------------------------------------------------- /lib/flutter_flow/form_field_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class FormFieldController extends ValueNotifier { 4 | FormFieldController(this.initialValue) : super(initialValue); 5 | 6 | final T? initialValue; 7 | 8 | void reset() => value = initialValue; 9 | } 10 | -------------------------------------------------------------------------------- /lib/flutter_flow/instant_timer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | extension TimerExt on Timer? { 4 | bool get isActive => this?.isActive ?? false; 5 | int get tick => this?.tick ?? 0; 6 | } 7 | 8 | class InstantTimer implements Timer { 9 | factory InstantTimer.periodic({ 10 | required Duration duration, 11 | required void Function(Timer timer) callback, 12 | bool startImmediately = true, 13 | }) { 14 | final myTimer = Timer.periodic(duration, callback); 15 | if (startImmediately) { 16 | Future.delayed(Duration(seconds: 0)).then((_) => callback(myTimer)); 17 | } 18 | return InstantTimer._(myTimer, startImmediately); 19 | } 20 | 21 | InstantTimer._(this._timer, this._startImmediately); 22 | final Timer _timer; 23 | final bool _startImmediately; 24 | 25 | @override 26 | void cancel() { 27 | _timer.cancel(); 28 | } 29 | 30 | @override 31 | bool get isActive => _timer.isActive; 32 | 33 | @override 34 | int get tick => _timer.tick + (_startImmediately ? 1 : 0); 35 | } 36 | -------------------------------------------------------------------------------- /lib/flutter_flow/internationalization.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | const _kLocaleStorageKey = '__locale_key__'; 6 | 7 | class FFLocalizations { 8 | FFLocalizations(this.locale); 9 | 10 | final Locale locale; 11 | 12 | static FFLocalizations of(BuildContext context) => 13 | Localizations.of(context, FFLocalizations)!; 14 | 15 | static List languages() => ['en']; 16 | 17 | static late SharedPreferences _prefs; 18 | static Future initialize() async => 19 | _prefs = await SharedPreferences.getInstance(); 20 | static Future storeLocale(String locale) => 21 | _prefs.setString(_kLocaleStorageKey, locale); 22 | static Locale? getStoredLocale() { 23 | final locale = _prefs.getString(_kLocaleStorageKey); 24 | return locale != null && locale.isNotEmpty ? createLocale(locale) : null; 25 | } 26 | 27 | String get languageCode => locale.toString(); 28 | String? get languageShortCode => 29 | _languagesWithShortCode.contains(locale.toString()) 30 | ? '${locale.toString()}_short' 31 | : null; 32 | int get languageIndex => languages().contains(languageCode) 33 | ? languages().indexOf(languageCode) 34 | : 0; 35 | 36 | String getText(String key) => 37 | (kTranslationsMap[key] ?? {})[locale.toString()] ?? ''; 38 | 39 | String getVariableText({ 40 | String? enText = '', 41 | }) => 42 | [enText][languageIndex] ?? ''; 43 | 44 | static const Set _languagesWithShortCode = { 45 | 'ar', 46 | 'az', 47 | 'ca', 48 | 'cs', 49 | 'da', 50 | 'de', 51 | 'dv', 52 | 'en', 53 | 'es', 54 | 'et', 55 | 'fi', 56 | 'fr', 57 | 'gr', 58 | 'he', 59 | 'hi', 60 | 'hu', 61 | 'it', 62 | 'km', 63 | 'ku', 64 | 'mn', 65 | 'ms', 66 | 'no', 67 | 'pt', 68 | 'ro', 69 | 'ru', 70 | 'rw', 71 | 'sv', 72 | 'th', 73 | 'uk', 74 | 'vi', 75 | }; 76 | } 77 | 78 | class FFLocalizationsDelegate extends LocalizationsDelegate { 79 | const FFLocalizationsDelegate(); 80 | 81 | @override 82 | bool isSupported(Locale locale) { 83 | final language = locale.toString(); 84 | return FFLocalizations.languages().contains( 85 | language.endsWith('_') 86 | ? language.substring(0, language.length - 1) 87 | : language, 88 | ); 89 | } 90 | 91 | @override 92 | Future load(Locale locale) => 93 | SynchronousFuture(FFLocalizations(locale)); 94 | 95 | @override 96 | bool shouldReload(FFLocalizationsDelegate old) => false; 97 | } 98 | 99 | Locale createLocale(String language) => language.contains('_') 100 | ? Locale.fromSubtags( 101 | languageCode: language.split('_').first, 102 | scriptCode: language.split('_').last, 103 | ) 104 | : Locale(language); 105 | 106 | final kTranslationsMap = 107 | >>[].reduce((a, b) => a..addAll(b)); 108 | -------------------------------------------------------------------------------- /lib/flutter_flow/lat_lng.dart: -------------------------------------------------------------------------------- 1 | class LatLng { 2 | const LatLng(this.latitude, this.longitude); 3 | final double latitude; 4 | final double longitude; 5 | 6 | @override 7 | String toString() => 'LatLng(lat: $latitude, lng: $longitude)'; 8 | 9 | String serialize() => '$latitude,$longitude'; 10 | 11 | @override 12 | int get hashCode => latitude.hashCode + longitude.hashCode; 13 | 14 | @override 15 | bool operator ==(other) => 16 | other is LatLng && 17 | latitude == other.latitude && 18 | longitude == other.longitude; 19 | } 20 | -------------------------------------------------------------------------------- /lib/flutter_flow/place.dart: -------------------------------------------------------------------------------- 1 | import 'lat_lng.dart'; 2 | 3 | class FFPlace { 4 | const FFPlace({ 5 | this.latLng = const LatLng(0.0, 0.0), 6 | this.name = '', 7 | this.address = '', 8 | this.city = '', 9 | this.state = '', 10 | this.country = '', 11 | this.zipCode = '', 12 | }); 13 | 14 | final LatLng latLng; 15 | final String name; 16 | final String address; 17 | final String city; 18 | final String state; 19 | final String country; 20 | final String zipCode; 21 | 22 | @override 23 | String toString() => '''FFPlace( 24 | latLng: $latLng, 25 | name: $name, 26 | address: $address, 27 | city: $city, 28 | state: $state, 29 | country: $country, 30 | zipCode: $zipCode, 31 | )'''; 32 | 33 | @override 34 | int get hashCode => latLng.hashCode; 35 | 36 | @override 37 | bool operator ==(other) => 38 | other is FFPlace && 39 | latLng == other.latLng && 40 | name == other.name && 41 | address == other.address && 42 | city == other.city && 43 | state == other.state && 44 | country == other.country && 45 | zipCode == other.zipCode; 46 | } 47 | -------------------------------------------------------------------------------- /lib/flutter_flow/uploaded_file.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data' show Uint8List; 3 | 4 | class FFUploadedFile { 5 | const FFUploadedFile({ 6 | this.name, 7 | this.bytes, 8 | this.height, 9 | this.width, 10 | this.blurHash, 11 | }); 12 | 13 | final String? name; 14 | final Uint8List? bytes; 15 | final double? height; 16 | final double? width; 17 | final String? blurHash; 18 | 19 | @override 20 | String toString() => 21 | 'FFUploadedFile(name: $name, bytes: ${bytes?.length ?? 0}, height: $height, width: $width, blurHash: $blurHash)'; 22 | 23 | String serialize() => jsonEncode( 24 | { 25 | 'name': name, 26 | 'bytes': bytes, 27 | 'height': height, 28 | 'width': width, 29 | 'blurHash': blurHash, 30 | }, 31 | ); 32 | 33 | static FFUploadedFile deserialize(String val) { 34 | final serializedData = jsonDecode(val) as Map; 35 | final data = { 36 | 'name': serializedData['name'] ?? '', 37 | 'bytes': serializedData['bytes'] ?? Uint8List.fromList([]), 38 | 'height': serializedData['height'], 39 | 'width': serializedData['width'], 40 | 'blurHash': serializedData['blurHash'], 41 | }; 42 | return FFUploadedFile( 43 | name: data['name'] as String, 44 | bytes: data['bytes'] as Uint8List, 45 | height: data['height'] as double?, 46 | width: data['width'] as double?, 47 | blurHash: data['blurHash'] as String?, 48 | ); 49 | } 50 | 51 | @override 52 | int get hashCode => Object.hash(name, bytes, height, width, blurHash); 53 | 54 | @override 55 | bool operator ==(other) => 56 | other is FFUploadedFile && 57 | name == other.name && 58 | bytes == other.bytes && 59 | height == other.height && 60 | width == other.width && 61 | blurHash == other.blurHash; 62 | } 63 | -------------------------------------------------------------------------------- /lib/index.dart: -------------------------------------------------------------------------------- 1 | // Export pages 2 | export '/pages/start_screen/start_screen_widget.dart' show StartScreenWidget; 3 | export '/pages/joining_pages/host_page/host_page_widget.dart' 4 | show HostPageWidget; 5 | export '/pages/joining_pages/player_page/player_page_widget.dart' 6 | show PlayerPageWidget; 7 | export '/pages/game_pages/field_operatives_view/field_operatives_view_widget.dart' 8 | show FieldOperativesViewWidget; 9 | export '/pages/game_pages/spy_view/spy_view_widget.dart' show SpyViewWidget; 10 | export '/pages/celebrate_pages/red_celebrate_page/red_celebrate_page_widget.dart' 11 | show RedCelebratePageWidget; 12 | export '/pages/celebrate_pages/blue_celebrate_page/blue_celebrate_page_widget.dart' 13 | show BlueCelebratePageWidget; 14 | export '/pages/create_join_screen/create_join_screen_widget.dart' 15 | show CreateJoinScreenWidget; 16 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:provider/provider.dart'; 2 | import 'package:flutter/gestures.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'package:flutter_localizations/flutter_localizations.dart'; 6 | import 'package:flutter_web_plugins/url_strategy.dart'; 7 | import 'package:firebase_core/firebase_core.dart'; 8 | import 'auth/firebase_auth/firebase_user_provider.dart'; 9 | import 'auth/firebase_auth/auth_util.dart'; 10 | 11 | import 'backend/firebase/firebase_config.dart'; 12 | import 'flutter_flow/flutter_flow_theme.dart'; 13 | import 'flutter_flow/flutter_flow_util.dart'; 14 | import 'flutter_flow/internationalization.dart'; 15 | import 'flutter_flow/nav/nav.dart'; 16 | import 'index.dart'; 17 | 18 | void main() async { 19 | WidgetsFlutterBinding.ensureInitialized(); 20 | usePathUrlStrategy(); 21 | await initFirebase(); 22 | 23 | final appState = FFAppState(); // Initialize FFAppState 24 | await appState.initializePersistedState(); 25 | 26 | runApp(ChangeNotifierProvider( 27 | create: (context) => appState, 28 | child: MyApp(), 29 | )); 30 | } 31 | 32 | class MyApp extends StatefulWidget { 33 | // This widget is the root of your application. 34 | @override 35 | State createState() => _MyAppState(); 36 | 37 | static _MyAppState of(BuildContext context) => 38 | context.findAncestorStateOfType<_MyAppState>()!; 39 | } 40 | 41 | class _MyAppState extends State { 42 | Locale? _locale; 43 | ThemeMode _themeMode = ThemeMode.system; 44 | 45 | late Stream userStream; 46 | 47 | late AppStateNotifier _appStateNotifier; 48 | late GoRouter _router; 49 | 50 | final authUserSub = authenticatedUserStream.listen((_) {}); 51 | 52 | @override 53 | void initState() { 54 | super.initState(); 55 | _appStateNotifier = AppStateNotifier.instance; 56 | _router = createRouter(_appStateNotifier); 57 | userStream = codewordsFirebaseUserStream() 58 | ..listen((user) => _appStateNotifier.update(user)); 59 | jwtTokenStream.listen((_) {}); 60 | Future.delayed( 61 | Duration(seconds: 1), 62 | () => _appStateNotifier.stopShowingSplashImage(), 63 | ); 64 | } 65 | 66 | @override 67 | void dispose() { 68 | authUserSub.cancel(); 69 | 70 | super.dispose(); 71 | } 72 | 73 | void setLocale(String language) { 74 | setState(() => _locale = createLocale(language)); 75 | } 76 | 77 | void setThemeMode(ThemeMode mode) => setState(() { 78 | _themeMode = mode; 79 | }); 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | return MaterialApp.router( 84 | title: 'Codewords', 85 | localizationsDelegates: [ 86 | FFLocalizationsDelegate(), 87 | GlobalMaterialLocalizations.delegate, 88 | GlobalWidgetsLocalizations.delegate, 89 | GlobalCupertinoLocalizations.delegate, 90 | ], 91 | locale: _locale, 92 | supportedLocales: const [Locale('en', '')], 93 | theme: ThemeData(brightness: Brightness.light), 94 | themeMode: _themeMode, 95 | routerConfig: _router, 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/pages/celebrate_pages/blue_celebrate_page/blue_celebrate_page_model.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/flutter_flow/flutter_flow_widgets.dart'; 4 | import '/custom_code/widgets/index.dart' as custom_widgets; 5 | import 'package:flutter/material.dart'; 6 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 7 | import 'package:google_fonts/google_fonts.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | class BlueCelebratePageModel extends FlutterFlowModel { 11 | /// Initialization and disposal methods. 12 | 13 | void initState(BuildContext context) {} 14 | 15 | void dispose() {} 16 | 17 | /// Additional helper methods are added here. 18 | 19 | } 20 | -------------------------------------------------------------------------------- /lib/pages/celebrate_pages/blue_celebrate_page/blue_celebrate_page_widget.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/flutter_flow/flutter_flow_widgets.dart'; 4 | import '/custom_code/widgets/index.dart' as custom_widgets; 5 | import 'package:flutter/material.dart'; 6 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 7 | import 'package:google_fonts/google_fonts.dart'; 8 | import 'package:provider/provider.dart'; 9 | import 'blue_celebrate_page_model.dart'; 10 | export 'blue_celebrate_page_model.dart'; 11 | 12 | class BlueCelebratePageWidget extends StatefulWidget { 13 | const BlueCelebratePageWidget({Key? key}) : super(key: key); 14 | 15 | @override 16 | _BlueCelebratePageWidgetState createState() => 17 | _BlueCelebratePageWidgetState(); 18 | } 19 | 20 | class _BlueCelebratePageWidgetState extends State { 21 | late BlueCelebratePageModel _model; 22 | 23 | final scaffoldKey = GlobalKey(); 24 | final _unfocusNode = FocusNode(); 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _model = createModel(context, () => BlueCelebratePageModel()); 30 | 31 | logFirebaseEvent('screen_view', 32 | parameters: {'screen_name': 'BlueCelebratePage'}); 33 | WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); 34 | } 35 | 36 | @override 37 | void dispose() { 38 | _model.dispose(); 39 | 40 | _unfocusNode.dispose(); 41 | super.dispose(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | context.watch(); 47 | 48 | return GestureDetector( 49 | onTap: () => FocusScope.of(context).requestFocus(_unfocusNode), 50 | child: Scaffold( 51 | key: scaffoldKey, 52 | backgroundColor: FlutterFlowTheme.of(context).primary, 53 | body: SafeArea( 54 | top: true, 55 | child: Container( 56 | width: double.infinity, 57 | height: double.infinity, 58 | decoration: BoxDecoration( 59 | color: FlutterFlowTheme.of(context).primary, 60 | ), 61 | child: Stack( 62 | children: [ 63 | Row( 64 | mainAxisSize: MainAxisSize.max, 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | children: [ 67 | Column( 68 | mainAxisSize: MainAxisSize.max, 69 | mainAxisAlignment: MainAxisAlignment.center, 70 | children: [ 71 | FaIcon( 72 | FontAwesomeIcons.trophy, 73 | color: Color(0xFFFFB938), 74 | size: 90.0, 75 | ), 76 | Text( 77 | 'WINNER', 78 | style: FlutterFlowTheme.of(context) 79 | .bodyMedium 80 | .override( 81 | fontFamily: 'Poppins', 82 | color: 83 | FlutterFlowTheme.of(context).primaryBtnText, 84 | fontSize: 36.0, 85 | ), 86 | ), 87 | Text( 88 | 'Blue Team', 89 | style: 90 | FlutterFlowTheme.of(context).bodyMedium.override( 91 | fontFamily: 'Poppins', 92 | color: FlutterFlowTheme.of(context) 93 | .primaryBackground, 94 | fontSize: 36.0, 95 | fontWeight: FontWeight.w500, 96 | ), 97 | ), 98 | Padding( 99 | padding: EdgeInsetsDirectional.fromSTEB( 100 | 0.0, 50.0, 0.0, 0.0), 101 | child: FFButtonWidget( 102 | onPressed: () async { 103 | logFirebaseEvent( 104 | 'BLUE_CELEBRATE_START_NEW_GAME_BTN_ON_TAP'); 105 | FFAppState().update(() { 106 | FFAppState().words = []; 107 | }); 108 | 109 | context.pushNamed( 110 | 'CreateJoinScreen', 111 | extra: { 112 | kTransitionInfoKey: TransitionInfo( 113 | hasTransition: true, 114 | transitionType: PageTransitionType.fade, 115 | ), 116 | }, 117 | ); 118 | }, 119 | text: 'Start New Game', 120 | options: FFButtonOptions( 121 | width: 200.0, 122 | height: 50.0, 123 | padding: EdgeInsetsDirectional.fromSTEB( 124 | 0.0, 0.0, 0.0, 0.0), 125 | iconPadding: EdgeInsetsDirectional.fromSTEB( 126 | 0.0, 0.0, 0.0, 0.0), 127 | color: Color(0x004B39EF), 128 | textStyle: FlutterFlowTheme.of(context) 129 | .titleSmall 130 | .override( 131 | fontFamily: 'Poppins', 132 | color: Colors.white, 133 | fontWeight: FontWeight.w500, 134 | ), 135 | elevation: 2.0, 136 | borderSide: BorderSide( 137 | color: 138 | FlutterFlowTheme.of(context).primaryBtnText, 139 | width: 4.0, 140 | ), 141 | borderRadius: BorderRadius.circular(16.0), 142 | ), 143 | ), 144 | ), 145 | ], 146 | ), 147 | ], 148 | ), 149 | Container( 150 | width: double.infinity, 151 | height: double.infinity, 152 | child: custom_widgets.ConfettiOverlay( 153 | width: double.infinity, 154 | height: double.infinity, 155 | ), 156 | ), 157 | ], 158 | ), 159 | ), 160 | ), 161 | ), 162 | ); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /lib/pages/celebrate_pages/red_celebrate_page/red_celebrate_page_model.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/flutter_flow/flutter_flow_widgets.dart'; 4 | import '/custom_code/widgets/index.dart' as custom_widgets; 5 | import 'package:flutter/material.dart'; 6 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 7 | import 'package:google_fonts/google_fonts.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | class RedCelebratePageModel extends FlutterFlowModel { 11 | /// Initialization and disposal methods. 12 | 13 | void initState(BuildContext context) {} 14 | 15 | void dispose() {} 16 | 17 | /// Additional helper methods are added here. 18 | 19 | } 20 | -------------------------------------------------------------------------------- /lib/pages/celebrate_pages/red_celebrate_page/red_celebrate_page_widget.dart: -------------------------------------------------------------------------------- 1 | import '/flutter_flow/flutter_flow_theme.dart'; 2 | import '/flutter_flow/flutter_flow_util.dart'; 3 | import '/flutter_flow/flutter_flow_widgets.dart'; 4 | import '/custom_code/widgets/index.dart' as custom_widgets; 5 | import 'package:flutter/material.dart'; 6 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 7 | import 'package:google_fonts/google_fonts.dart'; 8 | import 'package:provider/provider.dart'; 9 | import 'red_celebrate_page_model.dart'; 10 | export 'red_celebrate_page_model.dart'; 11 | 12 | class RedCelebratePageWidget extends StatefulWidget { 13 | const RedCelebratePageWidget({Key? key}) : super(key: key); 14 | 15 | @override 16 | _RedCelebratePageWidgetState createState() => _RedCelebratePageWidgetState(); 17 | } 18 | 19 | class _RedCelebratePageWidgetState extends State { 20 | late RedCelebratePageModel _model; 21 | 22 | final scaffoldKey = GlobalKey(); 23 | final _unfocusNode = FocusNode(); 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | _model = createModel(context, () => RedCelebratePageModel()); 29 | 30 | logFirebaseEvent('screen_view', 31 | parameters: {'screen_name': 'RedCelebratePage'}); 32 | WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | _model.dispose(); 38 | 39 | _unfocusNode.dispose(); 40 | super.dispose(); 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | context.watch(); 46 | 47 | return GestureDetector( 48 | onTap: () => FocusScope.of(context).requestFocus(_unfocusNode), 49 | child: Scaffold( 50 | key: scaffoldKey, 51 | backgroundColor: FlutterFlowTheme.of(context).alternate, 52 | body: SafeArea( 53 | top: true, 54 | child: Container( 55 | width: double.infinity, 56 | height: double.infinity, 57 | decoration: BoxDecoration( 58 | color: FlutterFlowTheme.of(context).alternate, 59 | ), 60 | child: Stack( 61 | children: [ 62 | Row( 63 | mainAxisSize: MainAxisSize.max, 64 | mainAxisAlignment: MainAxisAlignment.center, 65 | children: [ 66 | Column( 67 | mainAxisSize: MainAxisSize.max, 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | FaIcon( 71 | FontAwesomeIcons.trophy, 72 | color: Color(0xFFFFB938), 73 | size: 90.0, 74 | ), 75 | Text( 76 | 'WINNER', 77 | style: FlutterFlowTheme.of(context) 78 | .bodyMedium 79 | .override( 80 | fontFamily: 'Poppins', 81 | color: 82 | FlutterFlowTheme.of(context).primaryBtnText, 83 | fontSize: 36.0, 84 | ), 85 | ), 86 | Text( 87 | 'Red Team', 88 | style: 89 | FlutterFlowTheme.of(context).bodyMedium.override( 90 | fontFamily: 'Poppins', 91 | color: FlutterFlowTheme.of(context) 92 | .primaryBackground, 93 | fontSize: 36.0, 94 | fontWeight: FontWeight.w500, 95 | ), 96 | ), 97 | Padding( 98 | padding: EdgeInsetsDirectional.fromSTEB( 99 | 0.0, 50.0, 0.0, 0.0), 100 | child: FFButtonWidget( 101 | onPressed: () async { 102 | logFirebaseEvent( 103 | 'RED_CELEBRATE_START_NEW_GAME_BTN_ON_TAP'); 104 | FFAppState().update(() { 105 | FFAppState().words = []; 106 | }); 107 | 108 | context.pushNamed( 109 | 'CreateJoinScreen', 110 | extra: { 111 | kTransitionInfoKey: TransitionInfo( 112 | hasTransition: true, 113 | transitionType: PageTransitionType.fade, 114 | ), 115 | }, 116 | ); 117 | }, 118 | text: 'Start New Game', 119 | options: FFButtonOptions( 120 | width: 200.0, 121 | height: 50.0, 122 | padding: EdgeInsetsDirectional.fromSTEB( 123 | 0.0, 0.0, 0.0, 0.0), 124 | iconPadding: EdgeInsetsDirectional.fromSTEB( 125 | 0.0, 0.0, 0.0, 0.0), 126 | color: Color(0x004B39EF), 127 | textStyle: FlutterFlowTheme.of(context) 128 | .titleSmall 129 | .override( 130 | fontFamily: 'Poppins', 131 | color: Colors.white, 132 | fontWeight: FontWeight.w500, 133 | ), 134 | elevation: 2.0, 135 | borderSide: BorderSide( 136 | color: 137 | FlutterFlowTheme.of(context).primaryBtnText, 138 | width: 4.0, 139 | ), 140 | borderRadius: BorderRadius.circular(16.0), 141 | ), 142 | ), 143 | ), 144 | ], 145 | ), 146 | ], 147 | ), 148 | Container( 149 | width: double.infinity, 150 | height: double.infinity, 151 | child: custom_widgets.ConfettiOverlay( 152 | width: double.infinity, 153 | height: double.infinity, 154 | ), 155 | ), 156 | ], 157 | ), 158 | ), 159 | ), 160 | ), 161 | ); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /lib/pages/create_join_screen/create_join_screen_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/components/game_mode_dialog/game_mode_dialog_widget.dart'; 4 | import '/components/join_game/join_game_widget.dart'; 5 | import '/flutter_flow/flutter_flow_icon_button.dart'; 6 | import '/flutter_flow/flutter_flow_theme.dart'; 7 | import '/flutter_flow/flutter_flow_util.dart'; 8 | import '/flutter_flow/flutter_flow_widgets.dart'; 9 | import 'dart:async'; 10 | import 'package:aligned_dialog/aligned_dialog.dart'; 11 | import 'package:cloud_firestore/cloud_firestore.dart'; 12 | import 'package:flutter/material.dart'; 13 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 14 | import 'package:google_fonts/google_fonts.dart'; 15 | import 'package:provider/provider.dart'; 16 | 17 | class CreateJoinScreenModel extends FlutterFlowModel { 18 | /// State fields for stateful widgets in this page. 19 | 20 | // State field(s) for TextField widget. 21 | TextEditingController? textController; 22 | String? Function(BuildContext, String?)? textControllerValidator; 23 | Completer>? firestoreRequestCompleter; 24 | // Stores action output result for [Backend Call - Create Document] action in Button widget. 25 | PlayersRecord? playerDocumentJoin; 26 | 27 | /// Initialization and disposal methods. 28 | 29 | void initState(BuildContext context) {} 30 | 31 | void dispose() { 32 | textController?.dispose(); 33 | } 34 | 35 | /// Additional helper methods are added here. 36 | 37 | Future waitForFirestoreRequestCompleted({ 38 | double minWait = 0, 39 | double maxWait = double.infinity, 40 | }) async { 41 | final stopwatch = Stopwatch()..start(); 42 | while (true) { 43 | await Future.delayed(Duration(milliseconds: 50)); 44 | final timeElapsed = stopwatch.elapsedMilliseconds; 45 | final requestComplete = firestoreRequestCompleter?.isCompleted ?? false; 46 | if (timeElapsed > maxWait || (requestComplete && timeElapsed > minWait)) { 47 | break; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/pages/game_pages/field_operatives_view/field_operatives_view_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/api_requests/api_calls.dart'; 3 | import '/backend/backend.dart'; 4 | import '/backend/schema/structs/index.dart'; 5 | import '/components/loading_widget/loading_widget_widget.dart'; 6 | import '/flutter_flow/flutter_flow_animations.dart'; 7 | import '/flutter_flow/flutter_flow_icon_button.dart'; 8 | import '/flutter_flow/flutter_flow_theme.dart'; 9 | import '/flutter_flow/flutter_flow_util.dart'; 10 | import '/flutter_flow/flutter_flow_widgets.dart'; 11 | import '/flutter_flow/instant_timer.dart'; 12 | import '/custom_code/actions/index.dart' as actions; 13 | import '/custom_code/widgets/index.dart' as custom_widgets; 14 | import '/flutter_flow/custom_functions.dart' as functions; 15 | import 'package:auto_size_text/auto_size_text.dart'; 16 | import 'package:cloud_firestore/cloud_firestore.dart'; 17 | import 'package:flutter/material.dart'; 18 | import 'package:flutter/scheduler.dart'; 19 | import 'package:flutter_animate/flutter_animate.dart'; 20 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 21 | import 'package:google_fonts/google_fonts.dart'; 22 | import 'package:provider/provider.dart'; 23 | 24 | class FieldOperativesViewModel extends FlutterFlowModel { 25 | /// State fields for stateful widgets in this page. 26 | 27 | InstantTimer? blueAITimer; 28 | // Stores action output result for [Backend Call - API (getClue)] action in Button widget. 29 | ApiCallResponse? blueAIOutput; 30 | InstantTimer? redAITimer; 31 | // Stores action output result for [Backend Call - API (getClue)] action in Button widget. 32 | ApiCallResponse? redAIOutput; 33 | // Stores action output result for [Custom Action - wordTapped] action in WhiteContainer widget. 34 | List? updatedWordsList; 35 | // Stores action output result for [Custom Action - calculateWordsLeft] action in WhiteContainer widget. 36 | dynamic? wordsLeftJson; 37 | // Stores action output result for [Custom Action - getWordColor] action in WhiteContainer widget. 38 | String? wordColor; 39 | InstantTimer? redNeutralAITimer; 40 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 41 | ApiCallResponse? redNeutralAIOutput; 42 | InstantTimer? blueNeutralAITimer; 43 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 44 | ApiCallResponse? blueNeutralAIOutput; 45 | InstantTimer? redEndAITimer; 46 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 47 | ApiCallResponse? redEndAIOutput; 48 | InstantTimer? blueEndAITimer; 49 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 50 | ApiCallResponse? blueEndAIOutput; 51 | // Stores action output result for [Custom Action - declareWinner] action in WhiteContainer widget. 52 | String? winner; 53 | // Stores action output result for [Custom Action - wordTapped] action in WhiteContainer widget. 54 | List? updatedWordsListLarge; 55 | // Stores action output result for [Custom Action - calculateWordsLeft] action in WhiteContainer widget. 56 | dynamic? wordsLeftJsonLarge; 57 | // Stores action output result for [Custom Action - getWordColor] action in WhiteContainer widget. 58 | String? wordColorLarge; 59 | InstantTimer? redNeutralAILargeTimer; 60 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 61 | ApiCallResponse? redNeutralAIOutputLarge; 62 | InstantTimer? blueNeutralAILargeTimer; 63 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 64 | ApiCallResponse? blueNeutralAIOutputLarge; 65 | InstantTimer? blueEndAILargeTimer; 66 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 67 | ApiCallResponse? blueEndAIOutputLarge; 68 | InstantTimer? redEndAILargeTimer; 69 | // Stores action output result for [Backend Call - API (getClue)] action in WhiteContainer widget. 70 | ApiCallResponse? redEndAIOutputLarge; 71 | // Stores action output result for [Custom Action - declareWinner] action in WhiteContainer widget. 72 | String? winnerLarge; 73 | // Stores action output result for [Backend Call - API (getClue)] action in Button widget. 74 | ApiCallResponse? blueAIOutputLarge; 75 | // Stores action output result for [Backend Call - API (getClue)] action in Button widget. 76 | ApiCallResponse? redAIOutputLarge; 77 | 78 | /// Initialization and disposal methods. 79 | 80 | void initState(BuildContext context) {} 81 | 82 | void dispose() { 83 | blueAITimer?.cancel(); 84 | redAITimer?.cancel(); 85 | redNeutralAITimer?.cancel(); 86 | blueNeutralAITimer?.cancel(); 87 | redEndAITimer?.cancel(); 88 | blueEndAITimer?.cancel(); 89 | redNeutralAILargeTimer?.cancel(); 90 | blueNeutralAILargeTimer?.cancel(); 91 | blueEndAILargeTimer?.cancel(); 92 | redEndAILargeTimer?.cancel(); 93 | } 94 | 95 | /// Additional helper methods are added here. 96 | 97 | } 98 | -------------------------------------------------------------------------------- /lib/pages/game_pages/spy_view/spy_view_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/flutter_flow/flutter_flow_animations.dart'; 4 | import '/flutter_flow/flutter_flow_icon_button.dart'; 5 | import '/flutter_flow/flutter_flow_theme.dart'; 6 | import '/flutter_flow/flutter_flow_util.dart'; 7 | import '/flutter_flow/flutter_flow_widgets.dart'; 8 | import '/custom_code/widgets/index.dart' as custom_widgets; 9 | import '/flutter_flow/custom_functions.dart' as functions; 10 | import 'package:auto_size_text/auto_size_text.dart'; 11 | import 'package:flutter/material.dart'; 12 | import 'package:flutter/scheduler.dart'; 13 | import 'package:flutter_animate/flutter_animate.dart'; 14 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 15 | import 'package:google_fonts/google_fonts.dart'; 16 | import 'package:provider/provider.dart'; 17 | 18 | class SpyViewModel extends FlutterFlowModel { 19 | /// Initialization and disposal methods. 20 | 21 | void initState(BuildContext context) {} 22 | 23 | void dispose() {} 24 | 25 | /// Additional helper methods are added here. 26 | 27 | } 28 | -------------------------------------------------------------------------------- /lib/pages/joining_pages/host_page/host_page_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/api_requests/api_calls.dart'; 3 | import '/backend/backend.dart'; 4 | import '/backend/schema/structs/index.dart'; 5 | import '/components/loading_dialog/loading_dialog_widget.dart'; 6 | import '/flutter_flow/flutter_flow_theme.dart'; 7 | import '/flutter_flow/flutter_flow_util.dart'; 8 | import '/flutter_flow/flutter_flow_widgets.dart'; 9 | import '/flutter_flow/instant_timer.dart'; 10 | import '/custom_code/actions/index.dart' as actions; 11 | import '/flutter_flow/custom_functions.dart' as functions; 12 | import 'package:aligned_dialog/aligned_dialog.dart'; 13 | import 'package:cloud_firestore/cloud_firestore.dart'; 14 | import 'package:flutter/material.dart'; 15 | import 'package:flutter_spinkit/flutter_spinkit.dart'; 16 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 17 | import 'package:google_fonts/google_fonts.dart'; 18 | import 'package:provider/provider.dart'; 19 | 20 | class HostPageModel extends FlutterFlowModel { 21 | /// Local state fields for this page. 22 | 23 | bool isLoading = false; 24 | 25 | /// State fields for stateful widgets in this page. 26 | 27 | // Stores action output result for [Custom Action - generateBoardWords] action in FloatingActionButton widget. 28 | List? initialWords; 29 | InstantTimer? AITimer; 30 | // Stores action output result for [Backend Call - API (getClue)] action in FloatingActionButton widget. 31 | ApiCallResponse? aIOutput; 32 | 33 | /// Initialization and disposal methods. 34 | 35 | void initState(BuildContext context) {} 36 | 37 | void dispose() { 38 | AITimer?.cancel(); 39 | } 40 | 41 | /// Additional helper methods are added here. 42 | 43 | } 44 | -------------------------------------------------------------------------------- /lib/pages/joining_pages/player_page/player_page_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/flutter_flow/flutter_flow_theme.dart'; 4 | import '/flutter_flow/flutter_flow_util.dart'; 5 | import '/flutter_flow/flutter_flow_widgets.dart'; 6 | import 'package:cloud_firestore/cloud_firestore.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_spinkit/flutter_spinkit.dart'; 9 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 10 | import 'package:google_fonts/google_fonts.dart'; 11 | import 'package:provider/provider.dart'; 12 | 13 | class PlayerPageModel extends FlutterFlowModel { 14 | /// Initialization and disposal methods. 15 | 16 | void initState(BuildContext context) {} 17 | 18 | void dispose() {} 19 | 20 | /// Additional helper methods are added here. 21 | 22 | } 23 | -------------------------------------------------------------------------------- /lib/pages/start_screen/start_screen_model.dart: -------------------------------------------------------------------------------- 1 | import '/auth/firebase_auth/auth_util.dart'; 2 | import '/backend/backend.dart'; 3 | import '/flutter_flow/flutter_flow_animations.dart'; 4 | import '/flutter_flow/flutter_flow_icon_button.dart'; 5 | import '/flutter_flow/flutter_flow_theme.dart'; 6 | import '/flutter_flow/flutter_flow_util.dart'; 7 | import '/flutter_flow/flutter_flow_widgets.dart'; 8 | import 'package:cloud_firestore/cloud_firestore.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter/scheduler.dart'; 11 | import 'package:flutter_animate/flutter_animate.dart'; 12 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 13 | import 'package:google_fonts/google_fonts.dart'; 14 | import 'package:provider/provider.dart'; 15 | 16 | class StartScreenModel extends FlutterFlowModel { 17 | /// State fields for stateful widgets in this page. 18 | 19 | final formKey = GlobalKey(); 20 | // State field(s) for TextFieldSmall widget. 21 | TextEditingController? textFieldSmallController; 22 | String? Function(BuildContext, String?)? textFieldSmallControllerValidator; 23 | // State field(s) for TextFieldLarge widget. 24 | TextEditingController? textFieldLargeController; 25 | String? Function(BuildContext, String?)? textFieldLargeControllerValidator; 26 | 27 | /// Initialization and disposal methods. 28 | 29 | void initState(BuildContext context) {} 30 | 31 | void dispose() { 32 | textFieldSmallController?.dispose(); 33 | textFieldLargeController?.dispose(); 34 | } 35 | 36 | /// Additional helper methods are added here. 37 | 38 | } 39 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: codewords 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | flutter_localizations: 27 | sdk: flutter 28 | aligned_dialog: 0.0.6 29 | auto_size_text: 3.0.0 30 | cached_network_image: 3.2.1 31 | cloud_firestore: 4.2.0 32 | cloud_firestore_platform_interface: 5.9.1 33 | cloud_firestore_web: 3.1.1 34 | cloud_functions: 4.0.6 35 | cloud_functions_platform_interface: 5.1.25 36 | cloud_functions_web: 4.3.14 37 | confetti: 0.6.0 38 | equatable: 2.0.3 39 | firebase_analytics: 10.0.7 40 | firebase_analytics_platform_interface: 3.3.15 41 | firebase_analytics_web: 0.5.1+6 42 | firebase_auth: 4.2.0 43 | firebase_auth_platform_interface: 6.11.4 44 | firebase_auth_web: 5.2.0 45 | firebase_core: 2.4.0 46 | firebase_core_platform_interface: 4.5.2 47 | firebase_core_web: 2.0.2 48 | flutter_animate: 4.1.1+1 49 | flutter_cache_manager: 3.3.0 50 | flutter_spinkit: 5.1.0 51 | font_awesome_flutter: 10.1.0 52 | from_css_color: 2.0.0 53 | go_router: 7.1.1 54 | google_fonts: 4.0.3 55 | google_sign_in: 6.0.2 56 | google_sign_in_android: 6.1.8 57 | google_sign_in_ios: 5.6.1 58 | google_sign_in_platform_interface: 2.4.0 59 | google_sign_in_web: 0.11.0+2 60 | intl: 0.17.0 61 | json_path: 0.4.1 62 | mime_type: 1.0.0 63 | page_transition: 2.0.4 64 | path_provider: 2.0.14 65 | path_provider_android: 2.0.25 66 | path_provider_foundation: 2.2.2 67 | path_provider_platform_interface: 2.0.6 68 | plugin_platform_interface: 2.1.3 69 | provider: 6.0.4 70 | rxdart: 0.27.7 71 | shared_preferences: 2.0.15 72 | shared_preferences_android: 2.1.0 73 | shared_preferences_ios: 2.1.1 74 | shared_preferences_platform_interface: 2.2.0 75 | shared_preferences_web: 2.1.0 76 | sign_in_with_apple: 4.3.0 77 | sign_in_with_apple_platform_interface: 1.0.0 78 | sign_in_with_apple_web: 1.0.1 79 | sqflite: 2.2.6 80 | stream_transform: 2.1.0 81 | timeago: 3.2.2 82 | url_launcher: 6.1.10 83 | url_launcher_android: 6.0.27 84 | url_launcher_ios: 6.1.4 85 | url_launcher_platform_interface: 2.1.2 86 | 87 | 88 | # The following adds the Cupertino Icons font to your application. 89 | # Use with the CupertinoIcons class for iOS style icons. 90 | cupertino_icons: ^1.0.0 91 | 92 | dev_dependencies: 93 | flutter_launcher_icons: 0.12.0 94 | 95 | flutter_test: 96 | sdk: flutter 97 | 98 | 99 | flutter_icons: 100 | android: true 101 | ios: true 102 | remove_alpha_ios: true 103 | image_path: 'assets/images/app_launcher_icon.png' 104 | 105 | 106 | # For information on the generic Dart part of this file, see the 107 | # following page: https://dart.dev/tools/pub/pubspec 108 | 109 | # The following section is specific to Flutter. 110 | flutter: 111 | 112 | # The following line ensures that the Material Icons font is 113 | # included with your application, so that you can use the icons in 114 | # the material Icons class. 115 | uses-material-design: true 116 | 117 | # To add assets to your application, add an assets section, like this: 118 | assets: 119 | - assets/fonts/ 120 | - assets/images/ 121 | - assets/videos/ 122 | - assets/audios/ 123 | - assets/lottie_animations/ 124 | - assets/rive_animations/ 125 | - assets/pdfs/ 126 | 127 | 128 | 129 | # An image asset can refer to one or more resolution-specific "variants", see 130 | # https://flutter.dev/assets-and-images/#resolution-aware. 131 | 132 | # For details regarding adding assets from package dependencies, see 133 | # https://flutter.dev/assets-and-images/#from-packages 134 | 135 | # To add custom fonts to your application, add a fonts section here, 136 | # in this "flutter" section. Each entry in this list should have a 137 | # "family" key with the font family name, and a "fonts" key with a 138 | # list giving the asset and other descriptors for the font. For 139 | # example: 140 | # fonts: 141 | # - family: Schyler 142 | # fonts: 143 | # - asset: fonts/Schyler-Regular.ttf 144 | # - asset: fonts/Schyler-Italic.ttf 145 | # style: italic 146 | # - family: Trajan Pro 147 | # fonts: 148 | # - asset: fonts/TrajanPro.ttf 149 | # - asset: fonts/TrajanPro_Bold.ttf 150 | # weight: 700 151 | # 152 | # For details regarding fonts from package dependencies, 153 | # see https://flutter.dev/custom-fonts/#from-packages 154 | -------------------------------------------------------------------------------- /screenshots/codewords_ai_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/screenshots/codewords_ai_mode.png -------------------------------------------------------------------------------- /screenshots/codewords_screens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/screenshots/codewords_screens.png -------------------------------------------------------------------------------- /screenshots/codewords_screens_2_rows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/screenshots/codewords_screens_2_rows.png -------------------------------------------------------------------------------- /screenshots/codewords_screens_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/screenshots/codewords_screens_new.png -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:codewords/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /web/codewords_game_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/codewords_game_cover.png -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/favicon.png -------------------------------------------------------------------------------- /web/favicon_codewords.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/favicon_codewords.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/app_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbis04/codewords_FF/d54b817018bca86437b2c1dfc409dac21d9363d6/web/icons/app_launcher_icon.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Codewords 42 | 43 | 44 | 45 | 46 | 47 | 48 | 51 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Codewords", 3 | "short_name": "Codewords", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/app_launcher_icon.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/app_launcher_icon.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------