316 lines
10 KiB
Dart
316 lines
10 KiB
Dart
|
|
import 'package:dart_mq/dart_mq.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
|
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
|
|
import 'package:isar/isar.dart';
|
|
import 'package:stadtbote/content_views/utils/content_view_widget.dart';
|
|
import 'package:stadtbote/main.dart';
|
|
import 'package:stadtbote/messages/pop_content_view_message.dart';
|
|
import 'package:stadtbote/model/chat_message.dart' as sbmessage;
|
|
import 'package:stadtbote/model/chat_message.dart';
|
|
import 'package:stadtbote/model/session_status.dart';
|
|
import 'package:stadtbote/protocoll_messages/messages_showed.dart';
|
|
import 'package:stadtbote/tools/constants.dart';
|
|
import 'package:stadtbote/tools/messages/publish_payload_message.dart';
|
|
|
|
import '../tools/util.dart';
|
|
|
|
class MessagesPage extends ContentViewWidget {
|
|
const MessagesPage({super.key});
|
|
|
|
@override
|
|
State<MessagesPage> createState() => _MessagesPageState();
|
|
|
|
@override
|
|
Future<Widget> getHeaderWidget(BuildContext context) async {
|
|
await Future.delayed(const Duration(microseconds: 0));
|
|
|
|
return _HeaderWidget();
|
|
}
|
|
}
|
|
|
|
class _MessagesPageState extends State<MessagesPage> with ProducerMixin {
|
|
bool _initCompleted = false;
|
|
|
|
late String _sid;
|
|
|
|
late final List<types.Message> _messages = [];
|
|
|
|
final _user = const types.User(
|
|
id: '82091008-a484-4a89-ae75-a22bf8d6f3ac',
|
|
);
|
|
|
|
final _central = const types.User(
|
|
id: '82091008-a484-4a89-ae75-a22bf8d6f3ad',
|
|
);
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
Future.delayed(const Duration(seconds: 0), () async {
|
|
var status = await MyApp.isarInstance.sessionStatus.where().findFirst();
|
|
_sid = status != null ? status.sid : 'Unbekannt';
|
|
|
|
_sendMessagesReceivedMessage();
|
|
|
|
await _fetchMessages();
|
|
|
|
_initCompleted = true;
|
|
|
|
setState(() {});
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (!_initCompleted) {
|
|
return Util.getWaitWidget(context);
|
|
}
|
|
|
|
return Stack(
|
|
children: [
|
|
Chat(
|
|
messages: _messages,
|
|
textMessageOptions:const TextMessageOptions(isTextSelectable:false),
|
|
onSendPressed: _handleSendPressed,
|
|
showUserAvatars: false,
|
|
showUserNames: false,
|
|
user: _user,
|
|
onMessageTap: (context, message) => {
|
|
_showDeleteMessageDialog(context, message)
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
void _handleSendPressed(types.PartialText text) async {
|
|
var now = DateTime.now();
|
|
|
|
var message = sbmessage.ChatMessage();
|
|
message.text = text.text;
|
|
message.from = _sid;
|
|
message.subj = '';
|
|
message.time = now.toUtc().toIso8601String();
|
|
message.read = true;
|
|
message.id = await sbmessage.ChatMessage.getNextId();
|
|
|
|
await MyApp.isarInstance.writeTxn(() async {
|
|
await MyApp.isarInstance.chatMessages.put(message);
|
|
});
|
|
|
|
sendMessage(
|
|
routingKey: Constants.messageTopicPublishPayload,
|
|
payload: PublishPayloadMessage(topic: "message", message: message.toJson(), acknowledgeRequired: true),
|
|
);
|
|
|
|
_messages.insert(0, types.TextMessage(
|
|
author: _user,
|
|
createdAt: now.millisecondsSinceEpoch,
|
|
id: message.id.toString(),
|
|
text: text.text,
|
|
));
|
|
|
|
setState(() {});
|
|
}
|
|
|
|
Future<void> _fetchMessages() async {
|
|
_messages.clear();
|
|
|
|
var messages = await MyApp.isarInstance.chatMessages.where().findAll();
|
|
for (var message in messages) {
|
|
_messages.add(types.TextMessage(
|
|
author: message.from == _sid ? _user : _central,
|
|
createdAt: DateTime.parse(message.time).toLocal().millisecondsSinceEpoch,
|
|
id: message.id.toString(),
|
|
text: "${message.subj}\n${message.text}",
|
|
));
|
|
|
|
_messages.sort((a, b) => b.createdAt! > a.createdAt! ? 1 : 0);
|
|
|
|
message.read = true;
|
|
await MyApp.isarInstance.writeTxn(() async {
|
|
await MyApp.isarInstance.chatMessages.put(message);
|
|
});
|
|
}
|
|
|
|
setState(() {});
|
|
}
|
|
|
|
_showDeleteMessageDialog(BuildContext context, types.Message message) async {
|
|
await showDialog<void>(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
contentPadding: EdgeInsets.zero,
|
|
shadowColor: Colors.transparent,
|
|
backgroundColor: Colors.white,
|
|
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
|
return SizedBox(
|
|
key: GlobalKey(),
|
|
height: 120,
|
|
width: MediaQuery
|
|
.of(context)
|
|
.size
|
|
.width * 1.2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Container(
|
|
height: 100,
|
|
padding: const EdgeInsets.all(5),
|
|
child: Column(
|
|
children: [
|
|
const Text('Soll die Nachricht gelöscht werden?'),
|
|
const SizedBox(height: 20),
|
|
Row(children: [
|
|
Expanded(
|
|
child: getDefaultButton('Nein', () => {Navigator.of(context).pop()}),
|
|
),
|
|
const SizedBox(width: 20),
|
|
Expanded(
|
|
child: getDefaultButton('Ja', () async => {
|
|
await MyApp.isarInstance.writeTxn(() async => { await MyApp.isarInstance.chatMessages.delete(int.parse(message.id))}),
|
|
|
|
_fetchMessages(),
|
|
|
|
setState(() {}),
|
|
|
|
Navigator.of(MyApp.appNavigatorKey.currentContext!).pop()
|
|
}),
|
|
)
|
|
])
|
|
],
|
|
),
|
|
),
|
|
)
|
|
);
|
|
})
|
|
);
|
|
});
|
|
}
|
|
|
|
void _sendMessagesReceivedMessage() async {
|
|
var unreadChatMessages = await MyApp.isarInstance.chatMessages
|
|
.filter()
|
|
.readEqualTo(false)
|
|
.findAll();
|
|
|
|
if (unreadChatMessages.isNotEmpty) {
|
|
List<String> chatMessageIds = [];
|
|
for(var message in unreadChatMessages) {
|
|
chatMessageIds.add(message.id.toString());
|
|
}
|
|
|
|
var chatMessagesReceived = ChatMessagesReceived();
|
|
chatMessagesReceived.ids = chatMessageIds;
|
|
chatMessagesReceived.time = DateTime.now().toUtc().toIso8601String();
|
|
|
|
sendMessage(
|
|
routingKey: Constants.messageTopicChatMessagesReceived,
|
|
payload: chatMessagesReceived,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
class _HeaderWidget extends StatefulWidget {
|
|
@override
|
|
State<_HeaderWidget> createState() => _HeaderWidgetState();
|
|
}
|
|
|
|
class _HeaderWidgetState extends State<_HeaderWidget> with ProducerMixin {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
var cellWidth = (MediaQuery.of(context).size.width - 60 - 60 - 25) / 2;
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8),
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Visibility(
|
|
visible: true,
|
|
child: Container(
|
|
width: 60,
|
|
height: 60,
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.white,
|
|
),
|
|
child: FittedBox(
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
// TODO MESSAGING
|
|
sendMessage(
|
|
routingKey: Constants.messageTopicPopContentView,
|
|
payload: PopContentViewMessage(count: 1),
|
|
);
|
|
|
|
//await MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 1));
|
|
},
|
|
child: const CircleAvatar(
|
|
radius: 10,
|
|
backgroundColor: Constants.colorPrimary,
|
|
child: Padding(padding: EdgeInsets.all(1.0), child: Icon(Icons.arrow_back, size: 20.0, color: Colors.white)),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Visibility(
|
|
visible: false,
|
|
child: Container(
|
|
width: 60,
|
|
height: 60,
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.red,
|
|
),
|
|
child: FittedBox(
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
// TODO MESSAGING
|
|
sendMessage(
|
|
routingKey: Constants.messageTopicPopContentView,
|
|
payload: PopContentViewMessage(count: 1),
|
|
);
|
|
|
|
//await MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 1));
|
|
},
|
|
child: const CircleAvatar(
|
|
backgroundColor: Constants.colorPrimary,
|
|
radius: 10,
|
|
child: Padding(padding: EdgeInsets.all(1.0), child: Icon(Icons.info_outline, size: 20.0, color: Colors.white))),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(
|
|
height: 100,
|
|
width: cellWidth * 2,
|
|
child: const Center(
|
|
child: Text(
|
|
textAlign: TextAlign.center,
|
|
"Nachrichten",
|
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|