Recent Conversations Page, Conversations Page implemented'

This commit is contained in:
2025-02-16 18:37:42 +00:00
parent 7e33872886
commit 1a74d16d85
17 changed files with 707 additions and 150 deletions
+1 -1
View File
@@ -2,6 +2,6 @@
# A chat app built using Flutter for Both iOS and Android.
Backend is being covered by Appwrite. It is opensource and can be selfhosted, which is the main reason for it being used a backend.
Backend is being covered by Appwrite. It is opensource and can be selfhosted, which is the main reason for it being used as a backend.
+12 -8
View File
@@ -1,10 +1,14 @@
//const endPoint = 'http://10.15.45.11/v1';
//const endPoint = 'https://api.theonasanyas.com/v1';
const endPoint = 'https://cloud.appwrite.io/v1';
const projectId = '678bdc7c00203eff8af5';
const selfSigned = false;
const databaseId = '678c8659000a7d6b5bff';
const userCollectionId = '678c865e002fe1cddd06';
const chatsCollectionId = '678c866c0038822276ad';
const convCollectionId = '678c8667001944dee794';
const imageStorageBucket = '678d2162002a6770aaad';
class Constants {
static Constants instance = Constants();
var endPoint = 'https://cloud.appwrite.io/v1';
var projectId = '678bdc7c00203eff8af5';
var selfSigned = false;
var databaseId = '678c8659000a7d6b5bff';
var userCollectionId = '678c865e002fe1cddd06';
var chatsCollectionId = '678c866c0038822276ad';
var convCollectionId = '678c8667001944dee794';
var imageStorageBucket = '678d2162002a6770aaad';
}
+66 -15
View File
@@ -4,6 +4,7 @@ import 'package:appwrite/models.dart' as model;
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:messaging_app/components/constants.dart';
import 'package:messaging_app/models/chats.dart';
import 'package:messaging_app/models/conversations.dart';
import 'package:messaging_app/models/users.dart';
import 'package:messaging_app/service/navigation_service.dart';
@@ -25,9 +26,8 @@ class MessagingProviders extends ChangeNotifier {
late final Storage storage;
// Auth Status
late AuthStatus status;
AuthStatus? status;
late model.User? user;
late model.Session session;
static MessagingProviders instance = MessagingProviders();
@@ -37,7 +37,10 @@ class MessagingProviders extends ChangeNotifier {
}
_init() {
client.setEndpoint(endPoint).setProject(projectId).setSelfSigned();
client
.setEndpoint(Constants.instance.endPoint)
.setProject(Constants.instance.projectId)
.setSelfSigned();
account = Account(client);
database = Databases(client);
storage = Storage(client);
@@ -48,6 +51,7 @@ class MessagingProviders extends ChangeNotifier {
user = await account.get();
if (user != null) {
status = AuthStatus.authenticated;
await updateLastSeen();
_autoLogin();
}
} catch (e) {
@@ -69,13 +73,14 @@ class MessagingProviders extends ChangeNotifier {
try {
status = AuthStatus.authenticating;
session = await account.createEmailPasswordSession(
await account.createEmailPasswordSession(
email: _email, password: _password);
user = await account.get();
status = AuthStatus.authenticated;
SnackBarService.instance.showSnackBarSuccess("Welcome! ${user!.name}");
await updateLastSeen();
NavigationService.instance.navigateToReplacement("home");
} on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!);
@@ -109,7 +114,7 @@ class MessagingProviders extends ChangeNotifier {
}
Future<void> createUser(String _email, String _password, String _name,
Future<void> onSuccess(String _uid)) async {
Future<void> Function(String _uid) onSuccess) async {
notifyListeners();
try {
user = await account.create(
@@ -118,6 +123,7 @@ class MessagingProviders extends ChangeNotifier {
status = AuthStatus.authenticated;
await onSuccess(user!.$id);
SnackBarService.instance.showSnackBarSuccess("Welcome! ${user!.name}");
await updateLastSeen();
NavigationService.instance.goBack();
NavigationService.instance.navigateToReplacement("home");
} on AppwriteException catch (e) {
@@ -136,8 +142,8 @@ class MessagingProviders extends ChangeNotifier {
notifyListeners();
try {
await database.createDocument(
databaseId: databaseId,
collectionId: userCollectionId,
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.userCollectionId,
documentId: _documentId,
data: {
"name": _name,
@@ -166,18 +172,51 @@ class MessagingProviders extends ChangeNotifier {
notifyListeners();
}
Future<void> updateLastSeen() async {
await database.updateDocument(
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.userCollectionId,
documentId: user!.$id,
data: {"lastSeen": DateTime.now().toUtc().toIso8601String()},
);
}
Stream<Users> getUser(String userId) {
var _userData = database.getDocument(
databaseId: databaseId,
collectionId: userCollectionId,
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.userCollectionId,
documentId: userId,
);
return _userData.asStream().map((_snapshot) {
return Users.fromData(_snapshot);
return _userData.asStream().map((_document) {
return Users.fromData(_document);
});
}
Stream<List<Users>> getAllUsers(String _searchText) {
List<Users> _returnValue = [];
if (_searchText.isNotEmpty) {
var _usersData = database.listDocuments(
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.userCollectionId,
queries: [
Query.contains("name", _searchText),
],
);
return _usersData.asStream().map(
(_documentList) {
for (var _document in _documentList.documents) {
_returnValue.add(Users.fromData(_document));
}
return _returnValue;
},
);
} else {
return Stream.empty();
}
}
Stream<List<Conversations>> getUserConversation(String userId) {
//
List<dynamic> _chatId = [];
@@ -185,8 +224,8 @@ class MessagingProviders extends ChangeNotifier {
List<Conversations> _returnValue = [];
var _conversationData = database.getDocument(
databaseId: databaseId,
collectionId: convCollectionId,
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.convCollectionId,
documentId: userId.trim(),
);
@@ -203,12 +242,24 @@ class MessagingProviders extends ChangeNotifier {
);
}
Stream<Chats> getChat(String _chatId) {
var _chat = database.getDocument(
databaseId: Constants.instance.databaseId,
collectionId: Constants.instance.chatsCollectionId,
documentId: _chatId,
);
return _chat.asStream().map((_document) {
return Chats.fromData(_document);
});
}
uploadUserImage(XFile? file, String _uid) async {
notifyListeners();
try {
File _file = File(file!.path);
var _message = await storage.createFile(
bucketId: imageStorageBucket,
bucketId: Constants.instance.imageStorageBucket,
fileId: ID.unique(),
file: InputFile.fromPath(path: _file.path, filename: file.name),
permissions: [
@@ -217,7 +268,7 @@ class MessagingProviders extends ChangeNotifier {
],
);
return "$endPoint/storage/buckets/${_message.bucketId}/files/${_message.$id}/view?project=$projectId";
return "${Constants.instance.endPoint}/storage/buckets/${_message.bucketId}/files/${_message.$id}/view?project=${Constants.instance.projectId}";
} on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!);
//
+38
View File
@@ -0,0 +1,38 @@
import 'package:appwrite/models.dart';
import 'package:messaging_app/models/messages.dart';
class Chats {
String ownerId;
List<String> members;
String? type;
List<Messages>? messages;
Chats({
required this.ownerId,
required this.members,
required this.type,
required this.messages,
});
factory Chats.fromData(Document _document) {
List<Messages> _outMessages = [];
List<String> _outMembers = [];
List<dynamic> _messages = _document.data['messages'];
for (var _message in _messages) {
_outMessages.add(Messages.fromData(_message));
}
List<dynamic> _members = _document.data['members'];
for (var _member in _members) {
_outMembers.add(_member);
}
return Chats(
ownerId: _document.data['ownerId'],
members: _outMembers,
type: _document.data['type'],
messages: _outMessages,
);
}
}
+2 -2
View File
@@ -9,10 +9,10 @@ class Conversations {
required this.details,
});
factory Conversations.fromData(String _chatId, String details) {
factory Conversations.fromData(String _chatId, String _details) {
return Conversations(
chatId: _chatId,
details: Details.fromData(details),
details: Details.fromData(_details),
);
}
}
+8 -9
View File
@@ -3,8 +3,8 @@ import 'dart:convert';
class Details {
String name;
String image;
int? unseenCount;
String lastMessage;
int unseenCount;
String? lastMessage;
DateTime? timeStamp;
Details({
@@ -15,14 +15,13 @@ class Details {
required this.unseenCount,
});
factory Details.fromData(String _data) {
Map _decodedData = json.decode(_data);
factory Details.fromData(String _details) {
return Details(
name: _decodedData['name'],
image: _decodedData['image'],
lastMessage: _decodedData['lastMessage'],
timeStamp: DateTime.parse(_decodedData['timeStamp'] ?? ""),
unseenCount: _decodedData['unseenCount'],
name: json.decode(_details)['name'],
image: json.decode(_details)['image'],
lastMessage: json.decode(_details)['lastMessage'],
timeStamp: DateTime.parse(json.decode(_details)['timeStamp'] ?? ""),
unseenCount: json.decode(_details)['unseenCount'],
);
}
}
+33
View File
@@ -0,0 +1,33 @@
import 'dart:convert';
enum MessageType {
Text,
Image,
}
class Messages {
String message;
String senderId;
MessageType type;
DateTime timeStamp;
Messages({
required this.message,
required this.senderId,
required this.type,
required this.timeStamp,
});
factory Messages.fromData(String _message) {
var _messageType = json.decode(_message)['type'] == "text"
? MessageType.Text
: MessageType.Image;
return Messages(
message: json.decode(_message)['message'],
senderId: json.decode(_message)['senderId'],
type: _messageType,
timeStamp: DateTime.parse(json.decode(_message)['timeStamp'] ?? ""),
);
}
}
+8 -6
View File
@@ -1,25 +1,27 @@
import 'package:appwrite/models.dart';
class Users {
String id;
String name;
String email;
String image;
DateTime lastSeen;
Users({
required this.id,
required this.name,
required this.email,
required this.image,
required this.lastSeen,
});
factory Users.fromData(Document _snapshot) {
factory Users.fromData(Document _document) {
return Users(
name: _snapshot.data["name"],
email: _snapshot.data["email"],
image: _snapshot.data["image"],
lastSeen: DateTime.parse(_snapshot.data["lastSeen"]),
id: _document.data['\$id'],
name: _document.data['name'],
email: _document.data['email'],
image: _document.data['image'],
lastSeen: DateTime.parse(_document.data['lastSeen']),
);
}
}
+234
View File
@@ -0,0 +1,234 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/chats.dart';
import 'package:messaging_app/models/messages.dart';
import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
class ConversationsPage extends StatefulWidget {
ConversationsPage({
super.key,
required this.conversationId,
// required this.receiverId,
required this.chatImage,
required this.chatName,
});
String conversationId;
// String receiverId;
String chatName;
String chatImage;
@override
State<StatefulWidget> createState() {
return _ConversationsPageState();
}
}
class _ConversationsPageState extends State<ConversationsPage> {
//
late double _deviceHeight;
late double _deviceWidth;
late MessagingProviders _auth;
@override
Widget build(BuildContext context) {
//
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text(widget.chatName),
titleTextStyle: TextStyle(fontSize: 16),
),
body: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance,
child: _conversationPageUI(),
),
);
}
Widget _conversationPageUI() {
return Builder(builder: (_context) {
_auth = Provider.of<MessagingProviders>(_context);
return Stack(
clipBehavior: Clip.none,
children: [
_messageListView(),
_messageInputField(_context),
],
);
});
}
Widget _messageListView() {
return Container(
height: _deviceHeight * 0.75,
width: _deviceWidth,
child: StreamBuilder<Chats>(
stream: MessagingProviders.instance.getChat(widget.conversationId),
builder: (_context, _snapshot) {
return _snapshot.hasData
? ListView.builder(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
itemCount: _snapshot.data!.messages!.length,
itemBuilder: (BuildContext _context, int _index) {
var _message = _snapshot.data!.messages![_index];
return _messageView(_message);
},
)
: Text("");
}),
);
}
Widget _messageView(Messages _message) {
bool _isOwnMessage = false;
if (_message.senderId == _auth.user!.$id) {
_isOwnMessage = true;
}
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment:
_isOwnMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
_isOwnMessage ? Container() : _imageViewBubble(),
_textMessageBubble(_isOwnMessage, _message),
],
),
);
}
Widget _textMessageBubble(bool _isOwnMessage, Messages _message) {
List<Color> _colorScheme = _isOwnMessage
? [Colors.blue, Color.fromRGBO(42, 117, 188, 1)]
: [Color.fromRGBO(49, 69, 69, 1), Color.fromRGBO(43, 43, 43, 1)];
return Container(
height: _deviceHeight * 0.10,
width: _deviceWidth * 0.75,
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: LinearGradient(
colors: _colorScheme,
stops: [0.25, 0.85],
begin: Alignment.bottomLeft,
end: Alignment.bottomRight),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_message.message),
Text(
timeago.format(_message.timeStamp),
style: TextStyle(
color: Colors.white70,
),
),
],
),
);
}
Widget _imageViewBubble() {
return Container(
height: _deviceHeight * 0.05,
width: _deviceHeight * 0.05,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(500),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
widget.chatImage,
),
),
),
);
}
Widget _messageInputField(BuildContext _context) {
return Align(
alignment: Alignment.bottomCenter,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: [
_messageText(),
_imageUpload(),
_sendMessage(_context),
],
),
);
}
Widget _messageText() {
return Container(
padding: EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: Color.fromRGBO(43, 43, 43, 1),
borderRadius: BorderRadius.circular(30)
),
margin: EdgeInsets.symmetric(
horizontal: _deviceWidth * 0.04,
vertical: _deviceHeight * 0.02
),
width: _deviceWidth * 0.70,
child: TextFormField(
validator: (_input) {
if (_input == null) {
return "";
}
},
onChanged: (_input) {
//
},
onSaved: (_input) {
//
},
cursorColor: Colors.white,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "type a message",
),
autocorrect: false,
),
);
}
Widget _sendMessage(BuildContext context) {
return Container(
height: _deviceHeight * 0.045,
width: _deviceHeight * 0.045,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.send,
color: Colors.white,
),
),
);
}
Widget _imageUpload() {
return SizedBox(
height: _deviceHeight * 0.045,
width: _deviceHeight * 0.045,
child: FloatingActionButton(onPressed: () {},
backgroundColor: Colors.blue,
child: Icon(Icons.camera_enhance),),
);
}
}
+11 -9
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/pages/profile_page.dart';
import 'package:messaging_app/pages/recent_converstations.dart';
import 'package:messaging_app/pages/recent_converstations_page.dart';
import 'package:messaging_app/pages/search_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@@ -14,10 +15,11 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
//TickerProviderStateMixin
// //
late double _deviceHeight;
late double _deviceWidth;
late TabController _tabController;
late final TabController _tabController;
@override
void initState() {
@@ -42,10 +44,10 @@ class _HomePageState extends State<HomePage>
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text("Slick Messenger"),
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text("the messenger"),
titleTextStyle: TextStyle(fontSize: 16),
bottom: TabBar(
unselectedLabelColor: Colors.grey,
@@ -56,19 +58,19 @@ class _HomePageState extends State<HomePage>
Tab(
icon: Icon(
Icons.people_outline,
size: 25,
size: 30,
),
),
Tab(
icon: Icon(
Icons.chat_bubble_outline,
size: 25,
size: 30,
),
),
Tab(
icon: Icon(
Icons.person_outline,
size: 25,
size: 30,
),
),
],
@@ -82,7 +84,7 @@ class _HomePageState extends State<HomePage>
return TabBarView(
controller: _tabController,
children: [
Placeholder(),
SearchPage( deviceHeight: _deviceHeight , deviceWidth: _deviceWidth,),
RecentConverstationsPage(_deviceHeight, _deviceWidth),
ProfilePage(_deviceHeight, _deviceWidth),
],
+1 -1
View File
@@ -176,7 +176,7 @@ class _LoginPageState extends State<LoginPage> {
},
color: Colors.blue,
child: Text(
'Login'.toUpperCase(),
'LOGIN',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
+3
View File
@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/users.dart';
import 'package:messaging_app/service/snackbar_service.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class ProfilePage extends StatelessWidget {
//
@@ -27,6 +29,7 @@ class ProfilePage extends StatelessWidget {
Widget _profilePageUI() {
return Builder(builder: (BuildContext _context) {
SnackBarService.instance.buildContext = _context;
_auth = Provider.of<MessagingProviders>(_context);
return StreamBuilder<Users>(
stream: MessagingProviders.instance.getUser(_auth.user!.$id),
-95
View File
@@ -1,95 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/conversations.dart';
import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
class RecentConverstationsPage extends StatelessWidget {
//
final double _deviceHeight;
final double _deviceWidth;
late MessagingProviders _auth;
RecentConverstationsPage(this._deviceHeight, this._deviceWidth);
@override
Widget build(BuildContext context) {
return Container(
height: _deviceHeight,
width: _deviceWidth,
child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance,
child: _conversationView(),
),
);
}
Widget _conversationView() {
return Builder(builder: (_context) {
_auth = Provider.of<MessagingProviders>(_context);
return Container(
height: _deviceHeight,
width: _deviceWidth,
child: StreamBuilder<List<Conversations>>(
stream: MessagingProviders.instance
.getUserConversation(_auth.user!.$id),
builder: (_, _snapshot) {
return _snapshot.hasData
? ListView.builder(
itemCount: _snapshot.data!.length,
itemBuilder: (_context, _index) {
var _details = _snapshot.data![_index].details;
return ListTile(
onTap: () {
//
},
title: Text(_details.name),
subtitle: Text(_details.lastMessage),
leading: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_details.image),
),
),
),
trailing: _listTrailingWidget(_details.timeStamp),
);
},
)
: SpinKitWanderingCubes(
color: Colors.blue,
size: 50.0,
);
}),
);
});
}
Widget _listTrailingWidget(DateTime? _date) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
timeago.format(_date!),
style: TextStyle(fontSize: 15),
),
Container(
height: 12,
width: 12,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(100),
),
)
],
);
}
}
+120
View File
@@ -0,0 +1,120 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/conversations.dart';
import 'package:messaging_app/pages/conversations_page.dart';
import 'package:messaging_app/service/navigation_service.dart';
import 'package:messaging_app/service/snackbar_service.dart';
import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
// ignore: must_be_immutable
class RecentConverstationsPage extends StatelessWidget {
//
final double _deviceHeight;
final double _deviceWidth;
late MessagingProviders _auth;
RecentConverstationsPage(this._deviceHeight, this._deviceWidth);
@override
Widget build(BuildContext context) {
return Container(
height: _deviceHeight,
width: _deviceWidth,
child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance,
child: _conversationView(),
),
);
}
Widget _conversationView() {
return Builder(builder: (_context) {
SnackBarService.instance.buildContext = _context;
_auth = Provider.of<MessagingProviders>(_context);
return SizedBox(
height: _deviceHeight,
width: _deviceWidth,
child: StreamBuilder<List<Conversations>>(
stream: MessagingProviders.instance
.getUserConversation(_auth.user!.$id),
builder: (_, _snapshot) {
if (_snapshot.hasData) {
return ListView.builder(
itemCount: _snapshot.data!.length,
itemBuilder: (_context, _index) {
var _details = _snapshot.data![_index].details;
var _chatId = _snapshot.data![_index].chatId;
return ListTile(
onTap: () {
//
NavigationService.instance.navigateToRoute(
MaterialPageRoute(
builder: (BuildContext _context) {
return ConversationsPage(
conversationId: _chatId,
chatName: _details.name,
chatImage: _details.image,
);
},
),
);
},
title: Text(_details.name),
subtitle: Text(_details.lastMessage!),
leading: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_details.image),
),
),
),
trailing: _listTrailingWidget(_details.timeStamp),
);
},
);
}
if (_snapshot.hasError) {
return Align(
child: Text(
"no active conversation",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
);
} else {
return SpinKitWanderingCubes(
color: Colors.blue,
size: 50.0,
);
}
}),
);
});
}
Widget _listTrailingWidget(DateTime? _date) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"last message",
style: TextStyle(fontSize: 15),
),
Text(
timeago.format(_date!),
style: TextStyle(fontSize: 15),
)
],
);
}
}
+2 -2
View File
@@ -226,7 +226,7 @@ class _RegisterationPageState extends State<RegisterationPage> {
onPressed: () {
if (_image == null) {
SnackBarService.instance
.showSnackBarError("Please Select Image");
.showSnackBarError("Please Select an Image");
}
if (_formKey.currentState!.validate() && _image != null) {
//
@@ -247,7 +247,7 @@ class _RegisterationPageState extends State<RegisterationPage> {
},
color: Colors.blue,
child: Text(
'Register'.toUpperCase(),
"REGISTER",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
+168
View File
@@ -0,0 +1,168 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/models/users.dart';
import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
class SearchPage extends StatefulWidget {
SearchPage({
super.key,
required this.deviceHeight,
required this.deviceWidth,
});
double deviceHeight;
double deviceWidth;
late MessagingProviders _auth;
@override
State<SearchPage> createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
late String _searchText;
late List<Users> _usersData;
@override
void initState() {
super.initState();
_searchText = '';
_usersData = [];
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: widget.deviceHeight,
width: widget.deviceWidth,
child: ChangeNotifierProvider.value(
value: MessagingProviders.instance,
child: _searchPaheUI(),
),
);
}
Widget _searchPaheUI() {
return Builder(builder: (_context) {
widget._auth = Provider.of<MessagingProviders>(_context);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_searchPageUIField(),
_searchPageUIList(),
],
);
});
}
Widget _searchPageUIField() {
return Container(
height: widget.deviceHeight * 0.08,
width: widget.deviceWidth,
padding: EdgeInsets.symmetric(vertical: widget.deviceHeight * 0.02),
child: TextField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
onChanged: (_input) {
setState(() {
_searchText = _input;
});
},
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
labelText: "search",
labelStyle: TextStyle(color: Colors.white),
border: OutlineInputBorder(borderSide: BorderSide.none),
),
),
);
}
Widget _searchPageUIList() {
return StreamBuilder<List<Users>>(
stream: MessagingProviders.instance.getAllUsers(_searchText.trim()),
builder: (_, _snapshot) {
if (_snapshot.hasData) {
_usersData = _snapshot.data!
.where((_data) => _data.id != widget._auth.user!.$id)
.toList();
}
return _snapshot.hasData
? SizedBox(
height: widget.deviceHeight * 0.70,
child: ListView.builder(
itemCount: _usersData.length,
itemBuilder: (_, _index) {
var _userData = _usersData[_index];
var _isUserActive = _userData.lastSeen.isBefore(
DateTime.now().toUtc().subtract(
Duration(
minutes: 1,
),
),
);
return ListTile(
title: Text(_userData.name),
leading: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_userData.image),
),
),
),
trailing: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
_isUserActive
? Text(
"last seen",
style: TextStyle(
fontSize: 15,
),
)
: Text(
"active",
style: TextStyle(
fontSize: 15,
),
),
_isUserActive
? Text(
timeago.format(
_userData.lastSeen,
),
style: TextStyle(fontSize: 15),
)
: Container(
height: 10,
width: 10,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius:
BorderRadius.circular(100),
),
)
],
),
);
}),
)
: Container()
// : SpinKitWanderingCubes(
// color: Colors.blue,
// size: 50.0,
// );
;
});
}
}
-2
View File
@@ -6,8 +6,6 @@ class SnackBarService {
BuildContext? _buildContext;
static SnackBarService instance = SnackBarService();
SnackBarService() {}
set buildContext(BuildContext _context) {
_buildContext = _context;
}