kopia lustrzana https://gitlab.com/mysocialportal/relatica
Fix DM status update reflecting in notifications, etc.
rodzic
571f690320
commit
648d6e29dd
|
@ -101,14 +101,6 @@ class StandardAppDrawer extends ConsumerWidget {
|
|||
'Settings',
|
||||
() => context.pushNamed(ScreenPaths.settings),
|
||||
),
|
||||
// TODO Add back in clearing ability but has to do disk caches too
|
||||
// buildMenuButton(context, 'Clear Caches', () async {
|
||||
// final confirm = await showYesNoDialog(
|
||||
// context, 'You want to clear all memory and disk cache data?');
|
||||
// if (confirm == true) {
|
||||
// clearCaches();
|
||||
// }
|
||||
// }),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../riverpod_controllers/connection_manager_services.dart';
|
||||
import 'auth/profile.dart';
|
||||
import 'connection.dart';
|
||||
import 'direct_message.dart';
|
||||
|
||||
class DirectMessageThread {
|
||||
final List<DirectMessage> messages;
|
||||
|
||||
final List<Connection> participants;
|
||||
final List<String> participantIds;
|
||||
|
||||
final String title;
|
||||
|
||||
|
@ -17,14 +14,22 @@ class DirectMessageThread {
|
|||
|
||||
DirectMessageThread({
|
||||
required this.messages,
|
||||
required this.participants,
|
||||
required this.participantIds,
|
||||
required this.title,
|
||||
required this.parentUri,
|
||||
});
|
||||
|
||||
DirectMessageThread deepCopy() => DirectMessageThread(
|
||||
messages: List.from(messages),
|
||||
participants: List.from(participants),
|
||||
participantIds: List.from(participantIds),
|
||||
title: title,
|
||||
parentUri: parentUri,
|
||||
);
|
||||
|
||||
DirectMessageThread copy({List<DirectMessage>? messages}) =>
|
||||
DirectMessageThread(
|
||||
messages: messages ?? this.messages,
|
||||
participantIds: participantIds,
|
||||
title: title,
|
||||
parentUri: parentUri,
|
||||
);
|
||||
|
@ -36,7 +41,6 @@ class DirectMessageThread {
|
|||
.reduce((allUnseen, thisUnseen) => allUnseen && thisUnseen);
|
||||
|
||||
static List<DirectMessageThread> createThreads(
|
||||
Ref ref,
|
||||
Profile profile,
|
||||
Iterable<DirectMessage> messages,
|
||||
) {
|
||||
|
@ -60,14 +64,9 @@ class DirectMessageThread {
|
|||
title = m.title;
|
||||
}
|
||||
}
|
||||
final participants = participantIds
|
||||
.map((pid) => ref.read(connectionByIdProvider(profile, pid)))
|
||||
.where((pr) => pr.isSuccess)
|
||||
.map((pr) => pr.value)
|
||||
.toList();
|
||||
final thread = DirectMessageThread(
|
||||
messages: threadMessages,
|
||||
participants: participants,
|
||||
participantIds: participantIds.toList(),
|
||||
title: title,
|
||||
parentUri: parentUri,
|
||||
);
|
||||
|
@ -88,12 +87,12 @@ class DirectMessageThread {
|
|||
title == other.title &&
|
||||
parentUri == other.parentUri &&
|
||||
listEquals(messages, other.messages) &&
|
||||
listEquals(participants, other.participants);
|
||||
listEquals(participantIds, other.participantIds);
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
title.hashCode ^
|
||||
parentUri.hashCode ^
|
||||
Object.hashAll(messages) ^
|
||||
Object.hashAll(participants);
|
||||
Object.hashAll(participantIds);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ final activeProfileProvider = NotifierProvider<ActiveProfile, Profile>.internal(
|
|||
);
|
||||
|
||||
typedef _$ActiveProfile = Notifier<Profile>;
|
||||
String _$credentialSigninHash() => r'9c6515a30bbdd3d8272ad4bba57c98a9391866c9';
|
||||
String _$credentialSigninHash() => r'e9731ad5b916838122a2a86961af4cfe4bef57b5';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@ -236,7 +236,7 @@ class _CredentialSigninProviderElement
|
|||
(origin as CredentialSigninProvider).credentials;
|
||||
}
|
||||
|
||||
String _$profileManagerHash() => r'2bd46dca2f9307fa0197d21ba55627b89b297884';
|
||||
String _$profileManagerHash() => r'5f37162a9b7b19f3cd9e804d83dbb37cda96568b';
|
||||
|
||||
abstract class _$ProfileManager extends BuildlessNotifier<bool> {
|
||||
late final Profile profile;
|
||||
|
@ -381,7 +381,7 @@ class _ProfileManagerProviderElement
|
|||
}
|
||||
|
||||
String _$accountServicesInitializerHash() =>
|
||||
r'1872c6987b80737764687a679eb8b987f42c4ff3';
|
||||
r'386b364d2fe41581ad17d5823a7f47dc12bc4760';
|
||||
|
||||
/// See also [AccountServicesInitializer].
|
||||
@ProviderFor(AccountServicesInitializer)
|
||||
|
|
|
@ -6,7 +6,7 @@ part of 'blocks_services.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$blocksManagerHash() => r'd04635c7bf3072984d3575a2fdb6c84056729e5e';
|
||||
String _$blocksManagerHash() => r'e8285887e48ab751515c9a2e9fdc0a90ce12e437';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
@ -332,7 +332,7 @@ class _TimelineGroupingListProviderElement
|
|||
GroupingType get type => (origin as TimelineGroupingListProvider).type;
|
||||
}
|
||||
|
||||
String _$circlesRepoHash() => r'f02b6233914071968c47213c79bb64c81f562dd3';
|
||||
String _$circlesRepoHash() => r'82b95a626e70888ea4a4f0a2c1a736cd0bdcf9c9';
|
||||
|
||||
abstract class _$CirclesRepo extends BuildlessNotifier<ICirclesRepo> {
|
||||
late final Profile profile;
|
||||
|
@ -476,7 +476,7 @@ class _CirclesRepoProviderElement
|
|||
Profile get profile => (origin as _CirclesRepoProvider).profile;
|
||||
}
|
||||
|
||||
String _$circlesHash() => r'fbd0b71fa7027a8c1cf16413df288b666734b180';
|
||||
String _$circlesHash() => r'84741e2bec4232522eadd6f83046b4d147645985';
|
||||
|
||||
abstract class _$Circles
|
||||
extends BuildlessNotifier<List<TimelineGroupingListData>> {
|
||||
|
|
|
@ -1312,7 +1312,7 @@ class _ConnectionsRepoClearerProviderElement
|
|||
}
|
||||
|
||||
String _$connectionModifierHash() =>
|
||||
r'35d92e5d4c0162ca7c44ab9b9f296856a58704c0';
|
||||
r'75d5a90c167916273292f8e03d462f95a0fe04a3';
|
||||
|
||||
abstract class _$ConnectionModifier
|
||||
extends BuildlessAutoDisposeNotifier<Connection> {
|
||||
|
@ -1628,7 +1628,7 @@ class _UpdateStatusInternalProviderElement
|
|||
}
|
||||
|
||||
String _$allContactsUpdaterHash() =>
|
||||
r'cfab7072e13b11396b4e3aaaed75148fe97f0b55';
|
||||
r'84f97838de84166a1ed907d75eedaa1decf56daf';
|
||||
|
||||
abstract class _$AllContactsUpdater extends BuildlessNotifier<bool> {
|
||||
late final Profile profile;
|
||||
|
|
|
@ -12,6 +12,7 @@ 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';
|
||||
|
||||
|
@ -30,8 +31,7 @@ class DirectMessageThreadIds extends _$DirectMessageThreadIds {
|
|||
|
||||
await ref.read(directMessagesProvider(profile, PagingData()).future).match(
|
||||
onSuccess: (update) {
|
||||
final newThreads =
|
||||
DirectMessageThread.createThreads(ref, profile, update);
|
||||
final newThreads = DirectMessageThread.createThreads(profile, update);
|
||||
for (final t in newThreads) {
|
||||
threads.add(t.parentUri);
|
||||
ref
|
||||
|
@ -69,7 +69,7 @@ class DirectMessageThreadIds extends _$DirectMessageThreadIds {
|
|||
text,
|
||||
).future);
|
||||
result.match(onSuccess: (newMessage) {
|
||||
DirectMessageThread.createThreads(ref, profile, [newMessage])
|
||||
DirectMessageThread.createThreads(profile, [newMessage])
|
||||
.forEach((thread) {
|
||||
state = [...state, thread.parentUri];
|
||||
ref
|
||||
|
@ -97,7 +97,7 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
|||
threadId = id;
|
||||
state = DirectMessageThread(
|
||||
messages: [],
|
||||
participants: [],
|
||||
participantIds: [],
|
||||
title: 'Uninitialized',
|
||||
parentUri: '',
|
||||
);
|
||||
|
@ -108,6 +108,16 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
|||
state = thread;
|
||||
}
|
||||
|
||||
Future<void> 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<DirectMessage, ExecError> newReplyMessage(
|
||||
DirectMessage original, String text) async {
|
||||
if (!state.messages.contains(original)) {
|
||||
|
@ -159,6 +169,7 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
|||
final newState = state.deepCopy();
|
||||
newState.messages[oldIndex] = updatedItem;
|
||||
update(newState);
|
||||
ref.read(notificationsManagerProvider(profile).notifier).refreshDms();
|
||||
},
|
||||
onError: (error) {
|
||||
_logger.severe(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'direct_message_services.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$directMessageThreadIdsHash() =>
|
||||
r'76d081ab346af0247a62dc58f270a064b355f26f';
|
||||
r'ce42c0a00ab785c7685f8c135bada67bea2fcb14';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@ -175,7 +175,7 @@ class _DirectMessageThreadIdsProviderElement
|
|||
}
|
||||
|
||||
String _$directMessageThreadServiceHash() =>
|
||||
r'83940611b62a1bb4616f5ebbb93e1398f34db607';
|
||||
r'5ef67edc0bb13c3834ed998bd107af36762fde79';
|
||||
|
||||
abstract class _$DirectMessageThreadService
|
||||
extends BuildlessNotifier<DirectMessageThread> {
|
||||
|
|
|
@ -739,7 +739,7 @@ class _EntryTreeManagerProviderElement extends NotifierProviderElement<
|
|||
String get id => (origin as EntryTreeManagerProvider).id;
|
||||
}
|
||||
|
||||
String _$timelineUpdaterHash() => r'8359f110e4718fb2048d8ce3c0a885bd3d064d28';
|
||||
String _$timelineUpdaterHash() => r'38d091cafcfa347f52bd3260d7ab72178bd2dc7b';
|
||||
|
||||
abstract class _$TimelineUpdater extends BuildlessAutoDisposeNotifier<bool> {
|
||||
late final Profile profile;
|
||||
|
|
|
@ -294,7 +294,7 @@ class _VersionErrorStringProviderElement
|
|||
(origin as VersionErrorStringProvider).feature;
|
||||
}
|
||||
|
||||
String _$featureCheckHash() => r'efedd8bae092a28579b6e750088c07e1b35357d6';
|
||||
String _$featureCheckHash() => r'8e60d2e4278f205aac2e0e434b595cb7aa5b192b';
|
||||
|
||||
/// See also [featureCheck].
|
||||
@ProviderFor(featureCheck)
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'instance_info_services.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$instanceInfoManagerHash() =>
|
||||
r'8d591a07234dadde0560ded347cb3499779c4070';
|
||||
r'88f181cbbee4b4043bf0be55e8379fcc8ad2b8b3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
@ -46,6 +46,36 @@ Future<Result<List<DirectMessage>, ExecError>> directMessages(
|
|||
return result;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<Result<List<DirectMessage>, ExecError>> updateThread(
|
||||
Ref ref,
|
||||
Profile profile,
|
||||
String threadUri,
|
||||
PagingData page,
|
||||
) async {
|
||||
ref.read(directMessageLoadingProvider(profile));
|
||||
Future.microtask(
|
||||
() async =>
|
||||
ref.read(directMessageLoadingProvider(profile).notifier).begin(),
|
||||
);
|
||||
|
||||
final baseUrl =
|
||||
'https://${profile.serverName}/api/direct_messages/conversation';
|
||||
final pagingQP = page.toQueryParameters(limitKeyword: 'count');
|
||||
final url = '$baseUrl?$pagingQP&uri=$threadUri';
|
||||
final request = Uri.parse(url);
|
||||
_logger.finest(() => 'Getting direct messages with paging data $page');
|
||||
final result = (await ref
|
||||
.read(getApiListRequestProvider(profile, request).future)
|
||||
.andThenSuccessAsync((response) async => response.data
|
||||
.map((json) => DirectMessageFriendicaExtension.fromJson(json))
|
||||
.toList()))
|
||||
.execErrorCast();
|
||||
|
||||
ref.read(directMessageLoadingProvider(profile).notifier).end();
|
||||
return result;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<Result<DirectMessage, ExecError>> markDirectMessageRead(
|
||||
Ref ref,
|
||||
|
|
|
@ -180,6 +180,175 @@ class _DirectMessagesProviderElement extends AutoDisposeFutureProviderElement<
|
|||
PagingData get page => (origin as DirectMessagesProvider).page;
|
||||
}
|
||||
|
||||
String _$updateThreadHash() => r'425416c431e9f0c0f592c07eef2c3f3618c6fcfb';
|
||||
|
||||
/// See also [updateThread].
|
||||
@ProviderFor(updateThread)
|
||||
const updateThreadProvider = UpdateThreadFamily();
|
||||
|
||||
/// See also [updateThread].
|
||||
class UpdateThreadFamily
|
||||
extends Family<AsyncValue<Result<List<DirectMessage>, ExecError>>> {
|
||||
/// See also [updateThread].
|
||||
const UpdateThreadFamily();
|
||||
|
||||
/// See also [updateThread].
|
||||
UpdateThreadProvider call(
|
||||
Profile profile,
|
||||
String threadUri,
|
||||
PagingData page,
|
||||
) {
|
||||
return UpdateThreadProvider(
|
||||
profile,
|
||||
threadUri,
|
||||
page,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
UpdateThreadProvider getProviderOverride(
|
||||
covariant UpdateThreadProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.threadUri,
|
||||
provider.page,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'updateThreadProvider';
|
||||
}
|
||||
|
||||
/// See also [updateThread].
|
||||
class UpdateThreadProvider
|
||||
extends AutoDisposeFutureProvider<Result<List<DirectMessage>, ExecError>> {
|
||||
/// See also [updateThread].
|
||||
UpdateThreadProvider(
|
||||
Profile profile,
|
||||
String threadUri,
|
||||
PagingData page,
|
||||
) : this._internal(
|
||||
(ref) => updateThread(
|
||||
ref as UpdateThreadRef,
|
||||
profile,
|
||||
threadUri,
|
||||
page,
|
||||
),
|
||||
from: updateThreadProvider,
|
||||
name: r'updateThreadProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$updateThreadHash,
|
||||
dependencies: UpdateThreadFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
UpdateThreadFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
threadUri: threadUri,
|
||||
page: page,
|
||||
);
|
||||
|
||||
UpdateThreadProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.threadUri,
|
||||
required this.page,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final String threadUri;
|
||||
final PagingData page;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Result<List<DirectMessage>, ExecError>> Function(
|
||||
UpdateThreadRef provider)
|
||||
create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: UpdateThreadProvider._internal(
|
||||
(ref) => create(ref as UpdateThreadRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
threadUri: threadUri,
|
||||
page: page,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<Result<List<DirectMessage>, ExecError>>
|
||||
createElement() {
|
||||
return _UpdateThreadProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is UpdateThreadProvider &&
|
||||
other.profile == profile &&
|
||||
other.threadUri == threadUri &&
|
||||
other.page == page;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, threadUri.hashCode);
|
||||
hash = _SystemHash.combine(hash, page.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin UpdateThreadRef
|
||||
on AutoDisposeFutureProviderRef<Result<List<DirectMessage>, ExecError>> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `threadUri` of this provider.
|
||||
String get threadUri;
|
||||
|
||||
/// The parameter `page` of this provider.
|
||||
PagingData get page;
|
||||
}
|
||||
|
||||
class _UpdateThreadProviderElement extends AutoDisposeFutureProviderElement<
|
||||
Result<List<DirectMessage>, ExecError>> with UpdateThreadRef {
|
||||
_UpdateThreadProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as UpdateThreadProvider).profile;
|
||||
@override
|
||||
String get threadUri => (origin as UpdateThreadProvider).threadUri;
|
||||
@override
|
||||
PagingData get page => (origin as UpdateThreadProvider).page;
|
||||
}
|
||||
|
||||
String _$markDirectMessageReadHash() =>
|
||||
r'62d62dd9e1cf638b0364cdeab742df00da685ccc';
|
||||
|
||||
|
|
|
@ -645,7 +645,7 @@ class _GetMyFollowersProviderElement extends AutoDisposeFutureProviderElement<
|
|||
}
|
||||
|
||||
String _$connectionWithStatusClientHash() =>
|
||||
r'65dde1fad60635c3de95b440ae3046ce47676a9d';
|
||||
r'687d060bab00296f5aa802713af4ea47989536b4';
|
||||
|
||||
/// See also [connectionWithStatusClient].
|
||||
@ProviderFor(connectionWithStatusClient)
|
||||
|
|
|
@ -350,7 +350,7 @@ class _DeleteStatusEntryByIdProviderElement
|
|||
String get id => (origin as DeleteStatusEntryByIdProvider).id;
|
||||
}
|
||||
|
||||
String _$createNewStatusHash() => r'6c2ddd3e4acd4f01d30c2c8d85dc15e36db83501';
|
||||
String _$createNewStatusHash() => r'c140a6e3a2776edb93a0e389ef5115d3b2e85fb0';
|
||||
|
||||
/// See also [createNewStatus].
|
||||
@ProviderFor(createNewStatus)
|
||||
|
@ -568,7 +568,7 @@ class _CreateNewStatusProviderElement
|
|||
Visibility get visibility => (origin as CreateNewStatusProvider).visibility;
|
||||
}
|
||||
|
||||
String _$editStatusHash() => r'94d0d20e834b16f2d8a09feba003ec89b628bf22';
|
||||
String _$editStatusHash() => r'cad5eeef14a26a7886c129230fa5e7f1c78da7e7';
|
||||
|
||||
/// See also [editStatus].
|
||||
@ProviderFor(editStatus)
|
||||
|
@ -922,7 +922,7 @@ class _ResharePostProviderElement
|
|||
String get id => (origin as ResharePostProvider).id;
|
||||
}
|
||||
|
||||
String _$unResharePostHash() => r'4b7ca0426ec3c016624c825af43495ba2a21f17d';
|
||||
String _$unResharePostHash() => r'6f8ea49b584ca01a2a6d87064fa682d3dc78311d';
|
||||
|
||||
/// See also [unResharePost].
|
||||
@ProviderFor(unResharePost)
|
||||
|
|
|
@ -6,12 +6,14 @@ import 'package:stack_trace/stack_trace.dart';
|
|||
|
||||
import '../globals.dart';
|
||||
import '../models/auth/profile.dart';
|
||||
import '../models/connection.dart';
|
||||
import '../models/exec_error.dart';
|
||||
import '../models/networking/paged_response.dart';
|
||||
import '../models/networking/pages_manager.dart';
|
||||
import '../models/networking/paging_data.dart';
|
||||
import '../models/user_notification.dart';
|
||||
import '../serializers/mastodon/follow_request_mastodon_extensions.dart';
|
||||
import 'connection_manager_services.dart';
|
||||
import 'direct_message_services.dart';
|
||||
import 'feature_checker_services.dart';
|
||||
import 'follow_requests_services.dart';
|
||||
|
@ -62,7 +64,23 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
Future<void> refreshConnectionRequestNotifications() async {
|
||||
_logger.info('refreshConnectionRequestNotifications');
|
||||
connectionRequests.clear();
|
||||
await _postFetchOperations([], true, updateDms: false);
|
||||
await _postFetchOperations(
|
||||
[],
|
||||
true,
|
||||
updateDms: false,
|
||||
updateFollowRequests: true,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> refreshDms() async {
|
||||
_logger.info('refreshDms');
|
||||
dms.clear();
|
||||
await _postFetchOperations(
|
||||
[],
|
||||
true,
|
||||
updateDms: true,
|
||||
updateFollowRequests: false,
|
||||
);
|
||||
}
|
||||
|
||||
void clear({bool withListenerNotification = true}) {
|
||||
|
@ -254,7 +272,10 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
.map((id) => ref.watch(directMessageThreadServiceProvider(profile, id)))
|
||||
.where((t) => !t.allSeen)
|
||||
.map((t) {
|
||||
final fromAccount = t.participants.firstWhere((p) => p.id != myId);
|
||||
final fromAccountId = t.participantIds.firstWhere((pid) => pid != myId);
|
||||
final fromAccount = ref
|
||||
.watch(connectionByIdProvider(profile, fromAccountId))
|
||||
.getValueOrElse(() => Connection());
|
||||
final latestMessage =
|
||||
t.messages.reduce((s, m) => s.createdAt > m.createdAt ? s : m);
|
||||
return UserNotification(
|
||||
|
|
|
@ -7,7 +7,7 @@ part of 'notification_services.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$notificationsManagerHash() =>
|
||||
r'c7a691dce74c2a2db04fd78a459a13c9d8256e18';
|
||||
r'dc6a88e34b4d6bc3cea3541aba7453e223374842';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
@ -6,7 +6,7 @@ part of 'persistent_info_services.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$persistentInfoHash() => r'8881204fcc60dcf435340cc5c28e1e293c97dbe3';
|
||||
String _$persistentInfoHash() => r'62bf2f76f88d746cf75f4b663d76302d4c3213fd';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
@ -329,7 +329,7 @@ class _CheckTimelineEntryProviderElement
|
|||
}
|
||||
|
||||
String _$timelineEntryFiltersHash() =>
|
||||
r'dd386f6ecd047a1dcd8602451c7a445510b03f7d';
|
||||
r'cd4344f10166b5cabb7869c350e6d83f571cb20d';
|
||||
|
||||
abstract class _$TimelineEntryFilters
|
||||
extends BuildlessNotifier<Map<String, TimelineEntryFilter>> {
|
||||
|
|
|
@ -173,7 +173,7 @@ class _TimelineMaintainerProviderElement extends NotifierProviderElement<
|
|||
Profile get profile => (origin as TimelineMaintainerProvider).profile;
|
||||
}
|
||||
|
||||
String _$timelineManagerHash() => r'fa6c46745b69e61ce3dd8cb07822d428ea8b66f5';
|
||||
String _$timelineManagerHash() => r'9f806c36aeb207547fde5a352df1c1fb051cc9af';
|
||||
|
||||
abstract class _$TimelineManager extends BuildlessNotifier<Timeline> {
|
||||
late final Profile profile;
|
||||
|
|
|
@ -6,10 +6,14 @@ import '../controls/image_control.dart';
|
|||
import '../controls/padding.dart';
|
||||
import '../controls/responsive_max_width.dart';
|
||||
import '../controls/standard_appbar.dart';
|
||||
import '../controls/status_and_refresh_button.dart';
|
||||
import '../models/auth/profile.dart';
|
||||
import '../models/direct_message.dart';
|
||||
import '../models/direct_message_thread.dart';
|
||||
import '../riverpod_controllers/account_services.dart';
|
||||
import '../riverpod_controllers/connection_manager_services.dart';
|
||||
import '../riverpod_controllers/direct_message_services.dart';
|
||||
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||
import '../utils/clipboard_utils.dart';
|
||||
import '../utils/snackbar_builder.dart';
|
||||
|
||||
|
@ -29,63 +33,57 @@ class MessageThreadScreen extends ConsumerStatefulWidget {
|
|||
class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
||||
final textController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
ref
|
||||
.read(directMessageThreadServiceProvider(
|
||||
ref.read(activeProfileProvider),
|
||||
widget.parentThreadId,
|
||||
).notifier)
|
||||
.refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final profile = ref.watch(activeProfileProvider);
|
||||
final t = ref.watch(
|
||||
final loading = ref.watch(directMessageLoadingProvider(profile));
|
||||
final thread = ref.watch(
|
||||
directMessageThreadServiceProvider(profile, widget.parentThreadId));
|
||||
final title = t.title.isEmpty ? 'Thread' : t.title;
|
||||
final title = thread.title.isEmpty ? 'Thread' : thread.title;
|
||||
return Scaffold(
|
||||
appBar: StandardAppBar.build(context, title),
|
||||
body: buildBody(profile, t),
|
||||
appBar: StandardAppBar.build(context, title, actions: [
|
||||
StatusAndRefreshButton3(
|
||||
executing: loading,
|
||||
refreshFunction: () async => await ref
|
||||
.read(directMessageThreadServiceProvider(
|
||||
profile,
|
||||
widget.parentThreadId,
|
||||
).notifier)
|
||||
.refresh(),
|
||||
busyColor: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
]),
|
||||
body: buildBody(profile, thread, loading),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBody(
|
||||
Profile profile,
|
||||
DirectMessageThread thread,
|
||||
bool loading,
|
||||
) {
|
||||
final service = ref.read(
|
||||
directMessageThreadServiceProvider(profile, thread.parentUri).notifier);
|
||||
final yourId = profile.userId;
|
||||
final yourAvatarUrl = profile.avatar;
|
||||
final participants =
|
||||
Map.fromEntries(thread.participants.map((p) => MapEntry(p.id, p)));
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
if (loading) const LinearProgressIndicator(),
|
||||
Expanded(
|
||||
child: ResponsiveMaxWidth(
|
||||
child: ListView.separated(
|
||||
itemBuilder: (context, index) {
|
||||
final m = thread.messages[index];
|
||||
final textPieces = m.text.split('...\n');
|
||||
final text =
|
||||
textPieces.length == 1 ? textPieces[0] : textPieces[1];
|
||||
final imageUrl = m.senderId == yourId
|
||||
? yourAvatarUrl
|
||||
: participants[m.senderId]?.avatarUrl ?? '';
|
||||
return ListTile(
|
||||
onTap: m.seen ? null : () => service.markMessageRead(m),
|
||||
onLongPress: () async {
|
||||
await copyToClipboard(context: context, text: m.text);
|
||||
},
|
||||
leading: ImageControl(
|
||||
imageUrl: imageUrl,
|
||||
iconOverride: const Icon(Icons.person),
|
||||
width: 32.0,
|
||||
onTap: null,
|
||||
),
|
||||
title: Text(
|
||||
text,
|
||||
style: m.seen
|
||||
? null
|
||||
: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(
|
||||
DateTime.fromMillisecondsSinceEpoch(m.createdAt * 1000)
|
||||
.toString()),
|
||||
);
|
||||
return _DirectMessageListItem(
|
||||
m, profile, widget.parentThreadId);
|
||||
},
|
||||
separatorBuilder: (_, __) => const Divider(),
|
||||
itemCount: thread.messages.length),
|
||||
|
@ -119,17 +117,20 @@ class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
|||
return;
|
||||
}
|
||||
final othersMessages =
|
||||
thread.messages.where((m) => m.senderId != yourId);
|
||||
thread.messages.where((m) => m.senderId != profile.userId);
|
||||
if (othersMessages.isEmpty) {
|
||||
buildSnackbar(
|
||||
context, "Have to wait for a response before sending");
|
||||
return;
|
||||
}
|
||||
await service
|
||||
await ref
|
||||
.read(directMessageThreadServiceProvider(
|
||||
profile, thread.parentUri)
|
||||
.notifier)
|
||||
.newReplyMessage(
|
||||
othersMessages.last,
|
||||
textController.text,
|
||||
)
|
||||
othersMessages.last,
|
||||
textController.text,
|
||||
)
|
||||
.match(onSuccess: (_) {
|
||||
setState(() {
|
||||
textController.clear();
|
||||
|
@ -147,3 +148,46 @@ class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
|||
));
|
||||
}
|
||||
}
|
||||
|
||||
class _DirectMessageListItem extends ConsumerWidget {
|
||||
final DirectMessage message;
|
||||
final Profile profile;
|
||||
final String threadId;
|
||||
|
||||
const _DirectMessageListItem(this.message, this.profile, this.threadId);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final senderAvatar = ref
|
||||
.read(connectionByIdProvider(profile, message.senderId))
|
||||
.fold(onSuccess: (c) => c.avatarUrl, onError: (_) => '');
|
||||
final m = message;
|
||||
final textPieces = m.text.split('...\n');
|
||||
final text = textPieces.length == 1 ? textPieces[0] : textPieces[1];
|
||||
final imageUrl =
|
||||
m.senderId == profile.userId ? profile.avatar : senderAvatar;
|
||||
return ListTile(
|
||||
onTap: m.seen
|
||||
? null
|
||||
: () => ref
|
||||
.read(DirectMessageThreadServiceProvider(profile, threadId)
|
||||
.notifier)
|
||||
.markMessageRead(m),
|
||||
onLongPress: () async {
|
||||
await copyToClipboard(context: context, text: m.text);
|
||||
},
|
||||
leading: ImageControl(
|
||||
imageUrl: imageUrl,
|
||||
iconOverride: const Icon(Icons.person),
|
||||
width: 32.0,
|
||||
onTap: null,
|
||||
),
|
||||
title: Text(
|
||||
text,
|
||||
style: m.seen ? null : const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(
|
||||
DateTime.fromMillisecondsSinceEpoch(m.createdAt * 1000).toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import '../controls/standard_appbar.dart';
|
|||
import '../controls/status_and_refresh_button.dart';
|
||||
import '../models/auth/profile.dart';
|
||||
import '../riverpod_controllers/account_services.dart';
|
||||
import '../riverpod_controllers/connection_manager_services.dart';
|
||||
import '../riverpod_controllers/direct_message_services.dart';
|
||||
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||
import '../routes.dart';
|
||||
|
@ -19,13 +20,16 @@ class MessagesScreen extends ConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final profile = ref.watch(activeProfileProvider);
|
||||
final service = ref.watch(directMessageThreadIdsProvider(profile).notifier);
|
||||
ref.watch(directMessageThreadIdsProvider(profile));
|
||||
final loading = ref.watch(directMessageLoadingProvider(profile));
|
||||
|
||||
return Scaffold(
|
||||
appBar: StandardAppBar.build(context, 'Direct Message Threads', actions: [
|
||||
StatusAndRefreshButton2(
|
||||
watcher: (ref2) => ref2.watch(directMessageLoadingProvider(profile)),
|
||||
refreshFunction: () async => await service.update(),
|
||||
StatusAndRefreshButton3(
|
||||
executing: loading,
|
||||
refreshFunction: () async => await ref
|
||||
.read(directMessageThreadIdsProvider(profile).notifier)
|
||||
.update(),
|
||||
busyColor: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
IconButton(
|
||||
|
@ -37,44 +41,68 @@ class MessagesScreen extends ConsumerWidget {
|
|||
]),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await service.update();
|
||||
await ref
|
||||
.read(directMessageThreadIdsProvider(profile).notifier)
|
||||
.update();
|
||||
},
|
||||
child: Center(child: buildBody(profile, ref)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
if (loading) const LinearProgressIndicator(),
|
||||
Expanded(child: buildBody(profile, ref))
|
||||
],
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBody(Profile profile, WidgetRef ref) {
|
||||
final threadIds = ref.watch(directMessageThreadIdsProvider(profile));
|
||||
|
||||
return threadIds.isEmpty
|
||||
? const Text('No Direct Message Threads')
|
||||
: ResponsiveMaxWidth(
|
||||
child: ListView.separated(
|
||||
itemCount: threadIds.length,
|
||||
itemBuilder: (context, index) {
|
||||
itemBuilder: (context, i) {
|
||||
final index = i;
|
||||
final threadId = threadIds[index];
|
||||
final thread = ref.watch(
|
||||
directMessageThreadServiceProvider(profile, threadId));
|
||||
final style = thread.allSeen
|
||||
? null
|
||||
: const TextStyle(fontWeight: FontWeight.bold);
|
||||
final participantsAvatars = <String>[];
|
||||
final participantNames = <String>[];
|
||||
for (final pid in thread.participantIds) {
|
||||
if (pid == profile.userId) {
|
||||
continue;
|
||||
}
|
||||
ref.watch(connectionByIdProvider(profile, pid)).match(
|
||||
onSuccess: (c) {
|
||||
participantsAvatars.add(c.avatarUrl);
|
||||
participantNames.add('${c.name}(${c.handle})');
|
||||
},
|
||||
onError: (_) => participantNames.add('Person 1'));
|
||||
}
|
||||
return ListTile(
|
||||
onTap: () => context.pushNamed(
|
||||
ScreenPaths.thread,
|
||||
queryParameters: {'uri': thread.parentUri},
|
||||
),
|
||||
leading: ImageControl(
|
||||
imageUrl: thread.participants.first.avatarUrl.toString(),
|
||||
iconOverride: const Icon(Icons.person),
|
||||
width: 32.0,
|
||||
onTap: null,
|
||||
),
|
||||
leading: thread.participantIds.isEmpty
|
||||
? null
|
||||
: ImageControl(
|
||||
imageUrl: participantsAvatars.first,
|
||||
iconOverride: const Icon(Icons.person),
|
||||
width: 32.0,
|
||||
onTap: null,
|
||||
),
|
||||
title: Text(
|
||||
[
|
||||
'You',
|
||||
...thread.participants
|
||||
.map((p) => '${p.name}(${p.handle})')
|
||||
].join(thread.participants.length == 1 ? ' & ' : ', '),
|
||||
...participantNames,
|
||||
].join(participantNames.length == 1 ? ' & ' : ', '),
|
||||
softWrap: true,
|
||||
style: style,
|
||||
),
|
||||
|
@ -83,8 +111,10 @@ class MessagesScreen extends ConsumerWidget {
|
|||
style: style,
|
||||
),
|
||||
trailing: Text(
|
||||
ElapsedDateUtils.elapsedTimeStringFromEpochSeconds(
|
||||
thread.messages.last.createdAt),
|
||||
thread.messages.isEmpty
|
||||
? ''
|
||||
: ElapsedDateUtils.elapsedTimeStringFromEpochSeconds(
|
||||
thread.messages.last.createdAt),
|
||||
style: style,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -40,21 +40,6 @@ extension DirectMessageFriendicaExtension on DirectMessage {
|
|||
|
||||
final String parentUri = json['friendica_parent_uri'];
|
||||
|
||||
// TODO Add back when RP conversion is complete
|
||||
// getIt<ActiveProfileSelector<ConnectionsManager>>()
|
||||
// .activeEntry
|
||||
// .andThenSuccess((cm) {
|
||||
// if (getIt<AccountsService>().currentProfile.userId != senderId) {
|
||||
// final s = ConnectionFriendicaExtensions.fromJson(json['sender']);
|
||||
// cm.upsertConnection(s);
|
||||
// }
|
||||
//
|
||||
// if (getIt<AccountsService>().currentProfile.userId != recipientId) {
|
||||
// final r = ConnectionFriendicaExtensions.fromJson(json['recipient']);
|
||||
// cm.upsertConnection(r);
|
||||
// }
|
||||
// });
|
||||
|
||||
return DirectMessage(
|
||||
id: id,
|
||||
senderId: senderId,
|
||||
|
|
Ładowanie…
Reference in New Issue