├── .gitignore ├── .metadata ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_firebase_auth_starter │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── images │ ├── default.png │ ├── default.svg │ ├── defaultDark.png │ └── defaultold.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── constants │ ├── app_themes.dart │ ├── constants.dart │ ├── globals.dart │ └── routes.dart ├── helpers │ ├── helpers.dart │ └── validator.dart ├── localizations.dart ├── localizations.g.dart ├── main.dart ├── models │ ├── menu_option_model.dart │ ├── models.dart │ └── user_model.dart ├── services │ ├── auth_service.dart │ ├── auth_widget_builder.dart │ ├── language_provider.dart │ ├── services.dart │ └── theme_provider.dart ├── store │ ├── shared_preference_helper.dart │ └── store.dart └── ui │ ├── auth │ ├── auth.dart │ ├── reset_password_ui.dart │ ├── sign_in_options_ui.dart │ ├── sign_in_ui.dart │ ├── sign_up_ui.dart │ └── update_profile_ui.dart │ ├── components │ ├── avatar.dart │ ├── components.dart │ ├── dropdown_picker.dart │ ├── dropdown_picker_with_icon.dart │ ├── form_input_field.dart │ ├── form_input_field_with_icon.dart │ ├── form_vertical_spacing.dart │ ├── label_button.dart │ ├── loading_screen.dart │ ├── logo_graphic_header.dart │ ├── primary_button.dart │ ├── segmented_selector.dart │ └── sliding_segmented_control.dart │ ├── home_ui.dart │ ├── settings_ui.dart │ └── ui.dart ├── pubspec.lock ├── pubspec.yaml └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/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 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | # added by delay 46 | /ios/Flutter/ -------------------------------------------------------------------------------- /.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: e0c63cd35e15e407a80dc44281cc392535fcce25 8 | channel: dev 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Flutter Firebase Auth Starter Project 2 | 3 | ![Screenshots](https://cdn-images-1.medium.com/max/4776/1*wOmpyN5Poy2Y7u4NMmpj9g.png) 4 | 5 | ## I have [remade](https://github.com/delay/flutter_starter) this project with [GetX](https://github.com/jonataslaw/getx). I find the code is simpler. This project makes use of Provider. The GetX version is [here](https://github.com/delay/flutter_starter). I will no longer maintain this code. 6 | 7 | So why do another Auth project for flutter? There are dozens of projects already. Including [this one](https://medium.com/@jeffmcmorris/flutter-auth-with-firebase-example-96b64375fff3) I did last year when I was starting with flutter. I made this project for myself because none of the other projects had all of the features I needed. I wanted light and dark mode theming but also the ability to detect and switch themes automatically. I also wanted the ability to switch between languages easily and automatically detect the user’s language. I wanted a simple way to handle translating from english (the only language I know unfortunately). This is accomplished through the excellent package [flutter_sheet_localization](https://github.com/aloisdeniel/flutter_sheet_localization) which allows you to put your translation into a [google sheet](https://docs.google.com/spreadsheets/d/1oS7iJ6ocrZBA53SxRfKF0CG9HAaXeKtzvsTBhgG4Zzk/edit#gid=0) and easily translate into other languages. Also I needed a way to [do simple user roles](https://medium.com/firebase-developers/patterns-for-security-with-firebase-group-based-permissions-for-cloud-firestore-72859cdec8f6) and it needed to be secure. I see a lot of auth packages including roles in the user’s collection in firestore which is usually editable by that same user. This would make it trivial for the user to assign himself admin privileges. I also wanted to show how to put some basic rules in firestore to secure it. Finally I wanted to have a way the user could alter their profile and change their email or password. 8 | 9 | There are some really good projects and tutorials that I made use of in making this project. I highly recommend reviewing these other projects as they are much better at explaining things than I am and are far more knowledgeable. Fireship.io [quiz app](https://github.com/fireship-io/flutter-firebase-quizapp-course) and [courses](http://fireship.io) on flutter, [Code with Andrea](https://codewithandrea.com/), and this [starter project](https://github.com/KenAragorn/create_flutter_provider_app) by Ken Aragorn which was my starting point for my own stab at a starter project. 10 | 11 | To handle the language translation I used this [package](https://github.com/aloisdeniel/flutter_sheet_localization) which has excellent instructions on how to setup and use it. You need to create a translation for your app in google sheets. 12 | 13 | ![Google Sheets translation file](https://cdn-images-1.medium.com/max/2000/1*7ltKsU-Tmn418km0gGDftA.png) 14 | 15 | You can copy my [sheet](https://docs.google.com/spreadsheets/d/1oS7iJ6ocrZBA53SxRfKF0CG9HAaXeKtzvsTBhgG4Zzk/edit#gid=0) as a starting point for your own app. The cool thing about using a google sheet is you can have google translate a field with a simple google formula: `=GOOGLETRANSLATE(B4,en,fr)` This says translate the phrase in field B4 from english to french. Once you set this package up every time you make changes to your translation in google sheets, you delete your old localizations.g.dart then run the command: flutter packages pub run build_runner build This creates the localizations generated file again. 16 | 17 | To handle user roles I created a separate admin collection and added a document with the same document id as the uid of my user. The reason to do this is to make it secure as explained in this [medium article](https://medium.com/firebase-developers/patterns-for-security-with-firebase-group-based-permissions-for-cloud-firestore-72859cdec8f6). I went with the second method explained in that article. If we had just put the roles as a field in the users collection any user could have upgraded themselves to an admin user. So by moving the admin role to a separate collection we can create some rules in firestore that allow the user to update fields about themselves without giving them access to change the role they were assigned. You can also generate other roles for the user by simply adding additional collections for the other roles.. 18 | 19 | The rules I have setup in firestore for this project are fairly simple. Here are the rules I have created. 20 | 21 | ![firestore rules](https://cdn-images-1.medium.com/max/2000/1*fug6buAigKDnzzXXxvAgMg.png) 22 | 23 | The first rule matches any user in the admin collection and allows you to read that document only. No one is allowed to write to this collection. I manually add my admin users through the firebase console. The second rule allows the user to read and write only if the user matches the currently logged in user. So a user can only change information about themselves. Here is how my collections are setup in firestore. 24 | 25 | ![firestore collections](https://cdn-images-1.medium.com/max/2060/1*7xKVCWZggfwr7Y8KLs6z6g.png) 26 | 27 | Finally I wanted to explain a little bit about my ui. I try to control as much as possible with the theme. You can change a lot about the look with the user interface by changing the theme. I am still learning about what all can be changed with just the theme. I also break out small ui components into a separate components folder. Then I make a custom widget instead of using the standard widget directly. This allows me to make changes in one spot if I decide to make ui changes to say a form field in my form_input_field.dart instead of changing a bunch of TextFormField widgets spread through a dozen files. 28 | 29 | ## **Overview of project** 30 | 31 | **main.dart**— contains provider info for maintaining the state of the app for the theme, language and user. It initializes language and theme settings. Sets up routing and monitors the user for changes. 32 | 33 | **localizations.dart**— controls the language for the app. 34 | 35 | **localizations.g.dart** — this file is generated from our google sheet by the [flutter_sheet_localization](https://github.com/aloisdeniel/flutter_sheet_localization) package (do not manually edit this file). 36 | 37 | ## **/constants/** 38 | 39 | **app_themes.dart**— contains info related to our light and dark themes. 40 | 41 | **globals.dart** — contains some global app settings 42 | 43 | **routes.dart**— contains the app routes. 44 | 45 | ## /helpers/ 46 | 47 | **validator.dart**— contains some validation functions for our form fields. 48 | 49 | ## /models/ 50 | 51 | **user_model.dart**— contains the model for our user saved in firestore. 52 | 53 | **menu_option_model.dart** — contains our model for our language options and theme options in settings. 54 | 55 | ## /services/ 56 | 57 | **auth_widget_builder.dart** - holds our provider user data and initializes the user in the app. 58 | 59 | **auth_service.dart** — our user and authentication functions for creating, logging in and out our user and saving our user data. 60 | 61 | **language_provider.dart** — saves and loads our language. 62 | 63 | **theme_provider.dart**— saves and loads our theme. 64 | 65 | ## /store/ 66 | 67 | **shared_preferences_helper.dart**— saves our theme and language locally. 68 | 69 | ## /ui/ 70 | 71 | **home_ui.dart** — contains the ui for the home which shows info about the user. 72 | 73 | **settings_ui.dart** — contains the settings screen for setting the theme and language and some user settings. 74 | 75 | ## /ui/auth/ 76 | 77 | **reset_password_ui.dart**— sends a password reset email to the user. 78 | 79 | **sign_in_options_ui.dart** — (not currently in use) but provides other login options. 80 | 81 | **sign_in_ui.dart**— allows user to login with email and password. 82 | 83 | **sign_up_ui.dart**— allows user to create a new account. 84 | 85 | **update_profile_ui.dart**— allows user to change his email or name. 86 | 87 | ## /ui/components/ 88 | 89 | **avatar.dart** — displays a user avatar on the home_ui. 90 | 91 | **dropdown_picker.dart** — shows a dropdown list. 92 | 93 | **dropdown_picker_with_icon.dart** — shows a dropdown list with icons. 94 | 95 | **form_input_field.dart** — handles our form field elements. 96 | 97 | **form_input_field_with_icon.dart** — handles our form field elements but has an icon too. 98 | 99 | **form_vertical_spacing.dart** — just a space in the ui. 100 | 101 | **label_button.dart** — one type of button in ui. 102 | 103 | **logo_graphic_header.dart**— a graphic displayed in our ui. 104 | 105 | **primary_button.dart** — another button in the ui. 106 | 107 | **segmented_selector.dart** — a control used to select the theme. 108 | 109 | **sliding_segmented_control.dart** — some modifications of the Cupertino control which is used by segmented_selector.dart. 110 | 111 | Anyway hopefully this project will help someone. Feel free to use any of it, I didn't create all of this code as parts of it came from watching the tutorials and reviewing the projects mentioned above. Make sure you [setup firebase](https://firebase.google.com/docs/flutter/setup?platform=android) with your project. 112 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.flutter_firebase_auth_starter" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_firebase_auth_starter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_firebase_auth_starter 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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /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.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #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-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | include ':app' 6 | 7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 8 | def properties = new Properties() 9 | 10 | assert localPropertiesFile.exists() 11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 12 | 13 | def flutterSdkPath = properties.getProperty("flutter.sdk") 14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 16 | -------------------------------------------------------------------------------- /assets/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/assets/images/default.png -------------------------------------------------------------------------------- /assets/images/default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Combined Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /assets/images/defaultDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/assets/images/defaultDark.png -------------------------------------------------------------------------------- /assets/images/defaultold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/assets/images/defaultold.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 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | post_install do |installer| 82 | installer.pods_project.targets.each do |target| 83 | target.build_configurations.each do |config| 84 | config.build_settings['ENABLE_BITCODE'] = 'NO' 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - abseil/algorithm (0.20190808): 3 | - abseil/algorithm/algorithm (= 0.20190808) 4 | - abseil/algorithm/container (= 0.20190808) 5 | - abseil/algorithm/algorithm (0.20190808) 6 | - abseil/algorithm/container (0.20190808): 7 | - abseil/algorithm/algorithm 8 | - abseil/base/core_headers 9 | - abseil/meta/type_traits 10 | - abseil/base (0.20190808): 11 | - abseil/base/atomic_hook (= 0.20190808) 12 | - abseil/base/base (= 0.20190808) 13 | - abseil/base/base_internal (= 0.20190808) 14 | - abseil/base/bits (= 0.20190808) 15 | - abseil/base/config (= 0.20190808) 16 | - abseil/base/core_headers (= 0.20190808) 17 | - abseil/base/dynamic_annotations (= 0.20190808) 18 | - abseil/base/endian (= 0.20190808) 19 | - abseil/base/log_severity (= 0.20190808) 20 | - abseil/base/malloc_internal (= 0.20190808) 21 | - abseil/base/pretty_function (= 0.20190808) 22 | - abseil/base/spinlock_wait (= 0.20190808) 23 | - abseil/base/throw_delegate (= 0.20190808) 24 | - abseil/base/atomic_hook (0.20190808) 25 | - abseil/base/base (0.20190808): 26 | - abseil/base/atomic_hook 27 | - abseil/base/base_internal 28 | - abseil/base/config 29 | - abseil/base/core_headers 30 | - abseil/base/dynamic_annotations 31 | - abseil/base/log_severity 32 | - abseil/base/spinlock_wait 33 | - abseil/meta/type_traits 34 | - abseil/base/base_internal (0.20190808): 35 | - abseil/meta/type_traits 36 | - abseil/base/bits (0.20190808): 37 | - abseil/base/core_headers 38 | - abseil/base/config (0.20190808) 39 | - abseil/base/core_headers (0.20190808): 40 | - abseil/base/config 41 | - abseil/base/dynamic_annotations (0.20190808) 42 | - abseil/base/endian (0.20190808): 43 | - abseil/base/config 44 | - abseil/base/core_headers 45 | - abseil/base/log_severity (0.20190808): 46 | - abseil/base/core_headers 47 | - abseil/base/malloc_internal (0.20190808): 48 | - abseil/base/base 49 | - abseil/base/config 50 | - abseil/base/core_headers 51 | - abseil/base/dynamic_annotations 52 | - abseil/base/spinlock_wait 53 | - abseil/base/pretty_function (0.20190808) 54 | - abseil/base/spinlock_wait (0.20190808): 55 | - abseil/base/core_headers 56 | - abseil/base/throw_delegate (0.20190808): 57 | - abseil/base/base 58 | - abseil/base/config 59 | - abseil/memory (0.20190808): 60 | - abseil/memory/memory (= 0.20190808) 61 | - abseil/memory/memory (0.20190808): 62 | - abseil/base/core_headers 63 | - abseil/meta/type_traits 64 | - abseil/meta (0.20190808): 65 | - abseil/meta/type_traits (= 0.20190808) 66 | - abseil/meta/type_traits (0.20190808): 67 | - abseil/base/config 68 | - abseil/numeric/int128 (0.20190808): 69 | - abseil/base/config 70 | - abseil/base/core_headers 71 | - abseil/strings/internal (0.20190808): 72 | - abseil/base/core_headers 73 | - abseil/base/endian 74 | - abseil/meta/type_traits 75 | - abseil/strings/strings (0.20190808): 76 | - abseil/base/base 77 | - abseil/base/bits 78 | - abseil/base/config 79 | - abseil/base/core_headers 80 | - abseil/base/endian 81 | - abseil/base/throw_delegate 82 | - abseil/memory/memory 83 | - abseil/meta/type_traits 84 | - abseil/numeric/int128 85 | - abseil/strings/internal 86 | - abseil/time (0.20190808): 87 | - abseil/time/internal (= 0.20190808) 88 | - abseil/time/time (= 0.20190808) 89 | - abseil/time/internal (0.20190808): 90 | - abseil/time/internal/cctz (= 0.20190808) 91 | - abseil/time/internal/cctz (0.20190808): 92 | - abseil/time/internal/cctz/civil_time (= 0.20190808) 93 | - abseil/time/internal/cctz/includes (= 0.20190808) 94 | - abseil/time/internal/cctz/time_zone (= 0.20190808) 95 | - abseil/time/internal/cctz/civil_time (0.20190808) 96 | - abseil/time/internal/cctz/includes (0.20190808) 97 | - abseil/time/internal/cctz/time_zone (0.20190808): 98 | - abseil/time/internal/cctz/civil_time 99 | - abseil/time/time (0.20190808): 100 | - abseil/base/base 101 | - abseil/base/core_headers 102 | - abseil/numeric/int128 103 | - abseil/strings/strings 104 | - abseil/time/internal/cctz/civil_time 105 | - abseil/time/internal/cctz/time_zone 106 | - abseil/types (0.20190808): 107 | - abseil/types/any (= 0.20190808) 108 | - abseil/types/bad_any_cast (= 0.20190808) 109 | - abseil/types/bad_any_cast_impl (= 0.20190808) 110 | - abseil/types/bad_optional_access (= 0.20190808) 111 | - abseil/types/bad_variant_access (= 0.20190808) 112 | - abseil/types/compare (= 0.20190808) 113 | - abseil/types/optional (= 0.20190808) 114 | - abseil/types/span (= 0.20190808) 115 | - abseil/types/variant (= 0.20190808) 116 | - abseil/types/any (0.20190808): 117 | - abseil/base/config 118 | - abseil/base/core_headers 119 | - abseil/meta/type_traits 120 | - abseil/types/bad_any_cast 121 | - abseil/utility/utility 122 | - abseil/types/bad_any_cast (0.20190808): 123 | - abseil/base/config 124 | - abseil/types/bad_any_cast_impl 125 | - abseil/types/bad_any_cast_impl (0.20190808): 126 | - abseil/base/base 127 | - abseil/base/config 128 | - abseil/types/bad_optional_access (0.20190808): 129 | - abseil/base/base 130 | - abseil/base/config 131 | - abseil/types/bad_variant_access (0.20190808): 132 | - abseil/base/base 133 | - abseil/base/config 134 | - abseil/types/compare (0.20190808): 135 | - abseil/base/core_headers 136 | - abseil/meta/type_traits 137 | - abseil/types/optional (0.20190808): 138 | - abseil/base/base_internal 139 | - abseil/base/config 140 | - abseil/base/core_headers 141 | - abseil/memory/memory 142 | - abseil/meta/type_traits 143 | - abseil/types/bad_optional_access 144 | - abseil/utility/utility 145 | - abseil/types/span (0.20190808): 146 | - abseil/algorithm/algorithm 147 | - abseil/base/core_headers 148 | - abseil/base/throw_delegate 149 | - abseil/meta/type_traits 150 | - abseil/types/variant (0.20190808): 151 | - abseil/base/base_internal 152 | - abseil/base/config 153 | - abseil/base/core_headers 154 | - abseil/meta/type_traits 155 | - abseil/types/bad_variant_access 156 | - abseil/utility/utility 157 | - abseil/utility/utility (0.20190808): 158 | - abseil/base/base_internal 159 | - abseil/base/config 160 | - abseil/meta/type_traits 161 | - BoringSSL-GRPC (0.0.3): 162 | - BoringSSL-GRPC/Implementation (= 0.0.3) 163 | - BoringSSL-GRPC/Interface (= 0.0.3) 164 | - BoringSSL-GRPC/Implementation (0.0.3): 165 | - BoringSSL-GRPC/Interface (= 0.0.3) 166 | - BoringSSL-GRPC/Interface (0.0.3) 167 | - cloud_firestore (0.0.1): 168 | - Firebase/Core 169 | - Firebase/Firestore (~> 6.0) 170 | - Flutter 171 | - cloud_firestore_web (0.1.0): 172 | - Flutter 173 | - Firebase/Analytics (6.20.0): 174 | - Firebase/Core 175 | - Firebase/Auth (6.20.0): 176 | - Firebase/CoreOnly 177 | - FirebaseAuth (~> 6.5.0) 178 | - Firebase/Core (6.20.0): 179 | - Firebase/CoreOnly 180 | - FirebaseAnalytics (= 6.3.1) 181 | - Firebase/CoreOnly (6.20.0): 182 | - FirebaseCore (= 6.6.4) 183 | - Firebase/Firestore (6.20.0): 184 | - Firebase/CoreOnly 185 | - FirebaseFirestore (~> 1.11.2) 186 | - firebase_analytics (0.0.1): 187 | - Firebase/Analytics (~> 6.0) 188 | - Firebase/Core 189 | - Flutter 190 | - firebase_auth (0.0.1): 191 | - Firebase/Auth (~> 6.3) 192 | - Firebase/Core 193 | - Flutter 194 | - firebase_auth_web (0.1.0): 195 | - Flutter 196 | - firebase_core (0.0.1): 197 | - Firebase/Core 198 | - Flutter 199 | - firebase_core_web (0.1.0): 200 | - Flutter 201 | - FirebaseAnalytics (6.3.1): 202 | - FirebaseCore (~> 6.6) 203 | - FirebaseInstallations (~> 1.1) 204 | - GoogleAppMeasurement (= 6.3.1) 205 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 206 | - GoogleUtilities/MethodSwizzler (~> 6.0) 207 | - GoogleUtilities/Network (~> 6.0) 208 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 209 | - nanopb (= 0.3.9011) 210 | - FirebaseAuth (6.5.0): 211 | - FirebaseAuthInterop (~> 1.0) 212 | - FirebaseCore (~> 6.6) 213 | - GoogleUtilities/AppDelegateSwizzler (~> 6.5) 214 | - GoogleUtilities/Environment (~> 6.5) 215 | - GTMSessionFetcher/Core (~> 1.1) 216 | - FirebaseAuthInterop (1.1.0) 217 | - FirebaseCore (6.6.4): 218 | - FirebaseCoreDiagnostics (~> 1.2) 219 | - FirebaseCoreDiagnosticsInterop (~> 1.2) 220 | - GoogleUtilities/Environment (~> 6.5) 221 | - GoogleUtilities/Logger (~> 6.5) 222 | - FirebaseCoreDiagnostics (1.2.2): 223 | - FirebaseCoreDiagnosticsInterop (~> 1.2) 224 | - GoogleDataTransportCCTSupport (~> 2.0) 225 | - GoogleUtilities/Environment (~> 6.5) 226 | - GoogleUtilities/Logger (~> 6.5) 227 | - nanopb (~> 0.3.901) 228 | - FirebaseCoreDiagnosticsInterop (1.2.0) 229 | - FirebaseFirestore (1.11.2): 230 | - abseil/algorithm (= 0.20190808) 231 | - abseil/base (= 0.20190808) 232 | - abseil/memory (= 0.20190808) 233 | - abseil/meta (= 0.20190808) 234 | - abseil/strings/strings (= 0.20190808) 235 | - abseil/time (= 0.20190808) 236 | - abseil/types (= 0.20190808) 237 | - FirebaseAuthInterop (~> 1.0) 238 | - FirebaseCore (~> 6.2) 239 | - "gRPC-C++ (= 0.0.9)" 240 | - leveldb-library (~> 1.22) 241 | - nanopb (~> 0.3.901) 242 | - FirebaseInstallations (1.1.0): 243 | - FirebaseCore (~> 6.6) 244 | - GoogleUtilities/UserDefaults (~> 6.5) 245 | - PromisesObjC (~> 1.2) 246 | - Flutter (1.0.0) 247 | - GoogleAppMeasurement (6.3.1): 248 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 249 | - GoogleUtilities/MethodSwizzler (~> 6.0) 250 | - GoogleUtilities/Network (~> 6.0) 251 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 252 | - nanopb (= 0.3.9011) 253 | - GoogleDataTransport (5.0.0) 254 | - GoogleDataTransportCCTSupport (2.0.0): 255 | - GoogleDataTransport (~> 5.0) 256 | - nanopb (~> 0.3.901) 257 | - GoogleUtilities/AppDelegateSwizzler (6.5.2): 258 | - GoogleUtilities/Environment 259 | - GoogleUtilities/Logger 260 | - GoogleUtilities/Network 261 | - GoogleUtilities/Environment (6.5.2) 262 | - GoogleUtilities/Logger (6.5.2): 263 | - GoogleUtilities/Environment 264 | - GoogleUtilities/MethodSwizzler (6.5.2): 265 | - GoogleUtilities/Logger 266 | - GoogleUtilities/Network (6.5.2): 267 | - GoogleUtilities/Logger 268 | - "GoogleUtilities/NSData+zlib" 269 | - GoogleUtilities/Reachability 270 | - "GoogleUtilities/NSData+zlib (6.5.2)" 271 | - GoogleUtilities/Reachability (6.5.2): 272 | - GoogleUtilities/Logger 273 | - GoogleUtilities/UserDefaults (6.5.2): 274 | - GoogleUtilities/Logger 275 | - "gRPC-C++ (0.0.9)": 276 | - "gRPC-C++/Implementation (= 0.0.9)" 277 | - "gRPC-C++/Interface (= 0.0.9)" 278 | - "gRPC-C++/Implementation (0.0.9)": 279 | - "gRPC-C++/Interface (= 0.0.9)" 280 | - gRPC-Core (= 1.21.0) 281 | - nanopb (~> 0.3) 282 | - "gRPC-C++/Interface (0.0.9)" 283 | - gRPC-Core (1.21.0): 284 | - gRPC-Core/Implementation (= 1.21.0) 285 | - gRPC-Core/Interface (= 1.21.0) 286 | - gRPC-Core/Implementation (1.21.0): 287 | - BoringSSL-GRPC (= 0.0.3) 288 | - gRPC-Core/Interface (= 1.21.0) 289 | - nanopb (~> 0.3) 290 | - gRPC-Core/Interface (1.21.0) 291 | - GTMSessionFetcher/Core (1.3.1) 292 | - leveldb-library (1.22) 293 | - nanopb (0.3.9011): 294 | - nanopb/decode (= 0.3.9011) 295 | - nanopb/encode (= 0.3.9011) 296 | - nanopb/decode (0.3.9011) 297 | - nanopb/encode (0.3.9011) 298 | - PromisesObjC (1.2.8) 299 | - shared_preferences (0.0.1): 300 | - Flutter 301 | - shared_preferences_macos (0.0.1): 302 | - Flutter 303 | - shared_preferences_web (0.0.1): 304 | - Flutter 305 | 306 | DEPENDENCIES: 307 | - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) 308 | - cloud_firestore_web (from `.symlinks/plugins/cloud_firestore_web/ios`) 309 | - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) 310 | - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) 311 | - firebase_auth_web (from `.symlinks/plugins/firebase_auth_web/ios`) 312 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`) 313 | - firebase_core_web (from `.symlinks/plugins/firebase_core_web/ios`) 314 | - Flutter (from `Flutter`) 315 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 316 | - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) 317 | - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) 318 | 319 | SPEC REPOS: 320 | trunk: 321 | - abseil 322 | - BoringSSL-GRPC 323 | - Firebase 324 | - FirebaseAnalytics 325 | - FirebaseAuth 326 | - FirebaseAuthInterop 327 | - FirebaseCore 328 | - FirebaseCoreDiagnostics 329 | - FirebaseCoreDiagnosticsInterop 330 | - FirebaseFirestore 331 | - FirebaseInstallations 332 | - GoogleAppMeasurement 333 | - GoogleDataTransport 334 | - GoogleDataTransportCCTSupport 335 | - GoogleUtilities 336 | - "gRPC-C++" 337 | - gRPC-Core 338 | - GTMSessionFetcher 339 | - leveldb-library 340 | - nanopb 341 | - PromisesObjC 342 | 343 | EXTERNAL SOURCES: 344 | cloud_firestore: 345 | :path: ".symlinks/plugins/cloud_firestore/ios" 346 | cloud_firestore_web: 347 | :path: ".symlinks/plugins/cloud_firestore_web/ios" 348 | firebase_analytics: 349 | :path: ".symlinks/plugins/firebase_analytics/ios" 350 | firebase_auth: 351 | :path: ".symlinks/plugins/firebase_auth/ios" 352 | firebase_auth_web: 353 | :path: ".symlinks/plugins/firebase_auth_web/ios" 354 | firebase_core: 355 | :path: ".symlinks/plugins/firebase_core/ios" 356 | firebase_core_web: 357 | :path: ".symlinks/plugins/firebase_core_web/ios" 358 | Flutter: 359 | :path: Flutter 360 | shared_preferences: 361 | :path: ".symlinks/plugins/shared_preferences/ios" 362 | shared_preferences_macos: 363 | :path: ".symlinks/plugins/shared_preferences_macos/ios" 364 | shared_preferences_web: 365 | :path: ".symlinks/plugins/shared_preferences_web/ios" 366 | 367 | SPEC CHECKSUMS: 368 | abseil: 18063d773f5366ff8736a050fe035a28f635fd27 369 | BoringSSL-GRPC: db8764df3204ccea016e1c8dd15d9a9ad63ff318 370 | cloud_firestore: 31454d48df21f3e1a900015e36143c0d46a304b7 371 | cloud_firestore_web: 9ec3dc7f5f98de5129339802d491c1204462bfec 372 | Firebase: fe7f74012742ab403451dd283e6909b8f1fb348a 373 | firebase_analytics: dacdcfc524d722fff13dcff942f0dfa47e6be567 374 | firebase_auth: 4ee3a54d3f09434c508c284a62f895a741a30637 375 | firebase_auth_web: 0955c07bcc06e84af76b9d4e32e6f31518f2d7de 376 | firebase_core: 0d8be0e0d14c4902953aeb5ac5d7316d1fe4b978 377 | firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1 378 | FirebaseAnalytics: 572e467f3d977825266e8ccd52674aa3e6f47eac 379 | FirebaseAuth: 648892fd0afeb27ef97c1d2e667329855f1004bc 380 | FirebaseAuthInterop: a0f37ae05833af156e72028f648d313f7e7592e9 381 | FirebaseCore: ed0a24c758a57c2b88c5efa8e6a8195e868af589 382 | FirebaseCoreDiagnostics: e9b4cd8ba60dee0f2d13347332e4b7898cca5b61 383 | FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850 384 | FirebaseFirestore: 71925e62a5d1cbfaff46aa4d5107e525cc48356a 385 | FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b 386 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 387 | GoogleAppMeasurement: c29d405ff76e18551b5d158eaba6753fda8c7542 388 | GoogleDataTransport: a857c6a002d201b524dd4bc2ed7e7355ed07e785 389 | GoogleDataTransportCCTSupport: 32f75fbe904c82772fcbb6b6bd4525bfb6f2a862 390 | GoogleUtilities: ad0f3b691c67909d03a3327cc205222ab8f42e0e 391 | "gRPC-C++": 9dfe7b44821e7b3e44aacad2af29d2c21f7cde83 392 | gRPC-Core: c9aef9a261a1247e881b18059b84d597293c9947 393 | GTMSessionFetcher: cea130bbfe5a7edc8d06d3f0d17288c32ffe9925 394 | leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 395 | nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd 396 | PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6 397 | shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01 398 | shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 399 | shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 400 | 401 | PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a 402 | 403 | COCOAPODS: 1.9.1 404 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 2E22700D9E53398595D0A885 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C943A28E081525A9F6A2ED4 /* Pods_Runner.framework */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 35 | 17D6B5BF8C41B8A702D965E2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 52FDDBD0A1A74729D48F257D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 38 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 39 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 41 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 42 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 43 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 9C943A28E081525A9F6A2ED4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | C276AA4893264FC76325D331 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 2E22700D9E53398595D0A885 /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 9740EEB11CF90186004384FC /* Flutter */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 68 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 69 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 70 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 71 | ); 72 | name = Flutter; 73 | sourceTree = ""; 74 | }; 75 | 97C146E51CF9000F007C117D = { 76 | isa = PBXGroup; 77 | children = ( 78 | 9740EEB11CF90186004384FC /* Flutter */, 79 | 97C146F01CF9000F007C117D /* Runner */, 80 | 97C146EF1CF9000F007C117D /* Products */, 81 | F23B3ED81AEDCE3482E14DC8 /* Pods */, 82 | D3F90093DACB21A963535DCF /* Frameworks */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | 97C146EF1CF9000F007C117D /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146EE1CF9000F007C117D /* Runner.app */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | 97C146F01CF9000F007C117D /* Runner */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 98 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 99 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 100 | 97C147021CF9000F007C117D /* Info.plist */, 101 | 97C146F11CF9000F007C117D /* Supporting Files */, 102 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 103 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 104 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 105 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 106 | ); 107 | path = Runner; 108 | sourceTree = ""; 109 | }; 110 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | ); 114 | name = "Supporting Files"; 115 | sourceTree = ""; 116 | }; 117 | D3F90093DACB21A963535DCF /* Frameworks */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 9C943A28E081525A9F6A2ED4 /* Pods_Runner.framework */, 121 | ); 122 | name = Frameworks; 123 | sourceTree = ""; 124 | }; 125 | F23B3ED81AEDCE3482E14DC8 /* Pods */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 52FDDBD0A1A74729D48F257D /* Pods-Runner.debug.xcconfig */, 129 | 17D6B5BF8C41B8A702D965E2 /* Pods-Runner.release.xcconfig */, 130 | C276AA4893264FC76325D331 /* Pods-Runner.profile.xcconfig */, 131 | ); 132 | name = Pods; 133 | path = Pods; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 97C146ED1CF9000F007C117D /* Runner */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 142 | buildPhases = ( 143 | 42A9D2045E521707E170DFA7 /* [CP] Check Pods Manifest.lock */, 144 | 9740EEB61CF901F6004384FC /* Run Script */, 145 | 97C146EA1CF9000F007C117D /* Sources */, 146 | 97C146EB1CF9000F007C117D /* Frameworks */, 147 | 97C146EC1CF9000F007C117D /* Resources */, 148 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 149 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 150 | 50360A62472203DA8C88D9BF /* [CP] Embed Pods Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Runner; 157 | productName = Runner; 158 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 159 | productType = "com.apple.product-type.application"; 160 | }; 161 | /* End PBXNativeTarget section */ 162 | 163 | /* Begin PBXProject section */ 164 | 97C146E61CF9000F007C117D /* Project object */ = { 165 | isa = PBXProject; 166 | attributes = { 167 | LastUpgradeCheck = 1020; 168 | ORGANIZATIONNAME = ""; 169 | TargetAttributes = { 170 | 97C146ED1CF9000F007C117D = { 171 | CreatedOnToolsVersion = 7.3.1; 172 | LastSwiftMigration = 1100; 173 | }; 174 | }; 175 | }; 176 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 177 | compatibilityVersion = "Xcode 9.3"; 178 | developmentRegion = en; 179 | hasScannedForEncodings = 0; 180 | knownRegions = ( 181 | en, 182 | Base, 183 | ); 184 | mainGroup = 97C146E51CF9000F007C117D; 185 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 186 | projectDirPath = ""; 187 | projectRoot = ""; 188 | targets = ( 189 | 97C146ED1CF9000F007C117D /* Runner */, 190 | ); 191 | }; 192 | /* End PBXProject section */ 193 | 194 | /* Begin PBXResourcesBuildPhase section */ 195 | 97C146EC1CF9000F007C117D /* Resources */ = { 196 | isa = PBXResourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 200 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 201 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 202 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXResourcesBuildPhase section */ 207 | 208 | /* Begin PBXShellScriptBuildPhase section */ 209 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 210 | isa = PBXShellScriptBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | inputPaths = ( 215 | ); 216 | name = "Thin Binary"; 217 | outputPaths = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | shellPath = /bin/sh; 221 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 222 | }; 223 | 42A9D2045E521707E170DFA7 /* [CP] Check Pods Manifest.lock */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputFileListPaths = ( 229 | ); 230 | inputPaths = ( 231 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 232 | "${PODS_ROOT}/Manifest.lock", 233 | ); 234 | name = "[CP] Check Pods Manifest.lock"; 235 | outputFileListPaths = ( 236 | ); 237 | outputPaths = ( 238 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | shellPath = /bin/sh; 242 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 243 | showEnvVarsInLog = 0; 244 | }; 245 | 50360A62472203DA8C88D9BF /* [CP] Embed Pods Frameworks */ = { 246 | isa = PBXShellScriptBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | ); 250 | inputPaths = ( 251 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 252 | "${BUILT_PRODUCTS_DIR}/BoringSSL-GRPC/openssl_grpc.framework", 253 | "${PODS_ROOT}/../Flutter/Flutter.framework", 254 | "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", 255 | "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", 256 | "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", 257 | "${BUILT_PRODUCTS_DIR}/abseil/absl.framework", 258 | "${BUILT_PRODUCTS_DIR}/gRPC-C++/grpcpp.framework", 259 | "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework", 260 | "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework", 261 | "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", 262 | "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", 263 | ); 264 | name = "[CP] Embed Pods Frameworks"; 265 | outputPaths = ( 266 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl_grpc.framework", 267 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 268 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", 269 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", 270 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", 271 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/absl.framework", 272 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpcpp.framework", 273 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework", 274 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework", 275 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", 276 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | shellPath = /bin/sh; 280 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 281 | showEnvVarsInLog = 0; 282 | }; 283 | 9740EEB61CF901F6004384FC /* Run Script */ = { 284 | isa = PBXShellScriptBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | inputPaths = ( 289 | ); 290 | name = "Run Script"; 291 | outputPaths = ( 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | shellPath = /bin/sh; 295 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 296 | }; 297 | /* End PBXShellScriptBuildPhase section */ 298 | 299 | /* Begin PBXSourcesBuildPhase section */ 300 | 97C146EA1CF9000F007C117D /* Sources */ = { 301 | isa = PBXSourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 305 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXSourcesBuildPhase section */ 310 | 311 | /* Begin PBXVariantGroup section */ 312 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 313 | isa = PBXVariantGroup; 314 | children = ( 315 | 97C146FB1CF9000F007C117D /* Base */, 316 | ); 317 | name = Main.storyboard; 318 | sourceTree = ""; 319 | }; 320 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 321 | isa = PBXVariantGroup; 322 | children = ( 323 | 97C147001CF9000F007C117D /* Base */, 324 | ); 325 | name = LaunchScreen.storyboard; 326 | sourceTree = ""; 327 | }; 328 | /* End PBXVariantGroup section */ 329 | 330 | /* Begin XCBuildConfiguration section */ 331 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_ANALYZER_NONNULL = YES; 336 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 337 | CLANG_CXX_LIBRARY = "libc++"; 338 | CLANG_ENABLE_MODULES = YES; 339 | CLANG_ENABLE_OBJC_ARC = YES; 340 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 341 | CLANG_WARN_BOOL_CONVERSION = YES; 342 | CLANG_WARN_COMMA = YES; 343 | CLANG_WARN_CONSTANT_CONVERSION = YES; 344 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 345 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 346 | CLANG_WARN_EMPTY_BODY = YES; 347 | CLANG_WARN_ENUM_CONVERSION = YES; 348 | CLANG_WARN_INFINITE_RECURSION = YES; 349 | CLANG_WARN_INT_CONVERSION = YES; 350 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 351 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 352 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 353 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 355 | CLANG_WARN_STRICT_PROTOTYPES = YES; 356 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 357 | CLANG_WARN_UNREACHABLE_CODE = YES; 358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 360 | COPY_PHASE_STRIP = NO; 361 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 362 | ENABLE_NS_ASSERTIONS = NO; 363 | ENABLE_STRICT_OBJC_MSGSEND = YES; 364 | GCC_C_LANGUAGE_STANDARD = gnu99; 365 | GCC_NO_COMMON_BLOCKS = YES; 366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 368 | GCC_WARN_UNDECLARED_SELECTOR = YES; 369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 370 | GCC_WARN_UNUSED_FUNCTION = YES; 371 | GCC_WARN_UNUSED_VARIABLE = YES; 372 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 373 | MTL_ENABLE_DEBUG_INFO = NO; 374 | SDKROOT = iphoneos; 375 | SUPPORTED_PLATFORMS = iphoneos; 376 | TARGETED_DEVICE_FAMILY = "1,2"; 377 | VALIDATE_PRODUCT = YES; 378 | }; 379 | name = Profile; 380 | }; 381 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 382 | isa = XCBuildConfiguration; 383 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 384 | buildSettings = { 385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 386 | CLANG_ENABLE_MODULES = YES; 387 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 388 | ENABLE_BITCODE = NO; 389 | FRAMEWORK_SEARCH_PATHS = ( 390 | "$(inherited)", 391 | "$(PROJECT_DIR)/Flutter", 392 | ); 393 | INFOPLIST_FILE = Runner/Info.plist; 394 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 395 | LIBRARY_SEARCH_PATHS = ( 396 | "$(inherited)", 397 | "$(PROJECT_DIR)/Flutter", 398 | ); 399 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthStarter; 400 | PRODUCT_NAME = "$(TARGET_NAME)"; 401 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 402 | SWIFT_VERSION = 5.0; 403 | VERSIONING_SYSTEM = "apple-generic"; 404 | }; 405 | name = Profile; 406 | }; 407 | 97C147031CF9000F007C117D /* Debug */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ALWAYS_SEARCH_USER_PATHS = NO; 411 | CLANG_ANALYZER_NONNULL = YES; 412 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 413 | CLANG_CXX_LIBRARY = "libc++"; 414 | CLANG_ENABLE_MODULES = YES; 415 | CLANG_ENABLE_OBJC_ARC = YES; 416 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_COMMA = YES; 419 | CLANG_WARN_CONSTANT_CONVERSION = YES; 420 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_EMPTY_BODY = YES; 423 | CLANG_WARN_ENUM_CONVERSION = YES; 424 | CLANG_WARN_INFINITE_RECURSION = YES; 425 | CLANG_WARN_INT_CONVERSION = YES; 426 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 427 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 428 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 430 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 431 | CLANG_WARN_STRICT_PROTOTYPES = YES; 432 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 433 | CLANG_WARN_UNREACHABLE_CODE = YES; 434 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 435 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 436 | COPY_PHASE_STRIP = NO; 437 | DEBUG_INFORMATION_FORMAT = dwarf; 438 | ENABLE_STRICT_OBJC_MSGSEND = YES; 439 | ENABLE_TESTABILITY = YES; 440 | GCC_C_LANGUAGE_STANDARD = gnu99; 441 | GCC_DYNAMIC_NO_PIC = NO; 442 | GCC_NO_COMMON_BLOCKS = YES; 443 | GCC_OPTIMIZATION_LEVEL = 0; 444 | GCC_PREPROCESSOR_DEFINITIONS = ( 445 | "DEBUG=1", 446 | "$(inherited)", 447 | ); 448 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 449 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 450 | GCC_WARN_UNDECLARED_SELECTOR = YES; 451 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 452 | GCC_WARN_UNUSED_FUNCTION = YES; 453 | GCC_WARN_UNUSED_VARIABLE = YES; 454 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 455 | MTL_ENABLE_DEBUG_INFO = YES; 456 | ONLY_ACTIVE_ARCH = YES; 457 | SDKROOT = iphoneos; 458 | TARGETED_DEVICE_FAMILY = "1,2"; 459 | }; 460 | name = Debug; 461 | }; 462 | 97C147041CF9000F007C117D /* Release */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | ALWAYS_SEARCH_USER_PATHS = NO; 466 | CLANG_ANALYZER_NONNULL = YES; 467 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 468 | CLANG_CXX_LIBRARY = "libc++"; 469 | CLANG_ENABLE_MODULES = YES; 470 | CLANG_ENABLE_OBJC_ARC = YES; 471 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 472 | CLANG_WARN_BOOL_CONVERSION = YES; 473 | CLANG_WARN_COMMA = YES; 474 | CLANG_WARN_CONSTANT_CONVERSION = YES; 475 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 476 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 477 | CLANG_WARN_EMPTY_BODY = YES; 478 | CLANG_WARN_ENUM_CONVERSION = YES; 479 | CLANG_WARN_INFINITE_RECURSION = YES; 480 | CLANG_WARN_INT_CONVERSION = YES; 481 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 482 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 483 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 484 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 485 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 486 | CLANG_WARN_STRICT_PROTOTYPES = YES; 487 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 488 | CLANG_WARN_UNREACHABLE_CODE = YES; 489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 490 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 491 | COPY_PHASE_STRIP = NO; 492 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 493 | ENABLE_NS_ASSERTIONS = NO; 494 | ENABLE_STRICT_OBJC_MSGSEND = YES; 495 | GCC_C_LANGUAGE_STANDARD = gnu99; 496 | GCC_NO_COMMON_BLOCKS = YES; 497 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 498 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 499 | GCC_WARN_UNDECLARED_SELECTOR = YES; 500 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 501 | GCC_WARN_UNUSED_FUNCTION = YES; 502 | GCC_WARN_UNUSED_VARIABLE = YES; 503 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 504 | MTL_ENABLE_DEBUG_INFO = NO; 505 | SDKROOT = iphoneos; 506 | SUPPORTED_PLATFORMS = iphoneos; 507 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 508 | TARGETED_DEVICE_FAMILY = "1,2"; 509 | VALIDATE_PRODUCT = YES; 510 | }; 511 | name = Release; 512 | }; 513 | 97C147061CF9000F007C117D /* Debug */ = { 514 | isa = XCBuildConfiguration; 515 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 516 | buildSettings = { 517 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 518 | CLANG_ENABLE_MODULES = YES; 519 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 520 | ENABLE_BITCODE = NO; 521 | FRAMEWORK_SEARCH_PATHS = ( 522 | "$(inherited)", 523 | "$(PROJECT_DIR)/Flutter", 524 | ); 525 | INFOPLIST_FILE = Runner/Info.plist; 526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 527 | LIBRARY_SEARCH_PATHS = ( 528 | "$(inherited)", 529 | "$(PROJECT_DIR)/Flutter", 530 | ); 531 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthStarter; 532 | PRODUCT_NAME = "$(TARGET_NAME)"; 533 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 534 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 535 | SWIFT_VERSION = 5.0; 536 | VERSIONING_SYSTEM = "apple-generic"; 537 | }; 538 | name = Debug; 539 | }; 540 | 97C147071CF9000F007C117D /* Release */ = { 541 | isa = XCBuildConfiguration; 542 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 543 | buildSettings = { 544 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 545 | CLANG_ENABLE_MODULES = YES; 546 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 547 | ENABLE_BITCODE = NO; 548 | FRAMEWORK_SEARCH_PATHS = ( 549 | "$(inherited)", 550 | "$(PROJECT_DIR)/Flutter", 551 | ); 552 | INFOPLIST_FILE = Runner/Info.plist; 553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 554 | LIBRARY_SEARCH_PATHS = ( 555 | "$(inherited)", 556 | "$(PROJECT_DIR)/Flutter", 557 | ); 558 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthStarter; 559 | PRODUCT_NAME = "$(TARGET_NAME)"; 560 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 561 | SWIFT_VERSION = 5.0; 562 | VERSIONING_SYSTEM = "apple-generic"; 563 | }; 564 | name = Release; 565 | }; 566 | /* End XCBuildConfiguration section */ 567 | 568 | /* Begin XCConfigurationList section */ 569 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 570 | isa = XCConfigurationList; 571 | buildConfigurations = ( 572 | 97C147031CF9000F007C117D /* Debug */, 573 | 97C147041CF9000F007C117D /* Release */, 574 | 249021D3217E4FDB00AE95B9 /* Profile */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 97C147061CF9000F007C117D /* Debug */, 583 | 97C147071CF9000F007C117D /* Release */, 584 | 249021D4217E4FDB00AE95B9 /* Profile */, 585 | ); 586 | defaultConfigurationIsVisible = 0; 587 | defaultConfigurationName = Release; 588 | }; 589 | /* End XCConfigurationList section */ 590 | }; 591 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 592 | } 593 | -------------------------------------------------------------------------------- /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 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/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/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_firebase_auth_starter 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/constants/app_themes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppThemes { 4 | AppThemes._(); 5 | 6 | static const Color dodgerBlue = Color.fromRGBO(29, 161, 242, 1); 7 | static const Color whiteLilac = Color.fromRGBO(248, 250, 252, 1); 8 | static const Color blackPearl = Color.fromRGBO(30, 31, 43, 1); 9 | static const Color brinkPink = Color.fromRGBO(255, 97, 136, 1); 10 | static const Color juneBud = Color.fromRGBO(186, 215, 97, 1); 11 | static const Color white = Color.fromRGBO(255, 255, 255, 1); 12 | static const Color nevada = Color.fromRGBO(105, 109, 119, 1); 13 | static const Color ebonyClay = Color.fromRGBO(40, 42, 58, 1); 14 | 15 | static String font1 = "ProductSans"; 16 | static String font2 = "Roboto"; 17 | //constants color range for light theme 18 | //main color 19 | static const Color _lightPrimaryColor = dodgerBlue; 20 | 21 | //Background Colors 22 | static const Color _lightBackgroundColor = whiteLilac; 23 | static const Color _lightBackgroundAppBarColor = _lightPrimaryColor; 24 | static const Color _lightBackgroundSecondaryColor = white; 25 | static const Color _lightBackgroundAlertColor = blackPearl; 26 | static const Color _lightBackgroundErrorColor = brinkPink; 27 | static const Color _lightBackgroundSuccessColor = juneBud; 28 | 29 | //Text Colors 30 | static const Color _lightTextColor = Colors.black; 31 | static const Color _lightAlertTextColor = Colors.black; 32 | static const Color _lightTextSecondaryColor = Colors.black; 33 | 34 | //Border Color 35 | static const Color _lightBorderColor = nevada; 36 | 37 | //Icon Color 38 | static const Color _lightIconColor = nevada; 39 | 40 | //form input colors 41 | static const Color _lightInputFillColor = _lightBackgroundSecondaryColor; 42 | static const Color _lightBorderActiveColor = _lightPrimaryColor; 43 | static const Color _lightBorderErrorColor = brinkPink; 44 | 45 | //constants color range for dark theme 46 | static const Color _darkPrimaryColor = dodgerBlue; 47 | 48 | //Background Colors 49 | static const Color _darkBackgroundColor = ebonyClay; 50 | static const Color _darkBackgroundAppBarColor = _darkPrimaryColor; 51 | static const Color _darkBackgroundSecondaryColor = 52 | Color.fromRGBO(0, 0, 0, .6); 53 | static const Color _darkBackgroundAlertColor = Colors.black; 54 | static const Color _darkBackgroundErrorColor = 55 | Color.fromRGBO(255, 97, 136, 1); 56 | static const Color _darkBackgroundSuccessColor = 57 | Color.fromRGBO(186, 215, 97, 1); 58 | 59 | //Text Colors 60 | static const Color _darkTextColor = Colors.white; 61 | static const Color _darkAlertTextColor = Colors.black; 62 | static const Color _darkTextSecondaryColor = Colors.black; 63 | 64 | //Border Color 65 | static const Color _darkBorderColor = nevada; 66 | 67 | //Icon Color 68 | static const Color _darkIconColor = nevada; 69 | 70 | static const Color _darkInputFillColor = _darkBackgroundSecondaryColor; 71 | static const Color _darkBorderActiveColor = _darkPrimaryColor; 72 | static const Color _darkBorderErrorColor = brinkPink; 73 | 74 | //text theme for light theme 75 | static final TextTheme _lightTextTheme = TextTheme( 76 | headline1: TextStyle(fontSize: 20.0, color: _lightTextColor), 77 | bodyText1: TextStyle(fontSize: 16.0, color: _lightTextColor), 78 | bodyText2: TextStyle(fontSize: 14.0, color: Colors.grey), 79 | button: TextStyle( 80 | fontSize: 15.0, color: _lightTextColor, fontWeight: FontWeight.w600), 81 | headline6: TextStyle(fontSize: 16.0, color: _lightTextColor), 82 | subtitle1: TextStyle(fontSize: 16.0, color: _lightTextColor), 83 | caption: TextStyle(fontSize: 12.0, color: _lightBackgroundAppBarColor), 84 | ); 85 | 86 | //the light theme 87 | static final ThemeData lightTheme = ThemeData( 88 | brightness: Brightness.light, 89 | fontFamily: font1, 90 | scaffoldBackgroundColor: _lightBackgroundColor, 91 | floatingActionButtonTheme: FloatingActionButtonThemeData( 92 | backgroundColor: _lightPrimaryColor, 93 | ), 94 | appBarTheme: AppBarTheme( 95 | color: _lightBackgroundAppBarColor, 96 | iconTheme: IconThemeData(color: _lightTextColor), 97 | textTheme: _lightTextTheme, 98 | ), 99 | colorScheme: ColorScheme.light( 100 | primary: _lightPrimaryColor, 101 | primaryVariant: _lightBackgroundColor, 102 | // secondary: _lightSecondaryColor, 103 | ), 104 | snackBarTheme: 105 | SnackBarThemeData(backgroundColor: _lightBackgroundAlertColor), 106 | iconTheme: IconThemeData( 107 | color: _lightIconColor, 108 | ), 109 | popupMenuTheme: PopupMenuThemeData(color: _lightBackgroundAppBarColor), 110 | textTheme: _lightTextTheme, 111 | buttonTheme: ButtonThemeData( 112 | shape: RoundedRectangleBorder( 113 | borderRadius: BorderRadius.circular(8), 114 | ), 115 | buttonColor: _lightPrimaryColor, 116 | textTheme: ButtonTextTheme.primary), 117 | unselectedWidgetColor: _lightPrimaryColor, 118 | inputDecorationTheme: InputDecorationTheme( 119 | //prefixStyle: TextStyle(color: _lightIconColor), 120 | border: OutlineInputBorder( 121 | borderSide: BorderSide(width: 1.0), 122 | borderRadius: BorderRadius.all( 123 | Radius.circular(8.0), 124 | )), 125 | enabledBorder: OutlineInputBorder( 126 | borderSide: BorderSide(color: _lightBorderColor, width: 1.0), 127 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 128 | ), 129 | focusedBorder: OutlineInputBorder( 130 | borderSide: BorderSide(color: _lightBorderActiveColor), 131 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 132 | ), 133 | errorBorder: OutlineInputBorder( 134 | borderSide: BorderSide(color: _lightBorderErrorColor), 135 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 136 | ), 137 | focusedErrorBorder: OutlineInputBorder( 138 | borderSide: BorderSide(color: _lightBorderErrorColor), 139 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 140 | ), 141 | fillColor: _lightBackgroundSecondaryColor, 142 | //focusColor: _lightBorderActiveColor, 143 | ), 144 | ); 145 | 146 | //text theme for dark theme 147 | /*static final TextStyle _darkScreenHeadingTextStyle = 148 | _lightScreenHeadingTextStyle.copyWith(color: _darkTextColor); 149 | static final TextStyle _darkScreenTaskNameTextStyle = 150 | _lightScreenTaskNameTextStyle.copyWith(color: _darkTextColor); 151 | static final TextStyle _darkScreenTaskDurationTextStyle = 152 | _lightScreenTaskDurationTextStyle; 153 | static final TextStyle _darkScreenButtonTextStyle = TextStyle( 154 | fontSize: 14.0, color: _darkTextColor, fontWeight: FontWeight.w500); 155 | static final TextStyle _darkScreenCaptionTextStyle = TextStyle( 156 | fontSize: 12.0, 157 | color: _darkBackgroundAppBarColor, 158 | fontWeight: FontWeight.w100);*/ 159 | 160 | static final TextTheme _darkTextTheme = TextTheme( 161 | headline1: TextStyle(fontSize: 20.0, color: _darkTextColor), 162 | bodyText1: TextStyle(fontSize: 16.0, color: _darkTextColor), 163 | bodyText2: TextStyle(fontSize: 14.0, color: Colors.grey), 164 | button: TextStyle( 165 | fontSize: 15.0, color: _darkTextColor, fontWeight: FontWeight.w600), 166 | headline6: TextStyle(fontSize: 16.0, color: _darkTextColor), 167 | subtitle1: TextStyle(fontSize: 16.0, color: _darkTextColor), 168 | caption: TextStyle(fontSize: 12.0, color: _darkBackgroundAppBarColor), 169 | ); 170 | 171 | //the dark theme 172 | static final ThemeData darkTheme = ThemeData( 173 | brightness: Brightness.dark, 174 | //primarySwatch: _darkPrimaryColor, //cant be Color on MaterialColor so it can compute different shades. 175 | accentColor: _darkPrimaryColor, //prefix icon color form input on focus 176 | 177 | fontFamily: font1, 178 | scaffoldBackgroundColor: _darkBackgroundColor, 179 | floatingActionButtonTheme: FloatingActionButtonThemeData( 180 | backgroundColor: _darkPrimaryColor, 181 | ), 182 | appBarTheme: AppBarTheme( 183 | color: _darkBackgroundAppBarColor, 184 | iconTheme: IconThemeData(color: _darkTextColor), 185 | textTheme: _darkTextTheme, 186 | ), 187 | colorScheme: ColorScheme.dark( 188 | primary: _darkPrimaryColor, 189 | primaryVariant: _darkBackgroundColor, 190 | 191 | // secondary: _darkSecondaryColor, 192 | ), 193 | snackBarTheme: SnackBarThemeData( 194 | contentTextStyle: TextStyle(color: Colors.white), 195 | backgroundColor: _darkBackgroundAlertColor), 196 | iconTheme: IconThemeData( 197 | color: Colors.white, //_darkIconColor, 198 | ), 199 | popupMenuTheme: PopupMenuThemeData(color: _darkBackgroundAppBarColor), 200 | textTheme: _darkTextTheme, 201 | buttonTheme: ButtonThemeData( 202 | shape: RoundedRectangleBorder( 203 | borderRadius: BorderRadius.circular(8), 204 | ), 205 | buttonColor: _darkPrimaryColor, 206 | textTheme: ButtonTextTheme.primary), 207 | unselectedWidgetColor: _darkPrimaryColor, 208 | inputDecorationTheme: InputDecorationTheme( 209 | prefixStyle: TextStyle(color: _darkIconColor), 210 | //labelStyle: TextStyle(color: nevada), 211 | border: OutlineInputBorder( 212 | borderSide: BorderSide(width: 1.0), 213 | borderRadius: BorderRadius.all( 214 | Radius.circular(8.0), 215 | )), 216 | enabledBorder: OutlineInputBorder( 217 | borderSide: BorderSide(color: _darkBorderColor, width: 1.0), 218 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 219 | ), 220 | focusedBorder: OutlineInputBorder( 221 | borderSide: BorderSide(color: _darkBorderActiveColor), 222 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 223 | ), 224 | errorBorder: OutlineInputBorder( 225 | borderSide: BorderSide(color: _darkBorderErrorColor), 226 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 227 | ), 228 | focusedErrorBorder: OutlineInputBorder( 229 | borderSide: BorderSide(color: _darkBorderErrorColor), 230 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 231 | ), 232 | fillColor: _darkInputFillColor, 233 | //focusColor: _darkBorderActiveColor, 234 | ), 235 | ); 236 | } 237 | -------------------------------------------------------------------------------- /lib/constants/constants.dart: -------------------------------------------------------------------------------- 1 | export 'routes.dart'; 2 | export 'globals.dart'; 3 | export 'app_themes.dart'; 4 | -------------------------------------------------------------------------------- /lib/constants/globals.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_starter/models/models.dart'; 2 | 3 | class Globals { 4 | //List of languages that are supported. Used in selector. 5 | //Follow this plugin for translating a google sheet to languages 6 | //https://github.com/aloisdeniel/flutter_sheet_localization 7 | //Flutter App translations google sheet 8 | //https://docs.google.com/spreadsheets/d/1oS7iJ6ocrZBA53SxRfKF0CG9HAaXeKtzvsTBhgG4Zzk/edit?usp=sharing 9 | 10 | static final List languageOptions = [ 11 | MenuOptionsModel(key: "zh", value: "中文"), //Chinese 12 | MenuOptionsModel(key: "de", value: "Deutsche"), //German 13 | MenuOptionsModel(key: "en", value: "English"), //English 14 | MenuOptionsModel(key: "es", value: "Español"), //Spanish 15 | MenuOptionsModel(key: "fr", value: "Français"), //French 16 | MenuOptionsModel(key: "hi", value: "हिन्दी"), //Hindi 17 | MenuOptionsModel(key: "ja", value: "日本語"), //Japanese 18 | MenuOptionsModel(key: "pt", value: "Português"), //Portuguese 19 | MenuOptionsModel(key: "ru", value: "русский"), //Russian 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /lib/constants/routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_starter/ui/ui.dart'; 3 | import 'package:flutter_starter/ui/auth/auth.dart'; 4 | 5 | class Routes { 6 | Routes._(); //this is to prevent anyone from instantiating this object 7 | static const String signin = '/signin'; 8 | static const String signup = '/signup'; 9 | static const String home = '/home'; 10 | static const String settings = '/settings'; 11 | static const String resetPassword = '/reset-password'; 12 | static const String updateProfile = '/update-profile'; 13 | 14 | static final routes = { 15 | signin: (BuildContext context) => SignInUI(), 16 | signup: (BuildContext context) => SignUpUI(), 17 | settings: (BuildContext context) => SettingsUI(), 18 | resetPassword: (BuildContext context) => ResetPasswordUI(), 19 | updateProfile: (BuildContext context) => UpdateProfileUI(), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /lib/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'validator.dart'; 2 | -------------------------------------------------------------------------------- /lib/helpers/validator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_starter/localizations.dart'; 2 | 3 | // matching various patterns for kinds of data 4 | 5 | class Validator { 6 | AppLocalizations_Labels labels; 7 | Validator(this.labels); 8 | 9 | String email(String value) { 10 | Pattern pattern = r'^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+'; 11 | RegExp regex = new RegExp(pattern); 12 | if (!regex.hasMatch(value)) 13 | return labels.validator.email; 14 | else 15 | return null; 16 | } 17 | 18 | String password(String value) { 19 | Pattern pattern = r'^.{6,}$'; 20 | RegExp regex = new RegExp(pattern); 21 | if (!regex.hasMatch(value)) 22 | return labels.validator.password; 23 | else 24 | return null; 25 | } 26 | 27 | String name(String value) { 28 | Pattern pattern = r"^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$"; 29 | RegExp regex = new RegExp(pattern); 30 | if (!regex.hasMatch(value)) 31 | return labels.validator.name; 32 | else 33 | return null; 34 | } 35 | 36 | String number(String value) { 37 | Pattern pattern = r'^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$'; 38 | RegExp regex = new RegExp(pattern); 39 | if (!regex.hasMatch(value)) 40 | return labels.validator.number; 41 | else 42 | return null; 43 | } 44 | 45 | String amount(String value) { 46 | Pattern pattern = r'^\d+$'; 47 | RegExp regex = new RegExp(pattern); 48 | if (!regex.hasMatch(value)) 49 | return labels.validator.amount; 50 | else 51 | return null; 52 | } 53 | 54 | String notEmpty(String value) { 55 | Pattern pattern = r'^\S+$'; 56 | RegExp regex = new RegExp(pattern); 57 | if (!regex.hasMatch(value)) 58 | return labels.validator.notEmpty; 59 | else 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/localizations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:flutter_sheet_localization/flutter_sheet_localization.dart'; 4 | 5 | part 'localizations.g.dart'; 6 | //https://github.com/aloisdeniel/flutter_sheet_localization 7 | //to rebuild language files 8 | //delete the localizations.g.dart file 9 | //on command line run... 10 | //flutter packages pub run build_runner build 11 | 12 | @SheetLocalization("1oS7iJ6ocrZBA53SxRfKF0CG9HAaXeKtzvsTBhgG4Zzk", 13 | "0") // <- See 1. to get DOCID and SHEETID 14 | class AppLocalizationsDelegate extends LocalizationsDelegate { 15 | const AppLocalizationsDelegate(); 16 | 17 | @override 18 | bool isSupported(Locale locale) => 19 | AppLocalizations.languages.containsKey(locale); 20 | @override 21 | Future load(Locale locale) => 22 | SynchronousFuture(AppLocalizations(locale)); 23 | @override 24 | bool shouldReload(AppLocalizationsDelegate old) => false; 25 | } 26 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:firebase_analytics/firebase_analytics.dart'; 4 | import 'package:firebase_analytics/observer.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | import 'package:flutter_localizations/flutter_localizations.dart'; 7 | import 'localizations.dart'; 8 | import 'package:flutter_starter/services/services.dart'; 9 | import 'package:flutter_starter/constants/constants.dart'; 10 | import 'package:flutter_starter/ui/auth/auth.dart'; 11 | import 'package:flutter_starter/ui/ui.dart'; 12 | //import 'dart:js' as js; 13 | 14 | void main() { 15 | WidgetsFlutterBinding.ensureInitialized(); 16 | LanguageProvider().setInitialLocalLanguage(); 17 | //found bug https://github.com/flutter/flutter/issues/55892 18 | //SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) async { 19 | runApp( 20 | MultiProvider( 21 | providers: [ 22 | ChangeNotifierProvider( 23 | create: (context) => ThemeProvider(), 24 | ), 25 | ChangeNotifierProvider( 26 | create: (context) => LanguageProvider(), 27 | ), 28 | ChangeNotifierProvider( 29 | create: (context) => AuthService(), 30 | ), 31 | ], 32 | child: MyApp(), 33 | ), 34 | ); 35 | /* });*/ 36 | } 37 | 38 | class MyApp extends StatelessWidget { 39 | const MyApp({Key key}) : super(key: key); 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | //final labels = AppLocalizations.of(context); 44 | // js.context.callMethod("alert", ["Your debug message"]); 45 | return Consumer( 46 | builder: (_, languageProviderRef, __) { 47 | return Consumer( 48 | builder: (_, themeProviderRef, __) { 49 | //{context, data, child} 50 | return AuthWidgetBuilder( 51 | builder: (BuildContext context, 52 | AsyncSnapshot userSnapshot) { 53 | return MaterialApp( 54 | //begin language translation stuff 55 | //https://github.com/aloisdeniel/flutter_sheet_localization 56 | //https://github.com/aloisdeniel/flutter_sheet_localization/tree/master/flutter_sheet_localization_generator/example 57 | locale: languageProviderRef.getLocale, // <- Current locale 58 | localizationsDelegates: [ 59 | const AppLocalizationsDelegate(), // <- Your custom delegate 60 | GlobalMaterialLocalizations.delegate, 61 | GlobalWidgetsLocalizations.delegate, 62 | ], 63 | supportedLocales: AppLocalizations.languages.keys 64 | .toList(), // <- Supported locales 65 | //end language translation stuff 66 | navigatorObservers: [ 67 | FirebaseAnalyticsObserver(analytics: FirebaseAnalytics()), 68 | ], 69 | debugShowCheckedModeBanner: false, 70 | //title: labels.app.title, 71 | routes: Routes.routes, 72 | theme: AppThemes.lightTheme, 73 | darkTheme: AppThemes.darkTheme, 74 | themeMode: themeProviderRef.isDarkModeOn 75 | ? ThemeMode.dark 76 | : ThemeMode.light, 77 | home: 78 | (userSnapshot?.data?.uid != null) ? HomeUI() : SignInUI(), 79 | ); 80 | }, 81 | ); 82 | }, 83 | ); 84 | }, 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/models/menu_option_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // Model class to hold menu option data (language and theme) 4 | class MenuOptionsModel { 5 | String key; 6 | String value; 7 | IconData icon; 8 | 9 | MenuOptionsModel({this.key, this.value, this.icon}); 10 | } 11 | -------------------------------------------------------------------------------- /lib/models/models.dart: -------------------------------------------------------------------------------- 1 | export 'user_model.dart'; 2 | export 'menu_option_model.dart'; 3 | -------------------------------------------------------------------------------- /lib/models/user_model.dart: -------------------------------------------------------------------------------- 1 | //User Model 2 | class UserModel { 3 | String uid; 4 | String email; 5 | String name; 6 | String photoUrl; 7 | 8 | UserModel({this.uid, this.email, this.name, this.photoUrl}); 9 | 10 | factory UserModel.fromMap(Map data) { 11 | return UserModel( 12 | uid: data['uid'], 13 | email: data['email'] ?? '', 14 | name: data['name'] ?? '', 15 | photoUrl: data['photoUrl'] ?? '', 16 | ); 17 | } 18 | 19 | Map toJson() => 20 | {"uid": uid, "email": email, "name": name, "photoUrl": photoUrl}; 21 | } 22 | -------------------------------------------------------------------------------- /lib/services/auth_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | import 'package:cloud_firestore/cloud_firestore.dart'; 4 | import 'package:firebase_auth/firebase_auth.dart'; 5 | import 'package:simple_gravatar/simple_gravatar.dart'; 6 | import 'package:flutter_starter/models/models.dart'; 7 | 8 | class AuthService extends ChangeNotifier { 9 | final FirebaseAuth _auth = FirebaseAuth.instance; 10 | final Firestore _db = Firestore.instance; 11 | 12 | // Firebase user one-time fetch 13 | Future get getUser => _auth.currentUser(); 14 | 15 | // Firebase user a realtime stream 16 | Stream get user => _auth.onAuthStateChanged; 17 | 18 | //Streams the firestore user from the firestore collection 19 | Stream streamFirestoreUser(FirebaseUser firebaseUser) { 20 | if (firebaseUser?.uid != null) { 21 | return _db 22 | .document('/users/${firebaseUser.uid}') 23 | .snapshots() 24 | .map((snapshot) => UserModel.fromMap(snapshot.data)); 25 | } 26 | return null; 27 | } 28 | 29 | //Method to handle user sign in using email and password 30 | Future signInWithEmailAndPassword(String email, String password) async { 31 | try { 32 | await _auth.signInWithEmailAndPassword(email: email, password: password); 33 | return true; 34 | } catch (e) { 35 | return false; 36 | } 37 | } 38 | 39 | // User registration using email and password 40 | Future registerWithEmailAndPassword( 41 | String name, String email, String password) async { 42 | try { 43 | await _auth 44 | .createUserWithEmailAndPassword(email: email, password: password) 45 | .then((result) async { 46 | print('uID: ' + result.user.uid); 47 | print('email: ' + result.user.email); 48 | //get photo url from gravatar if user has one 49 | Gravatar gravatar = Gravatar(email); 50 | String gravatarUrl = gravatar.imageUrl( 51 | size: 200, 52 | defaultImage: GravatarImage.retro, 53 | rating: GravatarRating.pg, 54 | fileExtension: true, 55 | ); 56 | //create the new user object 57 | UserModel _newUser = UserModel( 58 | uid: result.user.uid, 59 | email: result.user.email, 60 | name: name, 61 | photoUrl: gravatarUrl); 62 | //update the user in firestore 63 | _updateUserFirestore(_newUser, result.user); 64 | }); 65 | return true; 66 | } catch (e) { 67 | return false; 68 | } 69 | } 70 | 71 | //handles updating the user when updating profile 72 | Future updateUser( 73 | UserModel user, String oldEmail, String password) async { 74 | bool _result = false; 75 | await _auth 76 | .signInWithEmailAndPassword(email: oldEmail, password: password) 77 | .then((_firebaseUser) { 78 | _firebaseUser.user.updateEmail(user.email); 79 | _updateUserFirestore(user, _firebaseUser.user); 80 | _result = true; 81 | }); 82 | return _result; 83 | } 84 | 85 | //updates the firestore users collection 86 | void _updateUserFirestore(UserModel user, FirebaseUser firebaseUser) { 87 | _db 88 | .document('/users/${firebaseUser.uid}') 89 | .setData(user.toJson(), merge: true); 90 | } 91 | 92 | //password reset email 93 | Future sendPasswordResetEmail(String email) async { 94 | await _auth.sendPasswordResetEmail(email: email); 95 | } 96 | 97 | Future isAdmin() async { 98 | bool _isAdmin = false; 99 | await _auth.currentUser().then((user) async { 100 | DocumentSnapshot adminRef = 101 | await _db.collection('admin').document(user?.uid).get(); 102 | if (adminRef.exists) { 103 | _isAdmin = true; 104 | } 105 | }); 106 | return _isAdmin; 107 | } 108 | 109 | // Sign out 110 | Future signOut() { 111 | return _auth.signOut(); 112 | } 113 | } 114 | 115 | /* Not currently used functions for managing 116 | google, apple and anonymous signin 117 | https://github.com/fireship-io/flutter-firebase-quizapp-course 118 | 119 | 120 | final GoogleSignIn _googleSignIn = GoogleSignIn(); 121 | // Determine if Apple Signin is available on device 122 | Future get appleSignInAvailable => AppleSignIn.isAvailable(); 123 | 124 | /// Sign in with Apple 125 | Future appleSignIn() async { 126 | try { 127 | final AuthorizationResult appleResult = 128 | await AppleSignIn.performRequests([ 129 | AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) 130 | ]); 131 | 132 | if (appleResult.error != null) { 133 | // handle errors from Apple 134 | } 135 | 136 | final AuthCredential credential = 137 | OAuthProvider(providerId: 'apple.com').getCredential( 138 | accessToken: 139 | String.fromCharCodes(appleResult.credential.authorizationCode), 140 | idToken: String.fromCharCodes(appleResult.credential.identityToken), 141 | ); 142 | 143 | AuthResult firebaseResult = await _auth.signInWithCredential(credential); 144 | FirebaseUser user = firebaseResult.user; 145 | 146 | // Update user data 147 | updateUserData(user); 148 | 149 | return user; 150 | } catch (error) { 151 | print(error); 152 | return null; 153 | } 154 | } 155 | 156 | /// Sign in with Google 157 | Future googleSignIn() async { 158 | try { 159 | GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn(); 160 | GoogleSignInAuthentication googleAuth = 161 | await googleSignInAccount.authentication; 162 | 163 | final AuthCredential credential = GoogleAuthProvider.getCredential( 164 | accessToken: googleAuth.accessToken, 165 | idToken: googleAuth.idToken, 166 | ); 167 | 168 | AuthResult result = await _auth.signInWithCredential(credential); 169 | FirebaseUser user = result.user; 170 | 171 | Gravatar gravatar = Gravatar(user.email); 172 | String gravatarUrl = gravatar.imageUrl( 173 | size: 200, 174 | defaultImage: GravatarImage.retro, 175 | rating: GravatarRating.pg, 176 | fileExtension: true, 177 | ); 178 | UserModel _newUser = UserModel( 179 | uid: user.uid, 180 | email: user.email, 181 | name: user.displayName, 182 | photoUrl: gravatarUrl); 183 | // _auth.signInWithEmailAndPassword(email: email, password: password); 184 | UserData(collection: 'users').upsert(_newUser.toJson()); 185 | 186 | // Update user data 187 | updateUserData(user); 188 | 189 | return user; 190 | } catch (error) { 191 | print(error); 192 | return null; 193 | } 194 | } 195 | 196 | /// Anonymous Firebase login 197 | Future anonLogin() async { 198 | AuthResult result = await _auth.signInAnonymously(); 199 | FirebaseUser user = result.user; 200 | 201 | updateUserData(user); 202 | return user; 203 | } 204 | 205 | /// Updates the User's data in Firestore on each new login 206 | Future updateUserData(FirebaseUser user) { 207 | DocumentReference reportRef = _db.collection('reports').document(user.uid); 208 | return reportRef.setData({'uid': user.uid, 'lastActivity': DateTime.now()}, 209 | merge: true); 210 | } 211 | */ 212 | -------------------------------------------------------------------------------- /lib/services/auth_widget_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_starter/models/models.dart'; 4 | import 'package:flutter_starter/services/auth_service.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | //https://www.youtube.com/watch?v=B0QX2woHxaU from this tutorial 8 | class AuthWidgetBuilder extends StatelessWidget { 9 | const AuthWidgetBuilder({Key key, @required this.builder}) : super(key: key); 10 | final Widget Function(BuildContext, AsyncSnapshot) builder; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | final authService = Provider.of(context, listen: false); 15 | return StreamBuilder( 16 | stream: authService.user, 17 | builder: (BuildContext context, AsyncSnapshot snapshot) { 18 | final FirebaseUser user = snapshot.data; 19 | if (user != null) { 20 | /* 21 | * For any other Provider services that rely on user data can be 22 | * added to the following MultiProvider list. 23 | * Once a user has been detected, a re-build will be initiated. 24 | */ 25 | return MultiProvider( 26 | providers: [ 27 | Provider.value(value: user), 28 | StreamProvider.value( 29 | value: AuthService().streamFirestoreUser(user)) 30 | ], 31 | child: builder(context, snapshot), 32 | ); 33 | } 34 | return builder(context, snapshot); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/services/language_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:ui' as ui; 3 | import 'package:flutter_starter/localizations.dart'; 4 | import 'package:flutter_starter/store/store.dart'; 5 | 6 | class LanguageProvider extends ChangeNotifier { 7 | // shared pref object 8 | SharedPreferenceHelper _sharedPrefsHelper; 9 | 10 | String _currentLanguage = ''; 11 | 12 | LanguageProvider() { 13 | _sharedPrefsHelper = SharedPreferenceHelper(); 14 | } 15 | 16 | // Retrieves and Sets language based on device settings 17 | setInitialLocalLanguage() async { 18 | _sharedPrefsHelper.appCurrentLanguage.then((currentLanguageCode) async { 19 | if ((currentLanguageCode == '') || (currentLanguageCode == null)) { 20 | //begin taken from devicelocale flutter plugin 21 | //gets language code (en-US) 22 | String deviceLanguage = ui.window.locale.toString(); 23 | deviceLanguage.substring(0, 2); //only get 1st 2 characters 24 | print('deviceLanguage: ' + deviceLanguage); 25 | updateLanguage(deviceLanguage); 26 | } 27 | }); 28 | } 29 | 30 | // Gets current language from shared preferences 31 | String get currentLanguage { 32 | _sharedPrefsHelper.appCurrentLanguage.then((value) { 33 | _currentLanguage = value; 34 | }); 35 | 36 | return _currentLanguage; 37 | } 38 | 39 | // gets the language app is set to 40 | Locale get getLocale { 41 | // gets the default language key (from the translation language system) 42 | Locale _updatedLocal = AppLocalizations.languages.keys.first; 43 | // looks for matching language key stored in shared preferences and sets to it 44 | AppLocalizations.languages.keys.forEach((locale) { 45 | if (locale.languageCode == currentLanguage) { 46 | _updatedLocal = locale; 47 | } 48 | }); 49 | return _updatedLocal; 50 | } 51 | 52 | // updates the language stored in sharepreferences 53 | void updateLanguage(String selectedLanguage) { 54 | _sharedPrefsHelper.changeLanguage(selectedLanguage); 55 | _sharedPrefsHelper.appCurrentLanguage.then((languageSelected) { 56 | _currentLanguage = languageSelected; 57 | }); 58 | 59 | notifyListeners(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/services/services.dart: -------------------------------------------------------------------------------- 1 | export 'theme_provider.dart'; 2 | export 'language_provider.dart'; 3 | export 'auth_service.dart'; 4 | export 'auth_widget_builder.dart'; 5 | -------------------------------------------------------------------------------- /lib/services/theme_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_starter/store/store.dart'; 3 | 4 | class ThemeProvider extends ChangeNotifier { 5 | // shared pref object 6 | SharedPreferenceHelper _sharedPrefsHelper; 7 | String _currentTheme = "system"; 8 | 9 | ThemeProvider() { 10 | _sharedPrefsHelper = SharedPreferenceHelper(); 11 | } 12 | 13 | // checks whether darkmode is set via system or previously by user 14 | bool get isDarkModeOn { 15 | if (getTheme == 'system') { 16 | if (WidgetsBinding.instance.window.platformBrightness == 17 | Brightness.dark) { 18 | return true; 19 | } 20 | } 21 | if (getTheme == 'dark') { 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | // gets currentTheme stored in shared preferences 28 | String get getTheme { 29 | _sharedPrefsHelper.getCurrentTheme.then((theme) { 30 | _currentTheme = theme; 31 | }); 32 | return _currentTheme; 33 | } 34 | 35 | // updates selected theme into sharepreferences 36 | // and notifies ui to update via provider 37 | void updateTheme(String theme) { 38 | _sharedPrefsHelper.changeTheme(theme); 39 | _sharedPrefsHelper.getCurrentTheme.then((theme) { 40 | _currentTheme = theme; 41 | }); 42 | notifyListeners(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/store/shared_preference_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class SharedPreferenceHelper { 4 | Future _sharedPreference; 5 | static const String current_language = ""; 6 | static const String current_theme = "system"; 7 | 8 | SharedPreferenceHelper() { 9 | _sharedPreference = SharedPreferences.getInstance(); 10 | } 11 | 12 | //Theme 13 | 14 | //Sets the theme to a new value and stores in sharedpreferences 15 | Future changeTheme(String value) { 16 | return _sharedPreference.then((prefs) { 17 | return prefs.setString(current_theme, value); 18 | }); 19 | } 20 | 21 | //gets the current theme stored in sharedpreferences. 22 | //If no theme returns 'system' 23 | Future get getCurrentTheme { 24 | return _sharedPreference.then((prefs) { 25 | String currentTheme = prefs.getString(current_theme) ?? 'system'; 26 | return currentTheme; 27 | }); 28 | } 29 | 30 | //Language 31 | 32 | //Sets the language to a new value and stores in sharedpreferences 33 | Future changeLanguage(String value) { 34 | return _sharedPreference.then((prefs) { 35 | return prefs.setString(current_language, value); 36 | }); 37 | } 38 | 39 | //gets the current language stored in sharedpreferences. 40 | Future get appCurrentLanguage { 41 | return _sharedPreference.then((prefs) { 42 | return prefs.getString(current_language); 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/store/store.dart: -------------------------------------------------------------------------------- 1 | export 'shared_preference_helper.dart'; 2 | -------------------------------------------------------------------------------- /lib/ui/auth/auth.dart: -------------------------------------------------------------------------------- 1 | export 'sign_in_ui.dart'; 2 | export 'sign_up_ui.dart'; 3 | export 'reset_password_ui.dart'; 4 | export 'update_profile_ui.dart'; 5 | -------------------------------------------------------------------------------- /lib/ui/auth/reset_password_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_starter/localizations.dart'; 4 | import 'package:flutter_starter/ui/components/components.dart'; 5 | import 'package:flutter_starter/helpers/helpers.dart'; 6 | import 'package:flutter_starter/services/services.dart'; 7 | 8 | class ResetPasswordUI extends StatefulWidget { 9 | _ResetPasswordUIState createState() => _ResetPasswordUIState(); 10 | } 11 | 12 | class _ResetPasswordUIState extends State { 13 | final GlobalKey _formKey = GlobalKey(); 14 | final TextEditingController _email = new TextEditingController(); 15 | final _scaffoldKey = GlobalKey(); 16 | bool _isButtonDisabled = false; 17 | String email = ''; 18 | @override 19 | void initState() { 20 | super.initState(); 21 | } 22 | 23 | @override 24 | void dispose() { 25 | _email.dispose(); 26 | super.dispose(); 27 | } 28 | 29 | Widget build(BuildContext context) { 30 | final labels = AppLocalizations.of(context); 31 | bool _loading = false; 32 | email = ModalRoute.of(context).settings.arguments; 33 | _email.text = email; 34 | 35 | return Scaffold( 36 | key: _scaffoldKey, 37 | appBar: appBar(), 38 | body: LoadingScreen( 39 | child: Form( 40 | key: _formKey, 41 | child: Padding( 42 | padding: const EdgeInsets.symmetric(horizontal: 24.0), 43 | child: Center( 44 | child: SingleChildScrollView( 45 | child: Column( 46 | mainAxisAlignment: MainAxisAlignment.center, 47 | crossAxisAlignment: CrossAxisAlignment.stretch, 48 | children: [ 49 | LogoGraphicHeader(), 50 | SizedBox(height: 48.0), 51 | FormInputFieldWithIcon( 52 | controller: _email, 53 | iconPrefix: Icons.email, 54 | labelText: labels.auth.emailFormField, 55 | validator: Validator(labels).email, 56 | keyboardType: TextInputType.emailAddress, 57 | onChanged: (value) => 58 | setState(() => _isButtonDisabled = false), 59 | onSaved: (value) => _email.text = value, 60 | ), 61 | FormVerticalSpace(), 62 | PrimaryButton( 63 | labelText: labels.auth.resetPasswordButton, 64 | onPressed: _isButtonDisabled 65 | ? null 66 | : () async { 67 | if (_formKey.currentState.validate()) { 68 | setState(() => 69 | _isButtonDisabled = !_isButtonDisabled); 70 | AuthService _auth = AuthService(); 71 | await _auth 72 | .sendPasswordResetEmail(_email.text); 73 | 74 | _scaffoldKey.currentState 75 | .showSnackBar(SnackBar( 76 | content: 77 | Text(labels.auth.resetPasswordNotice), 78 | )); 79 | } 80 | }), 81 | FormVerticalSpace(), 82 | signInLink() 83 | ], 84 | ), 85 | ), 86 | ), 87 | ), 88 | ), 89 | inAsyncCall: _loading, 90 | color: Theme.of(context).scaffoldBackgroundColor, 91 | ), 92 | ); 93 | } 94 | 95 | appBar() { 96 | final labels = AppLocalizations.of(context); 97 | if ((email == '') || (email == null)) { 98 | return null; 99 | } 100 | return AppBar(title: Text(labels.auth.resetPasswordTitle)); 101 | } 102 | 103 | signInLink() { 104 | final labels = AppLocalizations.of(context); 105 | if ((email == '') || (email == null)) { 106 | return LabelButton( 107 | labelText: labels.auth.signInonResetPasswordLabelButton, 108 | onPressed: () => Navigator.pushReplacementNamed(context, '/'), 109 | ); 110 | } 111 | return Container(width: 0, height: 0); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/ui/auth/sign_in_options_ui.dart: -------------------------------------------------------------------------------- 1 | /* Not currently used alternative signin options, google, apple, anonymous, etc*/ 2 | //import 'package:firebase_auth/firebase_auth.dart'; 3 | import 'package:flutter/material.dart'; 4 | //import 'package:flutter_auth_buttons/flutter_auth_buttons.dart'; 5 | import 'package:flutter_starter/ui/components/components.dart'; 6 | import 'package:flutter_starter/services/services.dart'; 7 | //import 'package:apple_sign_in/apple_sign_in.dart'; 8 | 9 | class SignInOptionsUI extends StatefulWidget { 10 | createState() => SignInOptionsUIState(); 11 | } 12 | 13 | class SignInOptionsUIState extends State { 14 | AuthService auth = AuthService(); 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | auth.getUser.then( 20 | (user) { 21 | if (user != null) { 22 | Navigator.pushReplacementNamed(context, '/topics'); 23 | } 24 | }, 25 | ); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | body: Center( 32 | child: Container( 33 | padding: EdgeInsets.all(30), 34 | decoration: BoxDecoration(), 35 | child: Column( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | children: [ 38 | LogoGraphicHeader(), 39 | SizedBox(height: 48.0), 40 | FormVerticalSpace(), 41 | /* GoogleSignInButton( 42 | darkMode: true, 43 | onPressed: () async { 44 | auth.googleSignIn(); 45 | }, 46 | ), 47 | FormVerticalSpace(), 48 | FutureBuilder( 49 | future: auth.appleSignInAvailable, 50 | builder: (context, snapshot) { 51 | if (snapshot.data == true) { 52 | return AppleSignInButton( 53 | style: AppleButtonStyle.black, 54 | onPressed: () async { 55 | FirebaseUser user = await auth.appleSignIn(); 56 | if (user != null) { 57 | Navigator.pushReplacementNamed(context, '/home'); 58 | } 59 | }, 60 | ); 61 | } else { 62 | return Container(); 63 | } 64 | }, 65 | ), 66 | FormVerticalSpace(),*/ 67 | PrimaryButton( 68 | onPressed: () async { 69 | Navigator.pushNamed(context, '/signin'); 70 | }, 71 | labelText: 'Sign In with Email & Password'), 72 | FormVerticalSpace(), 73 | /* PrimaryButton( 74 | onPressed: () async { 75 | auth.googleSignIn(); 76 | }, 77 | labelText: 'Sign In Anonymously'),*/ 78 | ], 79 | ), 80 | ), 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/ui/auth/sign_in_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_starter/localizations.dart'; 4 | import 'package:flutter_starter/ui/components/components.dart'; 5 | import 'package:flutter_starter/helpers/helpers.dart'; 6 | import 'package:flutter_starter/services/services.dart'; 7 | 8 | class SignInUI extends StatefulWidget { 9 | _SignInUIState createState() => _SignInUIState(); 10 | } 11 | 12 | class _SignInUIState extends State { 13 | final GlobalKey _formKey = GlobalKey(); 14 | final TextEditingController _email = new TextEditingController(); 15 | final TextEditingController _password = new TextEditingController(); 16 | final _scaffoldKey = GlobalKey(); 17 | bool _loading = false; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | } 23 | 24 | @override 25 | void dispose() { 26 | _email.dispose(); 27 | _password.dispose(); 28 | super.dispose(); 29 | } 30 | 31 | Widget build(BuildContext context) { 32 | final labels = AppLocalizations.of(context); 33 | 34 | return Scaffold( 35 | key: _scaffoldKey, 36 | body: LoadingScreen( 37 | child: Form( 38 | key: _formKey, 39 | child: Padding( 40 | padding: const EdgeInsets.symmetric(horizontal: 24.0), 41 | child: Center( 42 | child: SingleChildScrollView( 43 | child: Column( 44 | mainAxisAlignment: MainAxisAlignment.center, 45 | crossAxisAlignment: CrossAxisAlignment.stretch, 46 | children: [ 47 | LogoGraphicHeader(), 48 | SizedBox(height: 48.0), 49 | FormInputFieldWithIcon( 50 | controller: _email, 51 | iconPrefix: Icons.email, 52 | labelText: labels.auth.emailFormField, 53 | validator: Validator(labels).email, 54 | keyboardType: TextInputType.emailAddress, 55 | onChanged: (value) => null, 56 | onSaved: (value) => _email.text = value, 57 | ), 58 | FormVerticalSpace(), 59 | FormInputFieldWithIcon( 60 | controller: _password, 61 | iconPrefix: Icons.lock, 62 | labelText: labels.auth.passwordFormField, 63 | validator: Validator(labels).password, 64 | obscureText: true, 65 | onChanged: (value) => null, 66 | onSaved: (value) => _password.text = value, 67 | maxLines: 1, 68 | ), 69 | FormVerticalSpace(), 70 | PrimaryButton( 71 | labelText: labels.auth.signInButton, 72 | onPressed: () async { 73 | if (_formKey.currentState.validate()) { 74 | setState(() { 75 | _loading = true; 76 | }); 77 | AuthService _auth = AuthService(); 78 | bool status = await _auth 79 | .signInWithEmailAndPassword( 80 | _email.text, _password.text) 81 | .then((status) { 82 | setState(() { 83 | _loading = false; 84 | }); 85 | return status; 86 | }); 87 | if (!status) { 88 | _scaffoldKey.currentState.showSnackBar(SnackBar( 89 | content: Text(labels.auth.signInError), 90 | )); 91 | } 92 | } 93 | }), 94 | FormVerticalSpace(), 95 | LabelButton( 96 | labelText: labels.auth.resetPasswordLabelButton, 97 | onPressed: () => Navigator.pushReplacementNamed( 98 | context, '/reset-password'), 99 | ), 100 | LabelButton( 101 | labelText: labels.auth.signUpLabelButton, 102 | onPressed: () => 103 | Navigator.pushReplacementNamed(context, '/signup'), 104 | ), 105 | ], 106 | ), 107 | ), 108 | ), 109 | ), 110 | ), 111 | inAsyncCall: _loading, 112 | color: Theme.of(context).scaffoldBackgroundColor, 113 | ), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/ui/auth/sign_up_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_starter/localizations.dart'; 4 | import 'package:flutter_starter/ui/components/components.dart'; 5 | import 'package:flutter_starter/helpers/helpers.dart'; 6 | import 'package:flutter_starter/services/services.dart'; 7 | 8 | class SignUpUI extends StatefulWidget { 9 | _SignUpUIState createState() => _SignUpUIState(); 10 | } 11 | 12 | class _SignUpUIState extends State { 13 | final GlobalKey _formKey = GlobalKey(); 14 | final TextEditingController _name = new TextEditingController(); 15 | final TextEditingController _email = new TextEditingController(); 16 | final TextEditingController _password = new TextEditingController(); 17 | final _scaffoldKey = GlobalKey(); 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | } 23 | 24 | @override 25 | void dispose() { 26 | _name.dispose(); 27 | _email.dispose(); 28 | _password.dispose(); 29 | super.dispose(); 30 | } 31 | 32 | Widget build(BuildContext context) { 33 | final labels = AppLocalizations.of(context); 34 | bool _loading = false; 35 | 36 | return Scaffold( 37 | key: _scaffoldKey, 38 | body: LoadingScreen( 39 | child: Form( 40 | key: _formKey, 41 | child: Padding( 42 | padding: const EdgeInsets.symmetric(horizontal: 24.0), 43 | child: Center( 44 | child: SingleChildScrollView( 45 | child: Column( 46 | mainAxisAlignment: MainAxisAlignment.center, 47 | crossAxisAlignment: CrossAxisAlignment.stretch, 48 | children: [ 49 | LogoGraphicHeader(), 50 | SizedBox(height: 48.0), 51 | FormInputFieldWithIcon( 52 | controller: _name, 53 | iconPrefix: Icons.person, 54 | labelText: labels.auth.nameFormField, 55 | validator: Validator(labels).name, 56 | onChanged: (value) => null, 57 | onSaved: (value) => _name.text = value, 58 | ), 59 | FormVerticalSpace(), 60 | FormInputFieldWithIcon( 61 | controller: _email, 62 | iconPrefix: Icons.email, 63 | labelText: labels.auth.emailFormField, 64 | validator: Validator(labels).email, 65 | keyboardType: TextInputType.emailAddress, 66 | onChanged: (value) => null, 67 | onSaved: (value) => _email.text = value, 68 | ), 69 | FormVerticalSpace(), 70 | FormInputFieldWithIcon( 71 | controller: _password, 72 | iconPrefix: Icons.lock, 73 | labelText: labels.auth.passwordFormField, 74 | validator: Validator(labels).password, 75 | obscureText: true, 76 | maxLines: 1, 77 | onChanged: (value) => null, 78 | onSaved: (value) => _password.text = value, 79 | ), 80 | FormVerticalSpace(), 81 | PrimaryButton( 82 | labelText: labels.auth.signUpButton, 83 | onPressed: () async { 84 | if (_formKey.currentState.validate()) { 85 | SystemChannels.textInput.invokeMethod( 86 | 'TextInput.hide'); //to hide the keyboard - if any 87 | AuthService _auth = AuthService(); 88 | bool _isRegisterSucccess = 89 | await _auth.registerWithEmailAndPassword( 90 | _name.text, _email.text, _password.text); 91 | 92 | if (_isRegisterSucccess == false) { 93 | _scaffoldKey.currentState.showSnackBar(SnackBar( 94 | content: Text(labels.auth.signUpError), 95 | )); 96 | } 97 | } 98 | }), 99 | FormVerticalSpace(), 100 | LabelButton( 101 | labelText: labels.auth.signInLabelButton, 102 | onPressed: () => 103 | Navigator.pushReplacementNamed(context, '/'), 104 | ), 105 | ], 106 | ), 107 | ), 108 | ), 109 | ), 110 | ), 111 | inAsyncCall: _loading, 112 | color: Theme.of(context).scaffoldBackgroundColor, 113 | ), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/ui/auth/update_profile_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:flutter_starter/models/models.dart'; 5 | import 'package:flutter_starter/localizations.dart'; 6 | import 'package:flutter_starter/ui/components/components.dart'; 7 | import 'package:flutter_starter/helpers/helpers.dart'; 8 | import 'package:flutter_starter/services/services.dart'; 9 | 10 | class UpdateProfileUI extends StatefulWidget { 11 | _UpdateProfileUIState createState() => _UpdateProfileUIState(); 12 | } 13 | 14 | class _UpdateProfileUIState extends State { 15 | final GlobalKey _formKey = GlobalKey(); 16 | final TextEditingController _name = new TextEditingController(); 17 | final TextEditingController _email = new TextEditingController(); 18 | final _scaffoldKey = GlobalKey(); 19 | bool _loading = false; 20 | @override 21 | void initState() { 22 | super.initState(); 23 | } 24 | 25 | @override 26 | void dispose() { 27 | _name.dispose(); 28 | _email.dispose(); 29 | super.dispose(); 30 | } 31 | 32 | Widget build(BuildContext context) { 33 | final labels = AppLocalizations.of(context); 34 | return Scaffold( 35 | key: _scaffoldKey, 36 | appBar: AppBar(title: Text(labels.auth.updateProfileTitle)), 37 | body: LoadingScreen( 38 | child: updateProfileForm(context), 39 | inAsyncCall: _loading, 40 | color: Theme.of(context).scaffoldBackgroundColor, 41 | )); 42 | } 43 | 44 | updateProfileForm(BuildContext context) { 45 | final UserModel user = Provider.of(context); 46 | _name.text = user?.name; 47 | _email.text = user?.email; 48 | final labels = AppLocalizations.of(context); 49 | return Form( 50 | key: _formKey, 51 | child: Padding( 52 | padding: const EdgeInsets.symmetric(horizontal: 24.0), 53 | child: Center( 54 | child: SingleChildScrollView( 55 | child: Column( 56 | mainAxisAlignment: MainAxisAlignment.center, 57 | crossAxisAlignment: CrossAxisAlignment.stretch, 58 | children: [ 59 | LogoGraphicHeader(), 60 | SizedBox(height: 48.0), 61 | FormInputFieldWithIcon( 62 | controller: _name, 63 | iconPrefix: Icons.person, 64 | labelText: labels.auth.nameFormField, 65 | validator: Validator(labels).name, 66 | onChanged: (value) => null, 67 | onSaved: (value) => _name.text = value, 68 | ), 69 | FormVerticalSpace(), 70 | FormInputFieldWithIcon( 71 | controller: _email, 72 | iconPrefix: Icons.email, 73 | labelText: labels.auth.emailFormField, 74 | validator: Validator(labels).email, 75 | keyboardType: TextInputType.emailAddress, 76 | onChanged: (value) => null, 77 | onSaved: (value) => _email.text = value, 78 | ), 79 | FormVerticalSpace(), 80 | PrimaryButton( 81 | labelText: labels.auth.updateUser, 82 | onPressed: () { 83 | if (_formKey.currentState.validate()) { 84 | SystemChannels.textInput.invokeMethod('TextInput.hide'); 85 | UserModel _updatedUser = UserModel( 86 | uid: user?.uid, 87 | name: _name.text, 88 | email: _email.text, 89 | photoUrl: user?.photoUrl); 90 | _updateUserConfirm(context, _updatedUser, user?.email); 91 | } 92 | }), 93 | FormVerticalSpace(), 94 | LabelButton( 95 | labelText: labels.auth.changePasswordLabelButton, 96 | onPressed: () => Navigator.pushNamed( 97 | context, '/reset-password', 98 | arguments: user.email)), 99 | ], 100 | ), 101 | ), 102 | ), 103 | ), 104 | ); 105 | } 106 | 107 | Future _updateUserConfirm( 108 | BuildContext context, UserModel updatedUser, String oldEmail) async { 109 | final labels = AppLocalizations.of(context); 110 | AuthService _auth = AuthService(); 111 | final TextEditingController _password = new TextEditingController(); 112 | return showDialog( 113 | context: context, 114 | builder: (context) { 115 | return AlertDialog( 116 | shape: RoundedRectangleBorder( 117 | borderRadius: BorderRadius.all(Radius.circular(8.0))), 118 | title: Text( 119 | labels.auth.enterPassword, 120 | ), 121 | content: FormInputFieldWithIcon( 122 | controller: _password, 123 | iconPrefix: Icons.lock, 124 | labelText: labels.auth.passwordFormField, 125 | validator: Validator(labels).password, 126 | obscureText: true, 127 | onChanged: (value) => null, 128 | onSaved: (value) => _password.text = value, 129 | maxLines: 1, 130 | ), 131 | actions: [ 132 | new FlatButton( 133 | child: new Text(labels.auth.cancel.toUpperCase()), 134 | onPressed: () { 135 | Navigator.of(context).pop(); 136 | setState(() { 137 | _loading = false; 138 | }); 139 | }, 140 | ), 141 | new FlatButton( 142 | child: new Text(labels.auth.submit.toUpperCase()), 143 | onPressed: () async { 144 | setState(() { 145 | _loading = true; 146 | }); 147 | Navigator.of(context).pop(); 148 | try { 149 | await _auth 150 | .updateUser(updatedUser, oldEmail, _password.text) 151 | .then((result) { 152 | setState(() { 153 | _loading = false; 154 | }); 155 | 156 | if (result == true) { 157 | _scaffoldKey.currentState.showSnackBar( 158 | SnackBar( 159 | content: Text(labels.auth.updateUserSuccessNotice), 160 | ), 161 | ); 162 | } 163 | }); 164 | } on PlatformException catch (error) { 165 | //List errors = error.toString().split(','); 166 | // print("Error: " + errors[1]); 167 | print(error.code); 168 | String authError; 169 | switch (error.code) { 170 | case 'ERROR_WRONG_PASSWORD': 171 | authError = labels.auth.wrongPasswordNotice; 172 | break; 173 | default: 174 | authError = labels.auth.unknownError; 175 | break; 176 | } 177 | _scaffoldKey.currentState.showSnackBar(SnackBar( 178 | content: Text(authError), 179 | )); 180 | setState(() { 181 | _loading = false; 182 | }); 183 | } 184 | }, 185 | ) 186 | ], 187 | ); 188 | }); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /lib/ui/components/avatar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_starter/models/models.dart'; 3 | import 'package:flutter_starter/ui/components/components.dart'; 4 | 5 | class Avatar extends StatelessWidget { 6 | Avatar( 7 | this.user, 8 | ); 9 | final UserModel user; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | if ((user?.photoUrl == '') || (user?.photoUrl == null)) { 14 | return LogoGraphicHeader(); 15 | } 16 | return Hero( 17 | tag: 'User Avatar Image', 18 | child: CircleAvatar( 19 | foregroundColor: Colors.blue, 20 | backgroundColor: Colors.white, 21 | radius: 70.0, 22 | child: ClipOval( 23 | child: Image.network( 24 | user?.photoUrl, 25 | fit: BoxFit.cover, 26 | width: 120.0, 27 | height: 120.0, 28 | ), 29 | )), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/ui/components/components.dart: -------------------------------------------------------------------------------- 1 | export 'loading_screen.dart'; 2 | export 'form_input_field_with_icon.dart'; 3 | export 'form_input_field.dart'; 4 | export 'form_vertical_spacing.dart'; 5 | export 'primary_button.dart'; 6 | export 'label_button.dart'; 7 | export 'logo_graphic_header.dart'; 8 | export 'dropdown_picker.dart'; 9 | export 'dropdown_picker_with_icon.dart'; 10 | export 'avatar.dart'; 11 | -------------------------------------------------------------------------------- /lib/ui/components/dropdown_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | /* 3 | DropdownPicker( 4 | menuOptions: list of dropdown options in key value pairs, 5 | selectedOption: menu option string value, 6 | onChanged: (value) => print('changed'), 7 | ), 8 | */ 9 | 10 | class DropdownPicker extends StatelessWidget { 11 | DropdownPicker({this.menuOptions, this.selectedOption, this.onChanged}); 12 | 13 | final List menuOptions; 14 | final String selectedOption; 15 | final void Function(String) onChanged; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return DropdownButton( 20 | items: menuOptions 21 | .map((data) => DropdownMenuItem( 22 | child: Text( 23 | data.value, 24 | ), 25 | value: data.key, 26 | )) 27 | .toList(), 28 | value: selectedOption, 29 | onChanged: onChanged); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/ui/components/dropdown_picker_with_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /* 4 | DropdownPickerWithIcon( 5 | menuOptions: list of dropdown options in key value pairs, 6 | selectedOption: menu option string value, 7 | onChanged: (value) => print('changed'), 8 | ), 9 | */ 10 | class DropdownPickerWithIcon extends StatelessWidget { 11 | DropdownPickerWithIcon( 12 | {this.menuOptions, this.selectedOption, this.onChanged}); 13 | 14 | final List menuOptions; 15 | final String selectedOption; 16 | final void Function(String) onChanged; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | //if (Platform.isIOS) {} 21 | return DropdownButton( 22 | items: menuOptions 23 | .map((data) => DropdownMenuItem( 24 | child: Row( 25 | mainAxisAlignment: MainAxisAlignment.start, 26 | children: [ 27 | Icon(data.icon), 28 | SizedBox(width: 10), 29 | Text( 30 | data.value, 31 | ), 32 | ], 33 | ), 34 | value: data.key, 35 | )) 36 | .toList(), 37 | value: selectedOption, 38 | onChanged: onChanged); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/ui/components/form_input_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /* 4 | FormInputField( 5 | controller: _url, 6 | labelText: 'Post URL', 7 | validator: Validator.notEmpty, 8 | keyboardType: TextInputType.multiline, 9 | minLines: 3, 10 | onChanged: (value) => print('changed'), 11 | onSaved: (value) => print('implement me'), 12 | ), 13 | */ 14 | 15 | class FormInputField extends StatelessWidget { 16 | FormInputField( 17 | {this.controller, 18 | this.labelText, 19 | this.validator, 20 | this.keyboardType = TextInputType.text, 21 | this.obscureText = false, 22 | this.minLines = 1, 23 | this.onChanged, 24 | this.onSaved}); 25 | 26 | final TextEditingController controller; 27 | final String labelText; 28 | final String Function(String) validator; 29 | final TextInputType keyboardType; 30 | final bool obscureText; 31 | final int minLines; 32 | final void Function(String) onChanged; 33 | final void Function(String) onSaved; 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return TextFormField( 38 | decoration: InputDecoration( 39 | border: OutlineInputBorder( 40 | borderRadius: BorderRadius.all( 41 | Radius.circular(8.0), 42 | )), 43 | enabledBorder: OutlineInputBorder( 44 | borderSide: BorderSide(color: Colors.black45, width: 1.0), 45 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 46 | ), 47 | focusedBorder: OutlineInputBorder( 48 | borderSide: BorderSide( 49 | color: /*Palette.focusedinputBorderColor*/ Colors.black45, 50 | width: 1.0), 51 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 52 | ), 53 | filled: true, 54 | fillColor: Colors.black45, //Palette.inputFillColor, 55 | labelText: labelText, 56 | ), 57 | controller: controller, 58 | onSaved: onSaved, 59 | onChanged: onChanged, 60 | keyboardType: keyboardType, 61 | obscureText: obscureText, 62 | maxLines: null, 63 | minLines: minLines, 64 | validator: validator, 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/ui/components/form_input_field_with_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | /* 3 | FormInputFieldWithIcon( 4 | controller: _email, 5 | iconPrefix: Icons.link, 6 | labelText: 'Post URL', 7 | validator: Validator.notEmpty, 8 | keyboardType: TextInputType.multiline, 9 | minLines: 3, 10 | onChanged: (value) => print('changed'), 11 | onSaved: (value) => print('implement me'), 12 | ), 13 | */ 14 | 15 | class FormInputFieldWithIcon extends StatelessWidget { 16 | FormInputFieldWithIcon( 17 | {this.controller, 18 | this.iconPrefix, 19 | this.labelText, 20 | this.validator, 21 | this.keyboardType = TextInputType.text, 22 | this.obscureText = false, 23 | this.minLines = 1, 24 | this.maxLines, 25 | this.onChanged, 26 | this.onSaved}); 27 | 28 | final TextEditingController controller; 29 | final IconData iconPrefix; 30 | final String labelText; 31 | final String Function(String) validator; 32 | final TextInputType keyboardType; 33 | final bool obscureText; 34 | final int minLines; 35 | final int maxLines; 36 | final void Function(String) onChanged; 37 | final void Function(String) onSaved; 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return TextFormField( 42 | decoration: InputDecoration( 43 | filled: true, 44 | prefixIcon: Icon(iconPrefix), 45 | labelText: labelText, 46 | ), 47 | controller: controller, 48 | onSaved: onSaved, 49 | onChanged: onChanged, 50 | keyboardType: keyboardType, 51 | obscureText: obscureText, 52 | maxLines: maxLines, 53 | minLines: minLines, 54 | validator: validator, 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/ui/components/form_vertical_spacing.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FormVerticalSpace extends SizedBox { 4 | FormVerticalSpace({double height = 24.0}) : super(height: height); 5 | } 6 | -------------------------------------------------------------------------------- /lib/ui/components/label_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | /* 3 | LabelButton( 4 | labelText: 'Some Text', 5 | onPressed: () => print('implement me'), 6 | ), 7 | */ 8 | 9 | class LabelButton extends StatelessWidget { 10 | LabelButton({this.labelText, this.onPressed}); 11 | final String labelText; 12 | final void Function() onPressed; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return FlatButton( 17 | child: Text( 18 | labelText, 19 | ), 20 | onPressed: onPressed, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/ui/components/loading_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | //modification of library modal_progress_hud; 4 | 5 | /// 6 | /// Wrap around any widget that makes an async call to show a modal progress 7 | /// indicator while the async call is in progress. 8 | /// 9 | /// The progress indicator can be turned on or off using [inAsyncCall] 10 | /// 11 | /// The progress indicator defaults to a [CircularProgressIndicator] but can be 12 | /// any kind of widget 13 | /// 14 | /// The progress indicator can be positioned using [offset] otherwise it is 15 | /// centered 16 | /// 17 | /// The modal barrier can be dismissed using [dismissible] 18 | /// 19 | /// The color of the modal barrier can be set using [color] 20 | /// 21 | /// The opacity of the modal barrier can be set using [opacity] 22 | /// 23 | /// HUD=Heads Up Display 24 | /// 25 | class LoadingScreen extends StatelessWidget { 26 | final bool inAsyncCall; 27 | final double opacity; 28 | final Color color; 29 | final Widget progressIndicator; 30 | final Offset offset; 31 | final bool dismissible; 32 | final Widget child; 33 | 34 | LoadingScreen({ 35 | Key key, 36 | @required this.inAsyncCall, 37 | this.opacity = 0.7, 38 | this.color = Colors.white, 39 | this.progressIndicator = const CircularProgressIndicator(), 40 | this.offset, 41 | this.dismissible = false, 42 | @required this.child, 43 | }) : assert(child != null), 44 | assert(inAsyncCall != null), 45 | super(key: key); 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | List widgetList = []; 50 | widgetList.add(child); 51 | if (inAsyncCall) { 52 | Widget layOutProgressIndicator; 53 | if (offset == null) { 54 | layOutProgressIndicator = Center( 55 | child: Container( 56 | height: 60, 57 | width: 60, 58 | decoration: BoxDecoration( 59 | //color: Palette.primaryColor, 60 | shape: BoxShape.circle, 61 | ), 62 | //need this due to bug...https://github.com/flutter/flutter/issues/18399 63 | child: Align( 64 | alignment: Alignment.center, 65 | child: SizedBox( 66 | child: CircularProgressIndicator( 67 | // backgroundColor: Palette.textColorInvert, 68 | ), 69 | height: 30.0, 70 | width: 30.0, 71 | ), 72 | ))); 73 | } else { 74 | layOutProgressIndicator = Positioned( 75 | child: progressIndicator, 76 | left: offset.dx, 77 | top: offset.dy, 78 | ); 79 | } 80 | final modal = [ 81 | new Opacity( 82 | child: new ModalBarrier(dismissible: dismissible, color: color), 83 | opacity: opacity, 84 | ), 85 | layOutProgressIndicator 86 | ]; 87 | widgetList += modal; 88 | } 89 | return new Stack( 90 | children: widgetList, 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/ui/components/logo_graphic_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:flutter_starter/services/services.dart'; 4 | 5 | class LogoGraphicHeader extends StatelessWidget { 6 | LogoGraphicHeader(); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | final themeProvider = Provider.of(context); 11 | String _imageLogo = 'assets/images/default.png'; 12 | if (themeProvider.isDarkModeOn == true) { 13 | _imageLogo = 'assets/images/defaultDark.png'; 14 | } 15 | return Hero( 16 | tag: 'App Logo', 17 | child: CircleAvatar( 18 | foregroundColor: Colors.blue, 19 | backgroundColor: Colors.transparent, 20 | radius: 60.0, 21 | child: ClipOval( 22 | child: Image.asset( 23 | _imageLogo, 24 | fit: BoxFit.cover, 25 | width: 120.0, 26 | height: 120.0, 27 | ), 28 | )), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/ui/components/primary_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /* 4 | PrimaryButton( 5 | labelText: 'UPDATE', 6 | onPressed: () => print('Submit'), 7 | ), 8 | */ 9 | 10 | class PrimaryButton extends StatelessWidget { 11 | PrimaryButton({this.labelText, this.onPressed}); 12 | 13 | final String labelText; 14 | final void Function() onPressed; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return RaisedButton( 19 | onPressed: onPressed, 20 | padding: EdgeInsets.all(22), 21 | child: Text( 22 | labelText.toUpperCase(), 23 | style: TextStyle(fontWeight: FontWeight.bold), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/ui/components/segmented_selector.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_starter/ui/components/sliding_segmented_control.dart'; 3 | /* 4 | SegmentedSelector( 5 | menuOptions: list of dropdown options in key value pairs, 6 | selectedOption: menu option string value, 7 | onChanged: (value) => print('changed'), 8 | ), 9 | */ 10 | 11 | class SegmentedSelector extends StatelessWidget { 12 | SegmentedSelector( 13 | {this.menuOptions, this.selectedOption, this.onValueChanged}); 14 | 15 | final List menuOptions; 16 | final String selectedOption; 17 | final void Function(dynamic) onValueChanged; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | //if (Platform.isIOS) {} 22 | 23 | return CupertinoSlidingSegmentedControl( 24 | //thumbColor: Theme.of(context).primaryColor, 25 | groupValue: selectedOption, 26 | children: Map.fromIterable( 27 | menuOptions, 28 | key: (option) => option.key, 29 | value: (option) => Row( 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | children: [ 32 | Icon(option.icon), 33 | SizedBox(width: 6), 34 | Text(option.value), 35 | ], 36 | ), 37 | ), 38 | onValueChanged: onValueChanged); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/ui/home_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:flutter_starter/localizations.dart'; 4 | import 'package:flutter_starter/services/services.dart'; 5 | import 'package:flutter_starter/models/models.dart'; 6 | import 'package:flutter_starter/ui/components/components.dart'; 7 | 8 | class HomeUI extends StatefulWidget { 9 | @override 10 | _HomeUIState createState() => _HomeUIState(); 11 | } 12 | 13 | class _HomeUIState extends State { 14 | bool _loading = true; 15 | String _uid = ''; 16 | String _name = ''; 17 | String _email = ''; 18 | String _admin = ''; 19 | @override 20 | void initState() { 21 | super.initState(); 22 | } 23 | 24 | @override 25 | void dispose() { 26 | super.dispose(); 27 | } 28 | 29 | Widget build(BuildContext context) { 30 | final labels = AppLocalizations.of(context); 31 | final UserModel user = Provider.of(context); 32 | if (user != null) { 33 | setState(() { 34 | _loading = false; 35 | _uid = user.uid; 36 | _name = user.name; 37 | _email = user.email; 38 | }); 39 | } 40 | 41 | _isUserAdmin(); 42 | 43 | return Scaffold( 44 | appBar: AppBar( 45 | title: Text(labels.home.title), 46 | actions: [ 47 | IconButton( 48 | icon: Icon(Icons.settings), 49 | onPressed: () { 50 | Navigator.of(context).pushNamed('/settings'); 51 | }), 52 | ], 53 | ), 54 | body: LoadingScreen( 55 | child: Center( 56 | child: Column( 57 | children: [ 58 | SizedBox(height: 120), 59 | Avatar(user), 60 | Column( 61 | mainAxisAlignment: MainAxisAlignment.start, 62 | crossAxisAlignment: CrossAxisAlignment.start, 63 | children: [ 64 | FormVerticalSpace(), 65 | Text(labels.home.uidLabel + ': ' + _uid, 66 | style: TextStyle(fontSize: 16)), 67 | FormVerticalSpace(), 68 | Text(labels.home.nameLabel + ': ' + _name, 69 | style: TextStyle(fontSize: 16)), 70 | FormVerticalSpace(), 71 | Text(labels.home.emailLabel + ': ' + _email, 72 | style: TextStyle(fontSize: 16)), 73 | FormVerticalSpace(), 74 | Text(labels.home.adminUserLabel + ': ' + _admin, 75 | style: TextStyle(fontSize: 16)), 76 | ], 77 | ), 78 | ], 79 | ), 80 | ), 81 | inAsyncCall: _loading, 82 | color: Theme.of(context).scaffoldBackgroundColor, 83 | ), 84 | ); 85 | } 86 | 87 | _isUserAdmin() async { 88 | bool _isAdmin = await AuthService().isAdmin(); 89 | //handle setState bug //https://stackoverflow.com/questions/49340116/setstate-called-after-dispose 90 | if (mounted) { 91 | setState(() { 92 | _admin = _isAdmin.toString(); 93 | }); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/ui/settings_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter_starter/ui/components/segmented_selector.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:flutter_starter/localizations.dart'; 6 | import 'package:flutter_starter/services/services.dart'; 7 | import 'package:flutter_starter/ui/components/components.dart'; 8 | import 'package:flutter_starter/models/models.dart'; 9 | import 'package:flutter_starter/constants/constants.dart'; 10 | 11 | class SettingsUI extends StatelessWidget { 12 | @override 13 | Widget build(BuildContext context) { 14 | final labels = AppLocalizations.of(context); 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(labels.settings.title), 18 | ), 19 | body: _buildLayoutSection(context), 20 | ); 21 | } 22 | 23 | Widget _buildLayoutSection(BuildContext context) { 24 | final labels = AppLocalizations.of(context); 25 | final List themeOptions = [ 26 | MenuOptionsModel( 27 | key: "system", 28 | value: labels.settings.system, 29 | icon: Icons.brightness_4), 30 | MenuOptionsModel( 31 | key: "light", 32 | value: labels.settings.light, 33 | icon: Icons.brightness_low), 34 | MenuOptionsModel( 35 | key: "dark", value: labels.settings.dark, icon: Icons.brightness_3) 36 | ]; 37 | return ListView( 38 | children: [ 39 | ListTile( 40 | title: Text(labels.settings.language), 41 | //trailing: _languageDropdown(context), 42 | trailing: DropdownPicker( 43 | menuOptions: Globals.languageOptions, 44 | selectedOption: 45 | Provider.of(context).currentLanguage, 46 | onChanged: (value) { 47 | Provider.of(context, listen: false) 48 | .updateLanguage(value); 49 | }, 50 | ), 51 | ), 52 | ListTile( 53 | title: Text(labels.settings.theme), 54 | trailing: SegmentedSelector( 55 | selectedOption: Provider.of(context).getTheme, 56 | menuOptions: themeOptions, 57 | onValueChanged: (value) { 58 | Provider.of(context, listen: false) 59 | .updateTheme(value); 60 | }, 61 | ), 62 | ), 63 | ListTile( 64 | title: Text(labels.settings.updateProfile), 65 | trailing: RaisedButton( 66 | onPressed: () async { 67 | Navigator.of(context).pushNamed('/update-profile'); 68 | }, 69 | child: Text( 70 | labels.settings.updateProfile, 71 | ), 72 | )), 73 | ListTile( 74 | title: Text(labels.settings.signOut), 75 | trailing: RaisedButton( 76 | onPressed: () { 77 | AuthService _auth = AuthService(); 78 | _auth.signOut(); 79 | //Navigator.pushReplacementNamed(context, '/signin'); 80 | }, 81 | child: Text( 82 | labels.settings.signOut, 83 | ), 84 | )) 85 | 86 | /* ListTile( 87 | title: Text(labels.settings.theme), 88 | trailing: DropdownPickerWithIcon( 89 | menuOptions: themeOptions, 90 | selectedOption: Provider.of(context).getTheme, 91 | onChanged: (value) { 92 | Provider.of(context, listen: false) 93 | .updateTheme(value); 94 | }, 95 | ), 96 | ),*/ 97 | /* 98 | ListTile( 99 | title: Text(labels.settings.theme), 100 | trailing: CupertinoSlidingSegmentedControl( 101 | groupValue: Provider.of(context).getTheme, 102 | children: myTabs, 103 | onValueChanged: (value) { 104 | Provider.of(context, listen: false) 105 | .updateTheme(value); 106 | }, 107 | ), 108 | ),*/ 109 | ], 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/ui/ui.dart: -------------------------------------------------------------------------------- 1 | export 'home_ui.dart'; 2 | export 'settings_ui.dart'; 3 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "0.39.6" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.6.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.4.1" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.0.0" 39 | build: 40 | dependency: transitive 41 | description: 42 | name: build 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.2" 46 | build_config: 47 | dependency: transitive 48 | description: 49 | name: build_config 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.4.2" 53 | build_daemon: 54 | dependency: transitive 55 | description: 56 | name: build_daemon 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.1.4" 60 | build_resolvers: 61 | dependency: transitive 62 | description: 63 | name: build_resolvers 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.3.4" 67 | build_runner: 68 | dependency: "direct dev" 69 | description: 70 | name: build_runner 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.8.1" 74 | build_runner_core: 75 | dependency: transitive 76 | description: 77 | name: build_runner_core 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "5.0.0" 81 | built_collection: 82 | dependency: transitive 83 | description: 84 | name: built_collection 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "4.3.2" 88 | built_value: 89 | dependency: transitive 90 | description: 91 | name: built_value 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "7.0.9" 95 | charcode: 96 | dependency: transitive 97 | description: 98 | name: charcode 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.1.3" 102 | checked_yaml: 103 | dependency: transitive 104 | description: 105 | name: checked_yaml 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.0.2" 109 | clock: 110 | dependency: transitive 111 | description: 112 | name: clock 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.0.1" 116 | cloud_firestore: 117 | dependency: "direct main" 118 | description: 119 | name: cloud_firestore 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "0.13.4+2" 123 | cloud_firestore_platform_interface: 124 | dependency: transitive 125 | description: 126 | name: cloud_firestore_platform_interface 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.1.0" 130 | cloud_firestore_web: 131 | dependency: transitive 132 | description: 133 | name: cloud_firestore_web 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "0.1.1+2" 137 | code_builder: 138 | dependency: transitive 139 | description: 140 | name: code_builder 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "3.2.1" 144 | collection: 145 | dependency: transitive 146 | description: 147 | name: collection 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "1.14.12" 151 | convert: 152 | dependency: transitive 153 | description: 154 | name: convert 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "2.1.1" 158 | crypto: 159 | dependency: transitive 160 | description: 161 | name: crypto 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "2.1.4" 165 | csslib: 166 | dependency: transitive 167 | description: 168 | name: csslib 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "0.16.1" 172 | csv: 173 | dependency: transitive 174 | description: 175 | name: csv 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "4.0.3" 179 | cupertino_icons: 180 | dependency: "direct main" 181 | description: 182 | name: cupertino_icons 183 | url: "https://pub.dartlang.org" 184 | source: hosted 185 | version: "0.1.3" 186 | dart_style: 187 | dependency: transitive 188 | description: 189 | name: dart_style 190 | url: "https://pub.dartlang.org" 191 | source: hosted 192 | version: "1.3.4" 193 | fake_async: 194 | dependency: transitive 195 | description: 196 | name: fake_async 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "1.1.0" 200 | firebase: 201 | dependency: transitive 202 | description: 203 | name: firebase 204 | url: "https://pub.dartlang.org" 205 | source: hosted 206 | version: "7.2.1" 207 | firebase_analytics: 208 | dependency: "direct main" 209 | description: 210 | name: firebase_analytics 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "5.0.11" 214 | firebase_auth: 215 | dependency: "direct main" 216 | description: 217 | name: firebase_auth 218 | url: "https://pub.dartlang.org" 219 | source: hosted 220 | version: "0.15.5+3" 221 | firebase_auth_platform_interface: 222 | dependency: transitive 223 | description: 224 | name: firebase_auth_platform_interface 225 | url: "https://pub.dartlang.org" 226 | source: hosted 227 | version: "1.1.7" 228 | firebase_auth_web: 229 | dependency: transitive 230 | description: 231 | name: firebase_auth_web 232 | url: "https://pub.dartlang.org" 233 | source: hosted 234 | version: "0.1.2" 235 | firebase_core: 236 | dependency: "direct main" 237 | description: 238 | name: firebase_core 239 | url: "https://pub.dartlang.org" 240 | source: hosted 241 | version: "0.4.4+3" 242 | firebase_core_platform_interface: 243 | dependency: transitive 244 | description: 245 | name: firebase_core_platform_interface 246 | url: "https://pub.dartlang.org" 247 | source: hosted 248 | version: "1.0.4" 249 | firebase_core_web: 250 | dependency: transitive 251 | description: 252 | name: firebase_core_web 253 | url: "https://pub.dartlang.org" 254 | source: hosted 255 | version: "0.1.1+2" 256 | fixnum: 257 | dependency: transitive 258 | description: 259 | name: fixnum 260 | url: "https://pub.dartlang.org" 261 | source: hosted 262 | version: "0.10.11" 263 | flutter: 264 | dependency: "direct main" 265 | description: flutter 266 | source: sdk 267 | version: "0.0.0" 268 | flutter_localizations: 269 | dependency: "direct main" 270 | description: flutter 271 | source: sdk 272 | version: "0.0.0" 273 | flutter_platform_widgets: 274 | dependency: "direct main" 275 | description: 276 | name: flutter_platform_widgets 277 | url: "https://pub.dartlang.org" 278 | source: hosted 279 | version: "0.32.5" 280 | flutter_sheet_localization: 281 | dependency: "direct main" 282 | description: 283 | name: flutter_sheet_localization 284 | url: "https://pub.dartlang.org" 285 | source: hosted 286 | version: "1.0.0" 287 | flutter_sheet_localization_generator: 288 | dependency: "direct dev" 289 | description: 290 | name: flutter_sheet_localization_generator 291 | url: "https://pub.dartlang.org" 292 | source: hosted 293 | version: "1.2.0" 294 | flutter_test: 295 | dependency: "direct dev" 296 | description: flutter 297 | source: sdk 298 | version: "0.0.0" 299 | flutter_web_plugins: 300 | dependency: transitive 301 | description: flutter 302 | source: sdk 303 | version: "0.0.0" 304 | glob: 305 | dependency: transitive 306 | description: 307 | name: glob 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "1.2.0" 311 | graphs: 312 | dependency: transitive 313 | description: 314 | name: graphs 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "0.2.0" 318 | html: 319 | dependency: transitive 320 | description: 321 | name: html 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "0.14.0+3" 325 | http: 326 | dependency: transitive 327 | description: 328 | name: http 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "0.12.0+4" 332 | http_multi_server: 333 | dependency: transitive 334 | description: 335 | name: http_multi_server 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "2.2.0" 339 | http_parser: 340 | dependency: transitive 341 | description: 342 | name: http_parser 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "3.1.4" 346 | intl: 347 | dependency: transitive 348 | description: 349 | name: intl 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "0.16.1" 353 | io: 354 | dependency: transitive 355 | description: 356 | name: io 357 | url: "https://pub.dartlang.org" 358 | source: hosted 359 | version: "0.3.4" 360 | js: 361 | dependency: transitive 362 | description: 363 | name: js 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "0.6.1+1" 367 | json_annotation: 368 | dependency: transitive 369 | description: 370 | name: json_annotation 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "3.0.1" 374 | logging: 375 | dependency: transitive 376 | description: 377 | name: logging 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "0.11.4" 381 | matcher: 382 | dependency: transitive 383 | description: 384 | name: matcher 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "0.12.6" 388 | meta: 389 | dependency: transitive 390 | description: 391 | name: meta 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.1.8" 395 | mime: 396 | dependency: transitive 397 | description: 398 | name: mime 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "0.9.6+3" 402 | nested: 403 | dependency: transitive 404 | description: 405 | name: nested 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "0.0.4" 409 | node_interop: 410 | dependency: transitive 411 | description: 412 | name: node_interop 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "1.0.3" 416 | node_io: 417 | dependency: transitive 418 | description: 419 | name: node_io 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "1.0.1+2" 423 | package_config: 424 | dependency: transitive 425 | description: 426 | name: package_config 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "1.9.3" 430 | path: 431 | dependency: transitive 432 | description: 433 | name: path 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "1.7.0" 437 | pedantic: 438 | dependency: transitive 439 | description: 440 | name: pedantic 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "1.9.0" 444 | plugin_platform_interface: 445 | dependency: transitive 446 | description: 447 | name: plugin_platform_interface 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "1.0.2" 451 | pool: 452 | dependency: transitive 453 | description: 454 | name: pool 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "1.4.0" 458 | provider: 459 | dependency: "direct main" 460 | description: 461 | name: provider 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "4.0.5" 465 | pub_semver: 466 | dependency: transitive 467 | description: 468 | name: pub_semver 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "1.4.4" 472 | pubspec_parse: 473 | dependency: transitive 474 | description: 475 | name: pubspec_parse 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "0.1.5" 479 | quiver: 480 | dependency: transitive 481 | description: 482 | name: quiver 483 | url: "https://pub.dartlang.org" 484 | source: hosted 485 | version: "2.1.3" 486 | recase: 487 | dependency: transitive 488 | description: 489 | name: recase 490 | url: "https://pub.dartlang.org" 491 | source: hosted 492 | version: "2.0.1" 493 | shared_preferences: 494 | dependency: "direct main" 495 | description: 496 | name: shared_preferences 497 | url: "https://pub.dartlang.org" 498 | source: hosted 499 | version: "0.5.6+3" 500 | shared_preferences_macos: 501 | dependency: transitive 502 | description: 503 | name: shared_preferences_macos 504 | url: "https://pub.dartlang.org" 505 | source: hosted 506 | version: "0.0.1+6" 507 | shared_preferences_platform_interface: 508 | dependency: transitive 509 | description: 510 | name: shared_preferences_platform_interface 511 | url: "https://pub.dartlang.org" 512 | source: hosted 513 | version: "1.0.3" 514 | shared_preferences_web: 515 | dependency: transitive 516 | description: 517 | name: shared_preferences_web 518 | url: "https://pub.dartlang.org" 519 | source: hosted 520 | version: "0.1.2+4" 521 | shelf: 522 | dependency: transitive 523 | description: 524 | name: shelf 525 | url: "https://pub.dartlang.org" 526 | source: hosted 527 | version: "0.7.5" 528 | shelf_web_socket: 529 | dependency: transitive 530 | description: 531 | name: shelf_web_socket 532 | url: "https://pub.dartlang.org" 533 | source: hosted 534 | version: "0.2.3" 535 | simple_gravatar: 536 | dependency: "direct main" 537 | description: 538 | name: simple_gravatar 539 | url: "https://pub.dartlang.org" 540 | source: hosted 541 | version: "1.0.5" 542 | sky_engine: 543 | dependency: transitive 544 | description: flutter 545 | source: sdk 546 | version: "0.0.99" 547 | source_gen: 548 | dependency: transitive 549 | description: 550 | name: source_gen 551 | url: "https://pub.dartlang.org" 552 | source: hosted 553 | version: "0.9.5" 554 | source_span: 555 | dependency: transitive 556 | description: 557 | name: source_span 558 | url: "https://pub.dartlang.org" 559 | source: hosted 560 | version: "1.7.0" 561 | stack_trace: 562 | dependency: transitive 563 | description: 564 | name: stack_trace 565 | url: "https://pub.dartlang.org" 566 | source: hosted 567 | version: "1.9.3" 568 | stream_channel: 569 | dependency: transitive 570 | description: 571 | name: stream_channel 572 | url: "https://pub.dartlang.org" 573 | source: hosted 574 | version: "2.0.0" 575 | stream_transform: 576 | dependency: transitive 577 | description: 578 | name: stream_transform 579 | url: "https://pub.dartlang.org" 580 | source: hosted 581 | version: "1.2.0" 582 | string_scanner: 583 | dependency: transitive 584 | description: 585 | name: string_scanner 586 | url: "https://pub.dartlang.org" 587 | source: hosted 588 | version: "1.0.5" 589 | term_glyph: 590 | dependency: transitive 591 | description: 592 | name: term_glyph 593 | url: "https://pub.dartlang.org" 594 | source: hosted 595 | version: "1.1.0" 596 | test_api: 597 | dependency: transitive 598 | description: 599 | name: test_api 600 | url: "https://pub.dartlang.org" 601 | source: hosted 602 | version: "0.2.15" 603 | timing: 604 | dependency: transitive 605 | description: 606 | name: timing 607 | url: "https://pub.dartlang.org" 608 | source: hosted 609 | version: "0.1.1+2" 610 | typed_data: 611 | dependency: transitive 612 | description: 613 | name: typed_data 614 | url: "https://pub.dartlang.org" 615 | source: hosted 616 | version: "1.1.6" 617 | vector_math: 618 | dependency: transitive 619 | description: 620 | name: vector_math 621 | url: "https://pub.dartlang.org" 622 | source: hosted 623 | version: "2.0.8" 624 | watcher: 625 | dependency: transitive 626 | description: 627 | name: watcher 628 | url: "https://pub.dartlang.org" 629 | source: hosted 630 | version: "0.9.7+14" 631 | web_socket_channel: 632 | dependency: transitive 633 | description: 634 | name: web_socket_channel 635 | url: "https://pub.dartlang.org" 636 | source: hosted 637 | version: "1.1.0" 638 | yaml: 639 | dependency: transitive 640 | description: 641 | name: yaml 642 | url: "https://pub.dartlang.org" 643 | source: hosted 644 | version: "2.2.0" 645 | sdks: 646 | dart: ">=2.7.0 <3.0.0" 647 | flutter: ">=1.12.13+hotfix.4 <2.0.0" 648 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_starter 2 | description: A new Flutter project. 3 | 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: '>=2.7.0 <3.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | flutter_localizations: 13 | sdk: flutter 14 | cupertino_icons: 15 | 16 | firebase_core: 17 | firebase_analytics: 18 | cloud_firestore: 19 | 20 | firebase_auth: 21 | # google_sign_in: 22 | # apple_sign_in: 23 | 24 | provider: 25 | shared_preferences: 26 | # upstate: 27 | 28 | flutter_platform_widgets: 29 | flutter_sheet_localization: ^1.0.0 30 | simple_gravatar: 31 | # flutter_auth_buttons: 32 | 33 | dev_dependencies: 34 | flutter_test: 35 | sdk: flutter 36 | flutter_sheet_localization_generator: ^1.0.0 37 | build_runner: ^1.3.1 38 | 39 | flutter: 40 | uses-material-design: true 41 | assets: 42 | - assets/images/default.png 43 | - assets/images/defaultDark.png 44 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delay/flutter_firebase_auth_starter/8385cc5b179af29e32c6bd6de5e5bc73b90c316f/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | flutter_starter 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 50 | 53 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_starter", 3 | "short_name": "flutter_starter", 4 | "start_url": ".", 5 | "display": "minimal-ui", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------