├── .firebaserc
├── .gitignore
├── .metadata
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ ├── google-services.json
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_chat_app
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── images
│ ├── empty_inbox.jpg
│ ├── splash.gif
│ └── splash.jpg
├── firebase.json
├── functions
├── .gitignore
├── package-lock.json
├── package.json
├── src
│ └── index.ts
├── tsconfig.json
└── tslint.json
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── app
│ ├── locator.dart
│ ├── locator.iconfig.dart
│ ├── router.dart
│ └── router.gr.dart
├── helpers
│ └── UserSearchDelegate.dart
├── main.dart
├── models
│ ├── MessagesModel.dart
│ ├── TokenModel.dart
│ └── UserModel.dart
├── services
│ ├── auth_service.dart
│ ├── firebase_push_notification_serice.dart
│ ├── firestore_service.dart
│ └── services.dart
└── ui
│ ├── views
│ ├── chat
│ │ ├── chat_view.dart
│ │ └── chat_viewmodel.dart
│ ├── dashboard
│ │ ├── dashboard_view.dart
│ │ └── dashboard_viewmodel.dart
│ ├── login
│ │ ├── login_view.dart
│ │ └── login_viewmodel.dart
│ ├── signup
│ │ ├── signup_view.dart
│ │ └── signup_viewmodel.dart
│ └── startup
│ │ ├── startup_view.dart
│ │ └── startup_viewmodel.dart
│ └── widgets
│ ├── BusyButton.dart
│ ├── ChatBubble.dart
│ ├── DrawerWidget.dart
│ ├── MessagesList.dart
│ ├── UsersList.dart
│ └── UsersListViewModel.dart
├── pubspec.lock
├── pubspec.yaml
└── test
└── widget_test.dart
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "flutter-firebase-729c6"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Exceptions to above rules.
37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
38 |
--------------------------------------------------------------------------------
/.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: f139b11009aeb8ed2a3a3aa8b0066e482709dde3
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_chat_app
2 |
3 | A new Flutter project.
4 |
5 | ## Todo
6 |
7 | 1. Push Notificatiion for messages.
8 | 2. Make beautiful design
9 |
10 | ## Getting Started
11 |
12 | This project is a starting point for a Flutter application.
13 |
14 | A few resources to get you started if this is your first Flutter project:
15 |
16 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
17 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
18 |
19 | For help getting started with Flutter, view our
20 | [online documentation](https://flutter.dev/docs), which offers tutorials,
21 | samples, guidance on mobile development, and a full API reference.
22 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.example.flutter_chat_app"
42 | minSdkVersion 16
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | multiDexEnabled true
48 | }
49 |
50 | buildTypes {
51 | release {
52 | // TODO: Add your own signing config for the release build.
53 | // Signing with the debug keys for now, so `flutter run --release` works.
54 | signingConfig signingConfigs.debug
55 | }
56 | }
57 | }
58 |
59 | flutter {
60 | source '../..'
61 | }
62 |
63 | dependencies {
64 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
65 | testImplementation 'junit:junit:4.12'
66 | androidTestImplementation 'androidx.test:runner:1.1.1'
67 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
68 | }
69 |
70 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "212056289434",
4 | "firebase_url": "https://flutter-firebase-729c6.firebaseio.com",
5 | "project_id": "flutter-firebase-729c6",
6 | "storage_bucket": "flutter-firebase-729c6.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:212056289434:android:e6bf68f55315b2f5c2ef23",
12 | "android_client_info": {
13 | "package_name": "com.example.flutter_chat_app"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "212056289434-58c0ep8pif6lsbli7eucsbmjntciktro.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "com.example.flutter_chat_app",
22 | "certificate_hash": "cc7f4e84ae868866140394bf6d7acbd697a964dd"
23 | }
24 | },
25 | {
26 | "client_id": "212056289434-kg0vbo8ku23mhdseflgksisnjros06f6.apps.googleusercontent.com",
27 | "client_type": 3
28 | }
29 | ],
30 | "api_key": [
31 | {
32 | "current_key": "AIzaSyDOb3EU53KH4lMs1LG6bg2UrIEKR62Jlns"
33 | },
34 | {
35 | "current_key": "AIzaSyDRRDCoyUZ-DdfjIYKa2Ap94THepvWN2TA"
36 | }
37 | ],
38 | "services": {
39 | "appinvite_service": {
40 | "other_platform_oauth_client": [
41 | {
42 | "client_id": "212056289434-kg0vbo8ku23mhdseflgksisnjros06f6.apps.googleusercontent.com",
43 | "client_type": 3
44 | }
45 | ]
46 | }
47 | }
48 | },
49 | {
50 | "client_info": {
51 | "mobilesdk_app_id": "1:212056289434:android:d5cd86f5e4ca1cedc2ef23",
52 | "android_client_info": {
53 | "package_name": "com.example.flutter_fire"
54 | }
55 | },
56 | "oauth_client": [
57 | {
58 | "client_id": "212056289434-0qcvki98djgbutivt5col8ik5cs2ii59.apps.googleusercontent.com",
59 | "client_type": 1,
60 | "android_info": {
61 | "package_name": "com.example.flutter_fire",
62 | "certificate_hash": "cc7f4e84ae868866140394bf6d7acbd697a964dd"
63 | }
64 | },
65 | {
66 | "client_id": "212056289434-kg0vbo8ku23mhdseflgksisnjros06f6.apps.googleusercontent.com",
67 | "client_type": 3
68 | }
69 | ],
70 | "api_key": [
71 | {
72 | "current_key": "AIzaSyDOb3EU53KH4lMs1LG6bg2UrIEKR62Jlns"
73 | },
74 | {
75 | "current_key": "AIzaSyDRRDCoyUZ-DdfjIYKa2Ap94THepvWN2TA"
76 | }
77 | ],
78 | "services": {
79 | "appinvite_service": {
80 | "other_platform_oauth_client": [
81 | {
82 | "client_id": "212056289434-kg0vbo8ku23mhdseflgksisnjros06f6.apps.googleusercontent.com",
83 | "client_type": 3
84 | }
85 | ]
86 | }
87 | }
88 | }
89 | ],
90 | "configuration_version": "1"
91 | }
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_chat_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_chat_app
2 |
3 | import androidx.annotation.NonNull;
4 | import io.flutter.embedding.android.FlutterActivity
5 | import io.flutter.embedding.engine.FlutterEngine
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
10 | GeneratedPluginRegistrant.registerWith(flutterEngine);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.3'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | 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/empty_inbox.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/assets/images/empty_inbox.jpg
--------------------------------------------------------------------------------
/assets/images/splash.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/assets/images/splash.gif
--------------------------------------------------------------------------------
/assets/images/splash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/assets/images/splash.jpg
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "functions": {
3 | "predeploy": [
4 | "npm --prefix \"$RESOURCE_DIR\" run lint",
5 | "npm --prefix \"$RESOURCE_DIR\" run build"
6 | ]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/functions/.gitignore:
--------------------------------------------------------------------------------
1 | ## Compiled JavaScript files
2 | **/*.js
3 | **/*.js.map
4 |
5 | # Typescript v1 declaration files
6 | typings/
7 |
8 | node_modules/
--------------------------------------------------------------------------------
/functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "scripts": {
4 | "lint": "tslint --project tsconfig.json",
5 | "build": "tsc",
6 | "serve": "npm run build && firebase emulators:start --only functions",
7 | "shell": "npm run build && firebase functions:shell",
8 | "start": "npm run shell",
9 | "deploy": "firebase deploy --only functions",
10 | "logs": "firebase functions:log"
11 | },
12 | "engines": {
13 | "node": "8"
14 | },
15 | "main": "lib/index.js",
16 | "dependencies": {
17 | "firebase-admin": "^8.9.0",
18 | "firebase-functions": "^3.3.0"
19 | },
20 | "devDependencies": {
21 | "tslint": "^5.12.0",
22 | "typescript": "^3.2.2",
23 | "firebase-functions-test": "^0.1.6"
24 | },
25 | "private": true
26 | }
27 |
--------------------------------------------------------------------------------
/functions/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as functions from 'firebase-functions';
2 | import * as admin from 'firebase-admin';
3 |
4 | admin.initializeApp();
5 | const db = admin.firestore();
6 | const fcm = admin.messaging();
7 |
8 | // export const sendToMessages = functions.firestore
9 | // .document('messages/messageId')
10 | // .onCreate(async snapshot => {
11 | // const message = snapshot.data();
12 |
13 | // const payload: admin.messaging.MessagingPayload = {
14 | // notification: {
15 | // title: 'New message from user',
16 | // body: message.messageBody
17 | // }
18 | // }
19 | // fcm.sendToTopic('messages', payload);
20 |
21 | // });
22 |
23 |
24 | export const notifyNewMessage = functions.firestore
25 | .document('messages/{messageId}')
26 | .onCreate(async snapshot => {
27 | const message = snapshot.data();
28 |
29 | const querySnapshot = await db
30 | .collection('users')
31 | .doc(message.receiverId)
32 | .collection('tokens')
33 | .get();
34 |
35 | const tokens = querySnapshot.docs.map(snap => snap.id);
36 |
37 | const payload: admin.messaging.MessagingPayload = {
38 | notification: {
39 | title: `Flutter Chat App | ${message.senderName}`,
40 | body: message.messageBody,
41 | clickAction: 'FLUTTER_NOTIFICATION_CLICK',
42 | }
43 | }
44 | return fcm.sendToDevice(tokens, payload);
45 |
46 | });
47 |
48 |
49 |
50 | // // Start writing Firebase Functions
51 | // // https://firebase.google.com/docs/functions/typescript
52 | //
53 | // export const helloWorld = functions.https.onRequest((request, response) => {
54 | // functions.logger.info("Hello logs!", {structuredData: true});
55 | // response.send("Hello from Firebase!");
56 | // });
57 |
--------------------------------------------------------------------------------
/functions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "noImplicitReturns": true,
5 | "noUnusedLocals": true,
6 | "outDir": "lib",
7 | "sourceMap": true,
8 | "strict": true,
9 | "target": "es2017"
10 | },
11 | "compileOnSave": true,
12 | "include": [
13 | "src"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/functions/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | // -- Strict errors --
4 | // These lint rules are likely always a good idea.
5 |
6 | // Force function overloads to be declared together. This ensures readers understand APIs.
7 | "adjacent-overload-signatures": true,
8 |
9 | // Do not allow the subtle/obscure comma operator.
10 | "ban-comma-operator": true,
11 |
12 | // Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.
13 | "no-namespace": true,
14 |
15 | // Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.
16 | "no-parameter-reassignment": true,
17 |
18 | // Force the use of ES6-style imports instead of /// imports.
19 | "no-reference": true,
20 |
21 | // Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the
22 | // code currently being edited (they may be incorrectly handling a different type case that does not exist).
23 | "no-unnecessary-type-assertion": true,
24 |
25 | // Disallow nonsensical label usage.
26 | "label-position": true,
27 |
28 | // Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.
29 | "no-conditional-assignment": true,
30 |
31 | // Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).
32 | "no-construct": true,
33 |
34 | // Do not allow super() to be called twice in a constructor.
35 | "no-duplicate-super": true,
36 |
37 | // Do not allow the same case to appear more than once in a switch block.
38 | "no-duplicate-switch-case": true,
39 |
40 | // Do not allow a variable to be declared more than once in the same block. Consider function parameters in this
41 | // rule.
42 | "no-duplicate-variable": [true, "check-parameters"],
43 |
44 | // Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should
45 | // instead use a separate variable name.
46 | "no-shadowed-variable": true,
47 |
48 | // Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.
49 | "no-empty": [true, "allow-empty-catch"],
50 |
51 | // Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.
52 | // This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.
53 | "no-floating-promises": true,
54 |
55 | // Do not allow any imports for modules that are not in package.json. These will almost certainly fail when
56 | // deployed.
57 | "no-implicit-dependencies": true,
58 |
59 | // The 'this' keyword can only be used inside of classes.
60 | "no-invalid-this": true,
61 |
62 | // Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.
63 | "no-string-throw": true,
64 |
65 | // Disallow control flow statements, such as return, continue, break, and throw in finally blocks.
66 | "no-unsafe-finally": true,
67 |
68 | // Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();
69 | "no-void-expression": [true, "ignore-arrow-function-shorthand"],
70 |
71 | // Disallow duplicate imports in the same file.
72 | "no-duplicate-imports": true,
73 |
74 |
75 | // -- Strong Warnings --
76 | // These rules should almost never be needed, but may be included due to legacy code.
77 | // They are left as a warning to avoid frustration with blocked deploys when the developer
78 | // understand the warning and wants to deploy anyway.
79 |
80 | // Warn when an empty interface is defined. These are generally not useful.
81 | "no-empty-interface": {"severity": "warning"},
82 |
83 | // Warn when an import will have side effects.
84 | "no-import-side-effect": {"severity": "warning"},
85 |
86 | // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for
87 | // most values and let for values that will change.
88 | "no-var-keyword": {"severity": "warning"},
89 |
90 | // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.
91 | "triple-equals": {"severity": "warning"},
92 |
93 | // Warn when using deprecated APIs.
94 | "deprecation": {"severity": "warning"},
95 |
96 | // -- Light Warnings --
97 | // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info"
98 | // if TSLint supported such a level.
99 |
100 | // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.
101 | // (Even better: check out utils like .map if transforming an array!)
102 | "prefer-for-of": {"severity": "warning"},
103 |
104 | // Warns if function overloads could be unified into a single function with optional or rest parameters.
105 | "unified-signatures": {"severity": "warning"},
106 |
107 | // Prefer const for values that will not change. This better documents code.
108 | "prefer-const": {"severity": "warning"},
109 |
110 | // Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts.
111 | "trailing-comma": {"severity": "warning"}
112 | },
113 |
114 | "defaultSeverity": "error"
115 | }
116 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/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 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
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 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
18 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
19 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXCopyFilesBuildPhase section */
23 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
24 | isa = PBXCopyFilesBuildPhase;
25 | buildActionMask = 2147483647;
26 | dstPath = "";
27 | dstSubfolderSpec = 10;
28 | files = (
29 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
30 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
31 | );
32 | name = "Embed Frameworks";
33 | runOnlyForDeploymentPostprocessing = 0;
34 | };
35 | /* End PBXCopyFilesBuildPhase section */
36 |
37 | /* Begin PBXFileReference section */
38 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
39 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
40 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
41 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
42 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
43 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
45 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
46 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
47 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
48 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
49 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
50 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
51 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
52 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
61 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | /* End PBXFrameworksBuildPhase section */
66 |
67 | /* Begin PBXGroup section */
68 | 9740EEB11CF90186004384FC /* Flutter */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 3B80C3931E831B6300D905FE /* App.framework */,
72 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
73 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
74 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
75 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
76 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
77 | );
78 | name = Flutter;
79 | sourceTree = "";
80 | };
81 | 97C146E51CF9000F007C117D = {
82 | isa = PBXGroup;
83 | children = (
84 | 9740EEB11CF90186004384FC /* Flutter */,
85 | 97C146F01CF9000F007C117D /* Runner */,
86 | 97C146EF1CF9000F007C117D /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | 97C146EF1CF9000F007C117D /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 97C146EE1CF9000F007C117D /* Runner.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 97C146F01CF9000F007C117D /* Runner */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
102 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
103 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
104 | 97C147021CF9000F007C117D /* Info.plist */,
105 | 97C146F11CF9000F007C117D /* Supporting Files */,
106 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
107 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
108 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
109 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
110 | );
111 | path = Runner;
112 | sourceTree = "";
113 | };
114 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
115 | isa = PBXGroup;
116 | children = (
117 | );
118 | name = "Supporting Files";
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXNativeTarget section */
124 | 97C146ED1CF9000F007C117D /* Runner */ = {
125 | isa = PBXNativeTarget;
126 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
127 | buildPhases = (
128 | 9740EEB61CF901F6004384FC /* Run Script */,
129 | 97C146EA1CF9000F007C117D /* Sources */,
130 | 97C146EB1CF9000F007C117D /* Frameworks */,
131 | 97C146EC1CF9000F007C117D /* Resources */,
132 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
133 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
134 | );
135 | buildRules = (
136 | );
137 | dependencies = (
138 | );
139 | name = Runner;
140 | productName = Runner;
141 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
142 | productType = "com.apple.product-type.application";
143 | };
144 | /* End PBXNativeTarget section */
145 |
146 | /* Begin PBXProject section */
147 | 97C146E61CF9000F007C117D /* Project object */ = {
148 | isa = PBXProject;
149 | attributes = {
150 | LastUpgradeCheck = 1020;
151 | ORGANIZATIONNAME = "The Chromium Authors";
152 | TargetAttributes = {
153 | 97C146ED1CF9000F007C117D = {
154 | CreatedOnToolsVersion = 7.3.1;
155 | LastSwiftMigration = 1100;
156 | };
157 | };
158 | };
159 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
160 | compatibilityVersion = "Xcode 3.2";
161 | developmentRegion = en;
162 | hasScannedForEncodings = 0;
163 | knownRegions = (
164 | en,
165 | Base,
166 | );
167 | mainGroup = 97C146E51CF9000F007C117D;
168 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
169 | projectDirPath = "";
170 | projectRoot = "";
171 | targets = (
172 | 97C146ED1CF9000F007C117D /* Runner */,
173 | );
174 | };
175 | /* End PBXProject section */
176 |
177 | /* Begin PBXResourcesBuildPhase section */
178 | 97C146EC1CF9000F007C117D /* Resources */ = {
179 | isa = PBXResourcesBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
183 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
184 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
185 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
186 | );
187 | runOnlyForDeploymentPostprocessing = 0;
188 | };
189 | /* End PBXResourcesBuildPhase section */
190 |
191 | /* Begin PBXShellScriptBuildPhase section */
192 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
193 | isa = PBXShellScriptBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | );
197 | inputPaths = (
198 | );
199 | name = "Thin Binary";
200 | outputPaths = (
201 | );
202 | runOnlyForDeploymentPostprocessing = 0;
203 | shellPath = /bin/sh;
204 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
205 | };
206 | 9740EEB61CF901F6004384FC /* Run Script */ = {
207 | isa = PBXShellScriptBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | );
211 | inputPaths = (
212 | );
213 | name = "Run Script";
214 | outputPaths = (
215 | );
216 | runOnlyForDeploymentPostprocessing = 0;
217 | shellPath = /bin/sh;
218 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
219 | };
220 | /* End PBXShellScriptBuildPhase section */
221 |
222 | /* Begin PBXSourcesBuildPhase section */
223 | 97C146EA1CF9000F007C117D /* Sources */ = {
224 | isa = PBXSourcesBuildPhase;
225 | buildActionMask = 2147483647;
226 | files = (
227 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
228 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | /* End PBXSourcesBuildPhase section */
233 |
234 | /* Begin PBXVariantGroup section */
235 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
236 | isa = PBXVariantGroup;
237 | children = (
238 | 97C146FB1CF9000F007C117D /* Base */,
239 | );
240 | name = Main.storyboard;
241 | sourceTree = "";
242 | };
243 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
244 | isa = PBXVariantGroup;
245 | children = (
246 | 97C147001CF9000F007C117D /* Base */,
247 | );
248 | name = LaunchScreen.storyboard;
249 | sourceTree = "";
250 | };
251 | /* End PBXVariantGroup section */
252 |
253 | /* Begin XCBuildConfiguration section */
254 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
255 | isa = XCBuildConfiguration;
256 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_ANALYZER_NONNULL = YES;
260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
261 | CLANG_CXX_LIBRARY = "libc++";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
265 | CLANG_WARN_BOOL_CONVERSION = YES;
266 | CLANG_WARN_COMMA = YES;
267 | CLANG_WARN_CONSTANT_CONVERSION = YES;
268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
270 | CLANG_WARN_EMPTY_BODY = YES;
271 | CLANG_WARN_ENUM_CONVERSION = YES;
272 | CLANG_WARN_INFINITE_RECURSION = YES;
273 | CLANG_WARN_INT_CONVERSION = YES;
274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
279 | CLANG_WARN_STRICT_PROTOTYPES = YES;
280 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
281 | CLANG_WARN_UNREACHABLE_CODE = YES;
282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
284 | COPY_PHASE_STRIP = NO;
285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
286 | ENABLE_NS_ASSERTIONS = NO;
287 | ENABLE_STRICT_OBJC_MSGSEND = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu99;
289 | GCC_NO_COMMON_BLOCKS = YES;
290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
292 | GCC_WARN_UNDECLARED_SELECTOR = YES;
293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
294 | GCC_WARN_UNUSED_FUNCTION = YES;
295 | GCC_WARN_UNUSED_VARIABLE = YES;
296 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
297 | MTL_ENABLE_DEBUG_INFO = NO;
298 | SDKROOT = iphoneos;
299 | SUPPORTED_PLATFORMS = iphoneos;
300 | TARGETED_DEVICE_FAMILY = "1,2";
301 | VALIDATE_PRODUCT = YES;
302 | };
303 | name = Profile;
304 | };
305 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
306 | isa = XCBuildConfiguration;
307 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
308 | buildSettings = {
309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
310 | CLANG_ENABLE_MODULES = YES;
311 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
312 | ENABLE_BITCODE = NO;
313 | FRAMEWORK_SEARCH_PATHS = (
314 | "$(inherited)",
315 | "$(PROJECT_DIR)/Flutter",
316 | );
317 | INFOPLIST_FILE = Runner/Info.plist;
318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
319 | LIBRARY_SEARCH_PATHS = (
320 | "$(inherited)",
321 | "$(PROJECT_DIR)/Flutter",
322 | );
323 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterChatApp;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
326 | SWIFT_VERSION = 5.0;
327 | VERSIONING_SYSTEM = "apple-generic";
328 | };
329 | name = Profile;
330 | };
331 | 97C147031CF9000F007C117D /* Debug */ = {
332 | isa = XCBuildConfiguration;
333 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
334 | buildSettings = {
335 | ALWAYS_SEARCH_USER_PATHS = NO;
336 | CLANG_ANALYZER_NONNULL = YES;
337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
338 | CLANG_CXX_LIBRARY = "libc++";
339 | CLANG_ENABLE_MODULES = YES;
340 | CLANG_ENABLE_OBJC_ARC = YES;
341 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
342 | CLANG_WARN_BOOL_CONVERSION = YES;
343 | CLANG_WARN_COMMA = YES;
344 | CLANG_WARN_CONSTANT_CONVERSION = YES;
345 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
347 | CLANG_WARN_EMPTY_BODY = YES;
348 | CLANG_WARN_ENUM_CONVERSION = YES;
349 | CLANG_WARN_INFINITE_RECURSION = YES;
350 | CLANG_WARN_INT_CONVERSION = YES;
351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
355 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
356 | CLANG_WARN_STRICT_PROTOTYPES = YES;
357 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
358 | CLANG_WARN_UNREACHABLE_CODE = YES;
359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
360 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
361 | COPY_PHASE_STRIP = NO;
362 | DEBUG_INFORMATION_FORMAT = dwarf;
363 | ENABLE_STRICT_OBJC_MSGSEND = YES;
364 | ENABLE_TESTABILITY = YES;
365 | GCC_C_LANGUAGE_STANDARD = gnu99;
366 | GCC_DYNAMIC_NO_PIC = NO;
367 | GCC_NO_COMMON_BLOCKS = YES;
368 | GCC_OPTIMIZATION_LEVEL = 0;
369 | GCC_PREPROCESSOR_DEFINITIONS = (
370 | "DEBUG=1",
371 | "$(inherited)",
372 | );
373 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
374 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
375 | GCC_WARN_UNDECLARED_SELECTOR = YES;
376 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
377 | GCC_WARN_UNUSED_FUNCTION = YES;
378 | GCC_WARN_UNUSED_VARIABLE = YES;
379 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
380 | MTL_ENABLE_DEBUG_INFO = YES;
381 | ONLY_ACTIVE_ARCH = YES;
382 | SDKROOT = iphoneos;
383 | TARGETED_DEVICE_FAMILY = "1,2";
384 | };
385 | name = Debug;
386 | };
387 | 97C147041CF9000F007C117D /* Release */ = {
388 | isa = XCBuildConfiguration;
389 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
390 | buildSettings = {
391 | ALWAYS_SEARCH_USER_PATHS = NO;
392 | CLANG_ANALYZER_NONNULL = YES;
393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
394 | CLANG_CXX_LIBRARY = "libc++";
395 | CLANG_ENABLE_MODULES = YES;
396 | CLANG_ENABLE_OBJC_ARC = YES;
397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
398 | CLANG_WARN_BOOL_CONVERSION = YES;
399 | CLANG_WARN_COMMA = YES;
400 | CLANG_WARN_CONSTANT_CONVERSION = YES;
401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
403 | CLANG_WARN_EMPTY_BODY = YES;
404 | CLANG_WARN_ENUM_CONVERSION = YES;
405 | CLANG_WARN_INFINITE_RECURSION = YES;
406 | CLANG_WARN_INT_CONVERSION = YES;
407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
412 | CLANG_WARN_STRICT_PROTOTYPES = YES;
413 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
414 | CLANG_WARN_UNREACHABLE_CODE = YES;
415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
417 | COPY_PHASE_STRIP = NO;
418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
419 | ENABLE_NS_ASSERTIONS = NO;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | GCC_C_LANGUAGE_STANDARD = gnu99;
422 | GCC_NO_COMMON_BLOCKS = YES;
423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
425 | GCC_WARN_UNDECLARED_SELECTOR = YES;
426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
427 | GCC_WARN_UNUSED_FUNCTION = YES;
428 | GCC_WARN_UNUSED_VARIABLE = YES;
429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
430 | MTL_ENABLE_DEBUG_INFO = NO;
431 | SDKROOT = iphoneos;
432 | SUPPORTED_PLATFORMS = iphoneos;
433 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
434 | TARGETED_DEVICE_FAMILY = "1,2";
435 | VALIDATE_PRODUCT = YES;
436 | };
437 | name = Release;
438 | };
439 | 97C147061CF9000F007C117D /* Debug */ = {
440 | isa = XCBuildConfiguration;
441 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
442 | buildSettings = {
443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
444 | CLANG_ENABLE_MODULES = YES;
445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
446 | ENABLE_BITCODE = NO;
447 | FRAMEWORK_SEARCH_PATHS = (
448 | "$(inherited)",
449 | "$(PROJECT_DIR)/Flutter",
450 | );
451 | INFOPLIST_FILE = Runner/Info.plist;
452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
453 | LIBRARY_SEARCH_PATHS = (
454 | "$(inherited)",
455 | "$(PROJECT_DIR)/Flutter",
456 | );
457 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterChatApp;
458 | PRODUCT_NAME = "$(TARGET_NAME)";
459 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
461 | SWIFT_VERSION = 5.0;
462 | VERSIONING_SYSTEM = "apple-generic";
463 | };
464 | name = Debug;
465 | };
466 | 97C147071CF9000F007C117D /* Release */ = {
467 | isa = XCBuildConfiguration;
468 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
469 | buildSettings = {
470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
471 | CLANG_ENABLE_MODULES = YES;
472 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
473 | ENABLE_BITCODE = NO;
474 | FRAMEWORK_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(PROJECT_DIR)/Flutter",
477 | );
478 | INFOPLIST_FILE = Runner/Info.plist;
479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
480 | LIBRARY_SEARCH_PATHS = (
481 | "$(inherited)",
482 | "$(PROJECT_DIR)/Flutter",
483 | );
484 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterChatApp;
485 | PRODUCT_NAME = "$(TARGET_NAME)";
486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
487 | SWIFT_VERSION = 5.0;
488 | VERSIONING_SYSTEM = "apple-generic";
489 | };
490 | name = Release;
491 | };
492 | /* End XCBuildConfiguration section */
493 |
494 | /* Begin XCConfigurationList section */
495 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
496 | isa = XCConfigurationList;
497 | buildConfigurations = (
498 | 97C147031CF9000F007C117D /* Debug */,
499 | 97C147041CF9000F007C117D /* Release */,
500 | 249021D3217E4FDB00AE95B9 /* Profile */,
501 | );
502 | defaultConfigurationIsVisible = 0;
503 | defaultConfigurationName = Release;
504 | };
505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
506 | isa = XCConfigurationList;
507 | buildConfigurations = (
508 | 97C147061CF9000F007C117D /* Debug */,
509 | 97C147071CF9000F007C117D /* Release */,
510 | 249021D4217E4FDB00AE95B9 /* Profile */,
511 | );
512 | defaultConfigurationIsVisible = 0;
513 | defaultConfigurationName = Release;
514 | };
515 | /* End XCConfigurationList section */
516 | };
517 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
518 | }
519 |
--------------------------------------------------------------------------------
/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 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/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/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Huzaifaahmed20/flutter_fire_chat_app/a38c9be9ad86ee2d1f58d72124ae9cdc0b0977f7/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_chat_app
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/lib/app/locator.dart:
--------------------------------------------------------------------------------
1 | import 'package:get_it/get_it.dart';
2 | import 'package:injectable/injectable.dart';
3 |
4 | import 'locator.iconfig.dart';
5 |
6 | final locator = GetIt.instance;
7 |
8 | @injectableInit
9 | void setupLocator() => $initGetIt(locator);
--------------------------------------------------------------------------------
/lib/app/locator.iconfig.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | // **************************************************************************
4 | // InjectableConfigGenerator
5 | // **************************************************************************
6 |
7 | import 'package:flutter_chat_app/services/services.dart';
8 | import 'package:flutter_chat_app/services/auth_service.dart';
9 | import 'package:stacked_services/stacked_services.dart';
10 | import 'package:flutter_chat_app/services/firebase_push_notification_serice.dart';
11 | import 'package:flutter_chat_app/services/firestore_service.dart';
12 | import 'package:get_it/get_it.dart';
13 |
14 | void $initGetIt(GetIt g, {String environment}) {
15 | final servicesModule = _$ServicesModule();
16 | g.registerLazySingleton(() => servicesModule.authService);
17 | g.registerLazySingleton(() => servicesModule.dialogService);
18 | g.registerLazySingleton(
19 | () => servicesModule.pushNotificationService);
20 | g.registerLazySingleton(
21 | () => servicesModule.firestoreService);
22 | g.registerLazySingleton(
23 | () => servicesModule.navigationService);
24 | }
25 |
26 | class _$ServicesModule extends ServicesModule {
27 | @override
28 | AuthService get authService => AuthService();
29 | @override
30 | DialogService get dialogService => DialogService();
31 | @override
32 | FirebasePushNotificationService get pushNotificationService =>
33 | FirebasePushNotificationService();
34 | @override
35 | FirestoreService get firestoreService => FirestoreService();
36 | @override
37 | NavigationService get navigationService => NavigationService();
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/router.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route_annotations.dart';
2 | import 'package:flutter_chat_app/ui/views/chat/chat_view.dart';
3 | import 'package:flutter_chat_app/ui/views/dashboard/dashboard_view.dart';
4 | import 'package:flutter_chat_app/ui/views/login/login_view.dart';
5 | import 'package:flutter_chat_app/ui/views/signup/signup_view.dart';
6 | import 'package:flutter_chat_app/ui/views/startup/startup_view.dart';
7 |
8 | @MaterialAutoRouter()
9 | class $Router {
10 | @initial
11 | StartupView startupViewRoute;
12 | LoginView loginViewRoute;
13 | SignupView signupViewRoute;
14 | DashboardView dashboardViewRoute;
15 | ChatView chatViewRoute;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/app/router.gr.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | // **************************************************************************
4 | // AutoRouteGenerator
5 | // **************************************************************************
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter/cupertino.dart';
9 | import 'package:auto_route/auto_route.dart';
10 | import 'package:flutter_chat_app/ui/views/startup/startup_view.dart';
11 | import 'package:flutter_chat_app/ui/views/login/login_view.dart';
12 | import 'package:flutter_chat_app/ui/views/signup/signup_view.dart';
13 | import 'package:flutter_chat_app/ui/views/dashboard/dashboard_view.dart';
14 | import 'package:flutter_chat_app/ui/views/chat/chat_view.dart';
15 | import 'package:flutter_chat_app/models/UserModel.dart';
16 |
17 | abstract class Routes {
18 | static const startupViewRoute = '/';
19 | static const loginViewRoute = '/login-view-route';
20 | static const signupViewRoute = '/signup-view-route';
21 | static const dashboardViewRoute = '/dashboard-view-route';
22 | static const chatViewRoute = '/chat-view-route';
23 | static const all = {
24 | startupViewRoute,
25 | loginViewRoute,
26 | signupViewRoute,
27 | dashboardViewRoute,
28 | chatViewRoute,
29 | };
30 | }
31 |
32 | class Router extends RouterBase {
33 | @override
34 | Set get allRoutes => Routes.all;
35 |
36 | @Deprecated('call ExtendedNavigator.ofRouter() directly')
37 | static ExtendedNavigatorState get navigator =>
38 | ExtendedNavigator.ofRouter();
39 |
40 | @override
41 | Route onGenerateRoute(RouteSettings settings) {
42 | final args = settings.arguments;
43 | switch (settings.name) {
44 | case Routes.startupViewRoute:
45 | if (hasInvalidArgs(args)) {
46 | return misTypedArgsRoute(args);
47 | }
48 | final typedArgs =
49 | args as StartupViewArguments ?? StartupViewArguments();
50 | return MaterialPageRoute(
51 | builder: (context) => StartupView(key: typedArgs.key),
52 | settings: settings,
53 | );
54 | case Routes.loginViewRoute:
55 | return MaterialPageRoute(
56 | builder: (context) => LoginView(),
57 | settings: settings,
58 | );
59 | case Routes.signupViewRoute:
60 | return MaterialPageRoute(
61 | builder: (context) => SignupView(),
62 | settings: settings,
63 | );
64 | case Routes.dashboardViewRoute:
65 | return MaterialPageRoute(
66 | builder: (context) => DashboardView(),
67 | settings: settings,
68 | );
69 | case Routes.chatViewRoute:
70 | if (hasInvalidArgs(args, isRequired: true)) {
71 | return misTypedArgsRoute(args);
72 | }
73 | final typedArgs = args as ChatViewArguments;
74 | return MaterialPageRoute(
75 | builder: (context) => ChatView(typedArgs.friend),
76 | settings: settings,
77 | );
78 | default:
79 | return unknownRoutePage(settings.name);
80 | }
81 | }
82 | }
83 |
84 | // *************************************************************************
85 | // Arguments holder classes
86 | // **************************************************************************
87 |
88 | //StartupView arguments holder class
89 | class StartupViewArguments {
90 | final Key key;
91 | StartupViewArguments({this.key});
92 | }
93 |
94 | //ChatView arguments holder class
95 | class ChatViewArguments {
96 | final UserModel friend;
97 | ChatViewArguments({@required this.friend});
98 | }
99 |
--------------------------------------------------------------------------------
/lib/helpers/UserSearchDelegate.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/models/UserModel.dart';
3 | import '../ui/widgets/UsersList.dart';
4 |
5 |
6 | class UserSearchDelegate extends SearchDelegate {
7 | UserSearchDelegate({this.users});
8 | List users;
9 | @override
10 | List buildActions(BuildContext context) {
11 | return [
12 | IconButton(
13 | icon: Icon(Icons.clear),
14 | onPressed: () {
15 | query = '';
16 | },
17 | )
18 | ];
19 | }
20 |
21 | @override
22 | Widget buildLeading(BuildContext context) {
23 | return IconButton(
24 | icon: AnimatedIcon(
25 | icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
26 | onPressed: () {
27 | close(context, null);
28 | },
29 | );
30 | }
31 |
32 | @override
33 | Widget buildResults(BuildContext context) {
34 | // nothing todo for now
35 | }
36 |
37 | @override
38 | Widget buildSuggestions(BuildContext context) {
39 | List searcUsers = query.isEmpty
40 | ? users
41 | : users
42 | .where((i) =>
43 | i.name.toLowerCase().contains(query) ||
44 | i.email.toLowerCase().contains(query))
45 | .toList();
46 | if (searcUsers.length == 0) {
47 | return Center(
48 | child: Text('No users found'),
49 | );
50 | }
51 | return UsersList(users: searcUsers);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/app/locator.dart';
3 | import 'package:stacked_services/stacked_services.dart';
4 |
5 | import 'app/router.gr.dart';
6 |
7 | void main() {
8 | setupLocator();
9 | runApp(MyApp());
10 | }
11 |
12 | class MyApp extends StatelessWidget {
13 | @override
14 | Widget build(BuildContext context) {
15 | return MaterialApp(
16 | debugShowCheckedModeBanner: false,
17 | title: 'FireChat',
18 | initialRoute: Routes.startupViewRoute,
19 | onGenerateRoute: Router().onGenerateRoute,
20 | navigatorKey: locator().navigatorKey,
21 | );
22 | }
23 | }
24 |
25 | // class MainApp extends StatelessWidget {
26 | // @override
27 | // Widget build(BuildContext context) {
28 | // final auth = Provider.of(context, listen: false);
29 | // return StreamBuilder(
30 | // stream: auth.isAuth,
31 | // builder: (context, snapshot) {
32 | // if (snapshot.connectionState == ConnectionState.waiting) {
33 | // return Center(
34 | // child: CircularProgressIndicator(),
35 | // ); // Splash screen will be here
36 | // } else {
37 | // if (snapshot.hasData) {
38 | // return HomeScreen(snapshot.data);
39 | // }
40 | // return LoginScreen();
41 | // }
42 | // });
43 | // }
44 | // }
45 |
--------------------------------------------------------------------------------
/lib/models/MessagesModel.dart:
--------------------------------------------------------------------------------
1 | class MessagesModel {
2 | String receiverId;
3 | String senderId;
4 | String senderName;
5 | String receiverName;
6 | String messageBody;
7 | int createdAt;
8 |
9 | MessagesModel({
10 | this.receiverId,
11 | this.senderId,
12 | this.messageBody,
13 | this.createdAt,
14 | this.senderName,
15 | this.receiverName,
16 | });
17 |
18 | MessagesModel.fromData(Map data)
19 | : receiverId = data['receiverId'],
20 | senderId = data['senderId'],
21 | senderName = data['senderName'],
22 | receiverName = data['receiverName'],
23 | messageBody = data['messageBody'],
24 | createdAt = data['createdAt'];
25 |
26 | static MessagesModel fromMap(Map map) {
27 | if (map == null) return null;
28 |
29 | return MessagesModel(
30 | receiverId: map['receiverId'],
31 | senderId: map['senderId'],
32 | senderName: map['senderName'],
33 | receiverName: map['receiverName'],
34 | messageBody: map['messageBody'],
35 | createdAt: map['createdAt'],
36 | );
37 | }
38 |
39 | Map toJson() {
40 | return {
41 | 'receiverId': receiverId,
42 | 'senderId': senderId,
43 | 'senderName': senderName,
44 | 'receiverName': receiverName,
45 | 'messageBody': messageBody,
46 | 'createdAt': createdAt,
47 | };
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/models/TokenModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 |
3 | class TokenModel {
4 | String token;
5 | FieldValue createdAt;
6 |
7 | TokenModel({
8 | this.token,
9 | this.createdAt,
10 | });
11 |
12 | TokenModel.fromData(Map data)
13 | : token = data['token'],
14 | createdAt = data['createdAt'];
15 |
16 | static TokenModel fromMap(Map map) {
17 | if (map == null) return null;
18 |
19 | return TokenModel(
20 | token: map['token'],
21 | createdAt: map['createdAt'],
22 | );
23 | }
24 |
25 | Map toJson() {
26 | return {
27 | 'token': token,
28 | 'createdAt': createdAt,
29 | };
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/models/UserModel.dart:
--------------------------------------------------------------------------------
1 | class UserModel {
2 | String id;
3 | String name;
4 | String email;
5 |
6 | UserModel({this.id, this.name, this.email});
7 |
8 | UserModel.fromData(Map data)
9 | : id = data['id'],
10 | name = data['name'],
11 | email = data['email'];
12 |
13 | static UserModel fromMap(Map map) {
14 | if (map == null) return null;
15 |
16 | return UserModel(
17 | id: map['id'],
18 | name: map['name'],
19 | email: map['email'],
20 | );
21 | }
22 |
23 | Map toJson() {
24 | return {
25 | 'id': id,
26 | 'name': name,
27 | 'email': email,
28 | };
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/services/auth_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart';
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter_chat_app/app/locator.dart';
4 | import 'package:flutter_chat_app/models/UserModel.dart';
5 | import 'package:flutter_chat_app/services/firestore_service.dart';
6 |
7 | class AuthService {
8 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
9 | final FirestoreService _firestoreService = locator();
10 |
11 | UserModel _currentUser;
12 | UserModel get currentUser => _currentUser;
13 |
14 | Future loginWithEmail({
15 | @required String email,
16 | @required String password,
17 | }) async {
18 | try {
19 | var authResult = await _firebaseAuth.signInWithEmailAndPassword(
20 | email: email,
21 | password: password,
22 | );
23 | await _populateCurrentUser(authResult.user);
24 | return authResult.user != null;
25 | } catch (e) {
26 | return e.message;
27 | }
28 | }
29 |
30 | Future signUpWithEmail({
31 | @required String email,
32 | @required String password,
33 | @required String name,
34 | }) async {
35 | try {
36 | var authResult = await _firebaseAuth.createUserWithEmailAndPassword(
37 | email: email,
38 | password: password,
39 | );
40 |
41 | // create a new user profile on firestore
42 | _currentUser = UserModel(
43 | id: authResult.user.uid,
44 | email: email,
45 | name: name,
46 | );
47 |
48 | await _firestoreService.createUser(_currentUser);
49 |
50 | return authResult.user != null;
51 | } catch (e) {
52 | return e.message;
53 | }
54 | }
55 |
56 | Future isUserLoggedIn() async {
57 | var user = await _firebaseAuth.currentUser();
58 | if (user != null) {
59 | await _populateCurrentUser(user);
60 | }
61 | return user != null;
62 | }
63 |
64 | Future _populateCurrentUser(FirebaseUser user) async {
65 | if (user != null) {
66 | _currentUser = await _firestoreService.getUser(user.uid);
67 | }
68 | }
69 |
70 | void logOut() {
71 | _firebaseAuth.signOut();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/services/firebase_push_notification_serice.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:firebase_messaging/firebase_messaging.dart';
4 |
5 | class FirebasePushNotificationService {
6 | final FirebaseMessaging _fcm = FirebaseMessaging();
7 |
8 | Future initialize() {
9 | if (Platform.isIOS) {
10 | _fcm.requestNotificationPermissions(IosNotificationSettings());
11 | }
12 | _fcm.configure(
13 | onMessage: (Map message) async {
14 | print("onMessage: $message");
15 | // _showItemDialog(message);
16 | },
17 | onLaunch: (Map message) async {
18 | print("onLaunch: $message");
19 | // _navigateToItemDetail(message);
20 | },
21 | onResume: (Map message) async {
22 | print("onResume: $message");
23 | // _navigateToItemDetail(message);
24 | },
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/services/firestore_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:firebase_messaging/firebase_messaging.dart';
5 | import 'package:flutter/services.dart';
6 | import 'package:flutter_chat_app/models/MessagesModel.dart';
7 | import 'package:flutter_chat_app/models/TokenModel.dart';
8 | import 'package:flutter_chat_app/models/UserModel.dart';
9 |
10 | class FirestoreService {
11 | final CollectionReference _usersCollectionReference =
12 | Firestore.instance.collection('users');
13 | final CollectionReference _messagesCollectionReference =
14 | Firestore.instance.collection('messages');
15 | final FirebaseMessaging _fcm = FirebaseMessaging();
16 |
17 | final StreamController> _chatMessagesController =
18 | StreamController>.broadcast();
19 |
20 | Future createUser(UserModel user) async {
21 | try {
22 | await _usersCollectionReference.document(user.id).setData(user.toJson());
23 | } catch (e) {
24 | // TODO: Find or create a way to repeat error handling without so much repeated code
25 | if (e is PlatformException) {
26 | return e.message;
27 | }
28 |
29 | return e.toString();
30 | }
31 | }
32 |
33 | Future getUser(String uid) async {
34 | try {
35 | var userData = await _usersCollectionReference.document(uid).get();
36 |
37 | return UserModel.fromData(userData.data);
38 | } catch (e) {
39 | // TODO: Find or create a way to repeat error handling without so much repeated code
40 | if (e is PlatformException) {
41 | return e.message;
42 | }
43 |
44 | return e.toString();
45 | }
46 | }
47 |
48 | Future getAllUsersOnce(String currentUserUID) async {
49 | try {
50 | var usersDocumentSnapshot =
51 | await _usersCollectionReference.getDocuments();
52 | String fcmToken = await _fcm.getToken();
53 |
54 | final tokenRef = _usersCollectionReference
55 | .document(currentUserUID)
56 | .collection('tokens')
57 | .document(fcmToken);
58 | await tokenRef.setData(
59 | TokenModel(token: fcmToken, createdAt: FieldValue.serverTimestamp())
60 | .toJson(),
61 | );
62 | if (usersDocumentSnapshot.documents.isNotEmpty) {
63 | return usersDocumentSnapshot.documents
64 | .map((snapshot) => UserModel.fromMap(snapshot.data))
65 | .where((mappedItem) => mappedItem.id != currentUserUID)
66 | .toList();
67 | }
68 | } catch (e) {
69 | // TODO: Find or create a way to repeat error handling without so much repeated code
70 | if (e is PlatformException) {
71 | return e.message;
72 | }
73 |
74 | return e.toString();
75 | }
76 | }
77 |
78 | Future createMessage(MessagesModel message) async {
79 | try {
80 | await _messagesCollectionReference.document().setData(message.toJson());
81 | } catch (e) {
82 | // TODO: Find or create a way to repeat error handling without so much repeated code
83 | if (e is PlatformException) {
84 | return e.message;
85 | }
86 |
87 | return e.toString();
88 | }
89 | }
90 |
91 | Stream listenToMessagesRealTime(String friendId, String currentUserId) {
92 | // Register the handler for when the posts data changes
93 | _requestMessages(friendId, currentUserId);
94 | return _chatMessagesController.stream;
95 | }
96 |
97 | void _requestMessages(String friendId, String currentUserId) {
98 | var messagesQuerySnapshot =
99 | _messagesCollectionReference.orderBy('createdAt', descending: true);
100 |
101 | messagesQuerySnapshot.snapshots().listen((messageSnapshot) {
102 | if (messageSnapshot.documents.isNotEmpty) {
103 | var messages = messageSnapshot.documents
104 | .map((snapshot) => MessagesModel.fromMap(snapshot.data))
105 | .where((element) =>
106 | (element.receiverId == friendId &&
107 | element.senderId == currentUserId) ||
108 | (element.receiverId == currentUserId &&
109 | element.senderId == friendId))
110 | .toList();
111 |
112 | _chatMessagesController.add(messages);
113 | }
114 | });
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/lib/services/services.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/services/firebase_push_notification_serice.dart';
2 | import 'package:flutter_chat_app/services/firestore_service.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:stacked_services/stacked_services.dart';
5 | import 'package:flutter_chat_app/services/auth_service.dart';
6 |
7 | @module
8 | abstract class ServicesModule {
9 | @lazySingleton
10 | NavigationService get navigationService;
11 | @lazySingleton
12 | DialogService get dialogService;
13 | @lazySingleton
14 | AuthService get authService;
15 | @lazySingleton
16 | FirestoreService get firestoreService;
17 | @lazySingleton
18 | FirebasePushNotificationService get pushNotificationService;
19 | }
20 |
--------------------------------------------------------------------------------
/lib/ui/views/chat/chat_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:emoji_picker/emoji_picker.dart';
2 | import 'package:flutter/material.dart';
3 | // import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:flutter_chat_app/models/UserModel.dart';
5 | // import 'package:provider/provider.dart';
6 | import 'package:flutter_chat_app/ui/views/chat/chat_viewmodel.dart';
7 | import 'package:flutter_chat_app/ui/widgets/MessagesList.dart';
8 | import 'package:stacked/stacked.dart';
9 | import 'package:basic_utils/basic_utils.dart';
10 |
11 | // import '../models/UserModel.dart';
12 | // import '../providers/ChatProvider.dart';
13 | // import '../../widgets/MessagesList.dart';
14 |
15 | class ChatView extends StatelessWidget {
16 | static const routeName = '/chat';
17 | ChatView(this.friend);
18 | final UserModel friend;
19 | final TextEditingController _messageBodyController = TextEditingController();
20 | final FocusNode _messageFocus = FocusNode();
21 | @override
22 | Widget build(BuildContext context) {
23 | Widget buildChatMessages(model, friendId) {
24 | if (model.isBusy) {
25 | return Center(
26 | child: CircularProgressIndicator(),
27 | );
28 | } else {
29 | if (model.messages.length == 0) {
30 | return Expanded(
31 | child: Center(
32 | child: Image.asset('assets/images/empty_inbox.jpg', height: 200),
33 | ),
34 | );
35 | }
36 |
37 | return MessagesList(messages: model.messages, friendId: friend.id);
38 | }
39 | }
40 |
41 | return ViewModelBuilder.reactive(
42 | onModelReady: (model) => model.listenToMessages(friend.id),
43 | builder: (context, model, child) {
44 | return Scaffold(
45 | backgroundColor: Color(0xffF2F8FD),
46 | appBar: AppBar(
47 | iconTheme: IconThemeData(color: Colors.black54),
48 | elevation: 0,
49 | backgroundColor: Colors.transparent,
50 | title: Text(
51 | friend.name,
52 | style: TextStyle(color: Colors.black54, fontSize: 20),
53 | ),
54 | ),
55 | body: Column(
56 | crossAxisAlignment: CrossAxisAlignment.stretch,
57 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
58 | children: [
59 | buildChatMessages(model, friend.id),
60 | SizedBox(height: 20),
61 | Container(
62 | color: Colors.white,
63 | child: Row(
64 | children: [
65 | IconButton(
66 | icon: Icon(Icons.tag_faces),
67 | onPressed: () {
68 | _messageFocus.unfocus();
69 | model.showEmojiPicker();
70 | },
71 | ),
72 | IconButton(
73 | icon: Icon(Icons.attach_file),
74 | onPressed: () {},
75 | ),
76 | Expanded(
77 | child: TextField(
78 | focusNode: _messageFocus,
79 | onTap: () {
80 | if (model.isShowEmojiPicker) {
81 | model.showEmojiPicker();
82 | }
83 | },
84 | controller: _messageBodyController,
85 | decoration: InputDecoration(
86 | border: InputBorder.none,
87 | hintText: 'Send Message',
88 | ),
89 | ),
90 | ),
91 | IconButton(
92 | onPressed: () {
93 | if (_messageBodyController.text.isEmpty) {
94 | return;
95 | }
96 | model.sendMessage(_messageBodyController.text,
97 | friend.id, friend.name);
98 | _messageBodyController.clear();
99 | },
100 | icon: Icon(
101 | Icons.send,
102 | color: Colors.green,
103 | ),
104 | )
105 | ],
106 | ),
107 | ),
108 | model.isShowEmojiPicker
109 | ? EmojiPicker(
110 | rows: 3,
111 | columns: 7,
112 | selectedCategory: Category.SMILEYS,
113 | buttonMode: ButtonMode.MATERIAL,
114 | onEmojiSelected: (item, category) {
115 | _messageBodyController.text =
116 | StringUtils.addCharAtPosition(
117 | _messageBodyController.text,
118 | item.emoji,
119 | _messageBodyController.text.length);
120 | },
121 | )
122 | : Container()
123 | ],
124 | ),
125 | );
126 | },
127 | viewModelBuilder: () => ChatViewModel(),
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/lib/ui/views/chat/chat_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/app/locator.dart';
2 | import 'package:flutter_chat_app/models/MessagesModel.dart';
3 | import 'package:flutter_chat_app/services/auth_service.dart';
4 | import 'package:flutter_chat_app/services/firestore_service.dart';
5 | import 'package:stacked/stacked.dart';
6 |
7 | class ChatViewModel extends BaseViewModel {
8 | final AuthService _authService = locator();
9 | FirestoreService _firestoreService = locator();
10 |
11 | List _messages = [];
12 | List get messages => _messages;
13 | bool isShowEmojiPicker = false;
14 |
15 | // Stream listenToMessages() {}
16 |
17 | // @override
18 | // Stream get stream => listenToMessages();
19 |
20 | Future sendMessage(
21 | String messageBody, String receiverId, String receiverName) async {
22 | final MessagesModel message = MessagesModel(
23 | messageBody: messageBody,
24 | receiverId: receiverId,
25 | senderId: _authService.currentUser.id,
26 | senderName: _authService.currentUser.name,
27 | receiverName: receiverName,
28 | createdAt: DateTime.now().millisecondsSinceEpoch,
29 | );
30 | return await _firestoreService.createMessage(message);
31 | }
32 |
33 | void listenToMessages(String friendId) {
34 | setBusy(true);
35 |
36 | _firestoreService
37 | .listenToMessagesRealTime(friendId, _authService.currentUser.id)
38 | .listen((messagesData) {
39 | List updatedMessages = messagesData;
40 | if (updatedMessages != null && updatedMessages.length > 0) {
41 | _messages = updatedMessages;
42 | notifyListeners();
43 | } else {
44 | setBusy(false);
45 | }
46 |
47 | setBusy(false);
48 | });
49 | }
50 |
51 | void showEmojiPicker() {
52 | isShowEmojiPicker = !isShowEmojiPicker;
53 | notifyListeners();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/ui/views/dashboard/dashboard_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/ui/views/dashboard/dashboard_viewmodel.dart';
3 | import 'package:stacked/stacked.dart';
4 | // import 'package:flutter_chat_app/models/UserModel.dart';
5 | // import 'package:provider/provider.dart';
6 |
7 | // import '../providers/ChatProvider.dart';
8 | import '../../widgets/DrawerWidget.dart';
9 | import '../../widgets/UsersList.dart';
10 | import '../../../helpers/UserSearchDelegate.dart';
11 |
12 | class DashboardView extends StatelessWidget {
13 | @override
14 | Widget build(BuildContext context) {
15 | return ViewModelBuilder.reactive(
16 | builder: (context, model, child) {
17 | return Scaffold(
18 | drawer: DrawerWidget(model),
19 | appBar: AppBar(
20 | iconTheme: IconThemeData(color: Colors.black54),
21 | elevation: 0,
22 | backgroundColor: Colors.transparent,
23 | title: Text(
24 | 'Hi, ${model.user.name}',
25 | style: TextStyle(color: Colors.black54, fontSize: 20),
26 | ),
27 | actions: [
28 | IconButton(
29 | icon: Icon(Icons.search),
30 | onPressed: () =>
31 | showSearch(context: context, delegate: UserSearchDelegate(users: model.data)),
32 | )
33 | ],
34 | ),
35 | body: model.isBusy ? LinearProgressIndicator() : UsersList(users: model.data),
36 | );
37 | },
38 | viewModelBuilder: () => DashboardViewModel(),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/ui/views/dashboard/dashboard_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/app/locator.dart';
2 | import 'package:flutter_chat_app/app/router.gr.dart';
3 | import 'package:flutter_chat_app/models/UserModel.dart';
4 | import 'package:flutter_chat_app/services/auth_service.dart';
5 | import 'package:flutter_chat_app/services/firestore_service.dart';
6 | import 'package:stacked/stacked.dart';
7 | import 'package:stacked_services/stacked_services.dart';
8 |
9 | class DashboardViewModel extends FutureViewModel> {
10 | final AuthService _authService = locator();
11 | final FirestoreService _firestoreService = locator();
12 | final NavigationService _navigationService = locator();
13 |
14 | UserModel get user => _authService.currentUser;
15 |
16 | Future> users() async {
17 | return await _firestoreService.getAllUsersOnce(_authService.currentUser.id);
18 | }
19 |
20 | @override
21 | Future> futureToRun() {
22 | return users();
23 | }
24 |
25 | void signOut() {
26 | _authService.logOut();
27 | _navigationService.replaceWith(Routes.loginViewRoute);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/ui/views/login/login_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/ui/views/login/login_viewmodel.dart';
3 | import 'package:flutter_chat_app/ui/widgets/BusyButton.dart';
4 | import 'package:stacked/stacked.dart';
5 | // import './SignupScreen.dart';
6 | // import '../providers/AuthProvider.dart';
7 |
8 | class LoginView extends StatelessWidget {
9 | final TextEditingController _emailController = TextEditingController();
10 | final TextEditingController _passwordController = TextEditingController();
11 | final FocusNode _emailFocus = FocusNode();
12 | final FocusNode _passwordFocus = FocusNode();
13 |
14 | void _fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
15 | currentFocus.unfocus();
16 | FocusScope.of(context).requestFocus(nextFocus);
17 | }
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return ViewModelBuilder.reactive(
22 | builder: (context, model, child) => Scaffold(
23 | backgroundColor: Colors.white,
24 | appBar: AppBar(
25 | backgroundColor: Colors.transparent,
26 | elevation: 0,
27 | title: Text(
28 | 'Login',
29 | style: TextStyle(color: Colors.black, fontSize: 30),
30 | ),
31 | centerTitle: true,
32 | ),
33 | body: SingleChildScrollView(
34 | child: Column(
35 | children: [
36 | Image.asset(
37 | 'assets/images/splash.jpg',
38 | height: 300,
39 | width: 300,
40 | ),
41 | Card(
42 | elevation: 3,
43 | margin: EdgeInsets.symmetric(horizontal: 20),
44 | child: Padding(
45 | padding: const EdgeInsets.symmetric(vertical: 10),
46 | child: TextField(
47 | textInputAction: TextInputAction.next,
48 | focusNode: _emailFocus,
49 | onEditingComplete: () =>
50 | _fieldFocusChange(context, _emailFocus, _passwordFocus),
51 | style: TextStyle(fontSize: 20, color: Colors.blueGrey),
52 | enabled: !model.isBusy,
53 | controller: _emailController,
54 | decoration: InputDecoration(
55 | focusedBorder: InputBorder.none,
56 | border: InputBorder.none,
57 | prefixIcon: Icon(
58 | Icons.email,
59 | color: Colors.blueGrey,
60 | ),
61 | ),
62 | ),
63 | ),
64 | ),
65 | SizedBox(height: 20),
66 | Card(
67 | elevation: 3,
68 | margin: EdgeInsets.symmetric(horizontal: 20),
69 | child: Padding(
70 | padding: const EdgeInsets.symmetric(vertical: 10),
71 | child: TextField(
72 | textInputAction: TextInputAction.done,
73 | focusNode: _passwordFocus,
74 | onEditingComplete: () => model.login(
75 | email: _emailController.text,
76 | password: _passwordController.text,
77 | ),
78 | style: TextStyle(fontSize: 20, color: Colors.blueGrey),
79 | obscureText: model.hidePassword,
80 | enabled: !model.isBusy,
81 | controller: _passwordController,
82 | decoration: InputDecoration(
83 | focusedBorder: InputBorder.none,
84 | border: InputBorder.none,
85 | prefixIcon: Icon(
86 | Icons.vpn_key,
87 | color: Colors.blueGrey,
88 | ),
89 | suffixIcon: IconButton(
90 | onPressed: () => model.togglePasswordValue(),
91 | icon: Icon(
92 | model.hidePassword ? Icons.enhanced_encryption : Icons.remove_red_eye,
93 | color: Colors.blueGrey,
94 | ),
95 | ),
96 | ),
97 | ),
98 | ),
99 | ),
100 | SizedBox(height: 50),
101 | BusyButton(
102 | onPressed: () => model.login(
103 | email: _emailController.text,
104 | password: _passwordController.text,
105 | ),
106 | busy: model.isBusy,
107 | enabled: !model.isBusy,
108 | title: 'Log in',
109 | ),
110 | Center(
111 | child: Padding(
112 | padding: const EdgeInsets.only(top: 20),
113 | child: Text('Or'),
114 | )),
115 | FlatButton(
116 | onPressed: () => model.navigateToSignUp(),
117 | child: Text('Create an Account!'),
118 | textColor: Colors.blue,
119 | )
120 | ],
121 | ),
122 | ),
123 | ),
124 | viewModelBuilder: () => LoginViewModel(),
125 | );
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/lib/ui/views/login/login_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/app/locator.dart';
2 | import 'package:flutter_chat_app/app/router.gr.dart';
3 | import 'package:flutter_chat_app/services/auth_service.dart';
4 | import 'package:stacked/stacked.dart';
5 | import 'package:stacked_services/stacked_services.dart';
6 |
7 | class LoginViewModel extends BaseViewModel {
8 | final NavigationService _navigationService = locator();
9 | final AuthService _authService = locator();
10 | final DialogService _dialogService = locator();
11 |
12 | bool _hidePasswordValue = true;
13 |
14 | bool get hidePassword => _hidePasswordValue;
15 |
16 | void togglePasswordValue() {
17 | _hidePasswordValue = !_hidePasswordValue;
18 | notifyListeners();
19 | }
20 |
21 | void navigateToSignUp() => _navigationService.navigateTo(Routes.signupViewRoute);
22 |
23 | Future login({String email, String password}) async {
24 | setBusy(true);
25 |
26 | var result = await _authService.loginWithEmail(
27 | email: email,
28 | password: password,
29 | );
30 |
31 | if (result is bool) {
32 | if (result) {
33 | setBusy(false);
34 | _navigationService.replaceWith(Routes.dashboardViewRoute);
35 | } else {
36 | setBusy(false);
37 | await _dialogService.showDialog(
38 | title: 'Login Failure',
39 | description: 'General login failure. Please try again later',
40 | );
41 | }
42 | } else {
43 | setBusy(false);
44 | await _dialogService.showDialog(
45 | title: 'Login Failure',
46 | description: result,
47 | );
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/ui/views/signup/signup_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/ui/views/signup/signup_viewmodel.dart';
3 | import 'package:flutter_chat_app/ui/widgets/BusyButton.dart';
4 | import 'package:stacked/stacked.dart';
5 |
6 | class SignupView extends StatelessWidget {
7 | static const routeName = '/signup';
8 | final TextEditingController _emailController = TextEditingController();
9 | final TextEditingController _passwordController = TextEditingController();
10 | final TextEditingController _usernameController = TextEditingController();
11 |
12 | final FocusNode _usernameFocus = FocusNode();
13 | final FocusNode _emailFocus = FocusNode();
14 | final FocusNode _passwordFocus = FocusNode();
15 |
16 | void _fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
17 | currentFocus.unfocus();
18 | FocusScope.of(context).requestFocus(nextFocus);
19 | }
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return ViewModelBuilder.reactive(
24 | builder: (context, model, child) => Scaffold(
25 | backgroundColor: Colors.white,
26 | appBar: AppBar(
27 | backgroundColor: Colors.transparent,
28 | elevation: 0,
29 | title: Text(
30 | 'Sign Up',
31 | style: TextStyle(color: Colors.black, fontSize: 30),
32 | ),
33 | centerTitle: true,
34 | ),
35 | body: SingleChildScrollView(
36 | child: Column(
37 | mainAxisAlignment: MainAxisAlignment.center,
38 | children: [
39 | Image.asset(
40 | 'assets/images/splash.jpg',
41 | height: 300,
42 | width: 300,
43 | ),
44 | Card(
45 | elevation: 3,
46 | margin: EdgeInsets.symmetric(horizontal: 20),
47 | child: Padding(
48 | padding: const EdgeInsets.symmetric(vertical: 10),
49 | child: TextField(
50 | textInputAction: TextInputAction.next,
51 | focusNode: _usernameFocus,
52 | onEditingComplete: () =>
53 | _fieldFocusChange(context, _usernameFocus, _emailFocus),
54 | style: TextStyle(fontSize: 20, color: Colors.blueGrey),
55 | enabled: !model.isBusy,
56 | controller: _usernameController,
57 | decoration: InputDecoration(
58 | focusedBorder: InputBorder.none,
59 | border: InputBorder.none,
60 | prefixIcon: Icon(
61 | Icons.person,
62 | color: Colors.blueGrey,
63 | ),
64 | ),
65 | ),
66 | ),
67 | ),
68 | SizedBox(height: 10),
69 | Card(
70 | elevation: 3,
71 | margin: EdgeInsets.symmetric(horizontal: 20),
72 | child: Padding(
73 | padding: const EdgeInsets.symmetric(vertical: 10),
74 | child: TextField(
75 | textInputAction: TextInputAction.next,
76 | focusNode: _emailFocus,
77 | onEditingComplete: () =>
78 | _fieldFocusChange(context, _emailFocus, _passwordFocus),
79 | style: TextStyle(fontSize: 20, color: Colors.blueGrey),
80 | enabled: !model.isBusy,
81 | controller: _emailController,
82 | decoration: InputDecoration(
83 | focusedBorder: InputBorder.none,
84 | border: InputBorder.none,
85 | prefixIcon: Icon(
86 | Icons.email,
87 | color: Colors.blueGrey,
88 | ),
89 | ),
90 | ),
91 | ),
92 | ),
93 | SizedBox(height: 10),
94 | Card(
95 | elevation: 3,
96 | margin: EdgeInsets.symmetric(horizontal: 20),
97 | child: Padding(
98 | padding: const EdgeInsets.symmetric(vertical: 10),
99 | child: TextField(
100 | textInputAction: TextInputAction.done,
101 | focusNode: _passwordFocus,
102 | onEditingComplete: () => model.signUp(
103 | email: _emailController.text,
104 | password: _passwordController.text,
105 | name: _usernameController.text,
106 | ),
107 | style: TextStyle(fontSize: 20, color: Colors.blueGrey),
108 | obscureText: model.hidePassword,
109 | enabled: !model.isBusy,
110 | controller: _passwordController,
111 | decoration: InputDecoration(
112 | focusedBorder: InputBorder.none,
113 | border: InputBorder.none,
114 | prefixIcon: Icon(
115 | Icons.vpn_key,
116 | color: Colors.blueGrey,
117 | ),
118 | suffixIcon: IconButton(
119 | onPressed: () => model.togglePasswordValue(),
120 | icon: Icon(
121 | model.hidePassword ? Icons.enhanced_encryption : Icons.remove_red_eye,
122 | color: Colors.blueGrey,
123 | ),
124 | ),
125 | ),
126 | ),
127 | ),
128 | ),
129 | SizedBox(height: 40),
130 | BusyButton(
131 | onPressed: () => model.signUp(
132 | email: _emailController.text,
133 | password: _passwordController.text,
134 | name: _usernameController.text,
135 | ),
136 | busy: model.isBusy,
137 | enabled: !model.isBusy,
138 | title: 'Sign Up',
139 | ),
140 | ],
141 | ),
142 | ),
143 | ),
144 | viewModelBuilder: () => SignupViewModel(),
145 | );
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/lib/ui/views/signup/signup_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/app/locator.dart';
2 | import 'package:flutter_chat_app/app/router.gr.dart';
3 | import 'package:flutter_chat_app/services/auth_service.dart';
4 | import 'package:stacked/stacked.dart';
5 | import 'package:stacked_services/stacked_services.dart';
6 |
7 | class SignupViewModel extends BaseViewModel {
8 | final AuthService _authService = locator();
9 | final DialogService _dialogService = locator();
10 | final NavigationService _navigationService = locator();
11 |
12 | bool _hidePasswordValue = true;
13 |
14 | bool get hidePassword => _hidePasswordValue;
15 |
16 | void togglePasswordValue() {
17 | _hidePasswordValue = !_hidePasswordValue;
18 | notifyListeners();
19 | }
20 |
21 | Future signUp({String email, String password, String name}) async {
22 | setBusy(true);
23 | final result = await _authService.signUpWithEmail(email: email, password: password, name: name);
24 |
25 | if (result is bool) {
26 | if (result) {
27 | setBusy(false);
28 | _navigationService.replaceWith(Routes.dashboardViewRoute);
29 | } else {
30 | setBusy(false);
31 |
32 | await _dialogService.showDialog(
33 | title: 'Sign Up Failure',
34 | description: 'General sign up failure. Please try again later',
35 | );
36 | }
37 | } else {
38 | setBusy(false);
39 | await _dialogService.showDialog(
40 | title: 'Sign Up Failure',
41 | description: result,
42 | );
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/ui/views/startup/startup_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/ui/views/startup/startup_viewmodel.dart';
3 | import 'package:stacked/stacked.dart';
4 |
5 | class StartupView extends StatelessWidget {
6 | const StartupView({Key key}) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return ViewModelBuilder.reactive(
11 | onModelReady: (model) => model.handleStartUpLogic(),
12 | builder: (context, model, child) => Scaffold(
13 | backgroundColor: Colors.white,
14 | body: Column(
15 | mainAxisAlignment: MainAxisAlignment.center,
16 | children: [
17 | Hero(tag: 'splash', child: Image.asset('assets/images/splash.gif')),
18 | Text(
19 | 'Flutter Fire Chat',
20 | style: TextStyle(fontSize: 30),
21 | ),
22 | ],
23 | )),
24 | viewModelBuilder: () => StartupViewModel(),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/ui/views/startup/startup_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_chat_app/app/locator.dart';
4 | import 'package:flutter_chat_app/app/router.gr.dart';
5 | import 'package:flutter_chat_app/services/auth_service.dart';
6 | import 'package:flutter_chat_app/services/firebase_push_notification_serice.dart';
7 | import 'package:stacked/stacked.dart';
8 | import 'package:stacked_services/stacked_services.dart';
9 |
10 | class StartupViewModel extends BaseViewModel {
11 | NavigationService _navigationService = locator();
12 | AuthService _authService = locator();
13 | FirebasePushNotificationService _pushNotificationService =
14 | locator();
15 |
16 | Future handleStartUpLogic() async {
17 | Timer(Duration(seconds: 2), () async {
18 | await _pushNotificationService.initialize();
19 | bool hasLoggedInUser = await _authService.isUserLoggedIn();
20 | if (hasLoggedInUser) {
21 | _navigationService.replaceWith(Routes.dashboardViewRoute);
22 | } else {
23 | _navigationService.replaceWith(Routes.loginViewRoute);
24 | }
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/ui/widgets/BusyButton.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// A button that shows a busy indicator in place of title
4 | class BusyButton extends StatefulWidget {
5 | final bool busy;
6 | final String title;
7 | final Function onPressed;
8 | final bool enabled;
9 | const BusyButton(
10 | {@required this.title, this.busy = false, @required this.onPressed, this.enabled = true});
11 |
12 | @override
13 | _BusyButtonState createState() => _BusyButtonState();
14 | }
15 |
16 | class _BusyButtonState extends State {
17 | @override
18 | Widget build(BuildContext context) {
19 | return GestureDetector(
20 | onTap: widget.onPressed,
21 | child: InkWell(
22 | child: Card(
23 | elevation: 10,
24 | child: AnimatedContainer(
25 | height: widget.busy ? 60 : 60,
26 | width: widget.busy ? 60 : 300,
27 | duration: const Duration(milliseconds: 300),
28 | alignment: Alignment.center,
29 | padding: EdgeInsets.symmetric(
30 | horizontal: widget.busy ? 10 : 15, vertical: widget.busy ? 10 : 10),
31 | decoration: BoxDecoration(
32 | color: widget.enabled ? Colors.purple : Colors.grey[300],
33 | borderRadius: BorderRadius.circular(5),
34 | ),
35 | child: !widget.busy
36 | ? Text(
37 | widget.title,
38 | style: TextStyle(color: Colors.white),
39 | )
40 | : CircularProgressIndicator(
41 | strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.black)),
42 | ),
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/ui/widgets/ChatBubble.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:bubble/bubble.dart';
3 |
4 | class ChatBubble extends StatelessWidget {
5 | const ChatBubble({
6 | Key key,
7 | @required this.isSent,
8 | @required this.message,
9 | }) : super(key: key);
10 |
11 | final bool isSent;
12 | final String message;
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Bubble(
17 | margin: isSent
18 | ? BubbleEdges.only(top: 10, right: 20)
19 | : BubbleEdges.only(top: 10, left: 20),
20 | padding: BubbleEdges.all(15),
21 | elevation: 5,
22 | nipRadius: 5,
23 | nipWidth: 30,
24 | nipHeight: 10,
25 | alignment: isSent ? Alignment.topRight : Alignment.topLeft,
26 | nip: isSent ? BubbleNip.rightBottom : BubbleNip.leftTop,
27 | color: isSent ? Colors.blue : Colors.grey[200],
28 | child: Text(
29 | message,
30 | style: TextStyle(color: isSent ? Colors.white : Colors.black),
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/ui/widgets/DrawerWidget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/ui/views/dashboard/dashboard_viewmodel.dart';
3 |
4 | class DrawerWidget extends StatelessWidget {
5 | final DashboardViewModel model;
6 | DrawerWidget(this.model);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | // final auth = Provider.of(context);
11 | return Drawer(
12 | child: Column(
13 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
14 | crossAxisAlignment: CrossAxisAlignment.stretch,
15 | children: [
16 | Container(
17 | decoration: BoxDecoration(
18 | gradient: LinearGradient(
19 | begin: Alignment.topLeft,
20 | end: Alignment.bottomRight,
21 | stops: [0.3, 1],
22 | colors: [Colors.green, Colors.blue])),
23 | height: 200,
24 | child: Center(
25 | child: Text(
26 | '${model.user.name}',
27 | style: TextStyle(
28 | color: Colors.white,
29 | fontSize: 25,
30 | ),
31 | )),
32 | ),
33 | Expanded(
34 | child: ListView(
35 | children: [
36 | ListTile(
37 | leading: Icon(Icons.people),
38 | title: Text('Friends'),
39 | ),
40 | ListTile(
41 | leading: Icon(Icons.settings),
42 | title: Text('Settings'),
43 | ),
44 | ],
45 | ),
46 | ),
47 |
48 | // ListTile(leading: Icon(Icons.people),title: Text('Friends'),),
49 |
50 | FlatButton(
51 | color: Colors.red,
52 | textColor: Colors.white,
53 | child: Text('Logout'),
54 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
55 | onPressed: () => model.signOut(),
56 | )
57 | ],
58 | ),
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/ui/widgets/MessagesList.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/models/MessagesModel.dart';
3 | import './ChatBubble.dart';
4 |
5 | class MessagesList extends StatelessWidget {
6 | const MessagesList({
7 | Key key,
8 | @required this.messages,
9 | @required this.friendId,
10 | }) : super(key: key);
11 |
12 | final List messages;
13 | final String friendId;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Expanded(
18 | child: ListView.builder(
19 | reverse: true,
20 | itemCount: messages.length,
21 | itemBuilder: (ctx, idx) {
22 | bool isSent = messages[idx].senderId != friendId;
23 | return ChatBubble(
24 | isSent: isSent,
25 | message: messages[idx].messageBody,
26 | );
27 | },
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/ui/widgets/UsersList.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_chat_app/models/UserModel.dart';
3 | import 'package:flutter_chat_app/ui/widgets/UsersListViewModel.dart';
4 | import 'package:stacked/stacked.dart';
5 |
6 | class UsersList extends StatelessWidget {
7 | const UsersList({
8 | Key key,
9 | @required this.users,
10 | }) : super(key: key);
11 |
12 | final List users;
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return ViewModelBuilder.nonReactive(
17 | builder: (context, model, child) => Container(
18 | margin: EdgeInsets.only(top: 20),
19 | child: ListView.separated(
20 | separatorBuilder: (_, __) => Divider(
21 | color: Colors.grey[400],
22 | ),
23 | itemCount: users.length,
24 | itemBuilder: (ctx, idx) => Padding(
25 | padding: const EdgeInsets.symmetric(horizontal: 8),
26 | child: ListTile(
27 | leading: CircleAvatar(
28 | child: Text('${users[idx].name[0]}'),
29 | ),
30 | trailing: IconButton(
31 | icon: Icon(
32 | Icons.arrow_forward_ios,
33 | size: 15,
34 | ),
35 | onPressed: () => model.navigateToChatScreen(users[idx]),
36 | ),
37 | title: Text('${users[idx].name}'),
38 | subtitle: Text('${users[idx].email}'),
39 | onTap: () => model.navigateToChatScreen(users[idx]),
40 | ),
41 | ),
42 | ),
43 | ),
44 | viewModelBuilder: () => UsersListViewModel(),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/ui/widgets/UsersListViewModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_chat_app/app/locator.dart';
2 | import 'package:flutter_chat_app/app/router.gr.dart';
3 | import 'package:flutter_chat_app/models/UserModel.dart';
4 | import 'package:stacked/stacked.dart';
5 | import 'package:stacked_services/stacked_services.dart';
6 |
7 | class UsersListViewModel extends BaseViewModel {
8 | NavigationService _navigationService = locator();
9 |
10 | void navigateToChatScreen(UserModel friend) {
11 | _navigationService.navigateTo(
12 | Routes.chatViewRoute,
13 | arguments: ChatViewArguments(friend: friend),
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "4.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "0.39.10"
18 | archive:
19 | dependency: transitive
20 | description:
21 | name: archive
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.0.13"
25 | args:
26 | dependency: transitive
27 | description:
28 | name: args
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.6.0"
32 | asn1lib:
33 | dependency: transitive
34 | description:
35 | name: asn1lib
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "0.6.5"
39 | async:
40 | dependency: transitive
41 | description:
42 | name: async
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "2.4.1"
46 | auto_route:
47 | dependency: "direct main"
48 | description:
49 | name: auto_route
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "0.5.0"
53 | auto_route_generator:
54 | dependency: "direct dev"
55 | description:
56 | name: auto_route_generator
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.5.0"
60 | basic_utils:
61 | dependency: "direct main"
62 | description:
63 | name: basic_utils
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "2.5.5"
67 | boolean_selector:
68 | dependency: transitive
69 | description:
70 | name: boolean_selector
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "2.0.0"
74 | bubble:
75 | dependency: "direct main"
76 | description:
77 | name: bubble
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.1.9+1"
81 | build:
82 | dependency: transitive
83 | description:
84 | name: build
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "1.3.0"
88 | build_config:
89 | dependency: transitive
90 | description:
91 | name: build_config
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "0.4.2"
95 | build_daemon:
96 | dependency: transitive
97 | description:
98 | name: build_daemon
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "2.1.4"
102 | build_resolvers:
103 | dependency: transitive
104 | description:
105 | name: build_resolvers
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "1.3.9"
109 | build_runner:
110 | dependency: "direct dev"
111 | description:
112 | name: build_runner
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "1.10.0"
116 | build_runner_core:
117 | dependency: transitive
118 | description:
119 | name: build_runner_core
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "5.2.0"
123 | built_collection:
124 | dependency: transitive
125 | description:
126 | name: built_collection
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "4.3.2"
130 | built_value:
131 | dependency: transitive
132 | description:
133 | name: built_value
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "7.1.0"
137 | charcode:
138 | dependency: transitive
139 | description:
140 | name: charcode
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "1.1.3"
144 | checked_yaml:
145 | dependency: transitive
146 | description:
147 | name: checked_yaml
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "1.0.2"
151 | cloud_firestore:
152 | dependency: "direct main"
153 | description:
154 | name: cloud_firestore
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "0.13.5"
158 | cloud_firestore_platform_interface:
159 | dependency: transitive
160 | description:
161 | name: cloud_firestore_platform_interface
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "1.1.0"
165 | cloud_firestore_web:
166 | dependency: transitive
167 | description:
168 | name: cloud_firestore_web
169 | url: "https://pub.dartlang.org"
170 | source: hosted
171 | version: "0.1.1+2"
172 | code_builder:
173 | dependency: transitive
174 | description:
175 | name: code_builder
176 | url: "https://pub.dartlang.org"
177 | source: hosted
178 | version: "3.3.0"
179 | collection:
180 | dependency: transitive
181 | description:
182 | name: collection
183 | url: "https://pub.dartlang.org"
184 | source: hosted
185 | version: "1.14.12"
186 | convert:
187 | dependency: transitive
188 | description:
189 | name: convert
190 | url: "https://pub.dartlang.org"
191 | source: hosted
192 | version: "2.1.1"
193 | crypto:
194 | dependency: transitive
195 | description:
196 | name: crypto
197 | url: "https://pub.dartlang.org"
198 | source: hosted
199 | version: "2.1.4"
200 | csslib:
201 | dependency: transitive
202 | description:
203 | name: csslib
204 | url: "https://pub.dartlang.org"
205 | source: hosted
206 | version: "0.16.1"
207 | cupertino_icons:
208 | dependency: "direct main"
209 | description:
210 | name: cupertino_icons
211 | url: "https://pub.dartlang.org"
212 | source: hosted
213 | version: "0.1.3"
214 | dart_style:
215 | dependency: transitive
216 | description:
217 | name: dart_style
218 | url: "https://pub.dartlang.org"
219 | source: hosted
220 | version: "1.3.6"
221 | emoji_picker:
222 | dependency: "direct main"
223 | description:
224 | name: emoji_picker
225 | url: "https://pub.dartlang.org"
226 | source: hosted
227 | version: "0.1.0"
228 | file:
229 | dependency: transitive
230 | description:
231 | name: file
232 | url: "https://pub.dartlang.org"
233 | source: hosted
234 | version: "5.2.1"
235 | firebase:
236 | dependency: transitive
237 | description:
238 | name: firebase
239 | url: "https://pub.dartlang.org"
240 | source: hosted
241 | version: "7.3.0"
242 | firebase_auth:
243 | dependency: "direct main"
244 | description:
245 | name: firebase_auth
246 | url: "https://pub.dartlang.org"
247 | source: hosted
248 | version: "0.15.5+3"
249 | firebase_auth_platform_interface:
250 | dependency: transitive
251 | description:
252 | name: firebase_auth_platform_interface
253 | url: "https://pub.dartlang.org"
254 | source: hosted
255 | version: "1.1.7"
256 | firebase_auth_web:
257 | dependency: transitive
258 | description:
259 | name: firebase_auth_web
260 | url: "https://pub.dartlang.org"
261 | source: hosted
262 | version: "0.1.2"
263 | firebase_core:
264 | dependency: "direct main"
265 | description:
266 | name: firebase_core
267 | url: "https://pub.dartlang.org"
268 | source: hosted
269 | version: "0.4.4+3"
270 | firebase_core_platform_interface:
271 | dependency: transitive
272 | description:
273 | name: firebase_core_platform_interface
274 | url: "https://pub.dartlang.org"
275 | source: hosted
276 | version: "1.0.4"
277 | firebase_core_web:
278 | dependency: transitive
279 | description:
280 | name: firebase_core_web
281 | url: "https://pub.dartlang.org"
282 | source: hosted
283 | version: "0.1.1+2"
284 | firebase_messaging:
285 | dependency: "direct main"
286 | description:
287 | name: firebase_messaging
288 | url: "https://pub.dartlang.org"
289 | source: hosted
290 | version: "6.0.16"
291 | fixnum:
292 | dependency: transitive
293 | description:
294 | name: fixnum
295 | url: "https://pub.dartlang.org"
296 | source: hosted
297 | version: "0.10.11"
298 | flutter:
299 | dependency: "direct main"
300 | description: flutter
301 | source: sdk
302 | version: "0.0.0"
303 | flutter_test:
304 | dependency: "direct dev"
305 | description: flutter
306 | source: sdk
307 | version: "0.0.0"
308 | flutter_web_plugins:
309 | dependency: transitive
310 | description: flutter
311 | source: sdk
312 | version: "0.0.0"
313 | get:
314 | dependency: transitive
315 | description:
316 | name: get
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "2.13.0"
320 | get_it:
321 | dependency: "direct main"
322 | description:
323 | name: get_it
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "4.0.2"
327 | glob:
328 | dependency: transitive
329 | description:
330 | name: glob
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "1.2.0"
334 | graphs:
335 | dependency: transitive
336 | description:
337 | name: graphs
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "0.2.0"
341 | html:
342 | dependency: transitive
343 | description:
344 | name: html
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "0.14.0+3"
348 | http:
349 | dependency: transitive
350 | description:
351 | name: http
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "0.12.1"
355 | http_multi_server:
356 | dependency: transitive
357 | description:
358 | name: http_multi_server
359 | url: "https://pub.dartlang.org"
360 | source: hosted
361 | version: "2.2.0"
362 | http_parser:
363 | dependency: transitive
364 | description:
365 | name: http_parser
366 | url: "https://pub.dartlang.org"
367 | source: hosted
368 | version: "3.1.4"
369 | image:
370 | dependency: transitive
371 | description:
372 | name: image
373 | url: "https://pub.dartlang.org"
374 | source: hosted
375 | version: "2.1.12"
376 | injectable:
377 | dependency: "direct main"
378 | description:
379 | name: injectable
380 | url: "https://pub.dartlang.org"
381 | source: hosted
382 | version: "0.4.0+1"
383 | injectable_generator:
384 | dependency: "direct dev"
385 | description:
386 | name: injectable_generator
387 | url: "https://pub.dartlang.org"
388 | source: hosted
389 | version: "0.4.1"
390 | intl:
391 | dependency: transitive
392 | description:
393 | name: intl
394 | url: "https://pub.dartlang.org"
395 | source: hosted
396 | version: "0.16.1"
397 | io:
398 | dependency: transitive
399 | description:
400 | name: io
401 | url: "https://pub.dartlang.org"
402 | source: hosted
403 | version: "0.3.4"
404 | js:
405 | dependency: transitive
406 | description:
407 | name: js
408 | url: "https://pub.dartlang.org"
409 | source: hosted
410 | version: "0.6.1+1"
411 | json_annotation:
412 | dependency: transitive
413 | description:
414 | name: json_annotation
415 | url: "https://pub.dartlang.org"
416 | source: hosted
417 | version: "3.0.1"
418 | logging:
419 | dependency: transitive
420 | description:
421 | name: logging
422 | url: "https://pub.dartlang.org"
423 | source: hosted
424 | version: "0.11.4"
425 | matcher:
426 | dependency: transitive
427 | description:
428 | name: matcher
429 | url: "https://pub.dartlang.org"
430 | source: hosted
431 | version: "0.12.6"
432 | meta:
433 | dependency: transitive
434 | description:
435 | name: meta
436 | url: "https://pub.dartlang.org"
437 | source: hosted
438 | version: "1.1.8"
439 | mime:
440 | dependency: transitive
441 | description:
442 | name: mime
443 | url: "https://pub.dartlang.org"
444 | source: hosted
445 | version: "0.9.6+3"
446 | nested:
447 | dependency: transitive
448 | description:
449 | name: nested
450 | url: "https://pub.dartlang.org"
451 | source: hosted
452 | version: "0.0.4"
453 | node_interop:
454 | dependency: transitive
455 | description:
456 | name: node_interop
457 | url: "https://pub.dartlang.org"
458 | source: hosted
459 | version: "1.1.1"
460 | node_io:
461 | dependency: transitive
462 | description:
463 | name: node_io
464 | url: "https://pub.dartlang.org"
465 | source: hosted
466 | version: "1.1.1"
467 | observable_ish:
468 | dependency: transitive
469 | description:
470 | name: observable_ish
471 | url: "https://pub.dartlang.org"
472 | source: hosted
473 | version: "2.1.4"
474 | package_config:
475 | dependency: transitive
476 | description:
477 | name: package_config
478 | url: "https://pub.dartlang.org"
479 | source: hosted
480 | version: "1.9.3"
481 | path:
482 | dependency: transitive
483 | description:
484 | name: path
485 | url: "https://pub.dartlang.org"
486 | source: hosted
487 | version: "1.6.4"
488 | path_provider_linux:
489 | dependency: transitive
490 | description:
491 | name: path_provider_linux
492 | url: "https://pub.dartlang.org"
493 | source: hosted
494 | version: "0.0.1+2"
495 | path_provider_platform_interface:
496 | dependency: transitive
497 | description:
498 | name: path_provider_platform_interface
499 | url: "https://pub.dartlang.org"
500 | source: hosted
501 | version: "1.0.2"
502 | pedantic:
503 | dependency: transitive
504 | description:
505 | name: pedantic
506 | url: "https://pub.dartlang.org"
507 | source: hosted
508 | version: "1.8.0+1"
509 | petitparser:
510 | dependency: transitive
511 | description:
512 | name: petitparser
513 | url: "https://pub.dartlang.org"
514 | source: hosted
515 | version: "2.4.0"
516 | platform:
517 | dependency: transitive
518 | description:
519 | name: platform
520 | url: "https://pub.dartlang.org"
521 | source: hosted
522 | version: "2.2.1"
523 | plugin_platform_interface:
524 | dependency: transitive
525 | description:
526 | name: plugin_platform_interface
527 | url: "https://pub.dartlang.org"
528 | source: hosted
529 | version: "1.0.2"
530 | pointycastle:
531 | dependency: transitive
532 | description:
533 | name: pointycastle
534 | url: "https://pub.dartlang.org"
535 | source: hosted
536 | version: "1.0.2"
537 | pool:
538 | dependency: transitive
539 | description:
540 | name: pool
541 | url: "https://pub.dartlang.org"
542 | source: hosted
543 | version: "1.4.0"
544 | process:
545 | dependency: transitive
546 | description:
547 | name: process
548 | url: "https://pub.dartlang.org"
549 | source: hosted
550 | version: "3.0.13"
551 | provider:
552 | dependency: transitive
553 | description:
554 | name: provider
555 | url: "https://pub.dartlang.org"
556 | source: hosted
557 | version: "4.0.5+1"
558 | pub_semver:
559 | dependency: transitive
560 | description:
561 | name: pub_semver
562 | url: "https://pub.dartlang.org"
563 | source: hosted
564 | version: "1.4.4"
565 | pubspec_parse:
566 | dependency: transitive
567 | description:
568 | name: pubspec_parse
569 | url: "https://pub.dartlang.org"
570 | source: hosted
571 | version: "0.1.5"
572 | quiver:
573 | dependency: transitive
574 | description:
575 | name: quiver
576 | url: "https://pub.dartlang.org"
577 | source: hosted
578 | version: "2.1.3"
579 | shared_preferences:
580 | dependency: transitive
581 | description:
582 | name: shared_preferences
583 | url: "https://pub.dartlang.org"
584 | source: hosted
585 | version: "0.5.8"
586 | shared_preferences_linux:
587 | dependency: transitive
588 | description:
589 | name: shared_preferences_linux
590 | url: "https://pub.dartlang.org"
591 | source: hosted
592 | version: "0.0.2+1"
593 | shared_preferences_macos:
594 | dependency: transitive
595 | description:
596 | name: shared_preferences_macos
597 | url: "https://pub.dartlang.org"
598 | source: hosted
599 | version: "0.0.1+10"
600 | shared_preferences_platform_interface:
601 | dependency: transitive
602 | description:
603 | name: shared_preferences_platform_interface
604 | url: "https://pub.dartlang.org"
605 | source: hosted
606 | version: "1.0.4"
607 | shared_preferences_web:
608 | dependency: transitive
609 | description:
610 | name: shared_preferences_web
611 | url: "https://pub.dartlang.org"
612 | source: hosted
613 | version: "0.1.2+7"
614 | shelf:
615 | dependency: transitive
616 | description:
617 | name: shelf
618 | url: "https://pub.dartlang.org"
619 | source: hosted
620 | version: "0.7.5"
621 | shelf_web_socket:
622 | dependency: transitive
623 | description:
624 | name: shelf_web_socket
625 | url: "https://pub.dartlang.org"
626 | source: hosted
627 | version: "0.2.3"
628 | sky_engine:
629 | dependency: transitive
630 | description: flutter
631 | source: sdk
632 | version: "0.0.99"
633 | source_gen:
634 | dependency: transitive
635 | description:
636 | name: source_gen
637 | url: "https://pub.dartlang.org"
638 | source: hosted
639 | version: "0.9.5"
640 | source_span:
641 | dependency: transitive
642 | description:
643 | name: source_span
644 | url: "https://pub.dartlang.org"
645 | source: hosted
646 | version: "1.7.0"
647 | stack_trace:
648 | dependency: transitive
649 | description:
650 | name: stack_trace
651 | url: "https://pub.dartlang.org"
652 | source: hosted
653 | version: "1.9.3"
654 | stacked:
655 | dependency: "direct main"
656 | description:
657 | name: stacked
658 | url: "https://pub.dartlang.org"
659 | source: hosted
660 | version: "1.6.0"
661 | stacked_services:
662 | dependency: "direct main"
663 | description:
664 | name: stacked_services
665 | url: "https://pub.dartlang.org"
666 | source: hosted
667 | version: "0.4.1"
668 | stream_channel:
669 | dependency: transitive
670 | description:
671 | name: stream_channel
672 | url: "https://pub.dartlang.org"
673 | source: hosted
674 | version: "2.0.0"
675 | stream_transform:
676 | dependency: transitive
677 | description:
678 | name: stream_transform
679 | url: "https://pub.dartlang.org"
680 | source: hosted
681 | version: "1.2.0"
682 | string_scanner:
683 | dependency: transitive
684 | description:
685 | name: string_scanner
686 | url: "https://pub.dartlang.org"
687 | source: hosted
688 | version: "1.0.5"
689 | term_glyph:
690 | dependency: transitive
691 | description:
692 | name: term_glyph
693 | url: "https://pub.dartlang.org"
694 | source: hosted
695 | version: "1.1.0"
696 | test_api:
697 | dependency: transitive
698 | description:
699 | name: test_api
700 | url: "https://pub.dartlang.org"
701 | source: hosted
702 | version: "0.2.15"
703 | timing:
704 | dependency: transitive
705 | description:
706 | name: timing
707 | url: "https://pub.dartlang.org"
708 | source: hosted
709 | version: "0.1.1+2"
710 | typed_data:
711 | dependency: transitive
712 | description:
713 | name: typed_data
714 | url: "https://pub.dartlang.org"
715 | source: hosted
716 | version: "1.1.6"
717 | vector_math:
718 | dependency: transitive
719 | description:
720 | name: vector_math
721 | url: "https://pub.dartlang.org"
722 | source: hosted
723 | version: "2.0.8"
724 | watcher:
725 | dependency: transitive
726 | description:
727 | name: watcher
728 | url: "https://pub.dartlang.org"
729 | source: hosted
730 | version: "0.9.7+15"
731 | web_socket_channel:
732 | dependency: transitive
733 | description:
734 | name: web_socket_channel
735 | url: "https://pub.dartlang.org"
736 | source: hosted
737 | version: "1.1.0"
738 | xdg_directories:
739 | dependency: transitive
740 | description:
741 | name: xdg_directories
742 | url: "https://pub.dartlang.org"
743 | source: hosted
744 | version: "0.1.0"
745 | xml:
746 | dependency: transitive
747 | description:
748 | name: xml
749 | url: "https://pub.dartlang.org"
750 | source: hosted
751 | version: "3.6.1"
752 | yaml:
753 | dependency: transitive
754 | description:
755 | name: yaml
756 | url: "https://pub.dartlang.org"
757 | source: hosted
758 | version: "2.2.1"
759 | sdks:
760 | dart: ">=2.7.0 <3.0.0"
761 | flutter: ">=1.12.13+hotfix.5 <2.0.0"
762 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_chat_app
2 | description: A new Flutter project.
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 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.2.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 | #firebase
23 | firebase_core: ^0.4.4+3
24 | firebase_auth: ^0.15.5+3
25 | cloud_firestore: ^0.13.4+2
26 | firebase_messaging: ^6.0.16
27 | #ui
28 | bubble: ^1.1.9+1
29 | emoji_picker: ^0.1.0
30 | #utils
31 | basic_utils: ^2.5.5
32 |
33 | # state management
34 | stacked: ^1.5.7+1
35 | stacked_services:
36 | auto_route:
37 | get_it:
38 | injectable:
39 |
40 | # The following adds the Cupertino Icons font to your application.
41 | # Use with the CupertinoIcons class for iOS style icons.
42 | cupertino_icons: ^0.1.2
43 |
44 | dev_dependencies:
45 | flutter_test:
46 | sdk: flutter
47 | build_runner:
48 | auto_route_generator:
49 | injectable_generator:
50 |
51 | # For information on the generic Dart part of this file, see the
52 | # following page: https://dart.dev/tools/pub/pubspec
53 |
54 | # The following section is specific to Flutter.
55 | flutter:
56 | # The following line ensures that the Material Icons font is
57 | # included with your application, so that you can use the icons in
58 | # the material Icons class.
59 | uses-material-design: true
60 | # To add assets to your application, add an assets section, like this:
61 | assets:
62 | - assets/images/
63 | # An image asset can refer to one or more resolution-specific "variants", see
64 | # https://flutter.dev/assets-and-images/#resolution-aware.
65 | # For details regarding adding assets from package dependencies, see
66 | # https://flutter.dev/assets-and-images/#from-packages
67 | # To add custom fonts to your application, add a fonts section here,
68 | # in this "flutter" section. Each entry in this list should have a
69 | # "family" key with the font family name, and a "fonts" key with a
70 | # list giving the asset and other descriptors for the font. For
71 | # example:
72 | # fonts:
73 | # - family: Schyler
74 | # fonts:
75 | # - asset: fonts/Schyler-Regular.ttf
76 | # - asset: fonts/Schyler-Italic.ttf
77 | # style: italic
78 | # - family: Trajan Pro
79 | # fonts:
80 | # - asset: fonts/TrajanPro.ttf
81 | # - asset: fonts/TrajanPro_Bold.ttf
82 | # weight: 700
83 | #
84 | # For details regarding fonts from package dependencies,
85 | # see https://flutter.dev/custom-fonts/#from-packages
86 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:flutter_chat_app/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------