relatica/lib/services/notifications_manager.dart

200 lines
6.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:relatica/services/network_status_service.dart';
import 'package:result_monad/result_monad.dart';
import 'package:uuid/uuid.dart';
import '../friendica_client/paged_response.dart';
import '../friendica_client/pages_manager.dart';
import '../friendica_client/paging_data.dart';
import '../globals.dart';
import '../models/exec_error.dart';
import '../models/user_notification.dart';
import 'auth_service.dart';
import 'direct_message_service.dart';
class NotificationsManager extends ChangeNotifier {
static final _logger = Logger('NotificationManager');
final _notifications = <String, UserNotification>{};
final _pm = PagesManager<List<UserNotification>, String>(
idMapper: (nn) => nn.map((n) => n.id).toList(),
onRequest: _clientGetNotificationsRequest,
);
List<UserNotification> get notifications {
final result = List<UserNotification>.from(_notifications.values);
result.sort((n1, n2) {
if (n1.dismissed == n2.dismissed) {
return n2.timestamp.compareTo(n1.timestamp);
}
if (n1.dismissed && !n2.dismissed) {
return 1;
}
return -1;
});
return result;
}
void clear() {
_notifications.clear();
}
FutureResult<List<UserNotification>, ExecError> updateNotifications() async {
final nn = <UserNotification>[];
if (_pm.pages.isEmpty) {
final result = await _pm.initialize(50);
result.andThenSuccess((response) => nn.addAll(response.data));
} else {
for (var i = 0; i < _pm.pages.length; i++) {
final page = _pm.pages[i];
PagingData? pd;
if (i == 0) {
if (page.previous == null) {
_logger.severe(
"Expected first page to have a previous page so can query on this page of data but doesn't exist.");
continue;
}
final response = await _clientGetNotificationsRequest(page.next!);
response.match(
onSuccess: (response) => pd = response.previous,
onError: (error) =>
_logger.severe('Error getting previous page: $error'));
} else {
pd = page.next;
}
if (pd == null) {
_logger.severe('Paging data for next page was unexpectedly null');
continue;
}
final response = await _clientGetNotificationsRequest(pd!);
response.match(
onSuccess: (response) => nn.addAll(response.data),
onError: (error) =>
_logger.severe('Error getting previous page: $error'));
}
}
for (final n in nn) {
_notifications[n.id] = n;
}
_notifications.removeWhere(
(key, value) => value.type == NotificationType.direct_message,
);
getIt<NetworkStatusService>().startNotificationUpdate();
await getIt<DirectMessageService>().updateThreads();
getIt<NetworkStatusService>().finishNotificationUpdate();
for (final n in buildUnreadMessageNotifications()) {
_notifications[n.id] = n;
}
notifyListeners();
return Result.ok(notifications);
}
FutureResult<List<UserNotification>, ExecError>
loadNewerNotifications() async {
final result = await _pm.previousFromBeginning();
result.match(onSuccess: (response) {
for (final n in response.data) {
_notifications[n.id] = n;
}
}, onError: (error) {
_logger.severe('Error getting more updates: $error');
});
notifyListeners();
return Result.ok(notifications);
}
FutureResult<List<UserNotification>, ExecError>
loadOlderNotifications() async {
final result = await _pm.nextFromEnd();
result.match(onSuccess: (response) {
for (final n in response.data) {
_notifications[n.id] = n;
}
}, onError: (error) {
_logger.severe('Error getting more updates: $error');
});
notifyListeners();
return Result.ok(notifications);
}
FutureResult<bool, ExecError> markSeen(UserNotification notification) async {
final auth = getIt<AuthService>();
final clientResult = auth.currentClient;
if (clientResult.isFailure) {
_logger.severe('Error getting Friendica client: ${clientResult.error}');
return clientResult.errorCast();
}
final client = clientResult.value;
final result = await client.clearNotification(notification);
if (result.isSuccess) {
notifyListeners();
}
updateNotifications();
return result;
}
FutureResult<List<UserNotification>, ExecError> markAllAsRead() async {
final auth = getIt<AuthService>();
final clientResult = auth.currentClient;
if (clientResult.isFailure) {
_logger.severe('Error getting Friendica client: ${clientResult.error}');
return clientResult.errorCast();
}
final client = clientResult.value;
final result = await client.clearNotifications();
if (result.isFailure) {
return result.errorCast();
}
notifyListeners();
return updateNotifications();
}
List<UserNotification> buildUnreadMessageNotifications() {
final myId = getIt<AuthService>().currentId;
final result =
getIt<DirectMessageService>().getThreads(unreadyOnly: true).map((t) {
final fromAccount = t.participants.firstWhere((p) => p.id != myId);
final latestMessage =
t.messages.reduce((s, m) => s.createdAt > m.createdAt ? s : m);
return UserNotification(
id: const Uuid().v4(),
type: NotificationType.direct_message,
fromId: fromAccount.id,
fromName: fromAccount.name,
fromUrl: fromAccount.profileUrl,
timestamp: latestMessage.createdAt,
iid: t.parentUri,
dismissed: false,
content: '${fromAccount.name} sent you a direct message',
link: '');
}).toList();
return result;
}
static FutureResult<PagedResponse<List<UserNotification>>, ExecError>
_clientGetNotificationsRequest(PagingData page) async {
final auth = getIt<AuthService>();
final clientResult = auth.currentClient;
if (clientResult.isFailure) {
_logger.severe('Error getting Friendica client: ${clientResult.error}');
return clientResult.errorCast();
}
final client = clientResult.value;
final result = await client.getNotifications(page);
return result;
}
}