diff --git a/.gitignore b/.gitignore index 1ba9c33..9d0760c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,5 +39,10 @@ app.*.symbols # Obfuscation related app.*.map.json +# Firebase config files +android/app/google-services.json +firebase.json +lib/firebase_options.dart + # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata index 3223172..ce66da9 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: dadc3ead47e75319c8ed6b6f15899ad56725c68a - channel: master + revision: "4cf269e36de2573851eaef3c763994f8f9be494d" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + - platform: android + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore index bc2100d..55afd91 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -5,3 +5,9 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle index 6d2adbd..7f2dffb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,67 +1,47 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' +plugins { + id "com.android.application" + // START: FlutterFire Configuration + id 'com.google.gms.google-services' + // END: FlutterFire Configuration + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" } -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'com.google.gms.google-services' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 28 + namespace = "com.example.flutter_chat_app_tutorial" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } - lintOptions { - disable 'InvalidPackage' + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.chatapp" - minSdkVersion 19 - multiDexEnabled true - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + applicationId = "com.example.flutter_chat_app_tutorial" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = 23 + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' -} - -dependencies { - implementation "com.android.support:multidex:1.0.3" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'com.google.firebase:firebase-analytics:17.2.2' + source = "../.." } diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 05e2050..399f698 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9e348bd..446d4b6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,17 +1,13 @@ - - + - - @@ -44,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/chatapp/MainActivity.kt b/android/app/src/main/kotlin/com/example/chatapp/MainActivity.kt deleted file mode 100644 index 37930f0..0000000 --- a/android/app/src/main/kotlin/com/example/chatapp/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.chatapp - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/android/app/src/main/kotlin/com/example/flutter_chat_app_tutorial/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutter_chat_app_tutorial/MainActivity.kt new file mode 100644 index 0000000..6a30a8f --- /dev/null +++ b/android/app/src/main/kotlin/com/example/flutter_chat_app_tutorial/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.flutter_chat_app_tutorial + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 1f83a33..cb1ef88 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 05e2050..399f698 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/android/build.gradle b/android/build.gradle index b5e8417..d2ffbff 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,32 +1,18 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath 'com.google.gms:google-services:4.3.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d45..2597170 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 296b146..7bb2df6 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 5a2f14f..9759a22 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,15 +1,28 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.1.0" apply false + // START: FlutterFire Configuration + id "com.google.gms.google-services" version "4.3.15" apply false + // END: FlutterFire Configuration + id "org.jetbrains.kotlin.android" version "1.8.22" apply false } + +include ":app" diff --git a/lib/helper/helperfunctions.dart b/lib/helper/helperfunctions.dart index f60a8f7..7b89048 100644 --- a/lib/helper/helperfunctions.dart +++ b/lib/helper/helperfunctions.dart @@ -6,7 +6,7 @@ class HelperFunctions{ static String sharedPreferenceUserNameKey = "USERNAMEKEY"; static String sharedPreferenceUserEmailKey = "USEREMAILKEY"; - /// saving data to sharedpreference + /// saving data to shared preference static Future saveUserLoggedInSharedPreference(bool isUserLoggedIn) async{ SharedPreferences preferences = await SharedPreferences.getInstance(); @@ -23,21 +23,26 @@ class HelperFunctions{ return await preferences.setString(sharedPreferenceUserEmailKey, userEmail); } - /// fetching data from sharedpreference + /// fetching data from shared preference static Future getUserLoggedInSharedPreference() async{ SharedPreferences preferences = await SharedPreferences.getInstance(); - return await preferences.getBool(sharedPreferenceUserLoggedInKey); + return await preferences.getBool(sharedPreferenceUserLoggedInKey) ?? false; } static Future getUserNameSharedPreference() async{ SharedPreferences preferences = await SharedPreferences.getInstance(); - return await preferences.getString(sharedPreferenceUserNameKey); + return await preferences.getString(sharedPreferenceUserNameKey) ?? ""; } - static Future getUserEmailSharedPreference() async{ + static Future getUserEmailSharedPreference() async{ SharedPreferences preferences = await SharedPreferences.getInstance(); return await preferences.getString(sharedPreferenceUserEmailKey); } + static Future signOut() async{ + SharedPreferences preferences = await SharedPreferences.getInstance(); + return await preferences.clear(); + } + } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 12b87cb..6fa3fb2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,33 +1,37 @@ import 'package:chatapp/helper/authenticate.dart'; import 'package:chatapp/helper/helperfunctions.dart'; import 'package:chatapp/views/chatrooms.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'firebase_options.dart'; -void main() { + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); runApp(MyApp()); } class MyApp extends StatefulWidget { - // This widget is the root of your application. @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { - - bool userIsLoggedIn; + bool? userIsLoggedIn; @override void initState() { - getLoggedInState(); super.initState(); + getLoggedInState(); } - getLoggedInState() async { - await HelperFunctions.getUserLoggedInSharedPreference().then((value){ - setState(() { - userIsLoggedIn = value; - }); + Future getLoggedInState() async { + bool? value = await HelperFunctions.getUserLoggedInSharedPreference(); + setState(() { + userIsLoggedIn = value; }); } @@ -37,18 +41,21 @@ class _MyAppState extends State { title: 'FlutterChat', debugShowCheckedModeBanner: false, theme: ThemeData( - primaryColor: Color(0xff145C9E), - scaffoldBackgroundColor: Color(0xff1F1F1F), - accentColor: Color(0xff007EF4), + primaryColor: const Color(0xff145C9E), + scaffoldBackgroundColor: const Color(0xff1F1F1F), + colorScheme: ColorScheme.light( + primary: const Color(0xff145C9E), + secondary: const Color(0xff007EF4), + ), fontFamily: "OverpassRegular", visualDensity: VisualDensity.adaptivePlatformDensity, ), - home: userIsLoggedIn != null ? userIsLoggedIn ? ChatRoom() : Authenticate() - : Container( - child: Center( - child: Authenticate(), - ), - ), + home: userIsLoggedIn == null + ? const Center(child: CircularProgressIndicator()) + : userIsLoggedIn! + ? ChatRoom() + : Authenticate(), ); } } + diff --git a/lib/models/user.dart b/lib/models/user.dart index c3344ad..3868288 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,4 +1,4 @@ -class User { +class MyUser { final String uid; - User({this.uid}); + MyUser({required this.uid}); } diff --git a/lib/services/auth.dart b/lib/services/auth.dart index dff62b8..8a65d20 100644 --- a/lib/services/auth.dart +++ b/lib/services/auth.dart @@ -1,21 +1,18 @@ import 'package:chatapp/models/user.dart'; -import 'package:chatapp/views/chat.dart'; import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/material.dart'; -import 'package:google_sign_in/google_sign_in.dart'; class AuthService { final FirebaseAuth _auth = FirebaseAuth.instance; - User _userFromFirebaseUser(FirebaseUser user) { - return user != null ? User(uid: user.uid) : null; + MyUser? _userFromFirebaseUser(User? user) { + return user != null ? MyUser(uid: user.uid) : null; } Future signInWithEmailAndPassword(String email, String password) async { try { - AuthResult result = await _auth.signInWithEmailAndPassword( + UserCredential result = await _auth.signInWithEmailAndPassword( email: email, password: password); - FirebaseUser user = result.user; + User? user = result.user; return _userFromFirebaseUser(user); } catch (e) { print(e.toString()); @@ -25,9 +22,9 @@ class AuthService { Future signUpWithEmailAndPassword(String email, String password) async { try { - AuthResult result = await _auth.createUserWithEmailAndPassword( + UserCredential result = await _auth.createUserWithEmailAndPassword( email: email, password: password); - FirebaseUser user = result.user; + User? user = result.user; return _userFromFirebaseUser(user); } catch (e) { print(e.toString()); @@ -44,26 +41,39 @@ class AuthService { } } - Future signInWithGoogle(BuildContext context) async { - final GoogleSignIn _googleSignIn = new GoogleSignIn(); + // + // Future signInWithGoogle(BuildContext context) async { + // try { + // final GoogleSignIn googleSignIn = GoogleSignIn(); + // final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); + // + // if (googleUser == null) return null; // User cancelled sign-in + // + // final GoogleSignInAuthentication googleAuth = + // await googleUser.authentication; + // + // final AuthCredential credential = GoogleAuthProvider.credential( + // idToken: googleAuth.idToken, + // accessToken: googleAuth.accessToken, + // ); + // + // UserCredential result = await _auth.signInWithCredential(credential); + // User? userDetails = result.user; + // + // if (userDetails != null) { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => Chat()), + // ); + // } + // + // return userDetails; + // } catch (e) { + // print('Google Sign-In error: $e'); + // return null; + // } + // } - final GoogleSignInAccount googleSignInAccount = - await _googleSignIn.signIn(); - final GoogleSignInAuthentication googleSignInAuthentication = - await googleSignInAccount.authentication; - - final AuthCredential credential = GoogleAuthProvider.getCredential( - idToken: googleSignInAuthentication.idToken, - accessToken: googleSignInAuthentication.accessToken); - - AuthResult result = await _auth.signInWithCredential(credential); - FirebaseUser userDetails = result.user; - - if (result == null) { - } else { - Navigator.push(context, MaterialPageRoute(builder: (context) => Chat())); - } - } Future signOut() async { try { diff --git a/lib/services/database.dart b/lib/services/database.dart index a694a9a..33f1761 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -1,64 +1,73 @@ import 'package:cloud_firestore/cloud_firestore.dart'; class DatabaseMethods { - Future addUserInfo(userData) async { - Firestore.instance.collection("users").add(userData).catchError((e) { - print(e.toString()); - }); + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + + Future addUserInfo(Map userData) async { + try { + await _firestore.collection("users").add(userData); + } catch (e) { + print("Error adding user info: $e"); + } } - getUserInfo(String email) async { - return Firestore.instance - .collection("users") - .where("userEmail", isEqualTo: email) - .getDocuments() - .catchError((e) { - print(e.toString()); - }); + Future>> getUserInfo(String email) async { + try { + return await _firestore + .collection("users") + .where("userEmail", isEqualTo: email) + .get(); + } catch (e) { + print("Error fetching user info: $e"); + rethrow; + } } - searchByName(String searchField) { - return Firestore.instance - .collection("users") - .where('userName', isEqualTo: searchField) - .getDocuments(); + Future>> searchByName(String searchField) async { + try { + return await _firestore + .collection("users") + .where('userName', isEqualTo: searchField) + .get(); + } catch (e) { + print("Error searching user: $e"); + rethrow; + } } - Future addChatRoom(chatRoom, chatRoomId) { - Firestore.instance - .collection("chatRoom") - .document(chatRoomId) - .setData(chatRoom) - .catchError((e) { - print(e); - }); + Future addChatRoom(Map chatRoom, String chatRoomId) async { + try { + await _firestore.collection("chatRoom").doc(chatRoomId).set(chatRoom); + } catch (e) { + print("Error adding chatroom: $e"); + } } - getChats(String chatRoomId) async{ - return Firestore.instance + Stream>> getChats(String chatRoomId) { + return _firestore .collection("chatRoom") - .document(chatRoomId) + .doc(chatRoomId) .collection("chats") .orderBy('time') .snapshots(); } - - Future addMessage(String chatRoomId, chatMessageData){ - - Firestore.instance.collection("chatRoom") - .document(chatRoomId) - .collection("chats") - .add(chatMessageData).catchError((e){ - print(e.toString()); - }); + Future addMessage(String chatRoomId, Map chatMessageData) async { + try { + await _firestore + .collection("chatRoom") + .doc(chatRoomId) + .collection("chats") + .add(chatMessageData); + } catch (e) { + print("Error sending message: $e"); + } } - getUserChats(String itIsMyName) async { - return await Firestore.instance + Stream>> getUserChats(String userName) { + return _firestore .collection("chatRoom") - .where('users', arrayContains: itIsMyName) + .where('users', arrayContains: userName) .snapshots(); } - } diff --git a/lib/views/chat.dart b/lib/views/chat.dart index a86a99a..57c9847 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -8,29 +8,36 @@ import 'package:flutter/material.dart'; class Chat extends StatefulWidget { final String chatRoomId; - Chat({this.chatRoomId}); + Chat({required this.chatRoomId}); @override _ChatState createState() => _ChatState(); } class _ChatState extends State { - - Stream chats; + Stream? chats; TextEditingController messageEditingController = new TextEditingController(); - Widget chatMessages(){ - return StreamBuilder( + Widget chatMessages() { + return StreamBuilder( stream: chats, - builder: (context, snapshot){ - return snapshot.hasData ? ListView.builder( - itemCount: snapshot.data.documents.length, - itemBuilder: (context, index){ - return MessageTile( - message: snapshot.data.documents[index].data["message"], - sendByMe: Constants.myName == snapshot.data.documents[index].data["sendBy"], - ); - }) : Container(); + builder: (context, snapshot) { + if (!snapshot.hasData) + return const Center(child: CircularProgressIndicator()); + + final docs = snapshot.data!.docs; + + return ListView.builder( + itemCount: docs.length, + itemBuilder: (context, index) { + final data = docs[index].data() as Map; + + return MessageTile( + message: data['message'] ?? '', + sendByMe: Constants.myName == data['sendBy'], + ); + }, + ); }, ); } @@ -40,9 +47,7 @@ class _ChatState extends State { Map chatMessageMap = { "sendBy": Constants.myName, "message": messageEditingController.text, - 'time': DateTime - .now() - .millisecondsSinceEpoch, + 'time': DateTime.now().millisecondsSinceEpoch, }; DatabaseMethods().addMessage(widget.chatRoomId, chatMessageMap); @@ -55,27 +60,21 @@ class _ChatState extends State { @override void initState() { - DatabaseMethods().getChats(widget.chatRoomId).then((val) { - setState(() { - chats = val; - }); - }); super.initState(); + chats = DatabaseMethods().getChats(widget.chatRoomId); } @override Widget build(BuildContext context) { return Scaffold( - appBar: appBarMain(context), + appBar: AppBarMain(), body: Container( child: Stack( children: [ chatMessages(), - Container(alignment: Alignment.bottomCenter, - width: MediaQuery - .of(context) - .size - .width, + Container( + alignment: Alignment.bottomCenter, + width: MediaQuery.of(context).size.width, child: Container( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 24), color: Color(0x54FFFFFF), @@ -83,18 +82,19 @@ class _ChatState extends State { children: [ Expanded( child: TextField( - controller: messageEditingController, - style: simpleTextStyle(), - decoration: InputDecoration( - hintText: "Message ...", - hintStyle: TextStyle( - color: Colors.white, - fontSize: 16, - ), - border: InputBorder.none + controller: messageEditingController, + style: simpleTextStyle(), + decoration: InputDecoration( + hintText: "Message ...", + hintStyle: TextStyle( + color: Colors.white, + fontSize: 16, ), - )), - SizedBox(width: 16,), + border: InputBorder.none), + )), + SizedBox( + width: 16, + ), GestureDetector( onTap: () { addMessage(); @@ -109,13 +109,14 @@ class _ChatState extends State { const Color(0x0FFFFFFF) ], begin: FractionalOffset.topLeft, - end: FractionalOffset.bottomRight - ), - borderRadius: BorderRadius.circular(40) - ), + end: FractionalOffset.bottomRight), + borderRadius: BorderRadius.circular(40)), padding: EdgeInsets.all(12), - child: Image.asset("assets/images/send.png", - height: 25, width: 25,)), + child: Image.asset( + "assets/images/send.png", + height: 25, + width: 25, + )), ), ], ), @@ -126,61 +127,47 @@ class _ChatState extends State { ), ); } - } class MessageTile extends StatelessWidget { final String message; final bool sendByMe; - MessageTile({@required this.message, @required this.sendByMe}); - + MessageTile({required this.message, required this.sendByMe}); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only( - top: 8, - bottom: 8, - left: sendByMe ? 0 : 24, - right: sendByMe ? 24 : 0), + top: 8, bottom: 8, left: sendByMe ? 0 : 24, right: sendByMe ? 24 : 0), alignment: sendByMe ? Alignment.centerRight : Alignment.centerLeft, child: Container( - margin: sendByMe - ? EdgeInsets.only(left: 30) - : EdgeInsets.only(right: 30), - padding: EdgeInsets.only( - top: 17, bottom: 17, left: 20, right: 20), + margin: + sendByMe ? EdgeInsets.only(left: 30) : EdgeInsets.only(right: 30), + padding: EdgeInsets.only(top: 17, bottom: 17, left: 20, right: 20), decoration: BoxDecoration( - borderRadius: sendByMe ? BorderRadius.only( - topLeft: Radius.circular(23), - topRight: Radius.circular(23), - bottomLeft: Radius.circular(23) - ) : - BorderRadius.only( - topLeft: Radius.circular(23), - topRight: Radius.circular(23), - bottomRight: Radius.circular(23)), + borderRadius: sendByMe + ? BorderRadius.only( + topLeft: Radius.circular(23), + topRight: Radius.circular(23), + bottomLeft: Radius.circular(23)) + : BorderRadius.only( + topLeft: Radius.circular(23), + topRight: Radius.circular(23), + bottomRight: Radius.circular(23)), gradient: LinearGradient( - colors: sendByMe ? [ - const Color(0xff007EF4), - const Color(0xff2A75BC) - ] - : [ - const Color(0x1AFFFFFF), - const Color(0x1AFFFFFF) - ], - ) - ), + colors: sendByMe + ? [const Color(0xff007EF4), const Color(0xff2A75BC)] + : [const Color(0x1AFFFFFF), const Color(0x1AFFFFFF)], + )), child: Text(message, textAlign: TextAlign.start, style: TextStyle( - color: Colors.white, - fontSize: 16, - fontFamily: 'OverpassRegular', - fontWeight: FontWeight.w300)), + color: Colors.white, + fontSize: 16, + fontFamily: 'OverpassRegular', + fontWeight: FontWeight.w300)), ), ); } } - diff --git a/lib/views/chatrooms.dart b/lib/views/chatrooms.dart index d96f076..4fe2e95 100644 --- a/lib/views/chatrooms.dart +++ b/lib/views/chatrooms.dart @@ -6,6 +6,7 @@ import 'package:chatapp/services/auth.dart'; import 'package:chatapp/services/database.dart'; import 'package:chatapp/views/chat.dart'; import 'package:chatapp/views/search.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; class ChatRoom extends StatefulWidget { @@ -14,73 +15,95 @@ class ChatRoom extends StatefulWidget { } class _ChatRoomState extends State { - Stream chatRooms; - - Widget chatRoomsList() { - return StreamBuilder( - stream: chatRooms, - builder: (context, snapshot) { - return snapshot.hasData - ? ListView.builder( - itemCount: snapshot.data.documents.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return ChatRoomsTile( - userName: snapshot.data.documents[index].data['chatRoomId'] - .toString() - .replaceAll("_", "") - .replaceAll(Constants.myName, ""), - chatRoomId: snapshot.data.documents[index].data["chatRoomId"], - ); - }) - : Container(); - }, - ); - } + Stream? chatRooms; @override void initState() { - getUserInfogetChats(); super.initState(); + getUserInfogetChats(); } getUserInfogetChats() async { Constants.myName = await HelperFunctions.getUserNameSharedPreference(); - DatabaseMethods().getUserChats(Constants.myName).then((snapshots) { - setState(() { - chatRooms = snapshots; - print( - "we got the data + ${chatRooms.toString()} this is name ${Constants.myName}"); - }); + debugPrint("The username is ${Constants.myName}"); + + Stream chats = + await DatabaseMethods().getUserChats(Constants.myName); + + setState(() { + chatRooms = chats; }); } + Widget chatRoomsList() { + if (chatRooms == null) { + return Center(child: CircularProgressIndicator()); + } + + return StreamBuilder( + stream: chatRooms, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center(child: CircularProgressIndicator()); + } + + if (!snapshot.hasData || snapshot.data!.docs.isEmpty) { + return Center(child: Text("No chats yet.")); + } + + final docs = snapshot.data!.docs; + + return ListView.builder( + itemCount: docs.length, + shrinkWrap: true, + itemBuilder: (context, index) { + String chatRoomId = docs[index]['chatRoomId']; + String userName = chatRoomId + .replaceAll("_", "") + .replaceAll(Constants.myName, "") + .trim(); + if (userName.isEmpty) { + return SizedBox.shrink(); + } + return ChatRoomsTile( + userName: userName, + chatRoomId: chatRoomId, + ); + }, + ); + }, + ); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Image.asset( - "assets/images/logo.png", - height: 40, - ), + backgroundColor: Theme.of(context).primaryColor, + title: Image.asset("assets/images/logo.png", height: 40), elevation: 0.0, centerTitle: false, actions: [ GestureDetector( onTap: () { + //clear stored shared preferences + HelperFunctions.signOut(); + + //sign out from firebase AuthService().signOut(); - Navigator.pushReplacement(context, - MaterialPageRoute(builder: (context) => Authenticate())); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => Authenticate()), + ); }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 16), - child: Icon(Icons.exit_to_app)), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Icon(Icons.exit_to_app), + ), ) ], ), - body: Container( - child: chatRoomsList(), - ), + body: chatRoomsList(), floatingActionButton: FloatingActionButton( child: Icon(Icons.search), onPressed: () { @@ -92,11 +115,12 @@ class _ChatRoomState extends State { } } + class ChatRoomsTile extends StatelessWidget { final String userName; final String chatRoomId; - ChatRoomsTile({this.userName,@required this.chatRoomId}); + ChatRoomsTile({required this.userName,required this.chatRoomId}); @override Widget build(BuildContext context) { diff --git a/lib/views/search.dart b/lib/views/search.dart index bfcc6ee..01d3036 100644 --- a/lib/views/search.dart +++ b/lib/views/search.dart @@ -15,7 +15,7 @@ class _SearchState extends State { DatabaseMethods databaseMethods = new DatabaseMethods(); TextEditingController searchEditingController = new TextEditingController(); - QuerySnapshot searchResultSnapshot; + QuerySnapshot>? searchResultSnapshot; bool isLoading = false; bool haveUserSearched = false; @@ -37,18 +37,24 @@ class _SearchState extends State { } } - Widget userList(){ - return haveUserSearched ? ListView.builder( + Widget userList() { + return haveUserSearched + ? ListView.builder( shrinkWrap: true, - itemCount: searchResultSnapshot.documents.length, - itemBuilder: (context, index){ - return userTile( - searchResultSnapshot.documents[index].data["userName"], - searchResultSnapshot.documents[index].data["userEmail"], - ); - }) : Container(); + itemCount: searchResultSnapshot?.docs.length ?? 0, + itemBuilder: (context, index) { + final name = searchResultSnapshot!.docs[index]['userName']; + final email = searchResultSnapshot!.docs[index]['userEmail']; + + if (name == Constants.myName) return SizedBox.shrink(); // hide self + + return userTile(name, email); + }, + ) + : Container(); } + /// 1.create a chatroom, send user to the chatroom, other userdetails sendMessage(String userName){ List users = [Constants.myName,userName]; @@ -136,7 +142,7 @@ class _SearchState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: appBarMain(context), + appBar: AppBarMain(), body: isLoading ? Container( child: Center( child: CircularProgressIndicator(), diff --git a/lib/views/signin.dart b/lib/views/signin.dart index 3ed58ee..b0a6273 100644 --- a/lib/views/signin.dart +++ b/lib/views/signin.dart @@ -28,7 +28,7 @@ class _SignInState extends State { bool isLoading = false; signIn() async { - if (formKey.currentState.validate()) { + if (formKey.currentState?.validate() ?? false) { setState(() { isLoading = true; }); @@ -37,15 +37,17 @@ class _SignInState extends State { .signInWithEmailAndPassword( emailEditingController.text, passwordEditingController.text) .then((result) async { + print("sign in result: $result"); if (result != null) { - QuerySnapshot userInfoSnapshot = - await DatabaseMethods().getUserInfo(emailEditingController.text); + QuerySnapshot> userInfoSnapshot = + await DatabaseMethods().getUserInfo(emailEditingController.text); HelperFunctions.saveUserLoggedInSharedPreference(true); HelperFunctions.saveUserNameSharedPreference( - userInfoSnapshot.documents[0].data["userName"]); + userInfoSnapshot.docs[0]['userName']); + HelperFunctions.saveUserEmailSharedPreference( - userInfoSnapshot.documents[0].data["userEmail"]); + userInfoSnapshot.docs[0]['userEmail']); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => ChatRoom())); @@ -62,7 +64,7 @@ class _SignInState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: appBarMain(context), + appBar: AppBarMain(), body: isLoading ? Container( child: Center(child: CircularProgressIndicator()), @@ -78,11 +80,12 @@ class _SignInState extends State { children: [ TextFormField( validator: (val) { - return RegExp( - r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(val) + if (val == null || val.isEmpty) { + return "Email can't be empty"; + } + return RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(val) ? null - : "Please Enter Correct Email"; + : "Please enter a valid email"; }, controller: emailEditingController, style: simpleTextStyle(), @@ -90,11 +93,12 @@ class _SignInState extends State { ), TextFormField( obscureText: true, - validator: (val) { - return val.length > 6 - ? null - : "Enter Password 6+ characters"; - }, + validator: (val) { + if (val == null || val.isEmpty) { + return "Password can't be empty"; + } + return val.length > 6 ? null : "Enter password 6+ characters"; + }, style: simpleTextStyle(), controller: passwordEditingController, decoration: textFieldInputDecoration("password"), diff --git a/lib/views/signup.dart b/lib/views/signup.dart index 982b150..a618fe7 100644 --- a/lib/views/signup.dart +++ b/lib/views/signup.dart @@ -26,9 +26,9 @@ class _SignUpState extends State { final formKey = GlobalKey(); bool isLoading = false; - singUp() async { + signUp() async { - if(formKey.currentState.validate()){ + if(formKey.currentState?.validate() ?? false){ setState(() { isLoading = true; @@ -60,7 +60,7 @@ class _SignUpState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: appBarMain(context), + appBar: AppBarMain(), body: isLoading ? Container(child: Center(child: CircularProgressIndicator(),),) : Container( padding: EdgeInsets.symmetric(horizontal: 24), child: Column( @@ -73,17 +73,22 @@ class _SignUpState extends State { TextFormField( style: simpleTextStyle(), controller: usernameEditingController, - validator: (val){ - return val.isEmpty || val.length < 3 ? "Enter Username 3+ characters" : null; + validator: (val) { + return (val == null || val.isEmpty || val.length < 3) + ? "Enter Username 3+ characters" + : null; }, decoration: textFieldInputDecoration("username"), ), TextFormField( controller: emailEditingController, style: simpleTextStyle(), - validator: (val){ - return RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(val) ? - null : "Enter correct email"; + validator: (val) { + return (val == null || !RegExp( + r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") + .hasMatch(val)) + ? "Enter correct email" + : null; }, decoration: textFieldInputDecoration("email"), ), @@ -92,10 +97,11 @@ class _SignUpState extends State { style: simpleTextStyle(), decoration: textFieldInputDecoration("password"), controller: passwordEditingController, - validator: (val){ - return val.length < 6 ? "Enter Password 6+ characters" : null; + validator: (val) { + return (val == null || val.length < 6) + ? "Enter Password 6+ characters" + : null; }, - ), ], ), @@ -105,7 +111,7 @@ class _SignUpState extends State { ), GestureDetector( onTap: (){ - singUp(); + signUp(); }, child: Container( padding: EdgeInsets.symmetric(vertical: 16), @@ -167,6 +173,5 @@ class _SignUpState extends State { ), ), ); - ; } } diff --git a/lib/widget/widget.dart b/lib/widget/widget.dart index 6a46000..b73c742 100644 --- a/lib/widget/widget.dart +++ b/lib/widget/widget.dart @@ -1,14 +1,23 @@ import 'package:flutter/material.dart'; -Widget appBarMain(BuildContext context) { - return AppBar( - title: Image.asset( - "assets/images/logo.png", - height: 40, - ), - elevation: 0.0, - centerTitle: false, - ); +class AppBarMain extends StatelessWidget implements PreferredSizeWidget { + const AppBarMain({Key? key}) : super(key: key); + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: Theme.of(context).primaryColor, + title: Image.asset( + "assets/images/logo.png", + height: 40, + ), + elevation: 0.0, + centerTitle: false, + ); + } } InputDecoration textFieldInputDecoration(String hintText) { diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 5dfcd5e..ee4892f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,11 +6,15 @@ import FlutterMacOS import Foundation import cloud_firestore +import firebase_auth import firebase_core -import shared_preferences_macos +import google_sign_in_ios +import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FLTCloudFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTCloudFirestorePlugin")) + FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) + FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 13e6d6e..888c210 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,139 +1,158 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: + _flutterfire_internals: dependency: transitive description: - name: archive - url: "https://pub.dartlang.org" + name: _flutterfire_internals + sha256: de9ecbb3ddafd446095f7e833c853aff2fa1682b017921fe63a833f9d6f0e422 + url: "https://pub.dev" source: hosted - version: "2.0.13" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" + version: "1.3.54" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.0.0" - charcode: + version: "2.1.1" + characters: dependency: transitive description: - name: charcode - url: "https://pub.dartlang.org" + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" cloud_firestore: dependency: "direct main" description: name: cloud_firestore - url: "https://pub.dartlang.org" + sha256: "89a5e32716794b6a8d0ec1b5dfda988194e92daedaa3f3bed66fa0d0a595252e" + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "5.6.6" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface - url: "https://pub.dartlang.org" + sha256: "9f012844eb59be6827ed97415875c5a29ccacd28bc79bf85b4680738251a33df" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "6.6.6" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web - url: "https://pub.dartlang.org" + sha256: b8b754269be0e907acd9ff63ad60f66b84c78d330ca1d7e474f86c9527ddc803 + url: "https://pub.dev" source: hosted - version: "0.1.1+2" + version: "4.4.6" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.14.12" - convert: - dependency: transitive + version: "1.18.0" + cupertino_icons: + dependency: "direct main" description: - name: convert - url: "https://pub.dartlang.org" + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" source: hosted - version: "2.1.1" - crypto: + version: "1.0.8" + fake_async: dependency: transitive description: - name: crypto - url: "https://pub.dartlang.org" + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "2.1.4" - cupertino_icons: - dependency: "direct main" + version: "1.3.1" + ffi: + dependency: transitive description: - name: cupertino_icons - url: "https://pub.dartlang.org" + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" source: hosted - version: "0.1.3" - firebase: + version: "2.1.3" + file: dependency: transitive description: - name: firebase - url: "https://pub.dartlang.org" + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.0.1" firebase_auth: dependency: "direct main" description: name: firebase_auth - url: "https://pub.dartlang.org" + sha256: "54c62b2d187709114dd09ce658a8803ee91f9119b0e0d3fc2245130ad9bff9ad" + url: "https://pub.dev" source: hosted - version: "0.15.4" + version: "5.5.2" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - url: "https://pub.dartlang.org" + sha256: "5402d13f4bb7f29f2fb819f3b6b5a5a56c9f714aef2276546d397e25ac1b6b8e" + url: "https://pub.dev" source: hosted - version: "1.1.7" + version: "7.6.2" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - url: "https://pub.dartlang.org" + sha256: "2be496911f0807895d5fe8067b70b7d758142dd7fb26485cbe23e525e2547764" + url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "5.14.2" firebase_core: - dependency: transitive + dependency: "direct main" description: name: firebase_core - url: "https://pub.dartlang.org" + sha256: "017d17d9915670e6117497e640b2859e0b868026ea36bf3a57feb28c3b97debe" + url: "https://pub.dev" source: hosted - version: "0.4.4+3" + version: "3.13.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.dartlang.org" + sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf + url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "5.4.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.dartlang.org" + sha256: "129a34d1e0fb62e2b488d988a1fc26cc15636357e50944ffee2862efe8929b23" + url: "https://pub.dev" source: hosted - version: "0.1.1+2" + version: "2.22.0" flutter: dependency: "direct main" description: flutter @@ -149,139 +168,230 @@ packages: description: flutter source: sdk version: "0.0.0" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "55580f436822d64c8ff9a77e37d61f5fb1e6c7ec9d632a43ee324e2a05c3c6c9" + url: "https://pub.dev" + source: hosted + version: "0.3.3" google_sign_in: dependency: "direct main" description: name: google_sign_in - url: "https://pub.dartlang.org" + sha256: fad6ddc80c427b0bba705f2116204ce1173e09cf299f85e053d57a55e5b2dd56 + url: "https://pub.dev" + source: hosted + version: "6.2.2" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + sha256: "7af72e5502c313865c729223b60e8ae7bce0a1011b250c24edcf30d3d7032748" + url: "https://pub.dev" + source: hosted + version: "6.1.35" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: "102005f498ce18442e7158f6791033bbc15ad2dcc0afa4cf4752e2722a516c96" + url: "https://pub.dev" source: hosted - version: "4.4.3" + version: "5.9.0" google_sign_in_platform_interface: dependency: transitive description: name: google_sign_in_platform_interface - url: "https://pub.dartlang.org" + sha256: "5f6f79cf139c197261adb6ac024577518ae48fdff8e53205c5373b5f6430a8aa" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "2.5.0" google_sign_in_web: dependency: transitive description: name: google_sign_in_web - url: "https://pub.dartlang.org" + sha256: "460547beb4962b7623ac0fb8122d6b8268c951cf0b646dd150d60498430e4ded" + url: "https://pub.dev" source: hosted - version: "0.9.1" + version: "0.12.4+4" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" source: hosted - version: "0.12.1" + version: "1.3.0" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" source: hosted - version: "3.1.4" - image: + version: "10.0.5" + leak_tracker_flutter_testing: dependency: transitive description: - name: image - url: "https://pub.dartlang.org" + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" source: hosted - version: "2.1.12" - js: + version: "3.0.5" + leak_tracker_testing: dependency: transitive description: - name: js - url: "https://pub.dartlang.org" + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" source: hosted - version: "0.6.1+1" + version: "3.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.6" + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" source: hosted - version: "1.1.8" + version: "1.15.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.6.4" - pedantic: + version: "1.9.0" + path_provider_linux: dependency: transitive description: - name: pedantic - url: "https://pub.dartlang.org" + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" source: hosted - version: "1.9.0" - petitparser: + version: "2.2.1" + path_provider_platform_interface: dependency: transitive description: - name: petitparser - url: "https://pub.dartlang.org" + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" source: hosted - version: "3.0.2" - plugin_platform_interface: + version: "2.1.2" + path_provider_windows: dependency: transitive description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" source: hosted - version: "1.0.2" - quiver: + version: "2.3.0" + platform: dependency: transitive description: - name: quiver - url: "https://pub.dartlang.org" + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" random_string: dependency: "direct main" description: name: random_string - url: "https://pub.dartlang.org" + sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.3.1" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" source: hosted - version: "0.5.7" - shared_preferences_macos: + version: "2.5.3" + shared_preferences_android: dependency: transitive description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" + name: shared_preferences_android + sha256: "9f9f3d372d4304723e6136663bb291c0b93f5e4c8a4a6314347f481a33bda2b1" + url: "https://pub.dev" source: hosted - version: "0.0.1+7" + version: "2.4.7" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" source: hosted - version: "0.1.2+4" + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sky_engine: dependency: transitive description: flutter @@ -291,65 +401,90 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.9.3" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" source: hosted - version: "0.2.15" + version: "0.7.2" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.0.8" - xml: + version: "2.1.4" + vm_service: dependency: transitive description: - name: xml - url: "https://pub.dartlang.org" + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" source: hosted - version: "3.7.0" + version: "14.2.5" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" sdks: - dart: ">=2.7.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=3.5.1 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 38f6cf2..ac31949 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ^3.5.1 dependencies: flutter: @@ -27,12 +27,13 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.3 - google_sign_in: 4.4.3 - firebase_auth: 0.15.4 - shared_preferences: ^0.5.6+3 - random_string: ^2.0.1 - cloud_firestore: ^0.13.5 + cupertino_icons: ^1.0.8 + google_sign_in: ^6.2.2 + firebase_core: ^3.13.0 + firebase_auth: ^5.5.2 + shared_preferences: ^2.5.3 + random_string: ^2.3.1 + cloud_firestore: ^5.6.6 dev_dependencies: flutter_test: diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html index c7ec920..0658b60 100644 --- a/web/index.html +++ b/web/index.html @@ -1,6 +1,20 @@ + + @@ -8,26 +22,16 @@ - + - + - chatapp + flutter_chat_app_tutorial - - - + diff --git a/web/manifest.json b/web/manifest.json index 4a0c6ce..5dd8c4e 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,8 +1,8 @@ { - "name": "chatapp", - "short_name": "chatapp", + "name": "flutter_chat_app_tutorial", + "short_name": "flutter_chat_app_tutorial", "start_url": ".", - "display": "minimal-ui", + "display": "standalone", "background_color": "#0175C2", "theme_color": "#0175C2", "description": "A new Flutter project.", @@ -18,6 +18,18 @@ "src": "icons/Icon-512.png", "sizes": "512x512", "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" } ] }