├── .gitignore
├── .metadata
├── README.md
├── android
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── flutterfirebaseauthexample
│ │ │ └── MainActivity.java
│ │ └── 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
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── images
│ └── default.png
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── 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
│ └── main.m
├── lib
├── main.dart
├── models
│ ├── settings.dart
│ ├── state.dart
│ └── user.dart
├── ui
│ ├── screens
│ │ ├── forgot_password.dart
│ │ ├── home.dart
│ │ ├── sign_in.dart
│ │ └── sign_up.dart
│ ├── theme.dart
│ └── widgets
│ │ └── loading.dart
└── util
│ ├── auth.dart
│ ├── state_widget.dart
│ └── validator.dart
├── pubspec.yaml
└── website_images
└── screenshot_auth.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 |
40 | # iOS/XCode related
41 | **/ios/**/*.mode1v3
42 | **/ios/**/*.mode2v3
43 | **/ios/**/*.moved-aside
44 | **/ios/**/*.pbxuser
45 | **/ios/**/*.perspectivev3
46 | **/ios/**/*sync/
47 | **/ios/**/.sconsign.dblite
48 | **/ios/**/.tags*
49 | **/ios/**/.vagrant/
50 | **/ios/**/DerivedData/
51 | **/ios/**/Icon?
52 | **/ios/**/Pods/
53 | **/ios/**/.symlinks/
54 | **/ios/**/profile
55 | **/ios/**/xcuserdata
56 | **/ios/.generated/
57 | **/ios/Flutter/App.framework
58 | **/ios/Flutter/Flutter.framework
59 | **/ios/Flutter/Generated.xcconfig
60 | **/ios/Flutter/app.flx
61 | **/ios/Flutter/app.zip
62 | **/ios/Flutter/flutter_assets/
63 | **/ios/ServiceDefinitions.json
64 | **/ios/Runner/GeneratedPluginRegistrant.*
65 |
66 | # Exceptions to above rules.
67 | !**/ios/**/default.mode1v3
68 | !**/ios/**/default.mode2v3
69 | !**/ios/**/default.pbxuser
70 | !**/ios/**/default.perspectivev3
71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
72 |
--------------------------------------------------------------------------------
/.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: f3f124f506962680af0085e2a2ef47c88565e551
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Auth with Firebase Example
2 |
3 | 
4 |
5 | ## This project has been replaced with this [new flutter auth project](https://github.com/delay/flutter_firebase_auth_starter) I made. Please use it instead. It has more features and does things in a more flutter way.
6 |
7 | There are numerous tutorials on using firebase auth with flutter. I went through many of these to work through making my own take on a Firebase Auth flutter project that worked the way I needed it to. Definitely check out these projects which provide much more in depth tutorials.
8 |
9 | [Simple Recipe app made in flutter firebase and google sign in](https://medium.com/flutter-community/simple-recipes-app-made-in-flutter-firebase-and-google-sign-in-14d1535e9a59)
10 |
11 | [Instaflutter](https://github.com/instaflutter/flutter-login-screen-firebase-auth-facebook-login)
12 |
13 | [Flutter login UI](https://github.com/putraxor/flutter-login-ui)
14 |
15 | [How to do user login with firebase](https://medium.com/flutterpub/flutter-how-to-do-user-login-with-firebase-a6af760b14d5)
16 |
17 | I am still new to flutter so there are probably better ways to handle many of the options in this code.
18 | I setup my project to combine firebase auth with saving my user info to shared preferences on the mobile device. When logging in it reads the info from local storage first. If it doesn’t exist, the user logs into firebase and the user and settings data is retrieved from firestore and stored locally. This minimizes the number of requests required from firestore. I wanted to login with an email and password as opposed to logging in with google sign in or facebook sign in.
19 |
20 | I also use validation for text fields and handle and display error messages via a snackbar style notification [flushbar package](https://pub.dartlang.org/packages/flushbar). Finally I use global state to keep track of when the data changes.
21 |
22 | ## Overview of files...
23 |
24 | **main.dart** - this file initializes the app and contains the routing as well as the global state setup and references the custom theme.
25 |
26 | ## /ui/
27 |
28 | **theme.dart** - contains some custom theme info.
29 |
30 | ## /ui/screens/
31 |
32 | **home.dart** - HomeScreen when the user is logged in, also redirects the user when he is not logged in to the SignInScreen.
33 |
34 | **sign_in.dart** - SignInScreen . When signing in logs in with Firebase Auth, then retrieves data from the two collections in firestore and saves it locally, also calls the state_widget so the global state can be updated once logged in.
35 |
36 | **sign_up.dart** - SignUpScreen sets up a new user in Firebase Auth and writes two new documents in Firestore, one to the users collection and one to the settings collection on firebase.
37 |
38 | **forgot_password.dart** - ForgotPasswordScreen lets you send a firebase query to reset your password.
39 |
40 | ## /ui/widgets
41 |
42 | **loading.dart** - LoadingScreen - small modification to the excellent package [modal_progress_hud](https://pub.dartlang.org/packages/modal_progress_hud) to wrap the circular progress indicator.
43 |
44 | ## /util/
45 |
46 | **auth.dart** - The Auth class which controls authenticating and reading and storing info related to auth.
47 |
48 | **state_widget.dart** - The state widget class which initializes the user and logs them in and out.
49 |
50 | **validator.dart** - Validation class with some custom validations for email, password, etc.
51 |
52 | ## /models/
53 |
54 | > Used [quicktype](https://app.quicktype.io/#l=dart) to setup the models but added one extra function for firebase.
55 |
56 | **settings.dart** - model for settings. Eventually this will be used to hold the rest of the app settings.
57 |
58 | **user.dart** - model for user.
59 |
60 | **state.dart** - model for the state.
61 |
62 | Anyway hopefully this little 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) with your project.
63 |
--------------------------------------------------------------------------------
/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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 27
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.example.flutterfirebaseauthexample"
37 | minSdkVersion 16
38 | targetSdkVersion 27
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/example/flutterfirebaseauthexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.flutterfirebaseauthexample;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/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-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/assets/images/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delay/flutter_firebase_auth_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/assets/images/default.png
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
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 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |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 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | post_install do |installer|
64 | installer.pods_project.targets.each do |target|
65 | target.build_configurations.each do |config|
66 | config.build_settings['ENABLE_BITCODE'] = 'NO'
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/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 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXCopyFilesBuildPhase section */
26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
27 | isa = PBXCopyFilesBuildPhase;
28 | buildActionMask = 2147483647;
29 | dstPath = "";
30 | dstSubfolderSpec = 10;
31 | files = (
32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
34 | );
35 | name = "Embed Frameworks";
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXCopyFilesBuildPhase section */
39 |
40 | /* Begin PBXFileReference section */
41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | /* End PBXFrameworksBuildPhase section */
71 |
72 | /* Begin PBXGroup section */
73 | 9740EEB11CF90186004384FC /* Flutter */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
77 | 3B80C3931E831B6300D905FE /* App.framework */,
78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
83 | );
84 | name = Flutter;
85 | sourceTree = "";
86 | };
87 | 97C146E51CF9000F007C117D = {
88 | isa = PBXGroup;
89 | children = (
90 | 9740EEB11CF90186004384FC /* Flutter */,
91 | 97C146F01CF9000F007C117D /* Runner */,
92 | 97C146EF1CF9000F007C117D /* Products */,
93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
94 | );
95 | sourceTree = "";
96 | };
97 | 97C146EF1CF9000F007C117D /* Products */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 97C146EE1CF9000F007C117D /* Runner.app */,
101 | );
102 | name = Products;
103 | sourceTree = "";
104 | };
105 | 97C146F01CF9000F007C117D /* Runner */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
110 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
113 | 97C147021CF9000F007C117D /* Info.plist */,
114 | 97C146F11CF9000F007C117D /* Supporting Files */,
115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 97C146F21CF9000F007C117D /* main.m */,
125 | );
126 | name = "Supporting Files";
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | 97C146ED1CF9000F007C117D /* Runner */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
135 | buildPhases = (
136 | 9740EEB61CF901F6004384FC /* Run Script */,
137 | 97C146EA1CF9000F007C117D /* Sources */,
138 | 97C146EB1CF9000F007C117D /* Frameworks */,
139 | 97C146EC1CF9000F007C117D /* Resources */,
140 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Runner;
148 | productName = Runner;
149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 97C146E61CF9000F007C117D /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 0910;
159 | ORGANIZATIONNAME = "The Chromium Authors";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = English;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 97C146E51CF9000F007C117D;
175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 97C146ED1CF9000F007C117D /* Runner */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 97C146EC1CF9000F007C117D /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | };
198 | /* End PBXResourcesBuildPhase section */
199 |
200 | /* Begin PBXShellScriptBuildPhase section */
201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
202 | isa = PBXShellScriptBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | inputPaths = (
207 | );
208 | name = "Thin Binary";
209 | outputPaths = (
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | shellPath = /bin/sh;
213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
214 | };
215 | 9740EEB61CF901F6004384FC /* Run Script */ = {
216 | isa = PBXShellScriptBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | );
220 | inputPaths = (
221 | );
222 | name = "Run Script";
223 | outputPaths = (
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | shellPath = /bin/sh;
227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
228 | };
229 | /* End PBXShellScriptBuildPhase section */
230 |
231 | /* Begin PBXSourcesBuildPhase section */
232 | 97C146EA1CF9000F007C117D /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
237 | 97C146F31CF9000F007C117D /* main.m in Sources */,
238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXSourcesBuildPhase section */
243 |
244 | /* Begin PBXVariantGroup section */
245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
246 | isa = PBXVariantGroup;
247 | children = (
248 | 97C146FB1CF9000F007C117D /* Base */,
249 | );
250 | name = Main.storyboard;
251 | sourceTree = "";
252 | };
253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
254 | isa = PBXVariantGroup;
255 | children = (
256 | 97C147001CF9000F007C117D /* Base */,
257 | );
258 | name = LaunchScreen.storyboard;
259 | sourceTree = "";
260 | };
261 | /* End PBXVariantGroup section */
262 |
263 | /* Begin XCBuildConfiguration section */
264 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
265 | isa = XCBuildConfiguration;
266 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
279 | CLANG_WARN_EMPTY_BODY = YES;
280 | CLANG_WARN_ENUM_CONVERSION = YES;
281 | CLANG_WARN_INFINITE_RECURSION = YES;
282 | CLANG_WARN_INT_CONVERSION = YES;
283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
287 | CLANG_WARN_STRICT_PROTOTYPES = YES;
288 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
289 | CLANG_WARN_UNREACHABLE_CODE = YES;
290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
292 | COPY_PHASE_STRIP = NO;
293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
294 | ENABLE_NS_ASSERTIONS = NO;
295 | ENABLE_STRICT_OBJC_MSGSEND = YES;
296 | GCC_C_LANGUAGE_STANDARD = gnu99;
297 | GCC_NO_COMMON_BLOCKS = YES;
298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
300 | GCC_WARN_UNDECLARED_SELECTOR = YES;
301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
302 | GCC_WARN_UNUSED_FUNCTION = YES;
303 | GCC_WARN_UNUSED_VARIABLE = YES;
304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
305 | MTL_ENABLE_DEBUG_INFO = NO;
306 | SDKROOT = iphoneos;
307 | TARGETED_DEVICE_FAMILY = "1,2";
308 | VALIDATE_PRODUCT = YES;
309 | };
310 | name = Profile;
311 | };
312 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
313 | isa = XCBuildConfiguration;
314 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
318 | DEVELOPMENT_TEAM = S8QB4VV633;
319 | ENABLE_BITCODE = NO;
320 | FRAMEWORK_SEARCH_PATHS = (
321 | "$(inherited)",
322 | "$(PROJECT_DIR)/Flutter",
323 | );
324 | INFOPLIST_FILE = Runner/Info.plist;
325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
326 | LIBRARY_SEARCH_PATHS = (
327 | "$(inherited)",
328 | "$(PROJECT_DIR)/Flutter",
329 | );
330 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthExample;
331 | PRODUCT_NAME = "$(TARGET_NAME)";
332 | VERSIONING_SYSTEM = "apple-generic";
333 | };
334 | name = Profile;
335 | };
336 | 97C147031CF9000F007C117D /* Debug */ = {
337 | isa = XCBuildConfiguration;
338 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
339 | buildSettings = {
340 | ALWAYS_SEARCH_USER_PATHS = NO;
341 | CLANG_ANALYZER_NONNULL = YES;
342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
343 | CLANG_CXX_LIBRARY = "libc++";
344 | CLANG_ENABLE_MODULES = YES;
345 | CLANG_ENABLE_OBJC_ARC = YES;
346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
347 | CLANG_WARN_BOOL_CONVERSION = YES;
348 | CLANG_WARN_COMMA = YES;
349 | CLANG_WARN_CONSTANT_CONVERSION = YES;
350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
351 | CLANG_WARN_EMPTY_BODY = YES;
352 | CLANG_WARN_ENUM_CONVERSION = YES;
353 | CLANG_WARN_INFINITE_RECURSION = YES;
354 | CLANG_WARN_INT_CONVERSION = YES;
355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
359 | CLANG_WARN_STRICT_PROTOTYPES = YES;
360 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
361 | CLANG_WARN_UNREACHABLE_CODE = YES;
362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
364 | COPY_PHASE_STRIP = NO;
365 | DEBUG_INFORMATION_FORMAT = dwarf;
366 | ENABLE_STRICT_OBJC_MSGSEND = YES;
367 | ENABLE_TESTABILITY = YES;
368 | GCC_C_LANGUAGE_STANDARD = gnu99;
369 | GCC_DYNAMIC_NO_PIC = NO;
370 | GCC_NO_COMMON_BLOCKS = YES;
371 | GCC_OPTIMIZATION_LEVEL = 0;
372 | GCC_PREPROCESSOR_DEFINITIONS = (
373 | "DEBUG=1",
374 | "$(inherited)",
375 | );
376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
378 | GCC_WARN_UNDECLARED_SELECTOR = YES;
379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
380 | GCC_WARN_UNUSED_FUNCTION = YES;
381 | GCC_WARN_UNUSED_VARIABLE = YES;
382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
383 | MTL_ENABLE_DEBUG_INFO = YES;
384 | ONLY_ACTIVE_ARCH = YES;
385 | SDKROOT = iphoneos;
386 | TARGETED_DEVICE_FAMILY = "1,2";
387 | };
388 | name = Debug;
389 | };
390 | 97C147041CF9000F007C117D /* Release */ = {
391 | isa = XCBuildConfiguration;
392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
393 | buildSettings = {
394 | ALWAYS_SEARCH_USER_PATHS = NO;
395 | CLANG_ANALYZER_NONNULL = YES;
396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
397 | CLANG_CXX_LIBRARY = "libc++";
398 | CLANG_ENABLE_MODULES = YES;
399 | CLANG_ENABLE_OBJC_ARC = YES;
400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
401 | CLANG_WARN_BOOL_CONVERSION = YES;
402 | CLANG_WARN_COMMA = YES;
403 | CLANG_WARN_CONSTANT_CONVERSION = YES;
404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
405 | CLANG_WARN_EMPTY_BODY = YES;
406 | CLANG_WARN_ENUM_CONVERSION = YES;
407 | CLANG_WARN_INFINITE_RECURSION = YES;
408 | CLANG_WARN_INT_CONVERSION = YES;
409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNREACHABLE_CODE = YES;
416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
420 | ENABLE_NS_ASSERTIONS = NO;
421 | ENABLE_STRICT_OBJC_MSGSEND = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_NO_COMMON_BLOCKS = YES;
424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
426 | GCC_WARN_UNDECLARED_SELECTOR = YES;
427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
428 | GCC_WARN_UNUSED_FUNCTION = YES;
429 | GCC_WARN_UNUSED_VARIABLE = YES;
430 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
431 | MTL_ENABLE_DEBUG_INFO = NO;
432 | SDKROOT = iphoneos;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | VALIDATE_PRODUCT = YES;
435 | };
436 | name = Release;
437 | };
438 | 97C147061CF9000F007C117D /* Debug */ = {
439 | isa = XCBuildConfiguration;
440 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
444 | ENABLE_BITCODE = NO;
445 | FRAMEWORK_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "$(PROJECT_DIR)/Flutter",
448 | );
449 | INFOPLIST_FILE = Runner/Info.plist;
450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
451 | LIBRARY_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "$(PROJECT_DIR)/Flutter",
454 | );
455 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthExample;
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | VERSIONING_SYSTEM = "apple-generic";
458 | };
459 | name = Debug;
460 | };
461 | 97C147071CF9000F007C117D /* Release */ = {
462 | isa = XCBuildConfiguration;
463 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
464 | buildSettings = {
465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
466 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
467 | ENABLE_BITCODE = NO;
468 | FRAMEWORK_SEARCH_PATHS = (
469 | "$(inherited)",
470 | "$(PROJECT_DIR)/Flutter",
471 | );
472 | INFOPLIST_FILE = Runner/Info.plist;
473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
474 | LIBRARY_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(PROJECT_DIR)/Flutter",
477 | );
478 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterFirebaseAuthExample;
479 | PRODUCT_NAME = "$(TARGET_NAME)";
480 | VERSIONING_SYSTEM = "apple-generic";
481 | };
482 | name = Release;
483 | };
484 | /* End XCBuildConfiguration section */
485 |
486 | /* Begin XCConfigurationList section */
487 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
488 | isa = XCConfigurationList;
489 | buildConfigurations = (
490 | 97C147031CF9000F007C117D /* Debug */,
491 | 97C147041CF9000F007C117D /* Release */,
492 | 249021D3217E4FDB00AE95B9 /* Profile */,
493 | );
494 | defaultConfigurationIsVisible = 0;
495 | defaultConfigurationName = Release;
496 | };
497 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
498 | isa = XCConfigurationList;
499 | buildConfigurations = (
500 | 97C147061CF9000F007C117D /* Debug */,
501 | 97C147071CF9000F007C117D /* Release */,
502 | 249021D4217E4FDB00AE95B9 /* Profile */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | /* End XCConfigurationList section */
508 | };
509 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
510 | }
511 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/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 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_firebase_auth_example
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/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_firebase_auth_example/util/state_widget.dart';
3 | import 'package:flutter_firebase_auth_example/ui/theme.dart';
4 | import 'package:flutter_firebase_auth_example/ui/screens/home.dart';
5 | import 'package:flutter_firebase_auth_example/ui/screens/sign_in.dart';
6 | import 'package:flutter_firebase_auth_example/ui/screens/sign_up.dart';
7 | import 'package:flutter_firebase_auth_example/ui/screens/forgot_password.dart';
8 |
9 | class MyApp extends StatelessWidget {
10 | MyApp() {
11 | //Navigation.initPaths();
12 | }
13 | @override
14 | Widget build(BuildContext context) {
15 | return MaterialApp(
16 | title: 'MyApp Title',
17 | theme: buildTheme(),
18 | //onGenerateRoute: Navigation.router.generator,
19 | debugShowCheckedModeBanner: false,
20 | routes: {
21 | '/': (context) => HomeScreen(),
22 | '/signin': (context) => SignInScreen(),
23 | '/signup': (context) => SignUpScreen(),
24 | '/forgot-password': (context) => ForgotPasswordScreen(),
25 | },
26 | );
27 | }
28 | }
29 |
30 | void main() {
31 | StateWidget stateWidget = new StateWidget(
32 | child: new MyApp(),
33 | );
34 | runApp(stateWidget);
35 | }
36 |
--------------------------------------------------------------------------------
/lib/models/settings.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'dart:convert';
3 | // To parse this JSON data, do
4 | //
5 | // final settings = settingsFromJson(jsonString);
6 |
7 | Settings settingsFromJson(String str) {
8 | final jsonData = json.decode(str);
9 | return Settings.fromJson(jsonData);
10 | }
11 |
12 | String settingsToJson(Settings data) {
13 | final dyn = data.toJson();
14 | return json.encode(dyn);
15 | }
16 |
17 | class Settings {
18 | String settingsId;
19 |
20 | Settings({
21 | this.settingsId,
22 | });
23 |
24 | factory Settings.fromJson(Map json) => new Settings(
25 | settingsId: json["settingsId"],
26 | );
27 |
28 | Map toJson() => {
29 | "settingsId": settingsId,
30 | };
31 |
32 | factory Settings.fromDocument(DocumentSnapshot doc) {
33 | return Settings.fromJson(doc.data);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/models/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart';
2 | import 'package:flutter_firebase_auth_example/models/user.dart';
3 | import 'package:flutter_firebase_auth_example/models/settings.dart';
4 |
5 | class StateModel {
6 | bool isLoading;
7 | FirebaseUser firebaseUserAuth;
8 | User user;
9 | Settings settings;
10 |
11 | StateModel({
12 | this.isLoading = false,
13 | this.firebaseUserAuth,
14 | this.user,
15 | this.settings,
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/lib/models/user.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'package:cloud_firestore/cloud_firestore.dart';
3 |
4 | // To parse this JSON data, do
5 | //
6 | // final user = userFromJson(jsonString);
7 |
8 | User userFromJson(String str) {
9 | final jsonData = json.decode(str);
10 | return User.fromJson(jsonData);
11 | }
12 |
13 | String userToJson(User data) {
14 | final dyn = data.toJson();
15 | return json.encode(dyn);
16 | }
17 |
18 | class User {
19 | String userId;
20 | String firstName;
21 | String lastName;
22 | String email;
23 |
24 | User({
25 | this.userId,
26 | this.firstName,
27 | this.lastName,
28 | this.email,
29 | });
30 |
31 | factory User.fromJson(Map json) => new User(
32 | userId: json["userId"],
33 | firstName: json["firstName"],
34 | lastName: json["lastName"],
35 | email: json["email"],
36 | );
37 |
38 | Map toJson() => {
39 | "userId": userId,
40 | "firstName": firstName,
41 | "lastName": lastName,
42 | "email": email,
43 | };
44 |
45 | factory User.fromDocument(DocumentSnapshot doc) {
46 | return User.fromJson(doc.data);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/screens/forgot_password.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flushbar/flushbar.dart';
3 | import 'package:flutter/services.dart';
4 |
5 | import 'package:flutter_firebase_auth_example/util/auth.dart';
6 | import 'package:flutter_firebase_auth_example/util/validator.dart';
7 | import 'package:flutter_firebase_auth_example/ui/widgets/loading.dart';
8 |
9 | class ForgotPasswordScreen extends StatefulWidget {
10 | _ForgotPasswordScreenState createState() => _ForgotPasswordScreenState();
11 | }
12 |
13 | class _ForgotPasswordScreenState extends State {
14 | final GlobalKey _formKey = GlobalKey();
15 | final TextEditingController _email = new TextEditingController();
16 |
17 | bool _autoValidate = false;
18 | bool _loadingVisible = false;
19 | @override
20 | void initState() {
21 | super.initState();
22 | }
23 |
24 | Widget build(BuildContext context) {
25 | final logo = Hero(
26 | tag: 'hero',
27 | child: CircleAvatar(
28 | backgroundColor: Colors.transparent,
29 | radius: 60.0,
30 | child: ClipOval(
31 | child: Image.asset(
32 | 'assets/images/default.png',
33 | fit: BoxFit.cover,
34 | width: 120.0,
35 | height: 120.0,
36 | ),
37 | )),
38 | );
39 |
40 | final email = TextFormField(
41 | keyboardType: TextInputType.emailAddress,
42 | autofocus: false,
43 | controller: _email,
44 | validator: Validator.validateEmail,
45 | decoration: InputDecoration(
46 | prefixIcon: Padding(
47 | padding: EdgeInsets.only(left: 5.0),
48 | child: Icon(
49 | Icons.email,
50 | color: Colors.grey,
51 | ), // icon is 48px widget.
52 | ), // icon is 48px widget.
53 | hintText: 'Email',
54 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
55 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
56 | ),
57 | );
58 |
59 | final forgotPasswordButton = Padding(
60 | padding: EdgeInsets.symmetric(vertical: 16.0),
61 | child: RaisedButton(
62 | shape: RoundedRectangleBorder(
63 | borderRadius: BorderRadius.circular(24),
64 | ),
65 | onPressed: () {
66 | _forgotPassword(email: _email.text, context: context);
67 | },
68 | padding: EdgeInsets.all(12),
69 | color: Theme.of(context).primaryColor,
70 | child: Text('FORGOT PASSWORD', style: TextStyle(color: Colors.white)),
71 | ),
72 | );
73 |
74 | final signInLabel = FlatButton(
75 | child: Text(
76 | 'Sign In',
77 | style: TextStyle(color: Colors.black54),
78 | ),
79 | onPressed: () {
80 | Navigator.pushNamed(context, '/signin');
81 | },
82 | );
83 |
84 | return Scaffold(
85 | backgroundColor: Colors.white,
86 | body: LoadingScreen(
87 | child: Form(
88 | key: _formKey,
89 | autovalidate: _autoValidate,
90 | child: Padding(
91 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
92 | child: Center(
93 | child: SingleChildScrollView(
94 | child: Column(
95 | mainAxisAlignment: MainAxisAlignment.center,
96 | crossAxisAlignment: CrossAxisAlignment.stretch,
97 | children: [
98 | logo,
99 | SizedBox(height: 48.0),
100 | email,
101 | SizedBox(height: 12.0),
102 | forgotPasswordButton,
103 | signInLabel
104 | ],
105 | ),
106 | ),
107 | ),
108 | ),
109 | ),
110 | inAsyncCall: _loadingVisible),
111 | );
112 | }
113 |
114 | Future _changeLoadingVisible() async {
115 | setState(() {
116 | _loadingVisible = !_loadingVisible;
117 | });
118 | }
119 |
120 | void _forgotPassword({String email, BuildContext context}) async {
121 | SystemChannels.textInput.invokeMethod('TextInput.hide');
122 | if (_formKey.currentState.validate()) {
123 | try {
124 | await _changeLoadingVisible();
125 | await Auth.forgotPasswordEmail(email);
126 | await _changeLoadingVisible();
127 | Flushbar(
128 | title: "Password Reset Email Sent",
129 | message:
130 | 'Check your email and follow the instructions to reset your password.',
131 | duration: Duration(seconds: 20),
132 | )..show(context);
133 | } catch (e) {
134 | _changeLoadingVisible();
135 | print("Forgot Password Error: $e");
136 | String exception = Auth.getExceptionText(e);
137 | Flushbar(
138 | title: "Forgot Password Error",
139 | message: exception,
140 | duration: Duration(seconds: 10),
141 | )..show(context);
142 | }
143 | } else {
144 | setState(() => _autoValidate = true);
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/lib/ui/screens/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_firebase_auth_example/models/state.dart';
3 | import 'package:flutter_firebase_auth_example/util/state_widget.dart';
4 | import 'package:flutter_firebase_auth_example/ui/screens/sign_in.dart';
5 | import 'package:flutter_firebase_auth_example/ui/widgets/loading.dart';
6 |
7 | class HomeScreen extends StatefulWidget {
8 | _HomeScreenState createState() => _HomeScreenState();
9 | }
10 |
11 | class _HomeScreenState extends State {
12 | StateModel appState;
13 | bool _loadingVisible = false;
14 | @override
15 | void initState() {
16 | super.initState();
17 | }
18 |
19 | Widget build(BuildContext context) {
20 | appState = StateWidget.of(context).state;
21 | if (!appState.isLoading &&
22 | (appState.firebaseUserAuth == null ||
23 | appState.user == null ||
24 | appState.settings == null)) {
25 | return SignInScreen();
26 | } else {
27 | if (appState.isLoading) {
28 | _loadingVisible = true;
29 | } else {
30 | _loadingVisible = false;
31 | }
32 | final logo = Hero(
33 | tag: 'hero',
34 | child: CircleAvatar(
35 | backgroundColor: Colors.transparent,
36 | radius: 60.0,
37 | child: ClipOval(
38 | child: Image.asset(
39 | 'assets/images/default.png',
40 | fit: BoxFit.cover,
41 | width: 120.0,
42 | height: 120.0,
43 | ),
44 | )),
45 | );
46 |
47 | final signOutButton = Padding(
48 | padding: EdgeInsets.symmetric(vertical: 16.0),
49 | child: RaisedButton(
50 | shape: RoundedRectangleBorder(
51 | borderRadius: BorderRadius.circular(24),
52 | ),
53 | onPressed: () {
54 | StateWidget.of(context).logOutUser();
55 | },
56 | padding: EdgeInsets.all(12),
57 | color: Theme.of(context).primaryColor,
58 | child: Text('SIGN OUT', style: TextStyle(color: Colors.white)),
59 | ),
60 | );
61 |
62 | final forgotLabel = FlatButton(
63 | child: Text(
64 | 'Forgot password?',
65 | style: TextStyle(color: Colors.black54),
66 | ),
67 | onPressed: () {
68 | Navigator.pushNamed(context, '/forgot-password');
69 | },
70 | );
71 |
72 | final signUpLabel = FlatButton(
73 | child: Text(
74 | 'Sign Up',
75 | style: TextStyle(color: Colors.black54),
76 | ),
77 | onPressed: () {
78 | Navigator.pushNamed(context, '/signup');
79 | },
80 | );
81 |
82 | final signInLabel = FlatButton(
83 | child: Text(
84 | 'Sign In',
85 | style: TextStyle(color: Colors.black54),
86 | ),
87 | onPressed: () {
88 | Navigator.pushNamed(context, '/signin');
89 | },
90 | );
91 | //check for null https://stackoverflow.com/questions/49775261/check-null-in-ternary-operation
92 | final userId = appState?.firebaseUserAuth?.uid ?? '';
93 | final email = appState?.firebaseUserAuth?.email ?? '';
94 | final firstName = appState?.user?.firstName ?? '';
95 | final lastName = appState?.user?.lastName ?? '';
96 | final settingsId = appState?.settings?.settingsId ?? '';
97 | final userIdLabel = Text('App Id: ');
98 | final emailLabel = Text('Email: ');
99 | final firstNameLabel = Text('First Name: ');
100 | final lastNameLabel = Text('Last Name: ');
101 | final settingsIdLabel = Text('SetttingsId: ');
102 |
103 | return Scaffold(
104 | backgroundColor: Colors.white,
105 | body: LoadingScreen(
106 | child: Padding(
107 | padding: const EdgeInsets.symmetric(horizontal: 48.0),
108 | child: Center(
109 | child: SingleChildScrollView(
110 | child: Column(
111 | mainAxisAlignment: MainAxisAlignment.center,
112 | crossAxisAlignment: CrossAxisAlignment.stretch,
113 | children: [
114 | logo,
115 | SizedBox(height: 48.0),
116 | userIdLabel,
117 | Text(userId,
118 | style: TextStyle(fontWeight: FontWeight.bold)),
119 | SizedBox(height: 12.0),
120 | emailLabel,
121 | Text(email,
122 | style: TextStyle(fontWeight: FontWeight.bold)),
123 | SizedBox(height: 12.0),
124 | firstNameLabel,
125 | Text(firstName,
126 | style: TextStyle(fontWeight: FontWeight.bold)),
127 | SizedBox(height: 12.0),
128 | lastNameLabel,
129 | Text(lastName,
130 | style: TextStyle(fontWeight: FontWeight.bold)),
131 | SizedBox(height: 12.0),
132 | settingsIdLabel,
133 | Text(settingsId,
134 | style: TextStyle(fontWeight: FontWeight.bold)),
135 | SizedBox(height: 12.0),
136 | signOutButton,
137 | signInLabel,
138 | signUpLabel,
139 | forgotLabel
140 | ],
141 | ),
142 | ),
143 | ),
144 | ),
145 | inAsyncCall: _loadingVisible),
146 | );
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/lib/ui/screens/sign_in.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flushbar/flushbar.dart';
3 | import 'package:flutter/services.dart';
4 |
5 | import 'package:flutter_firebase_auth_example/util/state_widget.dart';
6 | import 'package:flutter_firebase_auth_example/util/auth.dart';
7 | import 'package:flutter_firebase_auth_example/util/validator.dart';
8 | import 'package:flutter_firebase_auth_example/ui/widgets/loading.dart';
9 |
10 | class SignInScreen extends StatefulWidget {
11 | _SignInScreenState createState() => _SignInScreenState();
12 | }
13 |
14 | class _SignInScreenState extends State {
15 | final GlobalKey _formKey = GlobalKey();
16 | final TextEditingController _email = new TextEditingController();
17 | final TextEditingController _password = new TextEditingController();
18 |
19 | bool _autoValidate = false;
20 | bool _loadingVisible = false;
21 | @override
22 | void initState() {
23 | super.initState();
24 | }
25 |
26 | Widget build(BuildContext context) {
27 | final logo = Hero(
28 | tag: 'hero',
29 | child: CircleAvatar(
30 | backgroundColor: Colors.transparent,
31 | radius: 60.0,
32 | child: ClipOval(
33 | child: Image.asset(
34 | 'assets/images/default.png',
35 | fit: BoxFit.cover,
36 | width: 120.0,
37 | height: 120.0,
38 | ),
39 | )),
40 | );
41 |
42 | final email = TextFormField(
43 | keyboardType: TextInputType.emailAddress,
44 | autofocus: false,
45 | controller: _email,
46 | validator: Validator.validateEmail,
47 | decoration: InputDecoration(
48 | prefixIcon: Padding(
49 | padding: EdgeInsets.only(left: 5.0),
50 | child: Icon(
51 | Icons.email,
52 | color: Colors.grey,
53 | ), // icon is 48px widget.
54 | ), // icon is 48px widget.
55 | hintText: 'Email',
56 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
57 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
58 | ),
59 | );
60 |
61 | final password = TextFormField(
62 | autofocus: false,
63 | obscureText: true,
64 | controller: _password,
65 | validator: Validator.validatePassword,
66 | decoration: InputDecoration(
67 | prefixIcon: Padding(
68 | padding: EdgeInsets.only(left: 5.0),
69 | child: Icon(
70 | Icons.lock,
71 | color: Colors.grey,
72 | ), // icon is 48px widget.
73 | ), // icon is 48px widget.
74 | hintText: 'Password',
75 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
76 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
77 | ),
78 | );
79 |
80 | final loginButton = Padding(
81 | padding: EdgeInsets.symmetric(vertical: 16.0),
82 | child: RaisedButton(
83 | shape: RoundedRectangleBorder(
84 | borderRadius: BorderRadius.circular(24),
85 | ),
86 | onPressed: () {
87 | _emailLogin(
88 | email: _email.text, password: _password.text, context: context);
89 | },
90 | padding: EdgeInsets.all(12),
91 | color: Theme.of(context).primaryColor,
92 | child: Text('SIGN IN', style: TextStyle(color: Colors.white)),
93 | ),
94 | );
95 |
96 | final forgotLabel = FlatButton(
97 | child: Text(
98 | 'Forgot password?',
99 | style: TextStyle(color: Colors.black54),
100 | ),
101 | onPressed: () {
102 | Navigator.pushNamed(context, '/forgot-password');
103 | },
104 | );
105 |
106 | final signUpLabel = FlatButton(
107 | child: Text(
108 | 'Create an Account',
109 | style: TextStyle(color: Colors.black54),
110 | ),
111 | onPressed: () {
112 | Navigator.pushNamed(context, '/signup');
113 | },
114 | );
115 |
116 | return Scaffold(
117 | backgroundColor: Colors.white,
118 | body: LoadingScreen(
119 | child: Form(
120 | key: _formKey,
121 | autovalidate: _autoValidate,
122 | child: Padding(
123 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
124 | child: Center(
125 | child: SingleChildScrollView(
126 | child: Column(
127 | mainAxisAlignment: MainAxisAlignment.center,
128 | crossAxisAlignment: CrossAxisAlignment.stretch,
129 | children: [
130 | logo,
131 | SizedBox(height: 48.0),
132 | email,
133 | SizedBox(height: 24.0),
134 | password,
135 | SizedBox(height: 12.0),
136 | loginButton,
137 | forgotLabel,
138 | signUpLabel
139 | ],
140 | ),
141 | ),
142 | ),
143 | ),
144 | ),
145 | inAsyncCall: _loadingVisible),
146 | );
147 | }
148 |
149 | Future _changeLoadingVisible() async {
150 | setState(() {
151 | _loadingVisible = !_loadingVisible;
152 | });
153 | }
154 |
155 | void _emailLogin(
156 | {String email, String password, BuildContext context}) async {
157 | if (_formKey.currentState.validate()) {
158 | try {
159 | SystemChannels.textInput.invokeMethod('TextInput.hide');
160 | await _changeLoadingVisible();
161 | //need await so it has chance to go through error if found.
162 | await StateWidget.of(context).logInUser(email, password);
163 | await Navigator.pushNamed(context, '/');
164 | } catch (e) {
165 | _changeLoadingVisible();
166 | print("Sign In Error: $e");
167 | String exception = Auth.getExceptionText(e);
168 | Flushbar(
169 | title: "Sign In Error",
170 | message: exception,
171 | duration: Duration(seconds: 5),
172 | )..show(context);
173 | }
174 | } else {
175 | setState(() => _autoValidate = true);
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/lib/ui/screens/sign_up.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flushbar/flushbar.dart';
3 | import 'package:flutter/services.dart';
4 |
5 | import 'package:flutter_firebase_auth_example/models/user.dart';
6 | import 'package:flutter_firebase_auth_example/util/auth.dart';
7 | import 'package:flutter_firebase_auth_example/util/validator.dart';
8 | import 'package:flutter_firebase_auth_example/ui/widgets/loading.dart';
9 |
10 | class SignUpScreen extends StatefulWidget {
11 | _SignUpScreenState createState() => _SignUpScreenState();
12 | }
13 |
14 | class _SignUpScreenState extends State {
15 | final GlobalKey _formKey = GlobalKey();
16 | final TextEditingController _firstName = new TextEditingController();
17 | final TextEditingController _lastName = new TextEditingController();
18 | final TextEditingController _email = new TextEditingController();
19 | final TextEditingController _password = new TextEditingController();
20 |
21 | bool _autoValidate = false;
22 | bool _loadingVisible = false;
23 | @override
24 | void initState() {
25 | super.initState();
26 | }
27 |
28 | Widget build(BuildContext context) {
29 | final logo = Hero(
30 | tag: 'hero',
31 | child: CircleAvatar(
32 | backgroundColor: Colors.transparent,
33 | radius: 60.0,
34 | child: ClipOval(
35 | child: Image.asset(
36 | 'assets/images/default.png',
37 | fit: BoxFit.cover,
38 | width: 120.0,
39 | height: 120.0,
40 | ),
41 | )),
42 | );
43 |
44 | final firstName = TextFormField(
45 | autofocus: false,
46 | textCapitalization: TextCapitalization.words,
47 | controller: _firstName,
48 | validator: Validator.validateName,
49 | decoration: InputDecoration(
50 | prefixIcon: Padding(
51 | padding: EdgeInsets.only(left: 5.0),
52 | child: Icon(
53 | Icons.person,
54 | color: Colors.grey,
55 | ), // icon is 48px widget.
56 | ), // icon is 48px widget.
57 | hintText: 'First Name',
58 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
59 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
60 | ),
61 | );
62 |
63 | final lastName = TextFormField(
64 | autofocus: false,
65 | textCapitalization: TextCapitalization.words,
66 | controller: _lastName,
67 | validator: Validator.validateName,
68 | decoration: InputDecoration(
69 | prefixIcon: Padding(
70 | padding: EdgeInsets.only(left: 5.0),
71 | child: Icon(
72 | Icons.person,
73 | color: Colors.grey,
74 | ), // icon is 48px widget.
75 | ), // icon is 48px widget.
76 | hintText: 'Last Name',
77 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
78 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
79 | ),
80 | );
81 |
82 | final email = TextFormField(
83 | keyboardType: TextInputType.emailAddress,
84 | autofocus: false,
85 | controller: _email,
86 | validator: Validator.validateEmail,
87 | decoration: InputDecoration(
88 | prefixIcon: Padding(
89 | padding: EdgeInsets.only(left: 5.0),
90 | child: Icon(
91 | Icons.email,
92 | color: Colors.grey,
93 | ), // icon is 48px widget.
94 | ), // icon is 48px widget.
95 | hintText: 'Email',
96 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
97 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
98 | ),
99 | );
100 |
101 | final password = TextFormField(
102 | autofocus: false,
103 | obscureText: true,
104 | controller: _password,
105 | validator: Validator.validatePassword,
106 | decoration: InputDecoration(
107 | prefixIcon: Padding(
108 | padding: EdgeInsets.only(left: 5.0),
109 | child: Icon(
110 | Icons.lock,
111 | color: Colors.grey,
112 | ), // icon is 48px widget.
113 | ), // icon is 48px widget.
114 | hintText: 'Password',
115 | contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
116 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
117 | ),
118 | );
119 |
120 | final signUpButton = Padding(
121 | padding: EdgeInsets.symmetric(vertical: 16.0),
122 | child: RaisedButton(
123 | shape: RoundedRectangleBorder(
124 | borderRadius: BorderRadius.circular(24),
125 | ),
126 | onPressed: () {
127 | _emailSignUp(
128 | firstName: _firstName.text,
129 | lastName: _lastName.text,
130 | email: _email.text,
131 | password: _password.text,
132 | context: context);
133 | },
134 | padding: EdgeInsets.all(12),
135 | color: Theme.of(context).primaryColor,
136 | child: Text('SIGN UP', style: TextStyle(color: Colors.white)),
137 | ),
138 | );
139 |
140 | final signInLabel = FlatButton(
141 | child: Text(
142 | 'Have an Account? Sign In.',
143 | style: TextStyle(color: Colors.black54),
144 | ),
145 | onPressed: () {
146 | Navigator.pushNamed(context, '/signin');
147 | },
148 | );
149 |
150 | return Scaffold(
151 | backgroundColor: Colors.white,
152 | body: LoadingScreen(
153 | child: Form(
154 | key: _formKey,
155 | autovalidate: _autoValidate,
156 | child: Padding(
157 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
158 | child: Center(
159 | child: SingleChildScrollView(
160 | child: Column(
161 | mainAxisAlignment: MainAxisAlignment.center,
162 | crossAxisAlignment: CrossAxisAlignment.stretch,
163 | children: [
164 | logo,
165 | SizedBox(height: 48.0),
166 | firstName,
167 | SizedBox(height: 24.0),
168 | lastName,
169 | SizedBox(height: 24.0),
170 | email,
171 | SizedBox(height: 24.0),
172 | password,
173 | SizedBox(height: 12.0),
174 | signUpButton,
175 | signInLabel
176 | ],
177 | ),
178 | ),
179 | ),
180 | ),
181 | ),
182 | inAsyncCall: _loadingVisible),
183 | );
184 | }
185 |
186 | Future _changeLoadingVisible() async {
187 | setState(() {
188 | _loadingVisible = !_loadingVisible;
189 | });
190 | }
191 |
192 | void _emailSignUp(
193 | {String firstName,
194 | String lastName,
195 | String email,
196 | String password,
197 | BuildContext context}) async {
198 | if (_formKey.currentState.validate()) {
199 | try {
200 | SystemChannels.textInput.invokeMethod('TextInput.hide');
201 | await _changeLoadingVisible();
202 | //need await so it has chance to go through error if found.
203 | await Auth.signUp(email, password).then((uID) {
204 | Auth.addUserSettingsDB(new User(
205 | userId: uID,
206 | email: email,
207 | firstName: firstName,
208 | lastName: lastName,
209 | ));
210 | });
211 | //now automatically login user too
212 | //await StateWidget.of(context).logInUser(email, password);
213 | await Navigator.pushNamed(context, '/signin');
214 | } catch (e) {
215 | _changeLoadingVisible();
216 | print("Sign Up Error: $e");
217 | String exception = Auth.getExceptionText(e);
218 | Flushbar(
219 | title: "Sign Up Error",
220 | message: exception,
221 | duration: Duration(seconds: 5),
222 | )..show(context);
223 | }
224 | } else {
225 | setState(() => _autoValidate = true);
226 | }
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/lib/ui/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | ThemeData buildTheme() {
4 | // We're going to define all of our font styles
5 | // in this method:
6 | TextTheme _buildTextTheme(TextTheme base) {
7 | return base.copyWith(
8 | headline: base.headline.copyWith(
9 | fontFamily: 'Merriweather',
10 | fontSize: 40.0,
11 | color: const Color(0xFF555555),
12 | ),
13 | title: base.title.copyWith(
14 | fontFamily: 'Merriweather',
15 | fontSize: 15.0,
16 | color: const Color(0xFF555555),
17 | ),
18 | caption: base.caption.copyWith(
19 | color: const Color(0xFF555555),
20 | ),
21 | body1: base.body1.copyWith(color: const Color(0xFF555555)));
22 | }
23 |
24 | // We want to override a default light blue theme.
25 | final ThemeData base = ThemeData.light();
26 |
27 | // And apply changes on it:
28 | return base.copyWith(
29 | textTheme: _buildTextTheme(base.textTheme),
30 | primaryColor: const Color(0xFF2196F3),
31 | accentColor: const Color(0xFFFFFFFF),
32 | iconTheme: IconThemeData(
33 | color: const Color(0xFFCCCCCC),
34 | size: 20.0,
35 | ),
36 | buttonColor: Colors.white,
37 | backgroundColor: Colors.white,
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/lib/ui/widgets/loading.dart:
--------------------------------------------------------------------------------
1 | //library modal_progress_hud;
2 |
3 | import 'package:flutter/material.dart';
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: Theme.of(context).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 | height: 30.0,
68 | width: 30.0,
69 | ),
70 | )));
71 | } else {
72 | layOutProgressIndicator = Positioned(
73 | child: progressIndicator,
74 | left: offset.dx,
75 | top: offset.dy,
76 | );
77 | }
78 | final modal = [
79 | new Opacity(
80 | child: new ModalBarrier(dismissible: dismissible, color: color),
81 | opacity: opacity,
82 | ),
83 | layOutProgressIndicator
84 | ];
85 | widgetList += modal;
86 | }
87 | return new Stack(
88 | children: widgetList,
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/util/auth.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | //import 'dart:convert';
3 | import 'package:firebase_auth/firebase_auth.dart';
4 | import 'package:cloud_firestore/cloud_firestore.dart';
5 | import 'package:flutter_firebase_auth_example/models/user.dart';
6 | import 'package:flutter_firebase_auth_example/models/settings.dart';
7 | import 'package:flutter/services.dart';
8 | import 'package:shared_preferences/shared_preferences.dart';
9 |
10 | enum authProblems { UserNotFound, PasswordNotValid, NetworkError, UnknownError }
11 |
12 | class Auth {
13 | static Future signUp(String email, String password) async {
14 | FirebaseUser user = await FirebaseAuth.instance
15 | .createUserWithEmailAndPassword(email: email, password: password);
16 | return user.uid;
17 | }
18 |
19 | static void addUserSettingsDB(User user) async {
20 | checkUserExist(user.userId).then((value) {
21 | if (!value) {
22 | print("user ${user.firstName} ${user.email} added");
23 | Firestore.instance
24 | .document("users/${user.userId}")
25 | .setData(user.toJson());
26 | _addSettings(new Settings(
27 | settingsId: user.userId,
28 | ));
29 | } else {
30 | print("user ${user.firstName} ${user.email} exists");
31 | }
32 | });
33 | }
34 |
35 | static Future checkUserExist(String userId) async {
36 | bool exists = false;
37 | try {
38 | await Firestore.instance.document("users/$userId").get().then((doc) {
39 | if (doc.exists)
40 | exists = true;
41 | else
42 | exists = false;
43 | });
44 | return exists;
45 | } catch (e) {
46 | return false;
47 | }
48 | }
49 |
50 | static void _addSettings(Settings settings) async {
51 | Firestore.instance
52 | .document("settings/${settings.settingsId}")
53 | .setData(settings.toJson());
54 | }
55 |
56 | static Future signIn(String email, String password) async {
57 | FirebaseUser user = await FirebaseAuth.instance
58 | .signInWithEmailAndPassword(email: email, password: password);
59 | return user.uid;
60 | }
61 |
62 | static Future getUserFirestore(String userId) async {
63 | if (userId != null) {
64 | return Firestore.instance
65 | .collection('users')
66 | .document(userId)
67 | .get()
68 | .then((documentSnapshot) => User.fromDocument(documentSnapshot));
69 | } else {
70 | print('firestore userId can not be null');
71 | return null;
72 | }
73 | }
74 |
75 | static Future getSettingsFirestore(String settingsId) async {
76 | if (settingsId != null) {
77 | return Firestore.instance
78 | .collection('settings')
79 | .document(settingsId)
80 | .get()
81 | .then((documentSnapshot) => Settings.fromDocument(documentSnapshot));
82 | } else {
83 | print('no firestore settings available');
84 | return null;
85 | }
86 | }
87 |
88 | static Future storeUserLocal(User user) async {
89 | SharedPreferences prefs = await SharedPreferences.getInstance();
90 | String storeUser = userToJson(user);
91 | await prefs.setString('user', storeUser);
92 | return user.userId;
93 | }
94 |
95 | static Future storeSettingsLocal(Settings settings) async {
96 | SharedPreferences prefs = await SharedPreferences.getInstance();
97 | String storeSettings = settingsToJson(settings);
98 | await prefs.setString('settings', storeSettings);
99 | return settings.settingsId;
100 | }
101 |
102 | static Future getCurrentFirebaseUser() async {
103 | FirebaseUser currentUser = await FirebaseAuth.instance.currentUser();
104 | return currentUser;
105 | }
106 |
107 | static Future getUserLocal() async {
108 | SharedPreferences prefs = await SharedPreferences.getInstance();
109 | if (prefs.getString('user') != null) {
110 | User user = userFromJson(prefs.getString('user'));
111 | //print('USER: $user');
112 | return user;
113 | } else {
114 | return null;
115 | }
116 | }
117 |
118 | static Future getSettingsLocal() async {
119 | SharedPreferences prefs = await SharedPreferences.getInstance();
120 | if (prefs.getString('settings') != null) {
121 | Settings settings = settingsFromJson(prefs.getString('settings'));
122 | //print('SETTINGS: $settings');
123 | return settings;
124 | } else {
125 | return null;
126 | }
127 | }
128 |
129 | static Future signOut() async {
130 | SharedPreferences prefs = await SharedPreferences.getInstance();
131 | await prefs.clear();
132 | FirebaseAuth.instance.signOut();
133 | }
134 |
135 | static Future forgotPasswordEmail(String email) async {
136 | await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
137 | }
138 |
139 | static String getExceptionText(Exception e) {
140 | if (e is PlatformException) {
141 | switch (e.message) {
142 | case 'There is no user record corresponding to this identifier. The user may have been deleted.':
143 | return 'User with this email address not found.';
144 | break;
145 | case 'The password is invalid or the user does not have a password.':
146 | return 'Invalid password.';
147 | break;
148 | case 'A network error (such as timeout, interrupted connection or unreachable host) has occurred.':
149 | return 'No internet connection.';
150 | break;
151 | case 'The email address is already in use by another account.':
152 | return 'This email address already has an account.';
153 | break;
154 | default:
155 | return 'Unknown error occured.';
156 | }
157 | } else {
158 | return 'Unknown error occured.';
159 | }
160 | }
161 |
162 | /*static Stream getUserFirestore(String userId) {
163 | print("...getUserFirestore...");
164 | if (userId != null) {
165 | //try firestore
166 | return Firestore.instance
167 | .collection("users")
168 | .where("userId", isEqualTo: userId)
169 | .snapshots()
170 | .map((QuerySnapshot snapshot) {
171 | return snapshot.documents.map((doc) {
172 | return User.fromDocument(doc);
173 | }).first;
174 | });
175 | } else {
176 | print('firestore user not found');
177 | return null;
178 | }
179 | }*/
180 |
181 | /*static Stream getSettingsFirestore(String settingsId) {
182 | print("...getSettingsFirestore...");
183 | if (settingsId != null) {
184 | //try firestore
185 | return Firestore.instance
186 | .collection("settings")
187 | .where("settingsId", isEqualTo: settingsId)
188 | .snapshots()
189 | .map((QuerySnapshot snapshot) {
190 | return snapshot.documents.map((doc) {
191 | return Settings.fromDocument(doc);
192 | }).first;
193 | });
194 | } else {
195 | print('no firestore settings available');
196 | return null;
197 | }
198 | }*/
199 | }
200 |
--------------------------------------------------------------------------------
/lib/util/state_widget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:firebase_auth/firebase_auth.dart';
5 | import 'package:flutter_firebase_auth_example/models/state.dart';
6 | import 'package:flutter_firebase_auth_example/models/user.dart';
7 | import 'package:flutter_firebase_auth_example/models/settings.dart';
8 | import 'package:flutter_firebase_auth_example/util/auth.dart';
9 |
10 | class StateWidget extends StatefulWidget {
11 | final StateModel state;
12 | final Widget child;
13 |
14 | StateWidget({
15 | @required this.child,
16 | this.state,
17 | });
18 |
19 | // Returns data of the nearest widget _StateDataWidget
20 | // in the widget tree.
21 | static _StateWidgetState of(BuildContext context) {
22 | return (context.inheritFromWidgetOfExactType(_StateDataWidget)
23 | as _StateDataWidget)
24 | .data;
25 | }
26 |
27 | @override
28 | _StateWidgetState createState() => new _StateWidgetState();
29 | }
30 |
31 | class _StateWidgetState extends State {
32 | StateModel state;
33 | //GoogleSignInAccount googleAccount;
34 | //final GoogleSignIn googleSignIn = new GoogleSignIn();
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | if (widget.state != null) {
40 | state = widget.state;
41 | } else {
42 | state = new StateModel(isLoading: true);
43 | initUser();
44 | }
45 | }
46 |
47 | Future initUser() async {
48 | //print('...initUser...');
49 | FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
50 | User user = await Auth.getUserLocal();
51 | Settings settings = await Auth.getSettingsLocal();
52 | setState(() {
53 | state.isLoading = false;
54 | state.firebaseUserAuth = firebaseUserAuth;
55 | state.user = user;
56 | state.settings = settings;
57 | });
58 | }
59 |
60 | Future logOutUser() async {
61 | await Auth.signOut();
62 | FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
63 | setState(() {
64 | state.user = null;
65 | state.settings = null;
66 | state.firebaseUserAuth = firebaseUserAuth;
67 | });
68 | }
69 |
70 | Future logInUser(email, password) async {
71 | String userId = await Auth.signIn(email, password);
72 | User user = await Auth.getUserFirestore(userId);
73 | await Auth.storeUserLocal(user);
74 | Settings settings = await Auth.getSettingsFirestore(userId);
75 | await Auth.storeSettingsLocal(settings);
76 | await initUser();
77 | }
78 |
79 | @override
80 | Widget build(BuildContext context) {
81 | return new _StateDataWidget(
82 | data: this,
83 | child: widget.child,
84 | );
85 | }
86 | }
87 |
88 | class _StateDataWidget extends InheritedWidget {
89 | final _StateWidgetState data;
90 |
91 | _StateDataWidget({
92 | Key key,
93 | @required Widget child,
94 | @required this.data,
95 | }) : super(key: key, child: child);
96 |
97 | // Rebuild the widgets that inherit from this widget
98 | // on every rebuild of _StateDataWidget:
99 | @override
100 | bool updateShouldNotify(_StateDataWidget old) => true;
101 | }
102 |
--------------------------------------------------------------------------------
/lib/util/validator.dart:
--------------------------------------------------------------------------------
1 | class Validator {
2 | static String validateEmail(String value) {
3 | Pattern pattern = r'^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+';
4 | RegExp regex = new RegExp(pattern);
5 | if (!regex.hasMatch(value))
6 | return 'Please enter a valid email address.';
7 | else
8 | return null;
9 | }
10 |
11 | static String validatePassword(String value) {
12 | Pattern pattern = r'^.{6,}$';
13 | RegExp regex = new RegExp(pattern);
14 | if (!regex.hasMatch(value))
15 | return 'Password must be at least 6 characters.';
16 | else
17 | return null;
18 | }
19 |
20 | static String validateName(String value) {
21 | Pattern pattern = r"^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$";
22 | RegExp regex = new RegExp(pattern);
23 | if (!regex.hasMatch(value))
24 | return 'Please enter a name.';
25 | else
26 | return null;
27 | }
28 |
29 | static String validateNumber(String value) {
30 | Pattern pattern = r'^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$';
31 | RegExp regex = new RegExp(pattern);
32 | if (!regex.hasMatch(value))
33 | return 'Please enter a number.';
34 | else
35 | return null;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_firebase_auth_example
2 | description: Flutter firebase auth example.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.0+1
11 |
12 | environment:
13 | sdk: '>=2.0.0-dev.68.0 <3.0.0'
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 |
19 | # The following adds the Cupertino Icons font to your application.
20 | # Use with the CupertinoIcons class for iOS style icons.
21 | cupertino_icons: ^0.1.2
22 | shared_preferences: any
23 | firebase_auth: ^0.8.1
24 | cloud_firestore: ^0.9.0+1
25 | flushbar: ^1.3.1
26 |
27 | dev_dependencies:
28 | flutter_test:
29 | sdk: flutter
30 |
31 | # For information on the generic Dart part of this file, see the
32 | # following page: https://www.dartlang.org/tools/pub/pubspec
33 |
34 | # The following section is specific to Flutter.
35 | flutter:
36 | # The following line ensures that the Material Icons font is
37 | # included with your application, so that you can use the icons in
38 | # the material Icons class.
39 | uses-material-design: true
40 | assets:
41 | - assets/images/default.png
42 | # To add assets to your application, add an assets section, like this:
43 | # assets:
44 | # - images/a_dot_burr.jpeg
45 | # - images/a_dot_ham.jpeg
46 | # An image asset can refer to one or more resolution-specific "variants", see
47 | # https://flutter.io/assets-and-images/#resolution-aware.
48 | # For details regarding adding assets from package dependencies, see
49 | # https://flutter.io/assets-and-images/#from-packages
50 | # To add custom fonts to your application, add a fonts section here,
51 | # in this "flutter" section. Each entry in this list should have a
52 | # "family" key with the font family name, and a "fonts" key with a
53 | # list giving the asset and other descriptors for the font. For
54 | # example:
55 | # fonts:
56 | # - family: Schyler
57 | # fonts:
58 | # - asset: fonts/Schyler-Regular.ttf
59 | # - asset: fonts/Schyler-Italic.ttf
60 | # style: italic
61 | # - family: Trajan Pro
62 | # fonts:
63 | # - asset: fonts/TrajanPro.ttf
64 | # - asset: fonts/TrajanPro_Bold.ttf
65 | # weight: 700
66 | #
67 | # For details regarding fonts from package dependencies,
68 | # see https://flutter.io/custom-fonts/#from-packages
69 |
--------------------------------------------------------------------------------
/website_images/screenshot_auth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delay/flutter_firebase_auth_example/7ec5cbccfedcfc08241fc58f86c8328ced993091/website_images/screenshot_auth.jpg
--------------------------------------------------------------------------------