Encrypted peer-to-peer IM for data security. Own data, own privacy. (Rust+Flutter)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

283 lines
9.8 KiB

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:esse/utils/adaptive.dart';
import 'package:esse/utils/better_print.dart';
import 'package:esse/l10n/localizations.dart';
import 'package:esse/widgets/shadow_dialog.dart';
import 'package:esse/widgets/user_info.dart';
import 'package:esse/widgets/chat_message.dart';
import 'package:esse/widgets/chat_input.dart';
import 'package:esse/provider.dart';
import 'package:esse/session.dart' show SessionType, Session, OnlineType;
import 'package:esse/rpc.dart';
import 'package:esse/apps/primitives.dart';
import 'package:esse/apps/chat/models.dart';
import 'package:esse/apps/group/add.dart';
class ChatDetail extends StatefulWidget {
final int id;
ChatDetail({Key? key, required this.id}) : super(key: key);
@override
_ChatDetailState createState() => _ChatDetailState();
}
class _ChatDetailState extends State<ChatDetail> {
bool _loading = false;
Friend _friend = Friend('', '');
Map<int, Message> _messages = {};
@override
initState() {
super.initState();
rpc.addListener('chat-message-create', _messageCreate);
rpc.addListener('chat-message-delivery', _messageDelivery);
}
// [friend, [message]]
_loadFriend() async {
this._messages.clear();
final res = await httpPost('chat-detail', [widget.id]);
if (res.isOk) {
this._loading = false;
this._friend = Friend.fromList(res.params[0]);
_messageList(res.params[1]);
} else {
print(res.error);
}
}
// [message]
_messageCreate(List params) {
final msg = Message.fromList(params);
if (msg.fid == _friend.id) {
if (!msg.isDelivery!) {
msg.isDelivery = null; // When message create, set is is none;
}
this._messages[msg.id] = msg;
setState(() {});
}
}
// [[message]]
_messageList(List params) {
// TOOD load more history.
params.forEach((param) {
final msg = Message.fromList(param);
this._messages[msg.id] = msg;
});
setState(() {});
}
// [message_id, is_delivery]
_messageDelivery(List params) {
final id = params[0];
final isDelivery = params[1];
if (this._messages.containsKey(id)) {
this._messages[id]!.isDelivery = isDelivery;
setState(() {});
}
}
_send(MessageType mtype, String raw) {
rpc.send('chat-message-create', [_friend.id, _friend.pid, mtype.toInt(), raw]);
}
@override
void deactivate() {
if (!isDisplayDesktop(context)) {
context.read<AccountProvider>().clearActivedSession(SessionType.Chat);
}
super.deactivate();
}
@override
Widget build(BuildContext context) {
final color = Theme.of(context).colorScheme;
final lang = AppLocalizations.of(context);
final isDesktop = isDisplayDesktop(context);
// check change friend.
if (this._friend.id != widget.id) {
_loadFriend();
setState(() { this._loading = true; });
}
final accountProvider = context.watch<AccountProvider>();
final session = accountProvider.activedSession;
final meName = accountProvider.account.name;
this._friend.online = session.isActive();
final recentMessageKeys = this._messages.keys.toList().reversed.toList();
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
leading: isDesktop ? null : IconButton(icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context)),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(this._loading ? lang.waiting : _friend.name,
maxLines: 1, overflow: TextOverflow.ellipsis),
const SizedBox(height: 2.0),
Text(this._friend.isClosed
? lang.closed
: session.onlineLang(lang),
style: TextStyle(color: color.primary, fontSize: 11.0))
]
),
bottom: isDesktop ? PreferredSize(
child: Container(color: const Color(0x40ADB0BB), height: 1.0),
preferredSize: Size.fromHeight(1.0)): null,
actions: [
const SizedBox(width: 20.0),
GestureDetector(
onTap: () {},
child: Container(
width: 20.0,
child: Icon(Icons.phone_rounded,
color: Color(0x26ADB0BB))),
),
const SizedBox(width: 20.0),
GestureDetector(
onTap: () {},
child: Container(
width: 20.0,
child: Icon(Icons.videocam_rounded,
color: Color(0x26ADB0BB))),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: PopupMenuButton<int>(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)
),
color: const Color(0xFFEDEDED),
child: Icon(Icons.more_vert_rounded, color: color.primary),
onSelected: (int value) {
if (value == 0) {
showShadowDialog(
context,
Icons.info,
lang.friendInfo,
UserInfo(
app: 'add-friend',
id: _friend.pid,
name: _friend.name,
title: lang.qrFriend,
remark: _friend.remark,
),
0.0,
);
} else if (value == 1) {
showShadowDialog(
context, Icons.group, lang.groupChatAdd, GroupAddScreen(fid: _friend.id), 0.0);
} else if (value == 2) {
print('TODO remark');
} else if (value == 3) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(lang.unfriend),
content: Text(_friend.name,
style: TextStyle(color: color.primary)),
actions: [
TextButton(
child: Text(lang.cancel),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text(lang.ok),
onPressed: () {
Navigator.pop(context);
rpc.send('chat-friend-close', [_friend.id]);
setState(() {
this._friend.isClosed = true;
});
},
),
]
);
},
);
} else if (value == 4) {
rpc.send('chat-request-create', [
_friend.pid, _friend.name, lang.fromContactCard(meName)
]);
} else if (value == 5) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(lang.delete + " " + lang.friend),
content: Text(_friend.name,
style: TextStyle(color: Colors.red)),
actions: [
TextButton(
child: Text(lang.cancel),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text(lang.ok),
onPressed: () {
Navigator.pop(context);
rpc.send('chat-friend-delete', [_friend.id]);
if (isDesktop) {
context.read<AccountProvider>().updateActivedWidget(null);
} else {
Navigator.pop(context);
}
},
),
]
);
},
);
}
},
itemBuilder: (context) {
return <PopupMenuEntry<int>>[
menuItem(Color(0xFF6174FF), 0, Icons.qr_code_rounded, lang.friendInfo),
if (this._friend.online)
menuItem(Color(0xFF6174FF), 1, Icons.group_rounded, lang.groupChatAdd),
//_menuItem(color.primary, 2, Icons.turned_in_rounded, lang.remark),
_friend.isClosed
? menuItem(Color(0xFF6174FF), 4, Icons.send_rounded, lang.addFriend)
: menuItem(Color(0xFF6174FF), 3, Icons.block_rounded, lang.unfriend),
menuItem(Colors.red, 5, Icons.delete_rounded, lang.delete),
];
},
)
)
]
),
body: Column(
children: [
Expanded(
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 20.0),
itemCount: recentMessageKeys.length,
reverse: true,
itemBuilder: (BuildContext context, index) => ChatMessage(
fpid: _friend.pid,
name: _friend.name,
message: this._messages[recentMessageKeys[index]]!,
)
)),
if (!this._friend.isClosed)
ChatInput(
sid: session.id,
online: this._friend.online,
callback: _send,
transferTo: this._friend.wallet,
waiting: session.online == OnlineType.Waiting
),
]
)
);
}
}