├── .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 | ![flutter firebase auth screenshots](https://github.com/delay/flutter_firebase_auth_example/blob/master/website_images/screenshot_auth.jpg) 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 --------------------------------------------------------------------------------