veilidchat/lib/components/chat_component.dart

206 lines
6.8 KiB
Dart
Raw Normal View History

2023-08-07 00:55:57 -04:00
import 'dart:async';
2023-08-08 02:03:26 -04:00
import 'package:awesome_extensions/awesome_extensions.dart';
2023-09-30 21:11:06 -04:00
import 'package:flutter/foundation.dart';
2023-07-29 10:55:35 -04:00
import 'package:flutter/material.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
2023-08-06 19:46:40 -04:00
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
2023-07-29 10:55:35 -04:00
2023-09-26 18:46:02 -04:00
import '../proto/proto.dart' as proto;
2023-08-07 00:55:57 -04:00
import '../providers/account.dart';
2023-08-08 02:03:26 -04:00
import '../providers/chat.dart';
2023-08-07 00:55:57 -04:00
import '../providers/conversation.dart';
2023-09-24 15:30:54 -04:00
import '../tools/tools.dart';
2023-09-26 18:46:02 -04:00
import '../veilid_init.dart';
2023-08-07 00:55:57 -04:00
import '../veilid_support/veilid_support.dart';
2023-08-02 21:09:28 -04:00
2023-07-29 10:55:35 -04:00
class ChatComponent extends ConsumerStatefulWidget {
2023-08-07 00:55:57 -04:00
const ChatComponent(
{required this.activeAccountInfo,
required this.activeChat,
required this.activeChatContact,
super.key});
final ActiveAccountInfo activeAccountInfo;
final TypedKey activeChat;
final proto.Contact activeChatContact;
2023-07-29 10:55:35 -04:00
@override
ChatComponentState createState() => ChatComponentState();
2023-09-29 22:45:50 -04:00
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
2023-09-30 21:11:06 -04:00
properties
..add(DiagnosticsProperty<ActiveAccountInfo>(
'activeAccountInfo', activeAccountInfo))
..add(DiagnosticsProperty<TypedKey>('activeChat', activeChat))
..add(DiagnosticsProperty<proto.Contact>(
'activeChatContact', activeChatContact));
2023-09-29 22:45:50 -04:00
}
2023-07-29 10:55:35 -04:00
}
class ChatComponentState extends ConsumerState<ChatComponent> {
final _unfocusNode = FocusNode();
2023-08-07 00:55:57 -04:00
late final types.User _localUser;
late final types.User _remoteUser;
2023-07-29 10:55:35 -04:00
@override
void initState() {
super.initState();
2023-08-07 00:55:57 -04:00
_localUser = types.User(
id: widget.activeAccountInfo.localAccount.identityMaster
.identityPublicTypedKey()
.toString(),
firstName: widget.activeAccountInfo.account.profile.name,
);
_remoteUser = types.User(
id: proto.TypedKeyProto.fromProto(
widget.activeChatContact.identityPublicKey)
.toString(),
firstName: widget.activeChatContact.remoteProfile.name);
2023-07-29 10:55:35 -04:00
}
@override
void dispose() {
_unfocusNode.dispose();
super.dispose();
}
2023-08-07 00:55:57 -04:00
types.Message protoMessageToMessage(proto.Message message) {
final isLocal = message.author ==
widget.activeAccountInfo.localAccount.identityMaster
.identityPublicTypedKey()
.toProto();
2023-07-29 10:55:35 -04:00
final textMessage = types.TextMessage(
2023-08-07 00:55:57 -04:00
author: isLocal ? _localUser : _remoteUser,
2023-08-08 02:03:26 -04:00
createdAt: (message.timestamp ~/ 1000).toInt(),
id: message.timestamp.toString(),
2023-07-29 10:55:35 -04:00
text: message.text,
);
2023-08-07 00:55:57 -04:00
return textMessage;
}
Future<void> _addMessage(proto.Message protoMessage) async {
if (protoMessage.text.isEmpty) {
return;
}
final message = protoMessageToMessage(protoMessage);
2023-07-29 10:55:35 -04:00
2023-08-09 02:33:31 -04:00
// setState(() {
// _messages.insert(0, message);
// });
2023-08-07 00:55:57 -04:00
// Now add the message to the conversation messages
2023-08-07 11:02:29 -04:00
final localConversationRecordKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.localConversationRecordKey);
2023-08-07 00:55:57 -04:00
final remoteIdentityPublicKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.identityPublicKey);
await addLocalConversationMessage(
activeAccountInfo: widget.activeAccountInfo,
2023-08-07 11:02:29 -04:00
localConversationRecordKey: localConversationRecordKey,
2023-08-07 00:55:57 -04:00
remoteIdentityPublicKey: remoteIdentityPublicKey,
message: protoMessage);
2023-08-09 02:33:31 -04:00
ref.invalidate(activeConversationMessagesProvider);
2023-08-07 00:55:57 -04:00
}
Future<void> _handleSendPressed(types.PartialText message) async {
final protoMessage = proto.Message()
..author = widget.activeAccountInfo.localAccount.identityMaster
.identityPublicTypedKey()
.toProto()
..timestamp = (await eventualVeilid.future).now().toInt64()
..text = message.text;
//..signature = signature;
await _addMessage(protoMessage);
2023-07-29 10:55:35 -04:00
}
2023-08-02 21:09:28 -04:00
void _handleAttachmentPressed() {
//
}
2023-07-29 10:55:35 -04:00
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
2023-08-02 21:09:28 -04:00
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final textTheme = Theme.of(context).textTheme;
2023-09-24 15:30:54 -04:00
final chatTheme = makeChatTheme(scale, textTheme);
2023-08-07 00:55:57 -04:00
final contactName = widget.activeChatContact.editedProfile.name;
2023-08-06 19:46:40 -04:00
2023-08-09 02:33:31 -04:00
final protoMessages =
ref.watch(activeConversationMessagesProvider).asData?.value;
if (protoMessages == null) {
return waitingPage(context);
}
final messages = <types.Message>[];
for (final protoMessage in protoMessages) {
final message = protoMessageToMessage(protoMessage);
messages.insert(0, message);
}
2023-08-02 21:09:28 -04:00
return DefaultTextStyle(
style: textTheme.bodySmall!,
child: Align(
2023-08-05 01:00:46 -04:00
alignment: AlignmentDirectional.centerEnd,
child: Stack(
children: [
Column(
2023-07-29 10:55:35 -04:00
children: [
2023-08-05 01:00:46 -04:00
Container(
height: 48,
decoration: BoxDecoration(
2023-09-24 15:30:54 -04:00
color: scale.primaryScale.subtleBorder,
2023-08-05 01:00:46 -04:00
),
2023-08-08 02:03:26 -04:00
child: Row(children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
16, 0, 16, 0),
child: Text(contactName,
textAlign: TextAlign.start,
style: textTheme.titleMedium),
)),
2023-09-24 15:30:54 -04:00
const Spacer(),
2023-08-08 02:03:26 -04:00
IconButton(
2023-09-21 21:00:58 -04:00
icon: const Icon(Icons.close),
2023-08-08 02:03:26 -04:00
onPressed: () async {
2023-09-30 21:00:22 -04:00
ref.read(activeChatStateProvider.notifier).state =
null;
2023-08-08 02:03:26 -04:00
}).paddingLTRB(16, 0, 16, 0)
]),
2023-08-05 01:00:46 -04:00
),
Expanded(
2023-09-24 15:30:54 -04:00
child: DecoratedBox(
2023-08-05 01:00:46 -04:00
decoration: const BoxDecoration(),
child: Chat(
theme: chatTheme,
2023-08-09 02:33:31 -04:00
messages: messages,
2023-08-05 01:00:46 -04:00
//onAttachmentPressed: _handleAttachmentPressed,
//onMessageTap: _handleMessageTap,
//onPreviewDataFetched: _handlePreviewDataFetched,
2023-08-02 21:09:28 -04:00
2023-08-07 00:55:57 -04:00
onSendPressed: (message) {
unawaited(_handleSendPressed(message));
},
2023-09-24 15:30:54 -04:00
//showUserAvatars: false,
//showUserNames: true,
2023-08-07 00:55:57 -04:00
user: _localUser,
2023-07-29 10:55:35 -04:00
),
2023-08-05 01:00:46 -04:00
),
2023-07-29 10:55:35 -04:00
),
],
),
2023-08-05 01:00:46 -04:00
],
),
));
2023-07-29 10:55:35 -04:00
}
}