Skip to content

Commit e4f54cd

Browse files
Wahid NasriWahid Nasri
Wahid Nasri
authored and
Wahid Nasri
committed
group chat ui and bug fixes
1 parent ad56c84 commit e4f54cd

File tree

10 files changed

+179
-60
lines changed

10 files changed

+179
-60
lines changed

lib/db/appdata/ContactsHandler.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ import 'package:flutter_mqtt/db/database.dart';
33
import 'package:flutter_mqtt/db/appdata/extensions/MessagesExtensions.dart';
44

55
class ContactsHandler {
6+
Stream<List<ContactChat>> getGroups() {
7+
var stream = MyDatabase.instance()!.contactDao.getAllGroupsAsync().map(
8+
(dbContacts) => dbContacts.map((dc) => dc.toContactChat()).toList());
9+
return stream;
10+
}
11+
Stream<List<ContactChat>> getContactsAndGroups() {
12+
var stream = MyDatabase.instance()!.contactDao.getAllContactsAndGroupsAsync().map(
13+
(dbContacts) => dbContacts.map((dc) => dc.toContactChat()).toList());
14+
return stream;
15+
}
616
Stream<List<ContactChat>> getContacts() {
717
var stream = MyDatabase.instance()!.contactDao.getAllContactsAsync().map(
818
(dbContacts) => dbContacts.map((dc) => dc.toContactChat()).toList());

lib/db/dao/contact_dao.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,21 @@ class ContactDao extends DatabaseAccessor<MyDatabase> with _$ContactDaoMixin {
1313
Future<int> addContact(DbContact cts) {
1414
return into(contacts).insertOnConflictUpdate(cts);
1515
}
16-
17-
Stream<List<DbContact>> getAllContactsAsync() {
16+
Stream<List<DbContact>> getAllContactsAndGroupsAsync() {
1817
return (select(contacts)).watch();
1918
}
19+
Stream<List<DbContact>> getAllContactsAsync() {
20+
return (select(contacts)..where((tbl) => tbl.isGroup.not())).watch();
21+
}
22+
Stream<List<DbContact>> getAllGroupsAsync() {
23+
return (select(contacts)..where((tbl) => tbl.isGroup)).watch();
24+
}
2025

2126
Future<List<DbContact>> getAllContacts() {
22-
return (select(contacts)).get();
27+
return (select(contacts)..where((tbl) => tbl.isGroup.not())).get();
28+
}
29+
Future<List<DbContact>> getAllGroups() {
30+
return (select(contacts)..where((tbl) => tbl.isGroup)).get();
2331
}
2432

2533
Future<void> deleteAllContacts() {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
3+
import 'package:flutter_mqtt/db/database.dart';
4+
import 'package:flutter_mqtt/ui/views/contact_avatar.dart';
5+
6+
class ContactOrGroupItem extends StatelessWidget {
7+
final ContactChat chat;
8+
final Function()? onTap;
9+
final Widget? subtitle;
10+
final Widget? trailing;
11+
const ContactOrGroupItem({Key? key, required this.chat, this.onTap, this.subtitle, this.trailing})
12+
: super(key: key);
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return InkWell(
17+
onTap: onTap,
18+
child: ListTile(
19+
title: Row(
20+
children: [
21+
(chat.isGroup ?? false
22+
? Padding(
23+
padding: const EdgeInsets.only(right: 8),
24+
child: Icon(Icons.group, size: 18),
25+
)
26+
: SizedBox()),
27+
Text(chat.firstName + " " + chat.lastName),
28+
],
29+
),
30+
subtitle: subtitle ?? Text("Room: " + chat.roomId),
31+
leading: Hero(tag: "avatar_" + chat.id, child: ContactAvatar(chat: chat)),
32+
trailing: trailing,
33+
),
34+
);
35+
}
36+
}

lib/ui/screens/fromdb/chat_db_pages.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:flutter_mqtt/global/ChatApp.dart';
1313
import 'package:flutter_mqtt/ui/screens/fromdb/contact_page.dart';
1414
import 'package:flutter_mqtt/ui/viewers/document_viewer.dart';
1515
import 'package:flutter_mqtt/ui/viewers/media_viewer.dart';
16+
import 'package:flutter_mqtt/ui/views/contact_avatar.dart';
1617
import 'package:flutter_mqtt/ui/widgets/message_typing.dart';
1718
import 'package:image_picker/image_picker.dart';
1819
import 'package:mime/mime.dart';
@@ -226,10 +227,7 @@ class _ChatUIPageState extends State<ChatUIDBPage> {
226227
padding: const EdgeInsets.only(right: 10),
227228
child: Hero(
228229
tag: "avatar_" + widget.contactChat.id,
229-
child: CircleAvatar(
230-
foregroundImage:
231-
NetworkImage(widget.contactChat.avatar ?? ""),
232-
radius: 15),
230+
child: ContactAvatar(chat: widget.contactChat, radius: 15,),
233231
),
234232
),
235233
Column(

lib/ui/screens/fromdb/contact_page.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_mqtt/abstraction/models/ChatMessage.dart';
33
import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
44
import 'package:flutter_mqtt/db/appdata/AppData.dart';
55
import 'package:flutter_mqtt/ui/screens/fromdb/media_messages_page.dart';
6+
import 'package:flutter_mqtt/ui/views/contact_avatar.dart';
67
import 'package:flutter_mqtt/ui/widgets/menu_action_item.dart';
78
import 'package:flutter_mqtt/ui/widgets/menu_action_item_switch.dart';
89

@@ -35,9 +36,9 @@ class _ContactDetailsPageState extends State<ContactDetailsPage> {
3536
tag: "avatar_" + widget.contactChat.id,
3637
child: Padding(
3738
padding: const EdgeInsets.all(20),
38-
child: CircleAvatar(
39-
foregroundImage:
40-
NetworkImage(widget.contactChat.avatar ?? ""),
39+
child: ContactAvatar(
40+
chat:
41+
widget.contactChat,
4142
radius: 100,
4243
),
4344
),

lib/ui/screens/main/chats_page.dart

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flutter_mqtt/db/appdata/AppData.dart';
44
import 'package:flutter_mqtt/db/database.dart';
55
import 'package:flutter_mqtt/db/tables/ExtendedDbContact.dart';
66
import 'package:flutter_mqtt/ui/extensions/UiMessages.dart';
7+
import 'package:flutter_mqtt/ui/items/contact_or_group_item.dart';
78
import 'package:flutter_mqtt/ui/screens/fromdb/chat_db_pages.dart';
89
import 'package:intl/intl.dart';
910

@@ -22,45 +23,46 @@ class ChatsPage extends StatelessWidget {
2223
return ListView.builder(
2324
itemCount: chats!.length,
2425
itemBuilder: (context, position) {
25-
var dt = DateTime.fromMillisecondsSinceEpoch(chats[position].send_time);
26-
return InkWell(
27-
onTap: () {
28-
_openRoom(context, chats[position].toContactChat());
29-
},
30-
child: ListTile(
31-
title: Text(chats[position].first_name +
32-
" " +
33-
chats[position].last_name),
26+
var dt = DateTime.fromMillisecondsSinceEpoch(
27+
chats[position].send_time);
28+
return ContactOrGroupItem(
29+
chat: chats[position].toContactChat(),
3430
subtitle: _subtitle(chats[position]),
35-
leading: ClipRRect(
36-
borderRadius: BorderRadius.circular(12.5),
37-
38-
child: Hero(
39-
tag: "avatar_" + chats[position].id,
40-
child: CircleAvatar(
41-
foregroundImage: NetworkImage( chats[position].avatar ??
42-
"https://complianz.io/wp-content/uploads/2019/03/placeholder-300x202.jpg",)
43-
),
44-
),
45-
),
46-
trailing: Text(DateFormat('HH:mm').format(dt)),//TODO: need more detailed formatting
47-
),
48-
);
31+
trailing: Text(DateFormat('HH:mm').format(dt)),
32+
onTap: () {
33+
_openRoom(context, chats[position].toContactChat());
34+
});
4935
});
5036
}
5137

5238
return Text("Loading..");
5339
});
5440
}
55-
Widget _subtitle(ExtendedDbContact chat){
56-
if(chat.message_type == "ChatImage"){
57-
return Row(children: [Icon(Icons.image, size: 15,), Text("Image")]);
58-
}
59-
else if(chat.message_type == "ChatDocument"){
60-
return Row(children: [Icon(Icons.attach_file_rounded, size: 15,), Text("File")]);
41+
42+
Widget _subtitle(ExtendedDbContact chat) {
43+
if (chat.message_type == "ChatImage") {
44+
return Row(children: [
45+
Icon(
46+
Icons.image,
47+
size: 15,
48+
),
49+
Text("Image")
50+
]);
51+
} else if (chat.message_type == "ChatDocument") {
52+
return Row(children: [
53+
Icon(
54+
Icons.attach_file_rounded,
55+
size: 15,
56+
),
57+
Text("File")
58+
]);
6159
}
62-
return Text(chat.message_text, maxLines: 1,);
60+
return Text(
61+
chat.message_text,
62+
maxLines: 1,
63+
);
6364
}
65+
6466
_openRoom(BuildContext context, ContactChat contact) {
6567
Navigator.push(
6668
context,

lib/ui/screens/main/groups_page.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
3+
import 'package:flutter_mqtt/db/appdata/AppData.dart';
4+
import 'package:flutter_mqtt/ui/items/contact_or_group_item.dart';
5+
import 'package:flutter_mqtt/ui/screens/fromdb/chat_db_pages.dart';
6+
7+
class GroupsPage extends StatelessWidget {
8+
const GroupsPage({Key? key}) : super(key: key);
9+
10+
@override
11+
Widget build(BuildContext context) {
12+
return StreamBuilder<List<ContactChat>>(
13+
stream: AppData.instance()!.contactsHandler.getGroups(),
14+
builder: (context, snapshot) {
15+
if (snapshot.hasError) {
16+
return Text(snapshot.error.toString());
17+
}
18+
if (snapshot.hasData) {
19+
final groups = snapshot.data;
20+
return ListView.builder(
21+
itemCount: groups!.length, itemBuilder: (context, position) {
22+
return ContactOrGroupItem(chat: groups[position], onTap: (){
23+
Navigator.push(
24+
context,
25+
MaterialPageRoute(
26+
builder: (context) => ChatUIDBPage(contactChat: groups[position])),
27+
);
28+
});
29+
});
30+
}
31+
return Container();
32+
});
33+
}
34+
}

lib/ui/screens/main/main_screen.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter_mqtt/ui/screens/fromdb/chat_db_pages.dart';
77
import 'package:flutter_mqtt/ui/screens/fromdb/profile_page.dart';
88
import 'package:flutter_mqtt/ui/screens/fromdb/rooms_db_page.dart';
99
import 'package:flutter_mqtt/ui/screens/main/chats_page.dart';
10+
import 'package:flutter_mqtt/ui/screens/main/groups_page.dart';
1011
import 'package:flutter_mqtt/ui/views/new_chat_view.dart';
1112
import 'package:salomon_bottom_bar/salomon_bottom_bar.dart';
1213
import 'package:flutter_mqtt/abstraction/models/enums/ConnectionState.dart'
@@ -25,7 +26,7 @@ class _MainScreenState extends State<MainScreen> {
2526
ChatsPage(
2627
key: UniqueKey(),
2728
),
28-
Center(child: Text("Groups")),
29+
Center(child: GroupsPage()),
2930
Center(child: Text("Calls")),
3031
ProfilePage(
3132
key: UniqueKey(),

lib/ui/views/contact_avatar.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
3+
4+
class ContactAvatar extends StatelessWidget {
5+
final ContactChat chat;
6+
final double? radius;
7+
const ContactAvatar({Key? key, required this.chat, this.radius})
8+
: super(key: key);
9+
10+
@override
11+
Widget build(BuildContext context) {
12+
if (chat.isGroup ?? false) {
13+
return chat.avatar != null
14+
? CircleAvatar(
15+
foregroundImage: NetworkImage(chat.avatar!),
16+
radius: radius ?? 20,
17+
)
18+
: CircleAvatar(
19+
child: Icon(
20+
Icons.group,
21+
size: radius ?? 25,
22+
),
23+
radius: radius ?? 20,
24+
);
25+
} else {
26+
return chat.avatar != null
27+
? CircleAvatar(
28+
foregroundImage: NetworkImage(
29+
chat.avatar!,
30+
),
31+
radius: radius ?? 20)
32+
: CircleAvatar(
33+
child: Icon(
34+
Icons.person,
35+
size: radius ?? 25,
36+
),
37+
radius: radius ?? 20);
38+
}
39+
}
40+
}

lib/ui/views/new_chat_view.dart

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
33
import 'package:flutter_mqtt/abstraction/models/enums/InvitationMessageType.dart';
44
import 'package:flutter_mqtt/db/appdata/AppData.dart';
55
import 'package:flutter_mqtt/global/ChatApp.dart';
6+
import 'package:flutter_mqtt/ui/items/contact_or_group_item.dart';
67
import 'package:flutter_mqtt/ui/screens/fromdb/create_group_page.dart';
78
import 'package:uuid/uuid.dart';
89

@@ -48,7 +49,7 @@ class _NewChatViewState extends State<NewChatView> {
4849

4950
Widget _contactsView() {
5051
return StreamBuilder<List<ContactChat>>(
51-
stream: AppData.instance()!.contactsHandler.getContacts(),
52+
stream: AppData.instance()!.contactsHandler.getContactsAndGroups(),
5253
builder: (context, snapshot) {
5354
if (snapshot.hasError) {
5455
return Text(snapshot.error.toString());
@@ -58,24 +59,12 @@ class _NewChatViewState extends State<NewChatView> {
5859
return ListView.builder(
5960
itemCount: chats!.length,
6061
itemBuilder: (context, position) {
61-
return InkWell(
62-
onTap: () {
63-
Navigator.pop(context);
64-
widget.openRoom!(chats[position]);
65-
},
66-
child: ListTile(
67-
title: Text(chats[position].firstName +
68-
" " +
69-
chats[position].lastName),
70-
subtitle: Row(children:[ (chats[position].isGroup??false ? Icon(Icons.group) : SizedBox()), Text("Room: " + chats[position].roomId)]),
71-
leading: CircleAvatar(
72-
foregroundImage: NetworkImage(
73-
chats[position].avatar ??
74-
"https://complianz.io/wp-content/uploads/2019/03/placeholder-300x202.jpg",
75-
),
76-
),
77-
),
78-
);
62+
return ContactOrGroupItem(
63+
chat: chats[position],
64+
onTap: () {
65+
Navigator.pop(context);
66+
widget.openRoom!(chats[position]);
67+
});
7968
});
8069
} else {
8170
return Text("Loading...");

0 commit comments

Comments
 (0)