haveno-app/lib/views/screens/base_chat_screen.dart
2024-12-08 06:38:57 +00:00

183 lines
6.2 KiB
Dart

// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:chatview/chatview.dart';
import 'package:haveno/profobuf_models.dart';
import 'package:uuid/uuid.dart';
abstract class BaseChatScreen extends StatefulWidget {
final String chatId;
final String chatTitle;
const BaseChatScreen({super.key, required this.chatId, required this.chatTitle});
@override
BaseChatScreenState createState();
}
abstract class BaseChatScreenState<T extends BaseChatScreen> extends State<T> {
ChatController? _chatController;
late final ChatUser _systemUser = ChatUser(id: 'me', name: 'Me');
late final ChatUser _myUser = ChatUser(id: 'me', name: 'Me');
List<ChatUser> otherUsers = [];
@override
void initState() {
super.initState();
_initializeChatController();
}
@override
void dispose() {
_chatController?.scrollController.dispose();
super.dispose();
}
Future<void> _initializeChatController() async {
final chatMessages = await loadChatMessages();
// Map ChatMessage to the Message type expected by the ChatController
final messageList = chatMessages.map(_mapChatMessageToMessage).toList();
_chatController = ChatController(
initialMessageList: messageList,
scrollController: ScrollController(),
currentUser: _myUser,
otherUsers: otherUsers,
);
}
Message _mapChatMessageToMessage(ChatMessage chatMessage) {
final sentBy = _determineSender(chatMessage);
return Message(
id: chatMessage.uid,
message: chatMessage.message,
createdAt: DateTime.fromMillisecondsSinceEpoch(chatMessage.date.toInt()),
sentBy: sentBy,
status: chatMessage.acknowledged ? MessageStatus.read : MessageStatus.delivered,
);
}
void _addSystemMessage(String text) {
final systemMessage = Message(
id: const Uuid().v1(),
message: text,
createdAt: DateTime.now(),
sentBy: _systemUser.name,
);
_chatController?.addMessage(systemMessage);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<void>(
future: _initializeChatController(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
return ChatView(
chatController: _chatController!,
onSendTap: _handleSendPressed,
chatViewState: _chatController!.initialMessageList.isEmpty ? ChatViewState.noData : ChatViewState.hasMessages,
appBar: ChatViewAppBar(
backGroundColor: Theme.of(context).scaffoldBackgroundColor,
profilePicture: 'X',
chatTitle: widget.chatTitle,
userStatus: 'Active',
actions: buildAppBarActions(),
),
featureActiveConfig: const FeatureActiveConfig(
enableSwipeToReply: true,
enableSwipeToSeeTime: true,
),
chatBackgroundConfig: ChatBackgroundConfiguration(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
messageSorter: (message1, message2) {
return message1.createdAt.compareTo(message2.createdAt);
}
),
sendMessageConfig: const SendMessageConfiguration(
replyMessageColor: Colors.white,
replyDialogColor: Colors.blue,
replyTitleColor: Colors.black,
closeIconColor: Colors.black,
textFieldBackgroundColor: Color(0xFF424242),
textFieldConfig: TextFieldConfiguration()
),
chatBubbleConfig: ChatBubbleConfiguration(
outgoingChatBubbleConfig: const ChatBubble(
color: Colors.blue,
borderRadius: BorderRadius.only(
topRight: Radius.circular(12),
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12),
),
),
inComingChatBubbleConfig: ChatBubble(
color: Colors.black.withOpacity(0.2),
textStyle: const TextStyle(color: Colors.white),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
),
);
},
),
);
}
void _handleSendPressed(String messageText, ReplyMessage replyMessage, MessageType messageType) async {
final newMessage = Message(
id: Uuid().v4(),
message: messageText,
createdAt: DateTime.now(),
sentBy: 'me',
messageType: messageType,
replyMessage: replyMessage,
);
_chatController?.addMessage(newMessage);
try {
await sendMessage(messageText);
newMessage.setStatus = MessageStatus.delivered;
} catch (e) {
newMessage.setStatus = MessageStatus.undelivered;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Message sending failed!')),
);
}
}
// These methods are to be implemented by subclasses
Future<List<ChatMessage>> loadChatMessages();
String _determineSender(ChatMessage chatMessage);
Future<void> sendMessage(String messageText);
List<Widget> buildAppBarActions();
}