Compare commits

...

2 Commits

4 changed files with 93 additions and 8 deletions

View File

@ -400,6 +400,14 @@ files:
- JsonImplementation
attributes:
conversationId: int
- name: MarkMessageAsReadCommand
extends: BackgroundCommand
implements:
- JsonImplementation
attributes:
conversationJid: String
sid: String
newUnreadCounter: int
generate_builder: true
# get${builder_Name}FromJson
builder_name: "Command"

View File

@ -64,6 +64,7 @@ void setupBackgroundEventHandler() {
EventTypeMatcher<RegenerateOwnDeviceCommand>(performRegenerateOwnDevice),
EventTypeMatcher<RetractMessageCommentCommand>(performMessageRetraction),
EventTypeMatcher<MarkConversationAsReadCommand>(performMarkConversationAsRead),
EventTypeMatcher<MarkMessageAsReadCommand>(performMarkMessageAsRead),
]);
GetIt.I.registerSingleton<EventHandler>(handler);
@ -607,16 +608,42 @@ Future<void> performMessageRetraction(RetractMessageCommentCommand command, { dy
}
Future<void> performMarkConversationAsRead(MarkConversationAsReadCommand command, { dynamic extra }) async {
// Update the database
final conversation = await GetIt.I.get<ConversationService>().updateConversation(
command.conversationId,
unreadCounter: 0,
);
// TODO(PapaTutuWawa): Send read marker as well
sendEvent(ConversationUpdatedEvent(conversation: conversation));
// Dismiss notifications for that chat
await GetIt.I.get<NotificationsService>().dismissNotificationsByJid(
conversation.jid,
);
sendEvent(ConversationUpdatedEvent(conversation: conversation));
final msg = await GetIt.I.get<MessageService>().getMessageById(
conversation.jid,
conversation.lastMessageId,
);
if (msg != null) {
await GetIt.I.get<XmppService>().sendReadMarker(
conversation.jid,
msg.sid,
);
}
}
Future<void> performMarkMessageAsRead(MarkMessageAsReadCommand command, { dynamic extra }) async {
final cs = GetIt.I.get<ConversationService>();
final oldConversation = await cs.getConversationByJid(command.conversationJid);
final conversation = await cs.updateConversation(
oldConversation!.id,
unreadCounter: command.newUnreadCounter,
);
sendEvent(ConversationUpdatedEvent(conversation: conversation));
await GetIt.I.get<XmppService>().sendReadMarker(
command.conversationJid,
command.sid,
);
}

View File

@ -4,7 +4,9 @@ import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:logging/logging.dart';
import 'package:moxxyv2/i18n/strings.g.dart';
import 'package:moxxyv2/service/events.dart';
import 'package:moxxyv2/service/xmpp.dart';
import 'package:moxxyv2/shared/commands.dart';
import 'package:moxxyv2/shared/helpers.dart';
import 'package:moxxyv2/shared/models/conversation.dart' as modelc;
import 'package:moxxyv2/shared/models/message.dart' as modelm;
@ -12,6 +14,8 @@ import 'package:moxxyv2/shared/models/message.dart' as modelm;
const _maxNotificationId = 2147483647;
const _messageChannelKey = 'message_channel';
const _warningChannelKey = 'warning_channel';
const _notificationActionKeyRead = 'markAsRead';
const _notificationActionKeyReply = 'reply';
// TODO(Unknown): Add resolution dependent drawables for the notification icon
class NotificationsService {
@ -19,8 +23,28 @@ class NotificationsService {
// ignore: unused_field
final Logger _log;
@pragma('vm:entry-point')
static Future<void> onReceivedAction(ReceivedAction action) async {
final logger = Logger('NotificationHandler');
if (action.buttonKeyPressed == _notificationActionKeyRead) {
// TODO(Unknown): Maybe refactor this call such that we don't have to use
// a command.
await performMarkMessageAsRead(
MarkMessageAsReadCommand(
conversationJid: action.payload!['conversationJid']!,
sid: action.payload!['sid']!,
newUnreadCounter: 0,
),
);
} else {
logger.warning('Received unknown notification action key ${action.buttonKeyPressed}');
}
}
Future<void> init() async {
await AwesomeNotifications().initialize(
final an = AwesomeNotifications();
await an.initialize(
'resource://drawable/ic_service_icon',
[
NotificationChannel(
@ -36,7 +60,10 @@ class NotificationsService {
],
debug: kDebugMode,
);
}
await an.setListeners(
onActionReceivedMethod: onReceivedAction,
);
}
/// Returns true if a notification should be shown. false otherwise.
bool shouldShowNotification(String jid) {
@ -67,18 +94,21 @@ class NotificationsService {
NotificationLayout.Messaging,
category: NotificationCategory.Message,
bigPicture: m.thumbnailable ? 'file://${m.mediaUrl}' : null,
payload: <String, String>{
'conversationJid': c.jid,
'sid': m.sid,
},
),
actionButtons: [
NotificationActionButton(
key: 'REPLY',
key: _notificationActionKeyReply,
label: t.notifications.message.reply,
requireInputText: true,
autoDismissible: false,
),
NotificationActionButton(
key: 'READ',
key: _notificationActionKeyRead,
label: t.notifications.message.markAsRead,
requireInputText: true,
)
],
);

View File

@ -274,6 +274,26 @@ class XmppService {
}
}
/// Send a read marker to [to] in order to mark the message with stanza id [sid]
/// as read. If sending chat markers is disabled in the preferences, then this
/// function will do nothing.
Future<void> sendReadMarker(String to, String sid) async {
final prefs = await GetIt.I.get<PreferencesService>().getPreferences();
if (!prefs.sendChatMarkers) return;
unawaited(
GetIt.I.get<XmppConnection>().sendStanza(
Stanza.message(
to: to,
type: 'chat',
children: [
makeChatMarker('displayed', sid),
],
),
),
);
}
/// Returns true if we are allowed to automatically download a file
Future<bool> _automaticFileDownloadAllowed() async {
final prefs = await GetIt.I.get<PreferencesService>().getPreferences();