在上一篇文章《Flutter实战一Flutter聊天应用(十九)》中,我们完成了删除用户的逻辑,就是将会话的有效性设置为false
就可以了。那么当会话的有效性为false
时,用户再次添加该会话,我们应该怎么处理呢?
打开add_session.dart
文件,将_AddSessionState
的_addSession
方法中将新会话写入数据库的代码提取出来。同时,在_AddSessionState
中新增一个_writeNewSession
方法,将之前提取的数据库操作代码放在_writeNewSession
方法中。
class _AddSessionState extends State<AddSession> {
//...
void _writeNewSession(String time, String message) {
chatsReference.child('$_myPhone/$_searchPhone').set({
"name": _searchUsername,
"phone": _searchPhone,
"messages": "$_myPhone$_searchPhone$message",
"lastMessage": "一起来聊天吧!",
"timestamp": time,
"activate": "true"
});
chatsReference.child('$_searchPhone/$_myPhone').set({
"name": widget.myName,
"phone": _myPhone,
"messages": "$_myPhone$_searchPhone$message",
"lastMessage": "一起来聊天吧!",
"timestamp": time,
"activate": "true"
});
}
//...
}
然后再修改_AddSessionState
的_addSession
方法,如果和查找到的用户已经存在过会话,判断该会话的有效性是true
还是false
。结果为false
则执行上面添加的_writeNewSession
方法,这样就会为双方增加一个新的聊天记录,同时也会将前一个会话的聊天记录移除。
class _AddSessionState extends State<AddSession> {
//...
Future<int> _addSession() async {
String time = new DateTime.now().toString();
int random = new Random().nextInt(100000);
String message = time.split(' ')[0].replaceAll('-', '') + random.toString();
return await chatsReference
.child('$_myPhone/$_searchPhone')
.once()
.then((DataSnapshot onValue) {
if (onValue.value == null) {
_writeNewSession(time, message);
return 1;
} else {
if (onValue.value["activate"] == "true") {
return 0;
} else {
_writeNewSession(time, message);
return 2;
}
}
});
}
//...
}
如果上面的结果为true
时,说明该会话当前已经在用户的聊天列表中,那么我们应该直接跳转到对应的聊天屏幕中去。添加屏幕的入口是在_GroupChatListState
中,所在现在我们打开group_chat_list.dart
文件,修改_GroupChatListState
的_floatingButtonCallback
方法。
//...
import 'chat_screen.dart';
//...
class _GroupChatListState extends State<GroupChatList> {
//...
void _floatingButtonCallback() {
showDialog<List<String>>(
context: context,
barrierDismissible: false,
child: new AddSession(phone, name)).then((List<String> onValue) {
if (onValue != null) {
Navigator.of(context).push(new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new ChatScreen(
messages: onValue[2],
myName: name,
sheName: onValue[0],
myPhone: phone,
shePhone: onValue[1]);
},
));
}
});
}
//...
}
在上面代码中,我们将添加屏幕的返回值设置成List<String>
,当查找到已经存在于聊天列表的会话时,添加屏幕会返回一个包含对方姓名、手机和聊天记录的字符串列表。根据返回的信息,我们可以创建一个ChatScreen
控件,也就是聊天屏幕。现在回到add_session.dart
文件中,修改_AddSessionState
的_addSession
方法。
//...
class _AddSessionState extends State<AddSession> {
//...
String _searchMessages = "";
//...
Future<int> _addSession() async {
//...
return await chatsReference
.child('$_myPhone/$_searchPhone')
.once()
.then((DataSnapshot onValue) {
if (onValue.value == null) {
_writeNewSession(time, message);
return 1;
} else {
if (onValue.value["activate"] == "true") {
_searchMessages = onValue.value["messages"];
return 0;
} else {
_writeNewSession(time, message);
return 2;
}
}
});
}
//...
}
上面添加了一个_searchMessages
变量,用于保存查找到的聊天记录,并在返回结果为true
时赋值给_searchMessages
。然后我们还要修改一下_AddSessionState
的_handleAppend
方法。
class _AddSessionState extends State<AddSession> {
//...
void _handleAppend() {
showDialog<int>(
context: context,
barrierDismissible: false,
child: new ShowAwait(_addSession())).then((int onValue) {
if (onValue == 1 || onValue == 2) {
Navigator.of(context).pop(null);
} else if (onValue == 0) {
Navigator
.of(context)
.pop([_searchUsername, _searchPhone, _searchMessages]);
}
});
}
//...
}
在上面代码中,当_addSession
方法返回1
或2
时,直接返回null给上一级屏幕,如果返回值是0
,说明是己存在聊天列表的会话,则返回查找到的姓名、手机及聊天记录。配合我们上面修改group_chat_list.dart
文件的代码,当查找到己存在聊天列表的会话时,应用程序会自动跳转到对应的聊天屏幕。
上面的图片展示的是当前添加屏幕的错误提示样式,使用的是弹窗提示,可是我们的添加屏幕本身就是以弹出窗口形式打开的,再使用弹窗提示,不就是两层弹窗了。我们需要对错误提示样式进行修改,修改_AddSessionState
的build
方法
class _AddSessionState extends State<AddSession> {
//...
String _errorPrompt = "";
//...
@override
Widget build(BuildContext context) {
return new SimpleDialog(title: new Text("添加会话"), children: <Widget>[
new Container(
//...
),
_errorPrompt == ""
? new Text("")
: new Center(
child: new Text(
_errorPrompt,
style: new TextStyle(color: Colors.red),
)),
_searchUsername == ""
? new Text("")
: new Container(
//...
),
//...
]);
}
}
在上面代码中,增加了一个_errorPrompt
变量,当该变量不为空时,就会以红色文本的形式显示在输入框与结果显示区中间。我们需要将所有错误提示都替换成修改_errorPrompt
变量,例如下面代码。
setState(() {
_errorPrompt = "该用户不存在!";
_searchUsername = "";
});
setState(() {
_errorPrompt = "";
});