Skip to content

Commit abbb0f4

Browse files
Wahid NasriWahid Nasri
Wahid Nasri
authored and
Wahid Nasri
committed
add group ui page
1 parent 6a47acf commit abbb0f4

File tree

5 files changed

+270
-7
lines changed

5 files changed

+270
-7
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
3+
import 'package:flutter_mqtt/abstraction/models/ContactChat.dart';
4+
import 'package:flutter_mqtt/db/appdata/AppData.dart';
5+
import 'package:flutter_mqtt/ui/widgets/avatar_cancellable.dart';
6+
7+
class CreateGroupPage extends StatefulWidget {
8+
const CreateGroupPage({Key? key}) : super(key: key);
9+
10+
@override
11+
_CreateGroupPageState createState() => _CreateGroupPageState();
12+
}
13+
14+
class _CreateGroupPageState extends State<CreateGroupPage> {
15+
int globalCount = 0;
16+
List<ContactChat> selected = List<ContactChat>.empty(growable: true);
17+
TextEditingController _groupNameController = TextEditingController();
18+
19+
int maxNameLength = 25;
20+
int currentNameLength = 0;
21+
@override
22+
Widget build(BuildContext context) {
23+
return Scaffold(
24+
appBar: AppBar(
25+
centerTitle: false,
26+
title: Column(
27+
mainAxisAlignment: MainAxisAlignment.start,
28+
crossAxisAlignment: CrossAxisAlignment.start,
29+
children: [
30+
Text("New Group"),
31+
Text(selected.length.toString() + "/" + globalCount.toString())
32+
],
33+
),
34+
),
35+
body: Column(
36+
children: [
37+
_groupNameView(),
38+
Divider(),
39+
_selectedView(),
40+
Expanded(child: _contactsView())
41+
],
42+
),
43+
floatingActionButton: Visibility(
44+
child: FloatingActionButton.extended(
45+
onPressed: () {},
46+
label: Text("Continue"),
47+
icon: Icon(Icons.arrow_right_alt_outlined)),
48+
visible: selected.length > 0),
49+
);
50+
}
51+
52+
Widget _groupNameView() {
53+
return Padding(
54+
padding: const EdgeInsets.all(8.0),
55+
child: Row(
56+
crossAxisAlignment: CrossAxisAlignment.center,
57+
children: [
58+
CircleAvatar(
59+
child: Icon(
60+
Icons.group_sharp,
61+
size: 30,
62+
),
63+
radius: 30,
64+
),
65+
SizedBox(width: 5),
66+
Expanded(
67+
child: TextField(
68+
controller: _groupNameController,
69+
maxLength: maxNameLength,
70+
onChanged: (txt) {
71+
setState(() {
72+
currentNameLength = txt.length;
73+
});
74+
},
75+
decoration: InputDecoration(
76+
border: InputBorder.none,
77+
hintText: 'Group Name',
78+
counterText: "",
79+
suffixText:
80+
'${currentNameLength.toString()}/${maxNameLength.toString()}',
81+
),
82+
))
83+
],
84+
),
85+
);
86+
}
87+
88+
Widget _contactsView() {
89+
return StreamBuilder<List<ContactChat>>(
90+
stream: AppData.instance()!.contactsHandler.getContacts(),
91+
builder: (context, snapshot) {
92+
if (snapshot.hasError) {
93+
return Text(snapshot.error.toString());
94+
}
95+
if (snapshot.hasData) {
96+
var chats = snapshot.data;
97+
globalCount = chats != null ? chats.length : 0;
98+
return Column(
99+
crossAxisAlignment: CrossAxisAlignment.start,
100+
children: [
101+
Padding(
102+
padding: const EdgeInsets.all(8.0),
103+
child: Text("Select your group members",
104+
style: TextStyle(
105+
fontWeight: FontWeight.bold,
106+
fontSize: 23,
107+
color: Colors.grey)),
108+
),
109+
Expanded(
110+
child: ListView.builder(
111+
itemCount: chats!.length,
112+
itemBuilder: (context, position) {
113+
return InkWell(
114+
onTap: () {
115+
_toggleSelection(chats[position]);
116+
},
117+
child: ListTile(
118+
title: Text(chats[position].firstName +
119+
" " +
120+
chats[position].lastName),
121+
subtitle: Text("Room: " + chats[position].roomId),
122+
leading: AvatarWithBadge(
123+
radius: 25,
124+
badgeRadius: 8,
125+
foregroundImage: NetworkImage(
126+
chats[position].avatar ?? "",
127+
),
128+
showBadge: selected.where((element) => element.id == chats[position].id).length > 0,
129+
),
130+
131+
),
132+
);
133+
}),
134+
),
135+
],
136+
);
137+
} else {
138+
return Text("Loading...");
139+
}
140+
});
141+
}
142+
143+
Widget _selectedView() {
144+
return Align(
145+
child: Column(
146+
children: [
147+
AnimatedContainer(
148+
curve: Curves.fastOutSlowIn,
149+
duration: Duration(milliseconds: 400),
150+
height: selected.length > 0 ? 80 : 0,
151+
child: ListView.builder(
152+
scrollDirection: Axis.horizontal,
153+
itemCount: selected.length,
154+
itemBuilder: (context, index) {
155+
return AvatarWithBadge(
156+
title: selected[index].firstName,
157+
foregroundImage: NetworkImage(selected[index].avatar ?? ""),
158+
onTap: () {
159+
_toggleSelection(selected[index]);
160+
},
161+
);
162+
return Container();
163+
}),
164+
),
165+
AnimatedOpacity(
166+
duration: Duration(milliseconds: 500),
167+
opacity: selected.length > 0 ? 1 : 0,
168+
child: Divider(),
169+
),
170+
],
171+
),
172+
alignment: Alignment.topCenter,
173+
);
174+
}
175+
176+
_toggleSelection(ContactChat contactChat) {
177+
bool alreadySelected =
178+
selected.where((element) => element.id == contactChat.id).isNotEmpty;
179+
if (alreadySelected) {
180+
setState(() {
181+
selected = selected
182+
.where((element) => element.id != contactChat.id)
183+
.toList(growable: true);
184+
});
185+
} else {
186+
setState(() {
187+
selected.add(contactChat);
188+
});
189+
}
190+
}
191+
}

lib/ui/screens/fromdb/profile_page.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@ class ProfilePage extends StatelessWidget {
3737
SizedBox(
3838
height: 50,
3939
),
40-
CircleAvatar(
41-
foregroundImage: NetworkImage(user.avatar ?? ""),
42-
radius: 100,
40+
Hero(
41+
tag: "my_avatar",
42+
child: CircleAvatar(
43+
foregroundImage: NetworkImage(user.avatar ?? ""),
44+
radius: 100,
45+
),
4346
),
4447
SizedBox(
4548
height: 20,

lib/ui/screens/main/main_screen.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ class _MainScreenState extends State<MainScreen> {
4949
},
5050
child: Padding(
5151
padding: const EdgeInsets.all(8.0),
52-
child: CircleAvatar(
53-
foregroundImage: NetworkImage(snapshot.data!.avatar ??
54-
"https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png"),
52+
child: Hero(
53+
tag: "my_avatar",
54+
child: CircleAvatar(
55+
foregroundImage: NetworkImage(snapshot.data!.avatar ??
56+
"https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png"),
57+
),
5558
),
5659
),
5760
);

lib/ui/views/new_chat_view.dart

Lines changed: 8 additions & 1 deletion
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/screens/fromdb/create_group_page.dart';
67
import 'package:uuid/uuid.dart';
78

89
enum ViewState { CONTACTS, INVITATIONS }
@@ -121,7 +122,13 @@ class _NewChatViewState extends State<NewChatView> {
121122
);
122123
}
123124

124-
void _createGroupTap() {}
125+
void _createGroupTap() {
126+
Navigator.pop(context);
127+
Navigator.push(
128+
context,
129+
MaterialPageRoute(builder: (context) => CreateGroupPage()),
130+
);
131+
}
125132

126133
void _inviteTap() {
127134
setState(() {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'package:flutter/material.dart';
2+
3+
class AvatarWithBadge extends StatelessWidget {
4+
final String? title;
5+
final Function()? onTap;
6+
final ImageProvider<Object>? foregroundImage;
7+
final double? radius;
8+
final bool showBadge;
9+
final Widget? badgeWidget;
10+
final double? badgeRadius;
11+
const AvatarWithBadge(
12+
{Key? key, this.title, this.onTap, this.foregroundImage, this.radius, this.showBadge = true, this.badgeWidget, this.badgeRadius})
13+
: super(key: key);
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
return InkWell(
18+
onTap: onTap,
19+
child: Column(
20+
children: [
21+
Padding(
22+
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
23+
child: Stack(
24+
children: [
25+
CircleAvatar(
26+
foregroundImage: foregroundImage,
27+
radius: radius ?? 30,
28+
),
29+
_buildBadge()
30+
],
31+
),
32+
),
33+
title != null ? Text(title!) : SizedBox()
34+
],
35+
),
36+
);
37+
}
38+
Widget _buildBadge(){
39+
if(showBadge){
40+
if(badgeWidget != null){
41+
return badgeWidget!;
42+
}
43+
return Positioned(
44+
child: CircleAvatar(
45+
backgroundColor: Colors.grey,
46+
radius: badgeRadius ?? 11,
47+
child: Icon(
48+
Icons.clear,
49+
color: Colors.white,
50+
size: 13,
51+
),
52+
),
53+
bottom: 0,
54+
right: 0,
55+
);
56+
}
57+
return SizedBox();
58+
}
59+
}

0 commit comments

Comments
 (0)