Skip to content

Commit 8653a9b

Browse files
author
Abdelouahed
committed
lottie animation + clean some code
1 parent 94e5ef8 commit 8653a9b

File tree

10 files changed

+192
-160
lines changed

10 files changed

+192
-160
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"v":"5.5.8","fr":60,"ip":0,"op":110,"w":144,"h":105,"nm":"typing indicator","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"▽ Dots","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[72,51,0],"ix":2},"a":{"a":0,"k":[36,9,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"dot 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[9,9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":3.053,"s":[9,10,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":15.273,"s":[9,-9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":25.174,"s":[9,12,0],"to":[0,0,0],"ti":[0,0,0]},{"t":32.744140625,"s":[9,9,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[6,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.472],"y":[1]},"o":{"x":[1],"y":[0]},"t":0,"s":[0.690196078431,0.725490196078,0.752941176471,1]},{"i":{"x":[0.49],"y":[1]},"o":{"x":[1],"y":[0]},"t":15.273,"s":[0.349019616842,0.392156869173,0.427450984716,1]},{"t":32.072265625,"s":[0.690196078431,0.725490196078,0.752941176471,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"dot 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"dot 2","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10.691,"s":[36,9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":15.273,"s":[36,10,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":25.963,"s":[36,-9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":36.984,"s":[36,14.326,0],"to":[0,0,0],"ti":[0,0,0]},{"t":43.97265625,"s":[36,9,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[6,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.472],"y":[1]},"o":{"x":[1],"y":[0]},"t":10.691,"s":[0.690196078431,0.725490196078,0.752941176471,1]},{"i":{"x":[0.49],"y":[1]},"o":{"x":[1],"y":[0]},"t":25.963,"s":[0.349019616842,0.392156869173,0.427450984716,1]},{"t":42.763671875,"s":[0.690196078431,0.725490196078,0.752941176471,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"dot 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"dot 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":21.383,"s":[63,9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":25.963,"s":[63,10,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":38.184,"s":[63,-9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":49.594,"s":[63,13.139,0],"to":[0,0,0],"ti":[0,0,0]},{"t":56,"s":[63,9,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[6,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.472],"y":[1]},"o":{"x":[1],"y":[0]},"t":21.383,"s":[0.690196078431,0.725490196078,0.752941176471,1]},{"i":{"x":[0.49],"y":[1]},"o":{"x":[1],"y":[0]},"t":36.656,"s":[0.349019616842,0.392156869173,0.427450984716,1]},{"t":53.45703125,"s":[0.690196078431,0.725490196078,0.752941176471,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"dot 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":110,"st":0,"bm":0}],"markers":[]}

lib/main.dart

+2-83
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33

44
import './providers/messages_provider.dart';
5-
import './widgets/chat.dart';
5+
import './ui/screens/join.dart';
66

77
void main() => runApp(MyApp());
88

@@ -21,88 +21,7 @@ class MyApp extends StatelessWidget {
2121
title: TextStyle(color: Colors.white),
2222
),
2323
),
24-
home: MyHomePage(),
25-
),
26-
);
27-
}
28-
}
29-
30-
class MyHomePage extends StatefulWidget {
31-
@override
32-
_MyHomePageState createState() => _MyHomePageState();
33-
}
34-
35-
class _MyHomePageState extends State<MyHomePage> {
36-
TextEditingController _textEditingController;
37-
38-
void _joinChat() {
39-
if (_textEditingController.text.isEmpty) return;
40-
41-
Navigator.of(context).push(
42-
MaterialPageRoute(
43-
builder: (ctx) => ChatScreen(_textEditingController.text),
44-
),
45-
);
46-
}
47-
48-
@override
49-
void initState() {
50-
super.initState();
51-
_textEditingController = TextEditingController();
52-
}
53-
54-
@override
55-
void dispose() {
56-
_textEditingController.dispose();
57-
super.dispose();
58-
}
59-
60-
@override
61-
Widget build(BuildContext context) {
62-
return Scaffold(
63-
appBar: AppBar(
64-
title: Text('Flutter Socket IO Chat'),
65-
),
66-
body: Center(
67-
child: Container(
68-
height: 200,
69-
child: Card(
70-
elevation: 10,
71-
shape: RoundedRectangleBorder(
72-
borderRadius: BorderRadius.circular(10),
73-
),
74-
margin: const EdgeInsets.all(20),
75-
child: Padding(
76-
padding: const EdgeInsets.all(8.0),
77-
child: Column(
78-
mainAxisAlignment: MainAxisAlignment.center,
79-
children: <Widget>[
80-
TextField(
81-
controller: _textEditingController,
82-
decoration: InputDecoration(
83-
labelText: "What's your nickname?",
84-
),
85-
onSubmitted: (_) {
86-
_joinChat();
87-
},
88-
),
89-
SizedBox(
90-
height: 30,
91-
),
92-
Align(
93-
alignment: Alignment.bottomRight,
94-
child: MaterialButton(
95-
onPressed: _joinChat,
96-
color: Theme.of(context).primaryColor,
97-
textColor: Theme.of(context).textTheme.title.color,
98-
child: Text('Join'),
99-
),
100-
)
101-
],
102-
),
103-
),
104-
),
105-
),
24+
home: JoinScreen(),
10625
),
10726
);
10827
}

lib/models/message.dart

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class Message {
55

66
const Message(this.senderName, this.content, this.date);
77

8+
bool isUserMessage(String senderName) => this.senderName == senderName;
9+
810
Map<String, dynamic> toJson() => {
911
'senderName': senderName,
1012
'content': content,

lib/socket_io_manager.dart

+18-20
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,28 @@ import 'package:flutter_socket_io/socket_io_manager.dart';
77
class SocketIoManager {
88
SocketIO _socketIO;
99

10-
SocketIoManager({@required String serverUrl, String nameSpace = '/'}) {
11-
_socketIO = SocketIOManager().createSocketIO(serverUrl, nameSpace);
10+
SocketIoManager(
11+
{@required String serverUrl,
12+
String nameSpace = '/',
13+
String query,
14+
Function socketStatusCallback}) {
15+
_socketIO = SocketIOManager().createSocketIO(serverUrl, nameSpace,
16+
query: query, socketStatusCallback: socketStatusCallback);
1217
}
1318

14-
void init() {
15-
_socketIO.init();
16-
}
19+
Future<void> init() => _socketIO.init();
1720

18-
void subscribe(String channel, Function(Map<String, dynamic>) onGetData) {
19-
_socketIO.subscribe(channel, (jsonData) {
20-
Map<String, dynamic> data = json.decode(jsonData);
21-
onGetData(data);
22-
});
23-
}
21+
Future<void> subscribe(
22+
String channel, Function(Map<String, dynamic>) onGetData) =>
23+
_socketIO.subscribe(channel, (jsonData) {
24+
Map<String, dynamic> data = json.decode(jsonData);
25+
onGetData(data);
26+
});
2427

25-
void connect() {
26-
_socketIO.connect();
27-
}
28+
Future<void> connect() => _socketIO.connect();
2829

29-
void sendMessage(String channel, String message) {
30-
_socketIO.sendMessage(channel, message);
31-
}
30+
Future<void> sendMessage(String channel, String message) =>
31+
_socketIO.sendMessage(channel, message);
3232

33-
void disconnect() {
34-
_socketIO.disconnect();
35-
}
33+
Future<void> disconnect() => _socketIO.disconnect();
3634
}

lib/widgets/chat.dart renamed to lib/ui/screens/chat.dart

+27-16
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import 'dart:convert';
22

33
import 'package:flutter/material.dart';
4+
import 'package:lottie/lottie.dart';
45
import 'package:provider/provider.dart';
56

6-
import '../providers/messages_provider.dart';
7-
import '../widgets/chat_item.dart';
8-
import '../models/message.dart';
9-
import '../constants.dart';
10-
import '../socket_io_manager.dart';
11-
import '../widgets/message_form.dart';
7+
import '../../providers/messages_provider.dart';
8+
import '../../models/message.dart';
9+
import '../../constants.dart';
10+
import '../../socket_io_manager.dart';
11+
import '../widgets/messages_item.dart';
12+
import '../widgets/messages_form.dart';
1213

1314
class ChatScreen extends StatefulWidget {
1415
final String senderName;
@@ -100,10 +101,10 @@ class _ChatScreenState extends State<ChatScreen> {
100101
reverse: true,
101102
controller: _scrollController,
102103
itemCount: messagesProvider.allMessages.length,
103-
itemBuilder: (ctx, index) => ChatItem(
104+
itemBuilder: (ctx, index) => MessagesItem(
104105
messagesProvider.allMessages[index],
105-
messagesProvider.allMessages[index].senderName ==
106-
widget.senderName,
106+
messagesProvider.allMessages[index]
107+
.isUserMessage(widget.senderName),
107108
),
108109
),
109110
),
@@ -112,13 +113,23 @@ class _ChatScreenState extends State<ChatScreen> {
112113
visible: _isTyping,
113114
child: Padding(
114115
padding: const EdgeInsets.all(8.0),
115-
child: Text(
116-
'$_userNameTyping is typing...',
117-
style: Theme.of(context).textTheme.title.copyWith(
118-
color: Colors.black54,
119-
fontWeight: FontWeight.w400,
120-
fontSize: 18,
121-
),
116+
child: Row(
117+
children: <Widget>[
118+
Text(
119+
'$_userNameTyping is typing',
120+
style: Theme.of(context).textTheme.title.copyWith(
121+
color: Colors.black54,
122+
fontWeight: FontWeight.w400,
123+
fontSize: 14,
124+
),
125+
),
126+
Lottie.asset(
127+
'assets/animations/chat-typing-indicator.json',
128+
width: 40,
129+
height: 40,
130+
alignment: Alignment.bottomLeft,
131+
),
132+
],
122133
),
123134
),
124135
),

lib/ui/screens/join.dart

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import 'package:flutter/material.dart';
2+
3+
import 'chat.dart';
4+
5+
class JoinScreen extends StatefulWidget {
6+
@override
7+
_JoinScreenState createState() => _JoinScreenState();
8+
}
9+
10+
class _JoinScreenState extends State<JoinScreen> {
11+
TextEditingController _textEditingController;
12+
13+
void _joinChat() {
14+
if (_textEditingController.text.isEmpty) return;
15+
16+
Navigator.of(context).push(
17+
MaterialPageRoute(
18+
builder: (ctx) => ChatScreen(_textEditingController.text),
19+
),
20+
);
21+
}
22+
23+
@override
24+
void initState() {
25+
super.initState();
26+
_textEditingController = TextEditingController();
27+
}
28+
29+
@override
30+
void dispose() {
31+
_textEditingController.dispose();
32+
super.dispose();
33+
}
34+
35+
@override
36+
Widget build(BuildContext context) {
37+
return Scaffold(
38+
appBar: AppBar(
39+
title: Text('Flutter Socket IO Chat'),
40+
),
41+
body: Center(
42+
child: Container(
43+
height: 200,
44+
child: Card(
45+
elevation: 10,
46+
shape: RoundedRectangleBorder(
47+
borderRadius: BorderRadius.circular(10),
48+
),
49+
margin: const EdgeInsets.all(20),
50+
child: Padding(
51+
padding: const EdgeInsets.all(8.0),
52+
child: Column(
53+
mainAxisAlignment: MainAxisAlignment.center,
54+
children: <Widget>[
55+
TextField(
56+
controller: _textEditingController,
57+
decoration: InputDecoration(
58+
labelText: "What's your nickname?",
59+
),
60+
onSubmitted: (_) {
61+
_joinChat();
62+
},
63+
),
64+
SizedBox(
65+
height: 30,
66+
),
67+
MaterialButton(
68+
minWidth: double.infinity,
69+
onPressed: _joinChat,
70+
color: Theme.of(context).primaryColor,
71+
textColor: Theme.of(context).textTheme.title.color,
72+
child: Text('JOIN'),
73+
),
74+
],
75+
),
76+
),
77+
),
78+
),
79+
),
80+
);
81+
}
82+
}

lib/widgets/message_form.dart renamed to lib/ui/widgets/messages_form.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class _MessageFormState extends State<MessageForm> {
3838

3939
void _runTimer() {
4040
if (_typingTimer != null && _typingTimer.isActive) _typingTimer.cancel();
41-
_typingTimer = Timer(Duration(milliseconds: 500), () {
41+
_typingTimer = Timer(Duration(milliseconds: 600), () {
4242
if (!_isTyping) return;
4343
_isTyping = false;
4444
widget.onStopTyping();

0 commit comments

Comments
 (0)