import 'package:logging/logging.dart'; import 'package:result_monad/result_monad.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:stack_trace/stack_trace.dart'; import '../models/auth/oauth_credentials.dart'; import '../models/auth/profile.dart'; import '../models/connection.dart'; import '../models/direct_message.dart'; import '../models/direct_message_thread.dart'; import '../models/exec_error.dart'; import '../models/networking/paging_data.dart'; import 'feature_checker_services.dart'; import 'networking/friendica_dms_client_services.dart'; import 'notification_services.dart'; part 'direct_message_services.g.dart'; @Riverpod(keepAlive: true) class DirectMessageThreadIds extends _$DirectMessageThreadIds { static final _logger = Logger('DirectMessageThreadIdsProvider'); @override List build(Profile profile) { update(); return []; } Future update() async { final threads = []; await ref.read(directMessagesProvider(profile, PagingData()).future).match( onSuccess: (update) { final newThreads = DirectMessageThread.createThreads(profile, update); for (final t in newThreads) { threads.add(t.parentUri); ref .read(directMessageThreadServiceProvider(profile, t.parentUri) .notifier) .update(t); } _logger.fine( 'Updated ${update.length} direct messages, across ${newThreads.length} threads'); }, onError: (error) { _logger.severe( 'Error getting direct messages: $error', Trace.current(), ); }, ); state = threads; } FutureResult newThread( Connection receiver, String text) async { if (profile.credentials is OAuthCredentials) { final result = ref.read(featureCheckResultProvider( profile, RelaticaFeatures.directMessageCreation)); if (result.isFailure) { return result.errorCast(); } } final result = await ref.read(postDirectMessageProvider( profile, null, receiver.id, text, ).future); result.match(onSuccess: (newMessage) { DirectMessageThread.createThreads(profile, [newMessage]) .forEach((thread) { state = [...state, thread.parentUri]; ref .read(directMessageThreadServiceProvider(profile, thread.parentUri) .notifier) .update(thread); }); }, onError: (error) { _logger.severe('Error getting direct messages: $error', Trace.current()); }); ref.invalidateSelf(); return result.execErrorCast(); } } @Riverpod(keepAlive: true) class DirectMessageThreadService extends _$DirectMessageThreadService { static final _logger = Logger('DirectMessageThreadServiceProvider'); String threadId = ''; @override DirectMessageThread build(Profile profile, String id) { _logger.finest('build id = $id'); threadId = id; state = DirectMessageThread( messages: [], participantIds: [], title: 'Uninitialized', parentUri: '', ); return state; } void update(DirectMessageThread thread) { state = thread; } Future refresh() async { await ref .read( updateThreadProvider(profile, state.parentUri, PagingData()).future) .withResult((messages) { messages.sort((m1, m2) => m1.createdAt.compareTo(m2.createdAt)); state = state.copy(messages: messages); }); } FutureResult newReplyMessage( DirectMessage original, String text) async { if (!state.messages.contains(original)) { final error = 'Message is not for this thread: ${state.parentUri}, $original'; _logger.severe(error, Trace.current()); return buildErrorResult( type: ErrorType.notFound, message: error, ); } if (profile.credentials is OAuthCredentials) { final result = ref.read(featureCheckResultProvider( profile, RelaticaFeatures.directMessageCreation)); if (result.isFailure) { return result.errorCast(); } } final result = await ref.read(postDirectMessageProvider( profile, original.id, original.senderId, text, ).future); result.match(onSuccess: (newMessage) { state.messages.add(newMessage); }, onError: (error) { _logger.severe('Error getting direct messages: $error', Trace.current()); }); update(state); return result.execErrorCast(); } Future markMessageRead(DirectMessage m) async { final oldIndex = state.messages.indexOf(m); if (oldIndex < 0) { _logger.severe( 'Message is not for this thread: ${state.parentUri}, $m', Trace.current(), ); return; } await ref.read(markDirectMessageReadProvider(profile, m).future).match( onSuccess: (updatedItem) { final newState = state.deepCopy(); newState.messages[oldIndex] = updatedItem; update(newState); ref.read(notificationsManagerProvider(profile).notifier).refreshDms(); }, onError: (error) { _logger.severe( 'Error getting direct messages: $error', Trace.current(), ); }, ); } }