diff --git a/login/assets/images/login_frame.png b/login/assets/images/login_frame.png new file mode 100644 index 0000000..c9f35cf Binary files /dev/null and b/login/assets/images/login_frame.png differ diff --git a/login/assets/images/login_frame.svg b/login/assets/images/login_frame.svg new file mode 100644 index 0000000..46443a6 --- /dev/null +++ b/login/assets/images/login_frame.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/login/lib/api/apis.dart b/login/lib/api/apis.dart index 3bef2ff..5f497fb 100644 --- a/login/lib/api/apis.dart +++ b/login/lib/api/apis.dart @@ -1,10 +1,13 @@ // ignore_for_file: avoid_print +import 'dart:convert'; import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_storage/firebase_storage.dart'; +import 'package:http/http.dart'; import 'package:login/model/chat_user_model.dart'; import 'package:login/model/messages.dart'; @@ -23,6 +26,58 @@ class APIs { //for returning current user static User get user => auth.currentUser!; + // for accessing firebase messaging (Push Notification) + static FirebaseMessaging fMessaging = FirebaseMessaging.instance; + + // for getting firebase messaging token + static Future getFirebaseMessagingToken() async { + await fMessaging.getToken().then((t) { + if (t != null) { + me.PushToken = t; + print('Push Token: $t'); + } + }); + + // for handling foreground messages + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + print('Got a message whilst in the foreground!'); + print('Message data: ${message.data}'); + + if (message.notification != null) { + print('Message also contained a notification: ${message.notification}'); + } + }); + } + + // for sending push notification + static Future sendPushNotification( + ChatUser chatUser, String msg) async { + try { + final body = { + "to": chatUser.PushToken, + "notification": { + "title": me.Name, //our name should be send + "body": msg, + }, + // "data": { + // "some_data": "User ID: ${me.id}", + // }, + }; + + var res = await post(Uri.parse('https://fcm.googleapis.com/fcm/send'), + headers: { + HttpHeaders.contentTypeHeader: 'application/json', + HttpHeaders.authorizationHeader: + 'key=AAAAJoFEO6I:APA91bElgw77iGQYJdEov_3ea5i3j6_vpjpPm7q4D4xahUmOPny_4W9g3Vus_FgrldMScGNcd7qn46lko8wTYsX-yZQsJhRrKaj5T_NV3TkJ8vLkMIxxkSKLuz2mwbNelOCo-t7ma-3N' + }, + body: jsonEncode(body)); + print('Response status: ${res.statusCode}'); + print('Response body: ${res.body}'); + } catch (e) { + print('\nsendPushNotificationE: $e'); + } + } + //for checking if user exists or not?? static Future userExists() async { return (await firestore.collection('Users').doc(user.uid).get()).exists; @@ -33,6 +88,9 @@ class APIs { await firestore.collection('Users').doc(user.uid).get().then((user) async { if (user.exists) { me = ChatUser.fromJson(user.data()!); + await getFirebaseMessagingToken(); + + APIs.updateActiveStatus(true); } else { await createUser().then((value) => getSelfInfo()); } @@ -119,6 +177,27 @@ class APIs { .snapshots(); } + // // for sending message + // static Future sendMessage( + // ChatUser chatUser, String msg, Type type) async { + // //message sending time (also used as id) + // final time = DateTime.now().millisecondsSinceEpoch.toString(); + + // //message to send + // final Message message = Message( + // toId: chatUser.Id, + // msg: msg, + // read: '', + // type: type, + // fromId: user.uid, + // sent: time); + + // final ref = firestore + // .collection('chats/${getConversationID(chatUser.Id)}/messages/'); + // await ref.doc(time).set(message.toJson()).then((value) => + // sendPushNotification(chatUser, type == Type.text ? msg : 'image')); + // } + // for sending message static Future sendMessage( ChatUser chatUser, @@ -139,7 +218,8 @@ class APIs { final ref = firestore .collection('chats/${getConversationID(chatUser.Id)}/messages/'); - await ref.doc(time).set(message.toJson()); + await ref.doc(time).set(message.toJson()).then((value) => + sendPushNotification(chatUser, type == Type.text ? msg : 'image'));; } //update read status of message diff --git a/login/lib/auth/loginscreen.dart b/login/lib/auth/loginscreen.dart index b75f07f..f77f62b 100644 --- a/login/lib/auth/loginscreen.dart +++ b/login/lib/auth/loginscreen.dart @@ -2,9 +2,11 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:login/api/apis.dart'; import 'package:login/auth/firebase_auth_servies.dart'; import 'package:login/auth/signuppage.dart'; +import 'package:login/main.dart'; import 'package:login/screens/homescreen.dart'; class LoginPage extends StatefulWidget { @@ -34,75 +36,165 @@ class _LoginPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Login Page'), - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextField( - controller: emailController, - keyboardType: TextInputType.emailAddress, - decoration: const InputDecoration( - labelText: 'Email', - border: OutlineInputBorder(), + backgroundColor: Colors.transparent, + title: Center( + child: Column( + children: [ + Text( + "Login", + style: TextStyle( + fontSize: 22.sp, + fontWeight: FontWeight.w600, + color: Colors.white), ), - ), - const SizedBox(height: 16.0), - TextField( - controller: passwordController, - obscureText: true, - decoration: const InputDecoration( - labelText: 'Password', - border: OutlineInputBorder(), + Text( + "Enter Email Password to continue", + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w300, + color: Colors.white), ), - ), - const SizedBox(height: 32.0), - isSignIn - ? const CircularProgressIndicator( - color: Colors.black, - ) - : ElevatedButton( - onPressed: () { - print('Email: ${emailController.text}'); - print('Password: ${passwordController.text}'); - _signIn(); - APIs.updateActiveStatus(true); - }, - child: const Text('Login'), - ), - InkWell( - onTap: () { - // - }, - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, + ], + ), + ), + ), + extendBodyBehindAppBar: true, + body: Container( + decoration: const BoxDecoration( + //gradient: LinearGradient(colors: Colors.white ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color.fromRGBO(0, 248, 248, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + ), + child: Stack(children: [ + //for showing the robot background image + Align( + alignment: Alignment.topCenter, + child: Image.asset("assets/images/login_frame.png"), + ), + Positioned( + bottom: 0, + child: Column( children: [ - Icon(Icons.account_circle), - Text("Sign in with Google "), + 20.verticalSpace, + SizedBox( + width: mq.width * 1, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + 20.verticalSpace, + TextField( + controller: emailController, + keyboardType: TextInputType.emailAddress, + style: const TextStyle( + color: + Colors.white, // Change text color to blue + ), + decoration: InputDecoration( + labelText: 'Email', + labelStyle: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w300, + color: Colors.white, + ), + border: const OutlineInputBorder(), + ), + ), + 15.verticalSpace, + TextField( + controller: passwordController, + obscureText: true, + style: const TextStyle( + color: + Colors.white, // Change text color to blue + ), + decoration: InputDecoration( + labelText: 'Password', + labelStyle: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w300, + color: Colors.white, + ), + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 32.0), + isSignIn + ? const CircularProgressIndicator( + color: Colors.black, + ) + : ElevatedButton.icon( + icon: const Icon(Icons.login, + color: Colors.white), + onPressed: () { + print('Email: ${emailController.text}'); + print( + 'Password: ${passwordController.text}'); + _signIn(); + + }, + label: Text( + "Login", + style: TextStyle( + color: Colors.white, + fontSize: 20.sp, + ), + ), + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + Colors.blueAccent), + // Change the color here + ), + ), + InkWell( + onTap: () { + // + }, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.account_circle), + Text("Sign in with Google "), + ], + ), + ), + const SizedBox( + height: 30, + ), + Row( + children: [ + const Text("New User?"), + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const SignUpPage()), + ); + }, + child: const Text("Sign up")) + ], + ), + ], + ), + ), + ], + ), + ) ], - ), - ), - const SizedBox( - height: 30, - ), - Row( - children: [ - const Text("New User?"), - TextButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SignUpPage()), - ); - }, - child: const Text("Sign up")) - ], - ), - ], - ), + )), + ]), ), ); } diff --git a/login/lib/auth/signuppage.dart b/login/lib/auth/signuppage.dart index 207fb3c..e60615a 100644 --- a/login/lib/auth/signuppage.dart +++ b/login/lib/auth/signuppage.dart @@ -32,100 +32,125 @@ class _SignUpPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + extendBodyBehindAppBar: true, appBar: AppBar( automaticallyImplyLeading: false, title: const Text("SignUp"), ), - body: Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - "Sign Up", - style: TextStyle(fontSize: 27, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 30, - ), - FormContainerWidget( - controller: _usernameController, - hintText: "Username", - isPasswordField: false, - ), - const SizedBox( - height: 10, - ), - FormContainerWidget( - controller: _emailController, - hintText: "Email", - isPasswordField: false, - ), - const SizedBox( - height: 10, - ), - FormContainerWidget( - controller: _passwordController, - hintText: "Password", - isPasswordField: true, - ), - const SizedBox( - height: 30, - ), - GestureDetector( - onTap: () { - _signUp(); - }, - child: Container( - width: double.infinity, - height: 45, - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(10), - ), - child: Center( - child: isSigningUp - ? const CircularProgressIndicator( - color: Colors.white, - ) - : const Text( - "Sign Up", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - )), + body: Column(children: [ + Center( + child: Align( + alignment: Alignment.topCenter, + child: Container( + decoration: const BoxDecoration( + //gradient: LinearGradient(colors: Colors.white ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color.fromRGBO(0, 248, 248, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + image: DecorationImage( + image: AssetImage("assets/images/login_frame.png"), + fit: BoxFit.cover, ), ), - const SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text("Already have an account?"), - const SizedBox( - width: 5, + ), + ), + ), + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + "Sign Up", + style: TextStyle(fontSize: 27, fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 30, + ), + FormContainerWidget( + controller: _usernameController, + hintText: "Username", + isPasswordField: false, + ), + const SizedBox( + height: 10, + ), + FormContainerWidget( + controller: _emailController, + hintText: "Email", + isPasswordField: false, + ), + const SizedBox( + height: 10, + ), + FormContainerWidget( + controller: _passwordController, + hintText: "Password", + isPasswordField: true, + ), + const SizedBox( + height: 30, + ), + GestureDetector( + onTap: () { + _signUp(); + }, + child: Container( + width: double.infinity, + height: 45, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + child: Center( + child: isSigningUp + ? const CircularProgressIndicator( + color: Colors.white, + ) + : const Text( + "Sign Up", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold), + )), ), - GestureDetector( - onTap: () { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => const LoginPage()), - (route) => false); - }, - child: const Text( - "Login", - style: TextStyle( - color: Colors.blue, fontWeight: FontWeight.bold), - )) - ], - ) - ], + ), + const SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Already have an account?"), + const SizedBox( + width: 5, + ), + GestureDetector( + onTap: () { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => const LoginPage()), + (route) => false); + }, + child: const Text( + "Login", + style: TextStyle( + color: Colors.blue, fontWeight: FontWeight.bold), + )) + ], + ) + ], + ), ), ), - ), + ]), ); } diff --git a/login/lib/dialogs/profile_dialog.dart b/login/lib/dialogs/profile_dialog.dart index 8c44185..b1d12ea 100644 --- a/login/lib/dialogs/profile_dialog.dart +++ b/login/lib/dialogs/profile_dialog.dart @@ -17,7 +17,7 @@ class ProfileDialog extends StatelessWidget { Widget build(BuildContext context) { return AlertDialog( contentPadding: EdgeInsets.zero, - backgroundColor: Colors.white.withOpacity(.9), + backgroundColor: const Color.fromRGBO(0, 163, 255, 1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), @@ -35,10 +35,10 @@ class ProfileDialog extends StatelessWidget { child: Text( user.Name, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - ), + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w500, + color: Colors.white), ), ), @@ -60,7 +60,7 @@ class ProfileDialog extends StatelessWidget { padding: const EdgeInsets.all(0), shape: const CircleBorder(), child: const Icon(Icons.info_outline, - color: Colors.blue, size: 30), + color: Colors.white, size: 30), ), ], ), diff --git a/login/lib/main.dart b/login/lib/main.dart index 3cde35a..3fdb2bb 100644 --- a/login/lib/main.dart +++ b/login/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -10,15 +11,27 @@ import 'firebase_options.dart'; // global object for accessing device screen size late Size mq; -void main() { +Future main() async { WidgetsFlutterBinding.ensureInitialized(); - _initialiseFirebase(); + await _initialiseFirebase(); runApp(const MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { const MyApp({super.key}); + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + static FirebaseMessaging fMessaging = FirebaseMessaging.instance; + @override + void initState() { + super.initState(); + fMessaging.requestPermission(); + } + // This widget is the root of your application. @override Widget build(BuildContext context) { diff --git a/login/lib/model/ai_message_model.dart b/login/lib/model/ai_message_model.dart new file mode 100644 index 0000000..76b5af3 --- /dev/null +++ b/login/lib/model/ai_message_model.dart @@ -0,0 +1,5 @@ +class AIMessage { + bool isSender; + String msg; + AIMessage(this.isSender, this.msg); +} diff --git a/login/lib/screens/chat_screen.dart b/login/lib/screens/chat_screen.dart index ef06dd4..28a8fe2 100644 --- a/login/lib/screens/chat_screen.dart +++ b/login/lib/screens/chat_screen.dart @@ -1,165 +1,165 @@ -// import 'dart:convert'; -// import 'package:chat_bubbles/bubbles/bubble_normal.dart'; -// import 'package:flutter/material.dart'; -// import 'package:http/http.dart' as http; -// import 'package:login/widgets/message.dart'; +import 'dart:convert'; +import 'package:chat_bubbles/bubbles/bubble_normal.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:login/model/ai_message_model.dart'; -// class ChatScreen extends StatefulWidget { -// const ChatScreen({super.key}); +class AIChatScreen extends StatefulWidget { + const AIChatScreen({super.key}); -// @override -// State createState() => _ChatScreenState(); -// } + @override + State createState() => _AIChatScreenState(); +} -// class _ChatScreenState extends State { -// TextEditingController controller = TextEditingController(); -// ScrollController scrollController = ScrollController(); -// List msgs = []; -// bool isTyping = false; +class _AIChatScreenState extends State { + TextEditingController controller = TextEditingController(); + ScrollController scrollController = ScrollController(); + List msgs = []; + bool isTyping = false; -// void sendMsg() async { -// String text = controller.text; -// String apiKey = "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"; -// controller.clear(); -// try { -// if (text.isNotEmpty) { -// setState(() { -// msgs.insert(0, Message(true, text)); -// isTyping = true; -// }); -// scrollController.animateTo(0.0, -// duration: const Duration(seconds: 1), curve: Curves.easeOut); -// var response = await http.post( -// Uri.parse("https://api.openai.com/v1/chat/completions"), -// headers: { -// "Authorization": "Bearer $apiKey", -// "Content-Type": "application/json" -// }, -// body: jsonEncode({ -// "model": "gpt-3.5-turbo", -// "messages": [ -// {"role": "user", "content": text} -// ] -// })); -// if (response.statusCode == 200) { -// var json = jsonDecode(response.body); -// setState(() { -// isTyping = false; -// msgs.insert( -// 0, -// Message( -// false, -// json["choices"][0]["message"]["content"] -// .toString() -// .trimLeft())); -// }); -// scrollController.animateTo(0.0, -// duration: const Duration(seconds: 1), curve: Curves.easeOut); -// } -// } -// } on Exception { -// // ignore: use_build_context_synchronously -// ScaffoldMessenger.of(context).showSnackBar(const SnackBar( -// content: Text("Some error occurred, please try again!"))); -// } -// } + void sendMsg() async { + String text = controller.text; + String apiKey = "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"; + controller.clear(); + try { + if (text.isNotEmpty) { + setState(() { + msgs.insert(0, AIMessage(true, text)); + isTyping = true; + }); + scrollController.animateTo(0.0, + duration: const Duration(seconds: 1), curve: Curves.easeOut); + var response = await http.post( + Uri.parse("https://api.openai.com/v1/chat/completions"), + headers: { + "Authorization": "Bearer $apiKey", + "Content-Type": "application/json" + }, + body: jsonEncode({ + "model": "gpt-3.5-turbo", + "messages": [ + {"role": "user", "content": text} + ] + })); + if (response.statusCode == 200) { + var json = jsonDecode(response.body); + setState(() { + isTyping = false; + msgs.insert( + 0, + AIMessage( + false, + json["choices"][0]["message"]["content"] + .toString() + .trimLeft())); + }); + scrollController.animateTo(0.0, + duration: const Duration(seconds: 1), curve: Curves.easeOut); + } + } + } on Exception { + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text("Some error occurred, please try again!"))); + } + } -// @override -// Widget build(BuildContext context) { -// return Scaffold( -// appBar: AppBar( -// title: const Text("Chat Bot"), -// ), -// body: Column( -// children: [ -// const SizedBox( -// height: 8, -// ), -// Expanded( -// child: ListView.builder( -// controller: scrollController, -// itemCount: msgs.length, -// shrinkWrap: true, -// reverse: true, -// itemBuilder: (context, index) { -// return Padding( -// padding: const EdgeInsets.symmetric(vertical: 4), -// child: isTyping && index == 0 -// ? Column( -// children: [ -// BubbleNormal( -// text: msgs[0].msg, -// isSender: true, -// color: Colors.blue.shade100, -// ), -// const Padding( -// padding: EdgeInsets.only(left: 16, top: 4), -// child: Align( -// alignment: Alignment.centerLeft, -// child: Text("Typing...")), -// ) -// ], -// ) -// : BubbleNormal( -// text: msgs[index].msg, -// isSender: msgs[index].isSender, -// color: msgs[index].isSender -// ? Colors.blue.shade100 -// : Colors.grey.shade200, -// )); -// }), -// ), -// Row( -// children: [ -// Expanded( -// child: Padding( -// padding: const EdgeInsets.all(8.0), -// child: Container( -// width: double.infinity, -// height: 40, -// decoration: BoxDecoration( -// color: Colors.grey[200], -// borderRadius: BorderRadius.circular(10)), -// child: Padding( -// padding: const EdgeInsets.symmetric(horizontal: 8), -// child: TextField( -// controller: controller, -// textCapitalization: TextCapitalization.sentences, -// onSubmitted: (value) { -// sendMsg(); -// }, -// textInputAction: TextInputAction.send, -// showCursor: true, -// decoration: const InputDecoration( -// border: InputBorder.none, hintText: "Enter text"), -// ), -// ), -// ), -// ), -// ), -// InkWell( -// onTap: () { -// sendMsg(); -// }, -// child: Container( -// height: 40, -// width: 40, -// decoration: BoxDecoration( -// color: Colors.blue, -// borderRadius: BorderRadius.circular(30)), -// child: const Icon( -// Icons.send, -// color: Colors.white, -// ), -// ), -// ), -// const SizedBox( -// width: 8, -// ) -// ], -// ), -// ], -// ), -// ); -// } -// } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Chat Bot"), + ), + body: Column( + children: [ + const SizedBox( + height: 8, + ), + Expanded( + child: ListView.builder( + controller: scrollController, + itemCount: msgs.length, + shrinkWrap: true, + reverse: true, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: isTyping && index == 0 + ? Column( + children: [ + BubbleNormal( + text: msgs[0].msg, + isSender: true, + color: Colors.blue.shade100, + ), + const Padding( + padding: EdgeInsets.only(left: 16, top: 4), + child: Align( + alignment: Alignment.centerLeft, + child: Text("Typing...")), + ) + ], + ) + : BubbleNormal( + text: msgs[index].msg, + isSender: msgs[index].isSender, + color: msgs[index].isSender + ? Colors.blue.shade100 + : Colors.grey.shade200, + )); + }), + ), + Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: double.infinity, + height: 40, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(10)), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: TextField( + controller: controller, + textCapitalization: TextCapitalization.sentences, + onSubmitted: (value) { + sendMsg(); + }, + textInputAction: TextInputAction.send, + showCursor: true, + decoration: const InputDecoration( + border: InputBorder.none, hintText: "Enter text"), + ), + ), + ), + ), + ), + InkWell( + onTap: () { + sendMsg(); + }, + child: Container( + height: 40, + width: 40, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(30)), + child: const Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + const SizedBox( + width: 8, + ) + ], + ), + ], + ), + ); + } +} diff --git a/login/lib/screens/homescreen.dart b/login/lib/screens/homescreen.dart index 9ac5703..6ad01fa 100644 --- a/login/lib/screens/homescreen.dart +++ b/login/lib/screens/homescreen.dart @@ -7,6 +7,7 @@ import 'package:login/model/chat_user_model.dart'; import 'package:login/screens/contact_list.dart'; import 'package:login/screens/profile_screen.dart'; import 'package:login/widgets/chat_user_card.dart'; +import 'package:login/widgets/custom_bottom_navighationbar.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -16,6 +17,14 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { + int _currentIndex = 0; + + void _onTabSelected(int index) { + setState(() { + _currentIndex = index; + }); + } + List _list = []; final List _searchlist = []; bool _isSearching = false; @@ -74,7 +83,7 @@ class _HomePageState extends State { ], ), floatingActionButton: FloatingActionButton( - backgroundColor: Colors.lightBlue, + backgroundColor: const Color.fromRGBO(0, 163, 255, 1), onPressed: () { Navigator.push( context, @@ -88,45 +97,62 @@ class _HomePageState extends State { color: Colors.white, ), ), - body: StreamBuilder( - stream: APIs.getAllUsers(), - builder: (context, snapshot) { - switch (snapshot.connectionState) { - // if data s loading - case ConnectionState.waiting: - case ConnectionState.none: - return const Center( - child: CircularProgressIndicator(), - ); - - //if some or all data is loaded then show it - case ConnectionState.active: - case ConnectionState.done: - final data = snapshot.data?.docs; - _list = - data?.map((e) => ChatUser.fromJson(e.data())).toList() ?? []; - - if (_list.isNotEmpty) { - return ListView.builder( - itemCount: _list.length, // Use the length of the list - padding: EdgeInsets.only(top: mq.height * .01), - physics: const BouncingScrollPhysics(), - itemBuilder: (context, index) { - //return Text('Name: ${list[index]}'); - return ChatUserCard(user: _list[index]); - }, - ); - } else { + body: Container( + decoration: const BoxDecoration( + //gradient: LinearGradient(colors: Colors.white ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color.fromRGBO(0, 248, 248, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + ), + child: StreamBuilder( + stream: APIs.getAllUsers(), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + // if data s loading + case ConnectionState.waiting: + case ConnectionState.none: return const Center( - child: Text( - "No Connections Found...", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 16), - ), + child: CircularProgressIndicator(), ); - } - } - }, + + //if some or all data is loaded then show it + case ConnectionState.active: + case ConnectionState.done: + final data = snapshot.data?.docs; + _list = + data?.map((e) => ChatUser.fromJson(e.data())).toList() ?? + []; + + if (_list.isNotEmpty) { + return ListView.builder( + itemCount: _list.length, // Use the length of the list + padding: EdgeInsets.only(top: mq.height * .01), + physics: const BouncingScrollPhysics(), + itemBuilder: (context, index) { + //return Text('Name: ${list[index]}'); + return ChatUserCard(user: _list[index]); + }, + ); + } else { + return const Center( + child: Text( + "No Connections Found...", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 16), + ), + ); + } + } + }, + ), + ), + bottomNavigationBar: CustomBottomTabBar( + onTabSelected: _onTabSelected, ), ); } diff --git a/login/lib/screens/onboard_screen.dart b/login/lib/screens/onboard_screen.dart index 3307030..3c6558a 100644 --- a/login/lib/screens/onboard_screen.dart +++ b/login/lib/screens/onboard_screen.dart @@ -2,6 +2,7 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:login/auth/loginscreen.dart'; import 'package:login/auth/signuppage.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; @@ -94,7 +95,7 @@ class _OnBoardScreenState extends State { ), // Buttons at the bottom Padding( - padding: const EdgeInsets.all(20.0), + padding: EdgeInsets.all(20.0.sp), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -116,7 +117,7 @@ class _OnBoardScreenState extends State { // Set button border shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( - 10.0), // Adjust the border radius as needed + 10.0.sp), // Adjust the border radius as needed side: const BorderSide( color: Colors.blue), // Set border color ), @@ -149,29 +150,32 @@ class _OnBoardScreenState extends State { child: const Text("Sign Up"), ), if (_currentPage < 2) - ElevatedButton( - onPressed: () { - _carouselController.jumpToPage(2); - }, - style: ElevatedButton.styleFrom( - // Set button size - foregroundColor: Colors.grey, - backgroundColor: Colors.white, - minimumSize: const Size(120, 50), - ), - child: const Row( - children: [ - Text( - "Skip", - style: TextStyle(color: Colors.blueAccent), - ), - SizedBox(width: 8.0), // Adjust the spacing as needed - Icon( - Icons.arrow_forward, - color: Colors.blueAccent, - size: 20.0, // Adjust the size as needed - ), - ], + Padding( + padding: EdgeInsets.all(16.0.sp), + child: InkWell( + onTap: () { + _carouselController.jumpToPage(2); + }, + // style: ElevatedButton.styleFrom( + // // Set button size + // foregroundColor: Colors.grey, + // backgroundColor: Colors.white, + // minimumSize: const Size(120, 50), + // ), + child: const Row( + children: [ + Text( + "Skip", + style: TextStyle(color: Colors.blueAccent), + ), + SizedBox(width: 8.0), // Adjust the spacing as needed + Icon( + Icons.arrow_forward, + color: Colors.blueAccent, + size: 20.0, // Adjust the size as needed + ), + ], + ), ), ), if (_currentPage < 2) diff --git a/login/lib/screens/profile_screen.dart b/login/lib/screens/profile_screen.dart index 2cadd89..dc0098a 100644 --- a/login/lib/screens/profile_screen.dart +++ b/login/lib/screens/profile_screen.dart @@ -30,194 +30,191 @@ class _ProfileScreenState extends State { return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: Scaffold( - appBar: AppBar( - title: const Text( - StringConstants.profilescreen, - textAlign: TextAlign.center, + appBar: AppBar( + title: const Text( + StringConstants.profilescreen, + textAlign: TextAlign.center, + ), + backgroundColor: Colors.lightBlue, + leading: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const HomePage(), + ), + ); + }, + child: const Icon( + CupertinoIcons.chevron_back, + color: Colors.white, ), - backgroundColor: Colors.lightBlue, - leading: InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const HomePage(), - ), - ); - }, - child: const Icon( - CupertinoIcons.chevron_back, - color: Colors.white, - ), + ), + ), + floatingActionButton: Container( + height: 70, + width: 110, + padding: const EdgeInsets.only(bottom: 16.0, right: 16.0), + child: FloatingActionButton( + backgroundColor: Colors.red, + onPressed: () async { + Dialogs.showProgressBar(context); + await APIs.updateActiveStatus(false); + await APIs.auth.signOut().then((value) async { + Navigator.pop(context); + Navigator.pop(context); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const LoginPage()), + (route) => false); + }); + }, + child: const Row( + children: [ + SizedBox( + width: 5, + ), + Text('LogOut'), + SizedBox( + width: 5, + ), + Icon( + Icons.exit_to_app, + color: Colors.white, + ), + ], ), ), - floatingActionButton: Container( - height: 70, - width: 110, - padding: const EdgeInsets.only(bottom: 16.0, right: 16.0), - child: FloatingActionButton( - backgroundColor: Colors.lightBlue, - onPressed: () async { - Dialogs.showProgressBar(context); - await APIs.updateActiveStatus(false); - await APIs.auth.signOut().then((value) async { - Navigator.pop(context); - Navigator.pop(context); - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => const LoginPage()), - (route) => false); - }); - }, - child: const Row( + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: mq.width * .05, + ), + child: Column( children: [ SizedBox( - width: 5, - ), - Text('LogOut'), - SizedBox( - width: 5, - ), - Icon( - Icons.exit_to_app, - color: Colors.white, + width: mq.width, + height: mq.height * .03, ), - ], - ), - ), - ), - body: Form( - key: _formKey, - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: mq.width * .05, - ), - child: Column( - children: [ - SizedBox( - width: mq.width, - height: mq.height * .03, - ), - Stack( - children: [ - //profile picture - _image != null - ? - - //local image - ClipRRect( - borderRadius: - BorderRadius.circular(mq.height * .1), - child: Image.file(File(_image!), - width: mq.height * .2, - height: mq.height * .2, - fit: BoxFit.cover), - ) - : + Stack( + children: [ + //profile picture + _image != null + ? - //image from server - ClipRRect( - borderRadius: - BorderRadius.circular(mq.height * .1), - child: CachedNetworkImage( + //local image + ClipRRect( + borderRadius: + BorderRadius.circular(mq.height * .1), + child: Image.file(File(_image!), width: mq.height * .2, height: mq.height * .2, - fit: BoxFit.cover, - imageUrl: widget.user.Image, - errorWidget: (context, url, error) => - const CircleAvatar( - child: Icon(CupertinoIcons.person)), - ), - ), + fit: BoxFit.cover), + ) + : - // edit image button - Positioned( - bottom: 0, - right: 0, - child: MaterialButton( - elevation: 1, - onPressed: () { - _showBottomSheet(); - }, - color: Colors.white, - shape: const CircleBorder(), - child: const Icon( - Icons.edit, - color: Colors.blue, + //image from server + ClipRRect( + borderRadius: + BorderRadius.circular(mq.height * .1), + child: CachedNetworkImage( + width: mq.height * .2, + height: mq.height * .2, + fit: BoxFit.cover, + imageUrl: widget.user.Image, + errorWidget: (context, url, error) => + const CircleAvatar( + child: Icon(CupertinoIcons.person)), + ), ), + + // edit image button + Positioned( + bottom: 0, + right: 0, + child: MaterialButton( + elevation: 1, + onPressed: () { + _showBottomSheet(); + }, + color: Colors.white, + shape: const CircleBorder(), + child: const Icon( + Icons.edit, + color: Colors.blue, ), - ) - ], - ), - SizedBox( - width: mq.width, - height: mq.height * .03, - ), - Text( - widget.user.Email, - style: const TextStyle( - fontWeight: FontWeight.w200, - fontSize: 16, - ), - ), - TextFormField( - initialValue: widget.user.Name, - onSaved: (val) => APIs.me.Name = val ?? '', - validator: (val) => val != null && val.isNotEmpty - ? null - : 'Required Field', - decoration: InputDecoration( - prefixIcon: - const Icon(Icons.person, color: Colors.blue), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12)), - hintText: 'ex: Your Full Name', - label: const Text('Name')), - ), - const SizedBox( - height: 20, - ), - TextFormField( - initialValue: widget.user.About, - onSaved: (val) => APIs.me.About = val ?? '', - validator: (val) => val != null && val.isNotEmpty - ? null - : 'Required Field', - decoration: InputDecoration( - prefixIcon: const Icon(Icons.info_outline, - color: Colors.blue), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12)), - hintText: 'ex: About Yourself', - label: const Text('About')), - ), - const SizedBox( - height: 40, - ), - ElevatedButton.icon( - style: ElevatedButton.styleFrom( - shape: const StadiumBorder(), - minimumSize: Size(mq.width * .5, mq.height * .06)), - onPressed: () { - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - APIs.updateUserInfo().then((value) { - Dialogs.showSnackbar( - context, 'Profile Updated Successfully!'); - }); - } - }, - icon: const Icon(Icons.edit, size: 28), - label: - const Text('UPDATE', style: TextStyle(fontSize: 16)), + ), + ) + ], + ), + SizedBox( + width: mq.width, + height: mq.height * .03, + ), + Text( + widget.user.Email, + style: const TextStyle( + fontWeight: FontWeight.w200, + fontSize: 16, ), - ], - ), + ), + TextFormField( + initialValue: widget.user.Name, + onSaved: (val) => APIs.me.Name = val ?? '', + validator: (val) => + val != null && val.isNotEmpty ? null : 'Required Field', + decoration: InputDecoration( + prefixIcon: + const Icon(Icons.person, color: Colors.blue), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12)), + hintText: 'ex: Your Full Name', + label: const Text('Name')), + ), + const SizedBox( + height: 20, + ), + TextFormField( + initialValue: widget.user.About, + onSaved: (val) => APIs.me.About = val ?? '', + validator: (val) => + val != null && val.isNotEmpty ? null : 'Required Field', + decoration: InputDecoration( + prefixIcon: + const Icon(Icons.info_outline, color: Colors.blue), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12)), + hintText: 'ex: About Yourself', + label: const Text('About')), + ), + const SizedBox( + height: 40, + ), + ElevatedButton.icon( + style: ElevatedButton.styleFrom( + shape: const StadiumBorder(), + minimumSize: Size(mq.width * .5, mq.height * .06)), + onPressed: () { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + APIs.updateUserInfo().then((value) { + Dialogs.showSnackbar( + context, 'Profile Updated Successfully!'); + }); + } + }, + icon: const Icon(Icons.edit, size: 28), + label: const Text('UPDATE', style: TextStyle(fontSize: 16)), + ), + ], ), ), - )), + ), + ), + ), ); } @@ -282,7 +279,6 @@ class _ProfileScreenState extends State { //take picture from camera button ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, shape: const CircleBorder(), fixedSize: Size(mq.width * .3, mq.height * .15)), onPressed: () async { diff --git a/login/lib/screens/settings_screen.dart b/login/lib/screens/settings_screen.dart new file mode 100644 index 0000000..868ab02 --- /dev/null +++ b/login/lib/screens/settings_screen.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class SettingsScreen extends StatefulWidget { + const SettingsScreen({super.key}); + + @override + State createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Settings"), + ), + ); + } +} diff --git a/login/lib/screens/user_chat_screen.dart b/login/lib/screens/user_chat_screen.dart index 3f80cd6..2a9e310 100644 --- a/login/lib/screens/user_chat_screen.dart +++ b/login/lib/screens/user_chat_screen.dart @@ -47,7 +47,7 @@ class _UserChatScreenState extends State { } //for storing all messages - List _list = []; + List list = []; //for handling message text controlling final _textController = TextEditingController(); @override @@ -57,10 +57,9 @@ class _UserChatScreenState extends State { appBar: AppBar( automaticallyImplyLeading: false, flexibleSpace: _appBar(), + backgroundColor: const Color.fromRGBO(0, 163, 255, 1), ), - backgroundColor: const Color.fromARGB(255, 234, 248, 255), - // AppBar( // automaticallyImplyLeading: false, // title: InkWell( @@ -110,62 +109,75 @@ class _UserChatScreenState extends State { // ), // )), // backgroundColor: const Color.fromARGB(255, 234, 248, 255), - body: Column( - children: [ - Expanded( - child: StreamBuilder( - stream: APIs.getAllMessages(widget.user), - builder: (context, snapshot) { - switch (snapshot.connectionState) { - // if data s loading - case ConnectionState.waiting: - case ConnectionState.none: - return const Center( - child: CircularProgressIndicator(), - ); + body: Container( + decoration: const BoxDecoration( + //gradient: LinearGradient(colors: Colors.white ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color.fromRGBO(0, 248, 248, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + ), + child: Column( + children: [ + Expanded( + child: StreamBuilder( + stream: APIs.getAllMessages(widget.user), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + // if data s loading + case ConnectionState.waiting: + case ConnectionState.none: + return const Center( + child: CircularProgressIndicator(), + ); - //if some or all data is loaded then show it - case ConnectionState.active: - case ConnectionState.done: - final data = snapshot.data?.docs; + //if some or all data is loaded then show it + case ConnectionState.active: + case ConnectionState.done: + final data = snapshot.data?.docs; - _newList = data - ?.map((e) => Message.fromJson(e.data())) - .toList() ?? - []; + _newList = data + ?.map((e) => Message.fromJson(e.data())) + .toList() ?? + []; - var _list = _newList.reversed.toList(); + var list = _newList.reversed.toList(); - if (_list.isNotEmpty) { - return ListView.builder( - reverse: true, - controller: - _scrollController, // Assign the ScrollController - itemCount: _list.length, - padding: EdgeInsets.only(top: mq.height * .01), - physics: const BouncingScrollPhysics(), - itemBuilder: (context, index) { - return MessageCard( - message: _list[index], - ); - }, - ); - } else { - return Center( - child: Text( - "Say Hii 👋", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20.sp, fontWeight: FontWeight.w400), - ), - ); - } - } - }, + if (list.isNotEmpty) { + return ListView.builder( + reverse: true, + controller: + _scrollController, // Assign the ScrollController + itemCount: list.length, + padding: EdgeInsets.only(top: mq.height * .01), + physics: const BouncingScrollPhysics(), + itemBuilder: (context, index) { + return MessageCard( + message: list[index], + ); + }, + ); + } else { + return Center( + child: Text( + "Say Hii 👋", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20.sp, fontWeight: FontWeight.w400), + ), + ); + } + } + }, + ), ), - ), - _chatInput(), - ], + _chatInput(), + ], + ), ), ), ); diff --git a/login/lib/screens/view_profile_screen.dart b/login/lib/screens/view_profile_screen.dart index 0e07cdd..4f6d621 100644 --- a/login/lib/screens/view_profile_screen.dart +++ b/login/lib/screens/view_profile_screen.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:login/dialogs/my_date_util.dart'; import 'package:login/main.dart'; import 'package:login/model/chat_user_model.dart'; @@ -23,80 +24,134 @@ class _ViewProfileScreenState extends State { onTap: () => FocusScope.of(context).unfocus(), child: Scaffold( //app bar - appBar: AppBar(title: Text(widget.user.Name)), - floatingActionButton: //user about - Row( - mainAxisAlignment: MainAxisAlignment.center, + // appBar: AppBar(title: Text(widget.user.Name)), + // floatingActionButton: //user about + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // const Text( + // 'Joined On: ', + // style: TextStyle( + // color: Colors.black87, + // fontWeight: FontWeight.w500, + // fontSize: 15), + // ), + // Text( + // MyDateUtil.getLastMessageTime( + // context: context, + // time: widget.user.CreatedAt, + // showYear: true), + // style: const TextStyle(color: Colors.black54, fontSize: 15)), + // ], + // ), + + //body + body: Container( + decoration: const BoxDecoration( + //gradient: LinearGradient(colors: Colors.white ), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color.fromRGBO(0, 248, 248, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: mq.width * .05), + child: Column( children: [ - const Text( - 'Joined On: ', + 50.verticalSpace, + Text( + widget.user.Name, style: TextStyle( - color: Colors.black87, - fontWeight: FontWeight.w500, - fontSize: 15), + fontSize: 20.sp, + fontWeight: FontWeight.w600, + color: Colors.white), + ), + // for adding some space + 20.verticalSpace, + //user profile picture + ClipRRect( + borderRadius: BorderRadius.circular(mq.height * .1), + child: CachedNetworkImage( + width: mq.height * .2, + height: mq.height * .2, + fit: BoxFit.cover, + imageUrl: widget.user.Image, + errorWidget: (context, url, error) => + const CircleAvatar(child: Icon(CupertinoIcons.person)), + ), ), - Text( - MyDateUtil.getLastMessageTime( - context: context, - time: widget.user.CreatedAt, - showYear: true), - style: const TextStyle(color: Colors.black54, fontSize: 15)), - ], - ), - //body - body: Padding( - padding: EdgeInsets.symmetric(horizontal: mq.width * .05), - child: SingleChildScrollView( - child: Column( - children: [ - // for adding some space - SizedBox(width: mq.width, height: mq.height * .03), + // user email label - //user profile picture - ClipRRect( - borderRadius: BorderRadius.circular(mq.height * .1), - child: CachedNetworkImage( - width: mq.height * .2, - height: mq.height * .2, - fit: BoxFit.cover, - imageUrl: widget.user.Image, - errorWidget: (context, url, error) => const CircleAvatar( - child: Icon(CupertinoIcons.person)), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Email: ', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w700, + fontSize: 16.sp, ), ), - - // for adding some space - SizedBox(height: mq.height * .03), - - // user email label Text(widget.user.Email, - style: - const TextStyle(color: Colors.black87, fontSize: 16)), - - // for adding some space - SizedBox(height: mq.height * .02), + style: TextStyle( + color: Colors.white, + fontSize: 14.sp, + )), + ], + ), + 20.verticalSpace, - //user about - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'About: ', - style: TextStyle( - color: Colors.black87, - fontWeight: FontWeight.w500, - fontSize: 15), - ), - Text(widget.user.About, - style: const TextStyle( - color: Colors.black54, fontSize: 15)), - ], + //user about + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'About: ', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w700, + fontSize: 18.sp, + ), ), + Text(widget.user.About, + style: TextStyle( + color: Colors.white, + fontSize: 18.sp, + )), ], ), - ), - )), + 20.verticalSpace, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Joined On: ', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w700, + fontSize: 18.sp), + ), + Text( + MyDateUtil.getLastMessageTime( + context: context, + time: widget.user.CreatedAt, + showYear: true), + style: TextStyle( + color: Colors.white, + fontSize: 18.sp, + )), + ], + ), + ], + ), + ), + )), ); } } diff --git a/login/lib/widgets/chat_user_card.dart b/login/lib/widgets/chat_user_card.dart index 2524c96..224ac28 100644 --- a/login/lib/widgets/chat_user_card.dart +++ b/login/lib/widgets/chat_user_card.dart @@ -1,12 +1,12 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:login/dialogs/my_date_util.dart'; import 'package:login/dialogs/profile_dialog.dart'; import 'package:login/main.dart'; import 'package:login/model/chat_user_model.dart'; import 'package:login/model/messages.dart'; -import 'package:login/screens/profile_screen.dart'; import 'package:login/screens/user_chat_screen.dart'; import '../api/apis.dart'; @@ -29,7 +29,7 @@ class _ChatUserCardState extends State { Widget build(BuildContext context) { return Card( margin: EdgeInsets.symmetric(horizontal: mq.width * .04, vertical: 4), - // color: Colors.blue.shade100, + color: Colors.black, elevation: 0.5, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), child: InkWell( @@ -69,16 +69,27 @@ class _ChatUserCardState extends State { ), //user name - title: Text(widget.user.Name), + title: Text( + widget.user.Name, + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: FontWeight.w400), + ), //last message subtitle: Text( - _message != null - ? _message!.type == Type.image - ? 'image' - : _message!.msg - : widget.user.About, - maxLines: 1), + _message != null + ? _message!.type == Type.image + ? 'image' + : _message!.msg + : widget.user.About, + maxLines: 1, + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: FontWeight.w200), + ), //last message time trailing: _message == null @@ -99,7 +110,7 @@ class _ChatUserCardState extends State { Text( MyDateUtil.getLastMessageTime( context: context, time: _message!.sent), - style: const TextStyle(color: Colors.black54), + style: const TextStyle(color: Colors.white), ), ); }, diff --git a/login/lib/widgets/custom_bottom_navighationbar.dart b/login/lib/widgets/custom_bottom_navighationbar.dart new file mode 100644 index 0000000..755657a --- /dev/null +++ b/login/lib/widgets/custom_bottom_navighationbar.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:login/screens/chat_screen.dart'; +import 'package:login/screens/homescreen.dart'; +import 'package:login/screens/settings_screen.dart'; + +class CustomBottomTabBar extends StatefulWidget { + final Function(int) onTabSelected; + + const CustomBottomTabBar({Key? key, required this.onTabSelected}) + : super(key: key); + + @override + _CustomBottomTabBarState createState() => _CustomBottomTabBarState(); +} + +class _CustomBottomTabBarState extends State { + int _selectedIndex = 0; + + void _onItemTapped(int index) { + setState(() { + _selectedIndex = index; + }); + if (index == 0) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const HomePage()), + ); + } else if (index == 1) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const AIChatScreen()), + ); + } else if (index == 2) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SettingsScreen()), + ); + } + } + + @override + Widget build(BuildContext context) { + return Expanded( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color.fromRGBO(0, 57, 89, 1), + Color.fromRGBO(0, 57, 89, 1), + ], + ), + ), + padding: EdgeInsets.only(left: 5.sp, right: 5.sp, bottom: 10.sp), + child: BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + icon: Icon( + Icons.chat, + ), + label: 'Chat', + ), + BottomNavigationBarItem( + icon: Icon( + Icons.chat, + ), + label: 'AI', + ), + BottomNavigationBarItem( + icon: Icon( + Icons.settings, + ), + label: 'Settings', + ), + ], + currentIndex: _selectedIndex, + selectedItemColor: Colors.white, + onTap: _onItemTapped, + backgroundColor: Colors.transparent, + unselectedItemColor: Colors.grey, + ), + ), + ); + } +} diff --git a/login/pubspec.lock b/login/pubspec.lock index 726d32f..3c44fa2 100644 --- a/login/pubspec.lock +++ b/login/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7 + sha256: "554f148e71e9e016d9c04d4af6b103ca3f74a1ceed7d7307b70a0f41e991eb77" url: "https://pub.dev" source: hosted - version: "1.3.16" + version: "1.3.26" args: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+1" crypto: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb" + sha256: "67bf0d5fd78f12f51c6b54a72f6141314136a1a90e98b1b7c45e7fac883254ed" url: "https://pub.dev" source: hosted - version: "2.24.2" + version: "2.27.1" firebase_core_platform_interface: dependency: transitive description: @@ -245,10 +245,34 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0 + sha256: "5377eaac3b9fe8aaf22638d87f92b62784f23572e132dfc029195e84d6cb37de" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.12.0" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "34fac43b70d5c41dc864eeb52417128da1f68b0a48604a0c56cd3190f0f609b8" + url: "https://pub.dev" + source: hosted + version: "14.7.20" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "1dcf7d0d6776396bb2e488c53b0e4cc671c45a65717a73d881e52190d23aca3c" + url: "https://pub.dev" + source: hosted + version: "4.5.28" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: ceabccf24d15d03c89dfd6c7eaef11c58fbf00b9c76ebc94028408943b8d2bfd + url: "https://pub.dev" + source: hosted + version: "3.7.0" firebase_storage: dependency: "direct main" description: @@ -340,10 +364,10 @@ packages: dependency: transitive description: name: google_identity_services_web - sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6" + sha256: "9482364c9f8b7bd36902572ebc3a7c2b5c8ee57a9c93e6eb5099c1a9ec5265d8" url: "https://pub.dev" source: hosted - version: "0.3.0+2" + version: "0.3.1+1" google_sign_in: dependency: "direct main" description: @@ -380,18 +404,18 @@ packages: dependency: transitive description: name: google_sign_in_web - sha256: "38e6ec2a7d65ec34bb7ae2db64a1d042b021330433b999e87330d45c688ff549" + sha256: fc0f14ed45ea616a6cfb4d1c7534c2221b7092cc4f29a709f0c3053cc3e821bd url: "https://pub.dev" source: hosted - version: "0.12.3+1" + version: "0.12.4" http: dependency: "direct main" description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" http_parser: dependency: transitive description: @@ -480,6 +504,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -492,26 +540,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -532,10 +580,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -765,14 +813,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" win32: dependency: transitive description: @@ -798,5 +854,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/login/pubspec.yaml b/login/pubspec.yaml index ee099bc..8865984 100644 --- a/login/pubspec.yaml +++ b/login/pubspec.yaml @@ -44,11 +44,13 @@ dependencies: carousel_slider: ^4.2.1 flutter_svg: ^2.0.9 smooth_page_indicator: ^1.1.0 - http: ^1.2.0 + http: ^1.2.1 chat_bubbles: ^1.5.0 image_picker: ^1.0.7 firebase_storage: ^11.6.0 flutter_screenutil: ^5.9.0 + firebase_messaging: ^14.7.20 + dev_dependencies: flutter_test: