Merge pull request 'dev' (#2) from dev into main

Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2025-04-06 18:50:29 +01:00
18 changed files with 376 additions and 557 deletions
+26 -88
View File
@@ -25,14 +25,13 @@ class MessagingProviders extends ChangeNotifier {
late final Account account; late final Account account;
late final Databases database; late final Databases database;
late final Storage storage; late final Storage storage;
late model.User? user;
// Auth Status // Auth Status
AuthStatus? status; AuthStatus? status;
late model.User? user;
static MessagingProviders instance = MessagingProviders(); static MessagingProviders instance = MessagingProviders();
MessagingProviders() { MessagingProviders() {
_init(); _init();
_loadUser(); _loadUser();
@@ -54,22 +53,15 @@ class MessagingProviders extends ChangeNotifier {
if (user != null) { if (user != null) {
status = AuthStatus.authenticated; status = AuthStatus.authenticated;
await updateLastSeen(); await updateLastSeen();
_autoLogin(); NavigationService.instance.navigateToReplacement("home");
} }
} catch (e) { } catch (e) {
status = AuthStatus.notAuthenticated; status = AuthStatus.notAuthenticated;
} finally {
notifyListeners();
} }
} }
void _autoLogin() {
NavigationService.instance.navigateToReplacement("home");
}
void login(String _email, String _password) async { void login(String _email, String _password) async {
// //
notifyListeners();
try { try {
status != AuthStatus.error; status != AuthStatus.error;
@@ -93,7 +85,6 @@ class MessagingProviders extends ChangeNotifier {
SnackBarService.instance.showSnackBarError(e.toString()); SnackBarService.instance.showSnackBarError(e.toString());
// //
} }
notifyListeners();
} on Exception catch (e) { } on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString()); SnackBarService.instance.showSnackBarError(e.toString());
} }
@@ -103,22 +94,20 @@ class MessagingProviders extends ChangeNotifier {
try { try {
await updateLastSeen(); await updateLastSeen();
await account.deleteSession(sessionId: 'current'); await account.deleteSession(sessionId: 'current');
user = null; // user = null;
status = AuthStatus.notAuthenticated; status = AuthStatus.notAuthenticated;
// await onSuccess(); // await onSuccess();
await NavigationService.instance.navigateToReplacement("login");
SnackBarService.instance.showSnackBarError("logged out successfully"); SnackBarService.instance.showSnackBarError("logged out successfully");
await NavigationService.instance.navigateToReplacement("login");
} on AppwriteException catch (e) { } on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!); SnackBarService.instance.showSnackBarError(e.message!);
} on Exception catch (e) { } on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString()); SnackBarService.instance.showSnackBarError(e.toString());
} }
notifyListeners();
} }
Future<void> createUser(String _email, String _password, String _name, Future<void> createUser(String _email, String _password, String _name,
Future<void> Function(String _uid) onSuccess) async { Future<void> Function(String _uid) onSuccess) async {
notifyListeners();
try { try {
user = await account.create( user = await account.create(
userId: ID.unique(), email: _email, password: _password, name: _name); userId: ID.unique(), email: _email, password: _password, name: _name);
@@ -137,12 +126,10 @@ class MessagingProviders extends ChangeNotifier {
SnackBarService.instance.showSnackBarError(e.toString()); SnackBarService.instance.showSnackBarError(e.toString());
// //
} }
notifyListeners();
} }
Future<void> createUserInDB( Future<void> createUserInDB(
String _documentId, String _email, String _name, String _imageURL) async { String _documentId, String _email, String _name, String _imageURL) async {
notifyListeners();
try { try {
await database.createDocument( await database.createDocument(
databaseId: Constants.instance.databaseId, databaseId: Constants.instance.databaseId,
@@ -172,7 +159,6 @@ class MessagingProviders extends ChangeNotifier {
user = null; user = null;
// //
} }
notifyListeners();
} }
Future<void> updateLastSeen() async { Future<void> updateLastSeen() async {
@@ -184,7 +170,7 @@ class MessagingProviders extends ChangeNotifier {
); );
} }
Stream<User> getUser(String userId) { Stream<User> getUser(String userId) async* {
// //
var _userData = database.getDocument( var _userData = database.getDocument(
databaseId: Constants.instance.databaseId, databaseId: Constants.instance.databaseId,
@@ -192,14 +178,14 @@ class MessagingProviders extends ChangeNotifier {
documentId: userId, documentId: userId,
); );
return _userData.asStream().map((_document) { updateLastSeen();
yield* _userData.asStream().map((_document) {
return User.fromData(_document); return User.fromData(_document);
}); });
} }
Stream<List<User>> getAllUsers(String _searchText) async* { Stream<List<User>> getAllUsers(String _searchText) async* {
// //
// while (true) {
List<User> _returnValue = []; List<User> _returnValue = [];
if (_searchText.isNotEmpty) { if (_searchText.isNotEmpty) {
var _usersData = database.listDocuments( var _usersData = database.listDocuments(
@@ -222,12 +208,10 @@ class MessagingProviders extends ChangeNotifier {
} else { } else {
yield* Stream.empty(); yield* Stream.empty();
} }
// }
} }
Stream<List<Conversations>> getUserConversation(String userId) async* { Stream<List<Conversations>> getUserConversation(String userId) async* {
// //
// while (true) {
List<dynamic> _chatId = []; List<dynamic> _chatId = [];
List<dynamic> _details = []; List<dynamic> _details = [];
List<dynamic> _lastModified = []; List<dynamic> _lastModified = [];
@@ -253,98 +237,53 @@ class MessagingProviders extends ChangeNotifier {
return _returnValue; return _returnValue;
}, },
); );
// }
notifyListeners();
} }
// Stream<List<Conversations>> getUserConversations(String userId) async* {
// //
// // while (true) {
// List<dynamic> _chatId = [];
// List<dynamic> _details = [];
// List<dynamic> _lastModified = [];
// List<Conversations> _returnValue = [];
// var _conversationData = await database.getDocument(
// databaseId: Constants.instance.databaseId,
// collectionId: Constants.instance.convCollectionId,
// documentId: userId.trim(),
// );
// yield _conversationData.toMap map(
// (_snapshot) {
// _chatId = _snapshot.data['chatId'];
// _details = _snapshot.data['details'];
// _lastModified = _snapshot.data['lastModified'];
// for (int i = 0; i < _chatId.length; i++) {
// _returnValue.add(Conversations.fromData(
// _chatId[i], _details[i], _lastModified[i]));
// }
// _returnValue.sort((a, b) => b.lastModified!.compareTo(a.lastModified!));
// return _returnValue;
// },
// );
// // }
// }
Stream<Chats> getMessage(String _chatId) async* { Stream<Chats> getMessage(String _chatId) async* {
// //
// while (true) { try {
var _chat = database.getDocument( var _chat = database.getDocument(
databaseId: Constants.instance.databaseId, databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.chatsCollectionId, collectionId: Constants.instance.chatsCollectionId,
documentId: _chatId, documentId: _chatId,
); );
yield* _chat.asStream().map( yield* _chat.asStream().map(
(_document) { (_document) {
return Chats.fromDocument(_document); return Chats.fromDocument(_document);
}, },
); );
// }
}
Future<String> getConversationLink(var _linkId) async {
//
try {
var _conversationLinkDetail = await database.getDocument(
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.conversationLinkId,
documentId: _linkId,
);
notifyListeners();
return _conversationLinkDetail.data['chatId'];
} on AppwriteException catch (e) { } on AppwriteException catch (e) {
notifyListeners(); e.message!;
return ''; yield* Stream.empty();
} on Exception catch (e) {
e.toString();
yield* Stream.empty();
} }
// else {}
notifyListeners();
} }
Future<String> newMesaage(Map<String, dynamic> _chat) async { Future<void> sendMessage(String _chatId, Map<String, dynamic> _messages,
String _newOrUpdate) async {
// //
var chatId = ID.unique(); if (_newOrUpdate == 'new') {
await database.createDocument( await database.createDocument(
databaseId: Constants.instance.databaseId, databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.chatsCollectionId, collectionId: Constants.instance.chatsCollectionId,
documentId: chatId, documentId: _chatId,
data: _chat, data: _messages,
); );
notifyListeners(); } else if (_newOrUpdate == 'update') {
return chatId;
}
Future<void> sendMessage(
String chatId, Map<String, dynamic> _messages) async {
//
await database.updateDocument( await database.updateDocument(
databaseId: Constants.instance.databaseId, databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.chatsCollectionId, collectionId: Constants.instance.chatsCollectionId,
documentId: chatId, documentId: _chatId,
data: _messages, data: _messages,
); );
}
notifyListeners(); notifyListeners();
} }
@@ -373,7 +312,6 @@ class MessagingProviders extends ChangeNotifier {
SnackBarService.instance.showSnackBarError(e.toString()); SnackBarService.instance.showSnackBarError(e.toString());
// //
} }
notifyListeners();
return ""; return "";
} }
} }
+1 -25
View File
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_routes.dart'; import 'package:messaging_app/messaging_app.dart';
import 'package:messaging_app/service/navigation_service.dart';
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@@ -10,26 +9,3 @@ void main() {
); );
} }
class MessagingApp extends StatelessWidget {
const MessagingApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging App',
navigatorKey: NavigationService.instance.navigatorKey,
theme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.black,
primaryColor: Color.fromRGBO(42, 117, 188, 1.0),
colorScheme: ColorScheme.dark(),
useMaterial3: true,
),
routes: MessagingRoutes.instance.messagingRoutes,
initialRoute: "login",
// home: RegisterationPage(),
);
}
}
-167
View File
@@ -1,167 +0,0 @@
import 'package:appwrite/appwrite.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlAppwrite Realtime Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Map<String, dynamic>> items = [];
final TextEditingController _nameController = TextEditingController();
RealtimeSubscription? subscription;
late final Client client;
final database = '67db1d75002a1826f6f9'; // your database id
final itemsCollection = '67db1e36001ffd2719b7'; // your collection id
late final Databases databases;
@override
initState() {
super.initState();
client = Client()
.setEndpoint('https://api.theonasanyas.com/v1')
.setProject('67833160000cb0801fdb'); // your project id
databases = Databases(client);
loadItems();
subscribe();
}
loadItems() async {
try {
final res = await databases.listDocuments(
databaseId: database,
collectionId: itemsCollection,
);
setState(() {
items = List<Map<String, dynamic>>.from(res.documents.map(
(e) => e.data,
));
});
} on AppwriteException catch (e) {
print(e.message);
}
}
void subscribe() {
final realtime = Realtime(client);
subscription = realtime.subscribe([
'documents' // subscribe to all documents in every database and collection
]);
// listen to changes
subscription!.stream.listen((data) {
// data will consist of `events` and a `payload`
final event = data.events.first;
if (data.payload.isNotEmpty) {
if (event.endsWith('.create')) {
var item = data.payload;
items.add(item);
setState(() {});
} else if (event.endsWith('.delete')) {
var item = data.payload;
items.removeWhere((it) => it['\$id'] == item['\$id']);
setState(() {});
}
}
});
}
@override
dispose() {
subscription?.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FlAppwrite Realtime Demo'),
),
body: ListView(children: [
...items.map((item) => ListTile(
title: Text(item['name']),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
await databases.deleteDocument(
databaseId: database,
collectionId: itemsCollection,
documentId: item['\$id'],
);
},
),
)),
]),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
// dialog to add new item
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Add new item'),
content: TextField(
controller: _nameController,
),
actions: [
TextButton(
child: const Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: const Text('Add'),
onPressed: () {
// add new item
final name = _nameController.text;
if (name.isNotEmpty) {
_nameController.clear();
_addItem(name);
}
Navigator.of(context).pop();
},
),
],
),
);
},
),
);
}
void _addItem(String name) async {
try {
await databases.createDocument(
databaseId: database,
collectionId: itemsCollection,
documentId: ID.unique(),
data: {'name': name},
);
} on AppwriteException catch (e) {
print(e.message);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_routes.dart';
import 'package:messaging_app/service/navigation_service.dart';
class MessagingApp extends StatelessWidget {
const MessagingApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging App',
navigatorKey: NavigationService.instance.navigatorKey,
theme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.black,
primaryColor: Color.fromRGBO(42, 117, 188, 1.0),
colorScheme: ColorScheme.dark(),
useMaterial3: true,
),
routes: MessagingRoutes.instance.messagingRoutes,
initialRoute: "login",
);
}
}
+12
View File
@@ -1,16 +1,28 @@
import 'package:messaging_app/models/details.dart'; import 'package:messaging_app/models/details.dart';
class Conversations { class Conversations {
String? id;
String chatId; String chatId;
Details details; Details details;
DateTime? lastModified; DateTime? lastModified;
Conversations({ Conversations({
this.id,
required this.chatId, required this.chatId,
required this.details, required this.details,
this.lastModified, this.lastModified,
}); });
// Convert the details string to a Details object
// and parse the lastModified string to a DateTime object
// Note: You may need to adjust the parsing logic based on your data format
// For example, if _details is a JSON string, you can use json.decode to parse it
// and create a Details object from the parsed data.
// Assuming _details is a JSON string, you can use the Details.fromData method
// to create a Details object.
// Assuming _lastModified is a string in ISO 8601 format
factory Conversations.fromData( factory Conversations.fromData(
String _chatId, String _details, String _lastModified) => String _chatId, String _details, String _lastModified) =>
Conversations( Conversations(
+10 -10
View File
@@ -3,28 +3,28 @@ import 'dart:convert';
class Details { class Details {
String name; String name;
String image; String image;
String email;
int unseenCount; int unseenCount;
String? lastMessage; String? lastMessage;
DateTime? timeStamp; DateTime? timeStamp;
String? type; String? type;
Details({ Details(
required this.name, {required this.name,
required this.image, required this.image,
required this.email,
required this.lastMessage, required this.lastMessage,
required this.timeStamp, required this.timeStamp,
required this.unseenCount, required this.unseenCount,
required this.type required this.type});
});
factory Details.fromData(String _details) { factory Details.fromData(String _details) => Details(
return Details( email: json.decode(_details)['email'],
name: json.decode(_details)['name'], name: json.decode(_details)['name'],
image: json.decode(_details)['image'], image: json.decode(_details)['image'],
lastMessage: json.decode(_details)['lastMessage'], lastMessage: json.decode(_details)['lastMessage'] ?? "",
timeStamp: DateTime.parse(json.decode(_details)['timeStamp'] ?? ""), timeStamp: DateTime.parse(json.decode(_details)['timeStamp']),
unseenCount: json.decode(_details)['unseenCount'], unseenCount: json.decode(_details)['unseenCount'],
type: json.decode(_details)['type'], type: json.decode(_details)['type'] ?? "",
); );
} }
}
-1
View File
@@ -27,7 +27,6 @@ class Messages {
timeStamp: _message['timeStamp'] ?? "", timeStamp: _message['timeStamp'] ?? "",
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"message": message, "message": message,
"senderId": senderId, "senderId": senderId,
+1 -3
View File
@@ -15,8 +15,7 @@ class User {
required this.lastSeen, required this.lastSeen,
}); });
factory User.fromData(Document _document) { factory User.fromData(Document _document) => User(
return User(
id: _document.data['\$id'], id: _document.data['\$id'],
name: _document.data['name'], name: _document.data['name'],
email: _document.data['email'], email: _document.data['email'],
@@ -24,4 +23,3 @@ class User {
lastSeen: DateTime.parse(_document.data['lastSeen']), lastSeen: DateTime.parse(_document.data['lastSeen']),
); );
} }
}
+93 -26
View File
@@ -11,19 +11,24 @@ import 'package:messaging_app/service/snackbar_service.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago; import 'package:timeago/timeago.dart' as timeago;
// ignore: must_be_immutable
class ConversationsPage extends StatefulWidget { class ConversationsPage extends StatefulWidget {
ConversationsPage({ ConversationsPage({
super.key, super.key,
required this.chatId, required this.chatId,
// required this.receiverId, this.userId,
required this.chatImage, required this.userName,
required this.chatName, required this.userImage,
this.userEmail,
// this.chatMessage,
}); });
String chatId; String chatId;
// String receiverId; String? userId;
String chatName; String userName;
String chatImage; String userImage;
String? userEmail;
// Map? chatMessage;
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
@@ -33,13 +38,12 @@ class ConversationsPage extends StatefulWidget {
class _ConversationsPageState extends State<ConversationsPage> { class _ConversationsPageState extends State<ConversationsPage> {
// //
MessagingProviders _auth = MessagingProviders.instance;
final ScrollController _scrollController = ScrollController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late double _deviceHeight; late double _deviceHeight;
late double _deviceWidth; late double _deviceWidth;
final ScrollController _scrollController;
final GlobalKey<FormState> _formKey;
late MessagingProviders _auth;
List<List<Messages>> _messagesArray; List<List<Messages>> _messagesArray;
List<Messages> _messages; List<Messages> _messages;
List<String> _members; List<String> _members;
@@ -48,8 +52,6 @@ class _ConversationsPageState extends State<ConversationsPage> {
_ConversationsPageState() _ConversationsPageState()
: _messageText = '', : _messageText = '',
_formKey = GlobalKey<FormState>(),
_scrollController = ScrollController(),
_messagesArray = [], _messagesArray = [],
_messages = [], _messages = [],
_members = [], _members = [],
@@ -63,12 +65,46 @@ class _ConversationsPageState extends State<ConversationsPage> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
actions: [
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => Dialog(
child: SizedBox(
height: _deviceHeight * 0.25,
width: _deviceHeight * 0.25,
child: Column(
children: [
Container(
// padding: EdgeInsets.all(20),
height: _deviceHeight * 0.20,
width: _deviceHeight * 0.20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: NetworkImage(widget.userImage),
fit: BoxFit.cover,
),
),
),
Text(widget.userName),
Text(widget.userEmail!)
],
),
),
),
);
},
icon: Icon(Icons.info_outline),
)
],
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text(widget.chatName), title: Text(widget.userName),
titleTextStyle: TextStyle(fontSize: 16), titleTextStyle: TextStyle(fontSize: 16),
), ),
body: ChangeNotifierProvider<MessagingProviders>.value( body: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance, value: _auth,
child: _conversationPageUI(), child: _conversationPageUI(),
), ),
); );
@@ -91,11 +127,11 @@ class _ConversationsPageState extends State<ConversationsPage> {
} }
Widget _messageListView() { Widget _messageListView() {
return Container( return SizedBox(
height: _deviceHeight * 0.80, height: _deviceHeight * 0.80,
width: _deviceWidth, width: _deviceWidth,
child: StreamBuilder<Chats>( child: StreamBuilder<Chats>(
stream: MessagingProviders.instance.getMessage(widget.chatId), stream: _auth.getMessage(widget.chatId),
builder: (_context, _snapshot) { builder: (_context, _snapshot) {
if (_snapshot.hasData) { if (_snapshot.hasData) {
_members = _snapshot.data!.members; _members = _snapshot.data!.members;
@@ -109,6 +145,15 @@ class _ConversationsPageState extends State<ConversationsPage> {
child: Text("No Chat"), child: Text("No Chat"),
); );
} else { } else {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(microseconds: 500),
curve: Curves.fastOutSlowIn);
}
});
return ListView.builder( return ListView.builder(
controller: _scrollController, controller: _scrollController,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
@@ -192,6 +237,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
), ),
Text( Text(
timeago.format(DateTime.parse(_message.timeStamp)), timeago.format(DateTime.parse(_message.timeStamp)),
// "${DateTime.parse(_message.timeStamp).}",
style: TextStyle(color: Colors.white70, fontSize: 10), style: TextStyle(color: Colors.white70, fontSize: 10),
), ),
], ],
@@ -252,7 +298,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
image: DecorationImage( image: DecorationImage(
fit: BoxFit.cover, fit: BoxFit.cover,
image: NetworkImage( image: NetworkImage(
widget.chatImage, widget.userImage,
), ),
), ),
), ),
@@ -317,7 +363,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
} }
Widget _sendText(BuildContext _context) { Widget _sendText(BuildContext _context) {
return Container( return SizedBox(
height: _deviceHeight * 0.045, height: _deviceHeight * 0.045,
width: _deviceHeight * 0.045, width: _deviceHeight * 0.045,
child: IconButton( child: IconButton(
@@ -348,8 +394,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
onPressed: () async { onPressed: () async {
XFile? _imageFile = await MediaService.instance.getImageFromLibrary(); XFile? _imageFile = await MediaService.instance.getImageFromLibrary();
if (_imageFile != null) { if (_imageFile != null) {
var _url = await MessagingProviders.instance var _url = await _auth.uploadUserImage(_imageFile, '_uid');
.uploadUserImage(_imageFile, '_uid');
await sendMessage('image', _url); await sendMessage('image', _url);
} }
@@ -386,9 +431,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
} }
await _auth.sendMessage( await _auth.sendMessage(
widget.chatId, widget.chatId, {"messages": outMessages}, 'update');
{"messages": outMessages},
);
}, },
), ),
], ],
@@ -396,7 +439,30 @@ class _ConversationsPageState extends State<ConversationsPage> {
} }
Future<void> sendMessage(var type, var _message) async { Future<void> sendMessage(var type, var _message) async {
List outMessages = []; List _outMessages = [];
if (_members.isEmpty) {
_members = [_auth.user!.$id, widget.userId!];
List<String> messagesTemp = [];
messagesTemp = [
json.encode({
_auth.user!.$id: [],
}),
json.encode({
widget.userId: [],
})
];
Map<String, dynamic> _chat = {
"ownerId": _auth.user!.$id,
"members": _members,
"messages": messagesTemp
};
await _auth.sendMessage(widget.chatId, _chat, 'new');
await Future.delayed(Duration(seconds: 1));
}
for (var i = 0; i < _members.length; i++) { for (var i = 0; i < _members.length; i++) {
_messagesArray[i].add( _messagesArray[i].add(
@@ -408,7 +474,7 @@ class _ConversationsPageState extends State<ConversationsPage> {
), ),
); );
outMessages.add( _outMessages.add(
json.encode( json.encode(
{_members[i]: _messagesArray[i]}, {_members[i]: _messagesArray[i]},
), ),
@@ -417,7 +483,8 @@ class _ConversationsPageState extends State<ConversationsPage> {
await _auth.sendMessage( await _auth.sendMessage(
widget.chatId, widget.chatId,
{"messages": outMessages}, {"messages": _outMessages},
'update',
); );
} }
} }
+7 -6
View File
@@ -80,12 +80,13 @@ class _HomePageState extends State<HomePage>
), ),
), ),
body: _tabBarPages(), body: _tabBarPages(),
floatingActionButton: _tabController.index == 1 // floatingActionButton: _tabController.index == 1
? Container() // ? Container()
: FloatingActionButton( // : FloatingActionButton(
child: Icon(Icons.add), // child: Icon(Icons.add),
onPressed: () {}, // onPressed: () {},
)); // ),
);
} }
Widget _tabBarPages() { Widget _tabBarPages() {
+9 -9
View File
@@ -23,12 +23,8 @@ class _LoginPageState extends State<LoginPage> {
String? _email; String? _email;
String? _password; String? _password;
late GlobalKey<FormState> _formKey; final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late MessagingProviders _auth; MessagingProviders _auth = MessagingProviders.instance;
_LoginPageState() {
_formKey = GlobalKey<FormState>();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -40,7 +36,7 @@ class _LoginPageState extends State<LoginPage> {
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: Align( body: Align(
child: ChangeNotifierProvider<MessagingProviders>.value( child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance, value: _auth,
child: _loginPageUI(), child: _loginPageUI(),
), ),
), ),
@@ -135,7 +131,9 @@ class _LoginPageState extends State<LoginPage> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "email address", hintText: "email address",
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))), borderSide: BorderSide(color: Colors.white),
),
),
); );
} }
@@ -160,7 +158,9 @@ class _LoginPageState extends State<LoginPage> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "password", hintText: "password",
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))), borderSide: BorderSide(color: Colors.white),
),
),
); );
} }
+9 -8
View File
@@ -11,17 +11,17 @@ class ProfilePage extends StatelessWidget {
final double _deviceHeight; final double _deviceHeight;
final double _deviceWidth; final double _deviceWidth;
late MessagingProviders _auth; MessagingProviders _auth = MessagingProviders.instance;
ProfilePage(this._deviceHeight, this._deviceWidth, {super.key}); ProfilePage(this._deviceHeight, this._deviceWidth, {super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return SizedBox(
height: _deviceHeight, height: _deviceHeight,
width: _deviceWidth, width: _deviceWidth,
child: ChangeNotifierProvider<MessagingProviders>.value( child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance, value: _auth,
child: _profilePageUI(), child: _profilePageUI(),
), ),
); );
@@ -29,10 +29,11 @@ class ProfilePage extends StatelessWidget {
Widget _profilePageUI() { Widget _profilePageUI() {
return Builder(builder: (BuildContext _context) { return Builder(builder: (BuildContext _context) {
// assert(_auth.user != null);
SnackBarService.instance.buildContext = _context; SnackBarService.instance.buildContext = _context;
_auth = Provider.of<MessagingProviders>(_context); _auth = Provider.of<MessagingProviders>(_context);
return StreamBuilder<User>( return StreamBuilder<User>(
stream: MessagingProviders.instance.getUser(_auth.user!.$id), stream: _auth.getUser(_auth.user!.$id),
builder: (_, _snapshot) { builder: (_, _snapshot) {
var _userData = _snapshot.data; var _userData = _snapshot.data;
return _snapshot.hasData return _snapshot.hasData
@@ -76,7 +77,7 @@ class ProfilePage extends StatelessWidget {
} }
Widget _userNameWidget(String _name) { Widget _userNameWidget(String _name) {
return Container( return SizedBox(
height: _deviceHeight * 0.05, height: _deviceHeight * 0.05,
width: _deviceWidth, width: _deviceWidth,
child: Text( child: Text(
@@ -91,7 +92,7 @@ class ProfilePage extends StatelessWidget {
} }
Widget _userEmailWidget(String _email) { Widget _userEmailWidget(String _email) {
return Container( return SizedBox(
height: _deviceHeight * 0.03, height: _deviceHeight * 0.03,
width: _deviceWidth, width: _deviceWidth,
child: Text( child: Text(
@@ -106,7 +107,7 @@ class ProfilePage extends StatelessWidget {
} }
Widget _logoutButton() { Widget _logoutButton() {
return Container( return SizedBox(
height: _deviceHeight * 0.06, height: _deviceHeight * 0.06,
width: _deviceWidth * 0.80, width: _deviceWidth * 0.80,
child: MaterialButton( child: MaterialButton(
@@ -115,7 +116,7 @@ class ProfilePage extends StatelessWidget {
}, },
color: Colors.red, color: Colors.red,
child: Text( child: Text(
"Logout".toUpperCase(), "logout".toUpperCase(),
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
+10 -20
View File
@@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:messaging_app/components/messaging_provider.dart'; import 'package:messaging_app/components/messaging_provider.dart';
@@ -25,18 +23,8 @@ class RecentConverstationsPage extends StatefulWidget {
} }
class _RecentConverstationsPageState extends State<RecentConverstationsPage> { class _RecentConverstationsPageState extends State<RecentConverstationsPage> {
late MessagingProviders _auth; //
MessagingProviders _auth = MessagingProviders.instance;
final myController = StreamController<List<Conversations>>.broadcast();
Stream<List<Conversations>> get messageStream => myController.stream;
void messager() {
MessagingProviders.instance.getUserConversation(_auth.user!.$id);
}
void dispose() {
myController.close();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -44,7 +32,7 @@ class _RecentConverstationsPageState extends State<RecentConverstationsPage> {
height: widget._deviceHeight, height: widget._deviceHeight,
width: widget._deviceWidth, width: widget._deviceWidth,
child: ChangeNotifierProvider<MessagingProviders>.value( child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance, value: _auth,
child: _conversationView(context), child: _conversationView(context),
), ),
); );
@@ -58,8 +46,7 @@ class _RecentConverstationsPageState extends State<RecentConverstationsPage> {
height: widget._deviceHeight, height: widget._deviceHeight,
width: widget._deviceWidth, width: widget._deviceWidth,
child: StreamBuilder<List<Conversations>>( child: StreamBuilder<List<Conversations>>(
stream: MessagingProviders.instance stream: _auth.getUserConversation(_auth.user!.$id),
.getUserConversation(_auth.user!.$id),
builder: (_context, _snapshot) { builder: (_context, _snapshot) {
if (_snapshot.hasData) { if (_snapshot.hasData) {
return ListView.builder( return ListView.builder(
@@ -75,8 +62,9 @@ class _RecentConverstationsPageState extends State<RecentConverstationsPage> {
builder: (BuildContext _context) { builder: (BuildContext _context) {
return ConversationsPage( return ConversationsPage(
chatId: _chatId, chatId: _chatId,
chatName: _details.name, userName: _details.name,
chatImage: _details.image, userImage : _details.image,
userEmail: _details.email,
); );
}, },
), ),
@@ -84,7 +72,9 @@ class _RecentConverstationsPageState extends State<RecentConverstationsPage> {
}, },
title: Text(_details.name), title: Text(_details.name),
subtitle: Text( subtitle: Text(
_details.type == 'text' _details.type == ''
? 'start chatting...'
: _details.type == 'text'
? _details.lastMessage! ? _details.lastMessage!
: 'attachment: image', : 'attachment: image',
), ),
+12 -8
View File
@@ -26,10 +26,8 @@ class _RegisterationPageState extends State<RegisterationPage> {
String? _email; String? _email;
String? _password; String? _password;
GlobalKey<FormState> _formKey; final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late MessagingProviders _auth; MessagingProviders _auth = MessagingProviders.instance;
_RegisterationPageState() : _formKey = GlobalKey<FormState>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -43,7 +41,7 @@ class _RegisterationPageState extends State<RegisterationPage> {
// color: Colors.blue, // color: Colors.blue,
alignment: Alignment.center, alignment: Alignment.center,
child: ChangeNotifierProvider<MessagingProviders>.value( child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance, value: _auth,
child: _registerationPageUI(), child: _registerationPageUI(),
), ),
), ),
@@ -165,7 +163,9 @@ class _RegisterationPageState extends State<RegisterationPage> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "name", hintText: "name",
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))), borderSide: BorderSide(color: Colors.white),
),
),
); );
} }
@@ -191,7 +191,9 @@ class _RegisterationPageState extends State<RegisterationPage> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "email", hintText: "email",
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))), borderSide: BorderSide(color: Colors.white),
),
),
); );
} }
@@ -216,7 +218,9 @@ class _RegisterationPageState extends State<RegisterationPage> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "password", hintText: "password",
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))), borderSide: BorderSide(color: Colors.white),
),
),
); );
} }
+20 -46
View File
@@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_provider.dart'; import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/users.dart'; import 'package:messaging_app/models/users.dart';
@@ -8,6 +6,7 @@ import 'package:messaging_app/service/navigation_service.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago; import 'package:timeago/timeago.dart' as timeago;
// ignore: must_be_immutable
class SearchPage extends StatefulWidget { class SearchPage extends StatefulWidget {
SearchPage({ SearchPage({
super.key, super.key,
@@ -17,7 +16,6 @@ class SearchPage extends StatefulWidget {
double deviceHeight; double deviceHeight;
double deviceWidth; double deviceWidth;
late MessagingProviders _auth;
@override @override
State<SearchPage> createState() => _SearchPageState(); State<SearchPage> createState() => _SearchPageState();
@@ -26,6 +24,7 @@ class SearchPage extends StatefulWidget {
class _SearchPageState extends State<SearchPage> { class _SearchPageState extends State<SearchPage> {
late String _searchText; late String _searchText;
late List<User> _usersData; late List<User> _usersData;
MessagingProviders _auth = MessagingProviders.instance;
// //
@override @override
void initState() { void initState() {
@@ -41,7 +40,7 @@ class _SearchPageState extends State<SearchPage> {
height: widget.deviceHeight, height: widget.deviceHeight,
width: widget.deviceWidth, width: widget.deviceWidth,
child: ChangeNotifierProvider.value( child: ChangeNotifierProvider.value(
value: MessagingProviders.instance, value: _auth,
child: _searchPaheUI(), child: _searchPaheUI(),
), ),
), ),
@@ -50,7 +49,7 @@ class _SearchPageState extends State<SearchPage> {
Widget _searchPaheUI() { Widget _searchPaheUI() {
return Builder(builder: (_context) { return Builder(builder: (_context) {
widget._auth = Provider.of<MessagingProviders>(_context); _auth = Provider.of<MessagingProviders>(_context);
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
@@ -67,7 +66,9 @@ class _SearchPageState extends State<SearchPage> {
return Container( return Container(
height: widget.deviceHeight * 0.08, height: widget.deviceHeight * 0.08,
width: widget.deviceWidth, width: widget.deviceWidth,
padding: EdgeInsets.symmetric(vertical: widget.deviceHeight * 0.02), padding: EdgeInsets.symmetric(
vertical: widget.deviceHeight * 0.02,
),
child: TextField( child: TextField(
autocorrect: false, autocorrect: false,
style: TextStyle( style: TextStyle(
@@ -90,11 +91,11 @@ class _SearchPageState extends State<SearchPage> {
Widget _searchPageUIList() { Widget _searchPageUIList() {
return StreamBuilder<List<User>>( return StreamBuilder<List<User>>(
stream: MessagingProviders.instance.getAllUsers(_searchText.trim()), stream: _auth.getAllUsers(_searchText.trim()),
builder: (_, _snapshot) { builder: (_, _snapshot) {
if (_snapshot.hasData) { if (_snapshot.hasData) {
_usersData = _snapshot.data! _usersData = _snapshot.data!
.where((_data) => _data.id != widget._auth.user!.$id) .where((_data) => _data.id != _auth.user!.$id)
.toList(); .toList();
} }
return _snapshot.hasData return _snapshot.hasData
@@ -114,46 +115,21 @@ class _SearchPageState extends State<SearchPage> {
return ListTile( return ListTile(
enabled: true, enabled: true,
onTap: () async { onTap: () async {
String _chatId; List _linkId = [
String _linkId = _auth.user!.$id.substring(0, 18),
'${widget._auth.user!.$id}${_userData.id}'; _userData.id.substring(0, 18)
_chatId = await MessagingProviders.instance
.getConversationLink(
_linkId.substring(0, 36));
if (_chatId.isEmpty) {
List<dynamic> _members = [
widget._auth.user!.$id,
_userData.id
]; ];
_linkId.sort();
List<String> messagesTemp = [];
messagesTemp = [
json.encode({
widget._auth.user!.$id: [],
}),
json.encode({
_userData.id: [],
})
];
Map<String, dynamic> _chat = {
"ownerId": widget._auth.user!.$id,
"members": _members,
"messages": messagesTemp
};
_chatId = await MessagingProviders.instance
.newMesaage(_chat);
}
NavigationService.instance.navigateToRoute( NavigationService.instance.navigateToRoute(
MaterialPageRoute( MaterialPageRoute(
builder: (BuildContext _context) { builder: (BuildContext _context) {
return ConversationsPage( return ConversationsPage(
chatId: _chatId, chatId: _linkId.join(),
chatName: _userData.name, userId: _userData.id,
chatImage: _userData.image, userName: _userData.name,
userImage: _userData.image,
userEmail: _userData.email,
); );
}, },
), ),
@@ -172,8 +148,7 @@ class _SearchPageState extends State<SearchPage> {
), ),
), ),
trailing: Column( trailing: Column(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceEvenly,
MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
@@ -211,12 +186,11 @@ class _SearchPageState extends State<SearchPage> {
); );
}), }),
) )
: Container() : Container();
// : SpinKitWanderingCubes( // : SpinKitWanderingCubes(
// color: Colors.blue, // color: Colors.blue,
// size: 50.0, // size: 50.0,
// ); // );
;
}); });
} }
} }