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',
|
'Settings',
|
||||||
() => context.pushNamed(ScreenPaths.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/foundation.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
import '../riverpod_controllers/connection_manager_services.dart';
|
|
||||||
import 'auth/profile.dart';
|
import 'auth/profile.dart';
|
||||||
import 'connection.dart';
|
|
||||||
import 'direct_message.dart';
|
import 'direct_message.dart';
|
||||||
|
|
||||||
class DirectMessageThread {
|
class DirectMessageThread {
|
||||||
final List<DirectMessage> messages;
|
final List<DirectMessage> messages;
|
||||||
|
|
||||||
final List<Connection> participants;
|
final List<String> participantIds;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
|
@ -17,14 +14,22 @@ class DirectMessageThread {
|
||||||
|
|
||||||
DirectMessageThread({
|
DirectMessageThread({
|
||||||
required this.messages,
|
required this.messages,
|
||||||
required this.participants,
|
required this.participantIds,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.parentUri,
|
required this.parentUri,
|
||||||
});
|
});
|
||||||
|
|
||||||
DirectMessageThread deepCopy() => DirectMessageThread(
|
DirectMessageThread deepCopy() => DirectMessageThread(
|
||||||
messages: List.from(messages),
|
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,
|
title: title,
|
||||||
parentUri: parentUri,
|
parentUri: parentUri,
|
||||||
);
|
);
|
||||||
|
@ -36,7 +41,6 @@ class DirectMessageThread {
|
||||||
.reduce((allUnseen, thisUnseen) => allUnseen && thisUnseen);
|
.reduce((allUnseen, thisUnseen) => allUnseen && thisUnseen);
|
||||||
|
|
||||||
static List<DirectMessageThread> createThreads(
|
static List<DirectMessageThread> createThreads(
|
||||||
Ref ref,
|
|
||||||
Profile profile,
|
Profile profile,
|
||||||
Iterable<DirectMessage> messages,
|
Iterable<DirectMessage> messages,
|
||||||
) {
|
) {
|
||||||
|
@ -60,14 +64,9 @@ class DirectMessageThread {
|
||||||
title = m.title;
|
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(
|
final thread = DirectMessageThread(
|
||||||
messages: threadMessages,
|
messages: threadMessages,
|
||||||
participants: participants,
|
participantIds: participantIds.toList(),
|
||||||
title: title,
|
title: title,
|
||||||
parentUri: parentUri,
|
parentUri: parentUri,
|
||||||
);
|
);
|
||||||
|
@ -88,12 +87,12 @@ class DirectMessageThread {
|
||||||
title == other.title &&
|
title == other.title &&
|
||||||
parentUri == other.parentUri &&
|
parentUri == other.parentUri &&
|
||||||
listEquals(messages, other.messages) &&
|
listEquals(messages, other.messages) &&
|
||||||
listEquals(participants, other.participants);
|
listEquals(participantIds, other.participantIds);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
title.hashCode ^
|
title.hashCode ^
|
||||||
parentUri.hashCode ^
|
parentUri.hashCode ^
|
||||||
Object.hashAll(messages) ^
|
Object.hashAll(messages) ^
|
||||||
Object.hashAll(participants);
|
Object.hashAll(participantIds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ final activeProfileProvider = NotifierProvider<ActiveProfile, Profile>.internal(
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$ActiveProfile = Notifier<Profile>;
|
typedef _$ActiveProfile = Notifier<Profile>;
|
||||||
String _$credentialSigninHash() => r'9c6515a30bbdd3d8272ad4bba57c98a9391866c9';
|
String _$credentialSigninHash() => r'e9731ad5b916838122a2a86961af4cfe4bef57b5';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@ -236,7 +236,7 @@ class _CredentialSigninProviderElement
|
||||||
(origin as CredentialSigninProvider).credentials;
|
(origin as CredentialSigninProvider).credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$profileManagerHash() => r'2bd46dca2f9307fa0197d21ba55627b89b297884';
|
String _$profileManagerHash() => r'5f37162a9b7b19f3cd9e804d83dbb37cda96568b';
|
||||||
|
|
||||||
abstract class _$ProfileManager extends BuildlessNotifier<bool> {
|
abstract class _$ProfileManager extends BuildlessNotifier<bool> {
|
||||||
late final Profile profile;
|
late final Profile profile;
|
||||||
|
@ -381,7 +381,7 @@ class _ProfileManagerProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$accountServicesInitializerHash() =>
|
String _$accountServicesInitializerHash() =>
|
||||||
r'1872c6987b80737764687a679eb8b987f42c4ff3';
|
r'386b364d2fe41581ad17d5823a7f47dc12bc4760';
|
||||||
|
|
||||||
/// See also [AccountServicesInitializer].
|
/// See also [AccountServicesInitializer].
|
||||||
@ProviderFor(AccountServicesInitializer)
|
@ProviderFor(AccountServicesInitializer)
|
||||||
|
|
|
@ -6,7 +6,7 @@ part of 'blocks_services.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$blocksManagerHash() => r'd04635c7bf3072984d3575a2fdb6c84056729e5e';
|
String _$blocksManagerHash() => r'e8285887e48ab751515c9a2e9fdc0a90ce12e437';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
@ -332,7 +332,7 @@ class _TimelineGroupingListProviderElement
|
||||||
GroupingType get type => (origin as TimelineGroupingListProvider).type;
|
GroupingType get type => (origin as TimelineGroupingListProvider).type;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$circlesRepoHash() => r'f02b6233914071968c47213c79bb64c81f562dd3';
|
String _$circlesRepoHash() => r'82b95a626e70888ea4a4f0a2c1a736cd0bdcf9c9';
|
||||||
|
|
||||||
abstract class _$CirclesRepo extends BuildlessNotifier<ICirclesRepo> {
|
abstract class _$CirclesRepo extends BuildlessNotifier<ICirclesRepo> {
|
||||||
late final Profile profile;
|
late final Profile profile;
|
||||||
|
@ -476,7 +476,7 @@ class _CirclesRepoProviderElement
|
||||||
Profile get profile => (origin as _CirclesRepoProvider).profile;
|
Profile get profile => (origin as _CirclesRepoProvider).profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$circlesHash() => r'fbd0b71fa7027a8c1cf16413df288b666734b180';
|
String _$circlesHash() => r'84741e2bec4232522eadd6f83046b4d147645985';
|
||||||
|
|
||||||
abstract class _$Circles
|
abstract class _$Circles
|
||||||
extends BuildlessNotifier<List<TimelineGroupingListData>> {
|
extends BuildlessNotifier<List<TimelineGroupingListData>> {
|
||||||
|
|
|
@ -1312,7 +1312,7 @@ class _ConnectionsRepoClearerProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$connectionModifierHash() =>
|
String _$connectionModifierHash() =>
|
||||||
r'35d92e5d4c0162ca7c44ab9b9f296856a58704c0';
|
r'75d5a90c167916273292f8e03d462f95a0fe04a3';
|
||||||
|
|
||||||
abstract class _$ConnectionModifier
|
abstract class _$ConnectionModifier
|
||||||
extends BuildlessAutoDisposeNotifier<Connection> {
|
extends BuildlessAutoDisposeNotifier<Connection> {
|
||||||
|
@ -1628,7 +1628,7 @@ class _UpdateStatusInternalProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$allContactsUpdaterHash() =>
|
String _$allContactsUpdaterHash() =>
|
||||||
r'cfab7072e13b11396b4e3aaaed75148fe97f0b55';
|
r'84f97838de84166a1ed907d75eedaa1decf56daf';
|
||||||
|
|
||||||
abstract class _$AllContactsUpdater extends BuildlessNotifier<bool> {
|
abstract class _$AllContactsUpdater extends BuildlessNotifier<bool> {
|
||||||
late final Profile profile;
|
late final Profile profile;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import '../models/exec_error.dart';
|
||||||
import '../models/networking/paging_data.dart';
|
import '../models/networking/paging_data.dart';
|
||||||
import 'feature_checker_services.dart';
|
import 'feature_checker_services.dart';
|
||||||
import 'networking/friendica_dms_client_services.dart';
|
import 'networking/friendica_dms_client_services.dart';
|
||||||
|
import 'notification_services.dart';
|
||||||
|
|
||||||
part 'direct_message_services.g.dart';
|
part 'direct_message_services.g.dart';
|
||||||
|
|
||||||
|
@ -30,8 +31,7 @@ class DirectMessageThreadIds extends _$DirectMessageThreadIds {
|
||||||
|
|
||||||
await ref.read(directMessagesProvider(profile, PagingData()).future).match(
|
await ref.read(directMessagesProvider(profile, PagingData()).future).match(
|
||||||
onSuccess: (update) {
|
onSuccess: (update) {
|
||||||
final newThreads =
|
final newThreads = DirectMessageThread.createThreads(profile, update);
|
||||||
DirectMessageThread.createThreads(ref, profile, update);
|
|
||||||
for (final t in newThreads) {
|
for (final t in newThreads) {
|
||||||
threads.add(t.parentUri);
|
threads.add(t.parentUri);
|
||||||
ref
|
ref
|
||||||
|
@ -69,7 +69,7 @@ class DirectMessageThreadIds extends _$DirectMessageThreadIds {
|
||||||
text,
|
text,
|
||||||
).future);
|
).future);
|
||||||
result.match(onSuccess: (newMessage) {
|
result.match(onSuccess: (newMessage) {
|
||||||
DirectMessageThread.createThreads(ref, profile, [newMessage])
|
DirectMessageThread.createThreads(profile, [newMessage])
|
||||||
.forEach((thread) {
|
.forEach((thread) {
|
||||||
state = [...state, thread.parentUri];
|
state = [...state, thread.parentUri];
|
||||||
ref
|
ref
|
||||||
|
@ -97,7 +97,7 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
||||||
threadId = id;
|
threadId = id;
|
||||||
state = DirectMessageThread(
|
state = DirectMessageThread(
|
||||||
messages: [],
|
messages: [],
|
||||||
participants: [],
|
participantIds: [],
|
||||||
title: 'Uninitialized',
|
title: 'Uninitialized',
|
||||||
parentUri: '',
|
parentUri: '',
|
||||||
);
|
);
|
||||||
|
@ -108,6 +108,16 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
||||||
state = thread;
|
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(
|
FutureResult<DirectMessage, ExecError> newReplyMessage(
|
||||||
DirectMessage original, String text) async {
|
DirectMessage original, String text) async {
|
||||||
if (!state.messages.contains(original)) {
|
if (!state.messages.contains(original)) {
|
||||||
|
@ -159,6 +169,7 @@ class DirectMessageThreadService extends _$DirectMessageThreadService {
|
||||||
final newState = state.deepCopy();
|
final newState = state.deepCopy();
|
||||||
newState.messages[oldIndex] = updatedItem;
|
newState.messages[oldIndex] = updatedItem;
|
||||||
update(newState);
|
update(newState);
|
||||||
|
ref.read(notificationsManagerProvider(profile).notifier).refreshDms();
|
||||||
},
|
},
|
||||||
onError: (error) {
|
onError: (error) {
|
||||||
_logger.severe(
|
_logger.severe(
|
||||||
|
|
|
@ -7,7 +7,7 @@ part of 'direct_message_services.dart';
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$directMessageThreadIdsHash() =>
|
String _$directMessageThreadIdsHash() =>
|
||||||
r'76d081ab346af0247a62dc58f270a064b355f26f';
|
r'ce42c0a00ab785c7685f8c135bada67bea2fcb14';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@ -175,7 +175,7 @@ class _DirectMessageThreadIdsProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$directMessageThreadServiceHash() =>
|
String _$directMessageThreadServiceHash() =>
|
||||||
r'83940611b62a1bb4616f5ebbb93e1398f34db607';
|
r'5ef67edc0bb13c3834ed998bd107af36762fde79';
|
||||||
|
|
||||||
abstract class _$DirectMessageThreadService
|
abstract class _$DirectMessageThreadService
|
||||||
extends BuildlessNotifier<DirectMessageThread> {
|
extends BuildlessNotifier<DirectMessageThread> {
|
||||||
|
|
|
@ -739,7 +739,7 @@ class _EntryTreeManagerProviderElement extends NotifierProviderElement<
|
||||||
String get id => (origin as EntryTreeManagerProvider).id;
|
String get id => (origin as EntryTreeManagerProvider).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$timelineUpdaterHash() => r'8359f110e4718fb2048d8ce3c0a885bd3d064d28';
|
String _$timelineUpdaterHash() => r'38d091cafcfa347f52bd3260d7ab72178bd2dc7b';
|
||||||
|
|
||||||
abstract class _$TimelineUpdater extends BuildlessAutoDisposeNotifier<bool> {
|
abstract class _$TimelineUpdater extends BuildlessAutoDisposeNotifier<bool> {
|
||||||
late final Profile profile;
|
late final Profile profile;
|
||||||
|
|
|
@ -294,7 +294,7 @@ class _VersionErrorStringProviderElement
|
||||||
(origin as VersionErrorStringProvider).feature;
|
(origin as VersionErrorStringProvider).feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$featureCheckHash() => r'efedd8bae092a28579b6e750088c07e1b35357d6';
|
String _$featureCheckHash() => r'8e60d2e4278f205aac2e0e434b595cb7aa5b192b';
|
||||||
|
|
||||||
/// See also [featureCheck].
|
/// See also [featureCheck].
|
||||||
@ProviderFor(featureCheck)
|
@ProviderFor(featureCheck)
|
||||||
|
|
|
@ -7,7 +7,7 @@ part of 'instance_info_services.dart';
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$instanceInfoManagerHash() =>
|
String _$instanceInfoManagerHash() =>
|
||||||
r'8d591a07234dadde0560ded347cb3499779c4070';
|
r'88f181cbbee4b4043bf0be55e8379fcc8ad2b8b3';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
@ -46,6 +46,36 @@ Future<Result<List<DirectMessage>, ExecError>> directMessages(
|
||||||
return result;
|
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
|
@riverpod
|
||||||
Future<Result<DirectMessage, ExecError>> markDirectMessageRead(
|
Future<Result<DirectMessage, ExecError>> markDirectMessageRead(
|
||||||
Ref ref,
|
Ref ref,
|
||||||
|
|
|
@ -180,6 +180,175 @@ class _DirectMessagesProviderElement extends AutoDisposeFutureProviderElement<
|
||||||
PagingData get page => (origin as DirectMessagesProvider).page;
|
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() =>
|
String _$markDirectMessageReadHash() =>
|
||||||
r'62d62dd9e1cf638b0364cdeab742df00da685ccc';
|
r'62d62dd9e1cf638b0364cdeab742df00da685ccc';
|
||||||
|
|
||||||
|
|
|
@ -645,7 +645,7 @@ class _GetMyFollowersProviderElement extends AutoDisposeFutureProviderElement<
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$connectionWithStatusClientHash() =>
|
String _$connectionWithStatusClientHash() =>
|
||||||
r'65dde1fad60635c3de95b440ae3046ce47676a9d';
|
r'687d060bab00296f5aa802713af4ea47989536b4';
|
||||||
|
|
||||||
/// See also [connectionWithStatusClient].
|
/// See also [connectionWithStatusClient].
|
||||||
@ProviderFor(connectionWithStatusClient)
|
@ProviderFor(connectionWithStatusClient)
|
||||||
|
|
|
@ -350,7 +350,7 @@ class _DeleteStatusEntryByIdProviderElement
|
||||||
String get id => (origin as DeleteStatusEntryByIdProvider).id;
|
String get id => (origin as DeleteStatusEntryByIdProvider).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$createNewStatusHash() => r'6c2ddd3e4acd4f01d30c2c8d85dc15e36db83501';
|
String _$createNewStatusHash() => r'c140a6e3a2776edb93a0e389ef5115d3b2e85fb0';
|
||||||
|
|
||||||
/// See also [createNewStatus].
|
/// See also [createNewStatus].
|
||||||
@ProviderFor(createNewStatus)
|
@ProviderFor(createNewStatus)
|
||||||
|
@ -568,7 +568,7 @@ class _CreateNewStatusProviderElement
|
||||||
Visibility get visibility => (origin as CreateNewStatusProvider).visibility;
|
Visibility get visibility => (origin as CreateNewStatusProvider).visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$editStatusHash() => r'94d0d20e834b16f2d8a09feba003ec89b628bf22';
|
String _$editStatusHash() => r'cad5eeef14a26a7886c129230fa5e7f1c78da7e7';
|
||||||
|
|
||||||
/// See also [editStatus].
|
/// See also [editStatus].
|
||||||
@ProviderFor(editStatus)
|
@ProviderFor(editStatus)
|
||||||
|
@ -922,7 +922,7 @@ class _ResharePostProviderElement
|
||||||
String get id => (origin as ResharePostProvider).id;
|
String get id => (origin as ResharePostProvider).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$unResharePostHash() => r'4b7ca0426ec3c016624c825af43495ba2a21f17d';
|
String _$unResharePostHash() => r'6f8ea49b584ca01a2a6d87064fa682d3dc78311d';
|
||||||
|
|
||||||
/// See also [unResharePost].
|
/// See also [unResharePost].
|
||||||
@ProviderFor(unResharePost)
|
@ProviderFor(unResharePost)
|
||||||
|
|
|
@ -6,12 +6,14 @@ import 'package:stack_trace/stack_trace.dart';
|
||||||
|
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../models/auth/profile.dart';
|
import '../models/auth/profile.dart';
|
||||||
|
import '../models/connection.dart';
|
||||||
import '../models/exec_error.dart';
|
import '../models/exec_error.dart';
|
||||||
import '../models/networking/paged_response.dart';
|
import '../models/networking/paged_response.dart';
|
||||||
import '../models/networking/pages_manager.dart';
|
import '../models/networking/pages_manager.dart';
|
||||||
import '../models/networking/paging_data.dart';
|
import '../models/networking/paging_data.dart';
|
||||||
import '../models/user_notification.dart';
|
import '../models/user_notification.dart';
|
||||||
import '../serializers/mastodon/follow_request_mastodon_extensions.dart';
|
import '../serializers/mastodon/follow_request_mastodon_extensions.dart';
|
||||||
|
import 'connection_manager_services.dart';
|
||||||
import 'direct_message_services.dart';
|
import 'direct_message_services.dart';
|
||||||
import 'feature_checker_services.dart';
|
import 'feature_checker_services.dart';
|
||||||
import 'follow_requests_services.dart';
|
import 'follow_requests_services.dart';
|
||||||
|
@ -62,7 +64,23 @@ class NotificationsManager extends _$NotificationsManager {
|
||||||
Future<void> refreshConnectionRequestNotifications() async {
|
Future<void> refreshConnectionRequestNotifications() async {
|
||||||
_logger.info('refreshConnectionRequestNotifications');
|
_logger.info('refreshConnectionRequestNotifications');
|
||||||
connectionRequests.clear();
|
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}) {
|
void clear({bool withListenerNotification = true}) {
|
||||||
|
@ -254,7 +272,10 @@ class NotificationsManager extends _$NotificationsManager {
|
||||||
.map((id) => ref.watch(directMessageThreadServiceProvider(profile, id)))
|
.map((id) => ref.watch(directMessageThreadServiceProvider(profile, id)))
|
||||||
.where((t) => !t.allSeen)
|
.where((t) => !t.allSeen)
|
||||||
.map((t) {
|
.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 =
|
final latestMessage =
|
||||||
t.messages.reduce((s, m) => s.createdAt > m.createdAt ? s : m);
|
t.messages.reduce((s, m) => s.createdAt > m.createdAt ? s : m);
|
||||||
return UserNotification(
|
return UserNotification(
|
||||||
|
|
|
@ -7,7 +7,7 @@ part of 'notification_services.dart';
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$notificationsManagerHash() =>
|
String _$notificationsManagerHash() =>
|
||||||
r'c7a691dce74c2a2db04fd78a459a13c9d8256e18';
|
r'dc6a88e34b4d6bc3cea3541aba7453e223374842';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
@ -6,7 +6,7 @@ part of 'persistent_info_services.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$persistentInfoHash() => r'8881204fcc60dcf435340cc5c28e1e293c97dbe3';
|
String _$persistentInfoHash() => r'62bf2f76f88d746cf75f4b663d76302d4c3213fd';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
@ -329,7 +329,7 @@ class _CheckTimelineEntryProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$timelineEntryFiltersHash() =>
|
String _$timelineEntryFiltersHash() =>
|
||||||
r'dd386f6ecd047a1dcd8602451c7a445510b03f7d';
|
r'cd4344f10166b5cabb7869c350e6d83f571cb20d';
|
||||||
|
|
||||||
abstract class _$TimelineEntryFilters
|
abstract class _$TimelineEntryFilters
|
||||||
extends BuildlessNotifier<Map<String, TimelineEntryFilter>> {
|
extends BuildlessNotifier<Map<String, TimelineEntryFilter>> {
|
||||||
|
|
|
@ -173,7 +173,7 @@ class _TimelineMaintainerProviderElement extends NotifierProviderElement<
|
||||||
Profile get profile => (origin as TimelineMaintainerProvider).profile;
|
Profile get profile => (origin as TimelineMaintainerProvider).profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$timelineManagerHash() => r'fa6c46745b69e61ce3dd8cb07822d428ea8b66f5';
|
String _$timelineManagerHash() => r'9f806c36aeb207547fde5a352df1c1fb051cc9af';
|
||||||
|
|
||||||
abstract class _$TimelineManager extends BuildlessNotifier<Timeline> {
|
abstract class _$TimelineManager extends BuildlessNotifier<Timeline> {
|
||||||
late final Profile profile;
|
late final Profile profile;
|
||||||
|
|
|
@ -6,10 +6,14 @@ import '../controls/image_control.dart';
|
||||||
import '../controls/padding.dart';
|
import '../controls/padding.dart';
|
||||||
import '../controls/responsive_max_width.dart';
|
import '../controls/responsive_max_width.dart';
|
||||||
import '../controls/standard_appbar.dart';
|
import '../controls/standard_appbar.dart';
|
||||||
|
import '../controls/status_and_refresh_button.dart';
|
||||||
import '../models/auth/profile.dart';
|
import '../models/auth/profile.dart';
|
||||||
|
import '../models/direct_message.dart';
|
||||||
import '../models/direct_message_thread.dart';
|
import '../models/direct_message_thread.dart';
|
||||||
import '../riverpod_controllers/account_services.dart';
|
import '../riverpod_controllers/account_services.dart';
|
||||||
|
import '../riverpod_controllers/connection_manager_services.dart';
|
||||||
import '../riverpod_controllers/direct_message_services.dart';
|
import '../riverpod_controllers/direct_message_services.dart';
|
||||||
|
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||||
import '../utils/clipboard_utils.dart';
|
import '../utils/clipboard_utils.dart';
|
||||||
import '../utils/snackbar_builder.dart';
|
import '../utils/snackbar_builder.dart';
|
||||||
|
|
||||||
|
@ -29,63 +33,57 @@ class MessageThreadScreen extends ConsumerStatefulWidget {
|
||||||
class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
||||||
final textController = TextEditingController();
|
final textController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
ref
|
||||||
|
.read(directMessageThreadServiceProvider(
|
||||||
|
ref.read(activeProfileProvider),
|
||||||
|
widget.parentThreadId,
|
||||||
|
).notifier)
|
||||||
|
.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final profile = ref.watch(activeProfileProvider);
|
final profile = ref.watch(activeProfileProvider);
|
||||||
final t = ref.watch(
|
final loading = ref.watch(directMessageLoadingProvider(profile));
|
||||||
|
final thread = ref.watch(
|
||||||
directMessageThreadServiceProvider(profile, widget.parentThreadId));
|
directMessageThreadServiceProvider(profile, widget.parentThreadId));
|
||||||
final title = t.title.isEmpty ? 'Thread' : t.title;
|
final title = thread.title.isEmpty ? 'Thread' : thread.title;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: StandardAppBar.build(context, title),
|
appBar: StandardAppBar.build(context, title, actions: [
|
||||||
body: buildBody(profile, t),
|
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(
|
Widget buildBody(
|
||||||
Profile profile,
|
Profile profile,
|
||||||
DirectMessageThread thread,
|
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(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
if (loading) const LinearProgressIndicator(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ResponsiveMaxWidth(
|
child: ResponsiveMaxWidth(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final m = thread.messages[index];
|
final m = thread.messages[index];
|
||||||
final textPieces = m.text.split('...\n');
|
return _DirectMessageListItem(
|
||||||
final text =
|
m, profile, widget.parentThreadId);
|
||||||
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()),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
separatorBuilder: (_, __) => const Divider(),
|
separatorBuilder: (_, __) => const Divider(),
|
||||||
itemCount: thread.messages.length),
|
itemCount: thread.messages.length),
|
||||||
|
@ -119,13 +117,16 @@ class _MessageThreadScreenState extends ConsumerState<MessageThreadScreen> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final othersMessages =
|
final othersMessages =
|
||||||
thread.messages.where((m) => m.senderId != yourId);
|
thread.messages.where((m) => m.senderId != profile.userId);
|
||||||
if (othersMessages.isEmpty) {
|
if (othersMessages.isEmpty) {
|
||||||
buildSnackbar(
|
buildSnackbar(
|
||||||
context, "Have to wait for a response before sending");
|
context, "Have to wait for a response before sending");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await service
|
await ref
|
||||||
|
.read(directMessageThreadServiceProvider(
|
||||||
|
profile, thread.parentUri)
|
||||||
|
.notifier)
|
||||||
.newReplyMessage(
|
.newReplyMessage(
|
||||||
othersMessages.last,
|
othersMessages.last,
|
||||||
textController.text,
|
textController.text,
|
||||||
|
@ -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 '../controls/status_and_refresh_button.dart';
|
||||||
import '../models/auth/profile.dart';
|
import '../models/auth/profile.dart';
|
||||||
import '../riverpod_controllers/account_services.dart';
|
import '../riverpod_controllers/account_services.dart';
|
||||||
|
import '../riverpod_controllers/connection_manager_services.dart';
|
||||||
import '../riverpod_controllers/direct_message_services.dart';
|
import '../riverpod_controllers/direct_message_services.dart';
|
||||||
import '../riverpod_controllers/networking/network_status_services.dart';
|
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||||
import '../routes.dart';
|
import '../routes.dart';
|
||||||
|
@ -19,13 +20,16 @@ class MessagesScreen extends ConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final profile = ref.watch(activeProfileProvider);
|
final profile = ref.watch(activeProfileProvider);
|
||||||
final service = ref.watch(directMessageThreadIdsProvider(profile).notifier);
|
ref.watch(directMessageThreadIdsProvider(profile));
|
||||||
|
final loading = ref.watch(directMessageLoadingProvider(profile));
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: StandardAppBar.build(context, 'Direct Message Threads', actions: [
|
appBar: StandardAppBar.build(context, 'Direct Message Threads', actions: [
|
||||||
StatusAndRefreshButton2(
|
StatusAndRefreshButton3(
|
||||||
watcher: (ref2) => ref2.watch(directMessageLoadingProvider(profile)),
|
executing: loading,
|
||||||
refreshFunction: () async => await service.update(),
|
refreshFunction: () async => await ref
|
||||||
|
.read(directMessageThreadIdsProvider(profile).notifier)
|
||||||
|
.update(),
|
||||||
busyColor: Theme.of(context).colorScheme.surface,
|
busyColor: Theme.of(context).colorScheme.surface,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
@ -37,34 +41,59 @@ class MessagesScreen extends ConsumerWidget {
|
||||||
]),
|
]),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () async {
|
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) {
|
Widget buildBody(Profile profile, WidgetRef ref) {
|
||||||
final threadIds = ref.watch(directMessageThreadIdsProvider(profile));
|
final threadIds = ref.watch(directMessageThreadIdsProvider(profile));
|
||||||
|
|
||||||
return threadIds.isEmpty
|
return threadIds.isEmpty
|
||||||
? const Text('No Direct Message Threads')
|
? const Text('No Direct Message Threads')
|
||||||
: ResponsiveMaxWidth(
|
: ResponsiveMaxWidth(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
itemCount: threadIds.length,
|
itemCount: threadIds.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, i) {
|
||||||
|
final index = i;
|
||||||
final threadId = threadIds[index];
|
final threadId = threadIds[index];
|
||||||
final thread = ref.watch(
|
final thread = ref.watch(
|
||||||
directMessageThreadServiceProvider(profile, threadId));
|
directMessageThreadServiceProvider(profile, threadId));
|
||||||
final style = thread.allSeen
|
final style = thread.allSeen
|
||||||
? null
|
? null
|
||||||
: const TextStyle(fontWeight: FontWeight.bold);
|
: 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(
|
return ListTile(
|
||||||
onTap: () => context.pushNamed(
|
onTap: () => context.pushNamed(
|
||||||
ScreenPaths.thread,
|
ScreenPaths.thread,
|
||||||
queryParameters: {'uri': thread.parentUri},
|
queryParameters: {'uri': thread.parentUri},
|
||||||
),
|
),
|
||||||
leading: ImageControl(
|
leading: thread.participantIds.isEmpty
|
||||||
imageUrl: thread.participants.first.avatarUrl.toString(),
|
? null
|
||||||
|
: ImageControl(
|
||||||
|
imageUrl: participantsAvatars.first,
|
||||||
iconOverride: const Icon(Icons.person),
|
iconOverride: const Icon(Icons.person),
|
||||||
width: 32.0,
|
width: 32.0,
|
||||||
onTap: null,
|
onTap: null,
|
||||||
|
@ -72,9 +101,8 @@ class MessagesScreen extends ConsumerWidget {
|
||||||
title: Text(
|
title: Text(
|
||||||
[
|
[
|
||||||
'You',
|
'You',
|
||||||
...thread.participants
|
...participantNames,
|
||||||
.map((p) => '${p.name}(${p.handle})')
|
].join(participantNames.length == 1 ? ' & ' : ', '),
|
||||||
].join(thread.participants.length == 1 ? ' & ' : ', '),
|
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
|
@ -83,7 +111,9 @@ class MessagesScreen extends ConsumerWidget {
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
ElapsedDateUtils.elapsedTimeStringFromEpochSeconds(
|
thread.messages.isEmpty
|
||||||
|
? ''
|
||||||
|
: ElapsedDateUtils.elapsedTimeStringFromEpochSeconds(
|
||||||
thread.messages.last.createdAt),
|
thread.messages.last.createdAt),
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
|
|
|
@ -40,21 +40,6 @@ extension DirectMessageFriendicaExtension on DirectMessage {
|
||||||
|
|
||||||
final String parentUri = json['friendica_parent_uri'];
|
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(
|
return DirectMessage(
|
||||||
id: id,
|
id: id,
|
||||||
senderId: senderId,
|
senderId: senderId,
|
||||||
|
|
Ładowanie…
Reference in New Issue