Merge branch 'notifications-update-fixes' into 'main'

Fix don't mark connection requests as unread on "markAllUnread" since they...

See merge request mysocialportal/relatica!73
main
HankG 2025-10-13 21:21:13 +00:00
commit 6997bc60fe
3 zmienionych plików z 77 dodań i 64 usunięć

Wyświetl plik

@ -27,7 +27,8 @@ class AppBottomNavBar extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final profile = ref.watch(activeProfileProvider); final profile = ref.watch(activeProfileProvider);
ref.watch(notificationsManagerProvider(profile)); ref.watch(notificationsManagerProvider(profile));
final hasNotifications = ref.read(hasNotificationsProvider(profile, false)); final hasNotifications =
ref.watch(hasNotificationsProvider(profile, false));
return BottomNavigationBar( return BottomNavigationBar(
onTap: (index) { onTap: (index) {

Wyświetl plik

@ -48,17 +48,23 @@ class _NotificationsStore extends _$NotificationsStore {
} }
void markAllRead() { void markAllRead() {
final connectionRequests = _values
.where((n) => n.type == NotificationType.follow_request)
.toList();
final updated = _values.map((n) => n.copy(dismissed: true)).toList(); final updated = _values.map((n) => n.copy(dismissed: true)).toList();
_values.clear(); _values.clear();
_values.addAll(connectionRequests);
_values.addAll(updated); _values.addAll(updated);
state = _rval; state = _rval;
} }
List<UserNotification> get _rval => _values.toList()..sort(); List<UserNotification> get _rval =>
_values.toList()
..sort();
@override @override
bool updateShouldNotify( bool updateShouldNotify(List<UserNotification> previous,
List<UserNotification> previous, List<UserNotification> next) { List<UserNotification> next) {
final rval = !listEqualsWithComparer( final rval = !listEqualsWithComparer(
previous, previous,
next, next,
@ -70,8 +76,8 @@ class _NotificationsStore extends _$NotificationsStore {
} }
@riverpod @riverpod
List<UserNotification> userNotificationsByType( List<UserNotification> userNotificationsByType(Ref ref, Profile profile,
Ref ref, Profile profile, NotificationType type, bool isRead) { NotificationType type, bool isRead) {
_logger.fine('Build userNotificationsByTypeProvider($type,$isRead,$profile)'); _logger.fine('Build userNotificationsByTypeProvider($type,$isRead,$profile)');
final notifications = ref.watch(_NotificationsStoreProvider(profile, type)); final notifications = ref.watch(_NotificationsStoreProvider(profile, type));
return notifications.where((n) => n.dismissed == isRead).toList(); return notifications.where((n) => n.dismissed == isRead).toList();
@ -161,8 +167,8 @@ class NotificationsManager extends _$NotificationsManager {
_logger.info('clearConnectionRequestNotifications'); _logger.info('clearConnectionRequestNotifications');
ref ref
.read(_NotificationsStoreProvider( .read(_NotificationsStoreProvider(
profile, NotificationType.follow_request) profile, NotificationType.follow_request)
.notifier) .notifier)
.clear(); .clear();
state = const AsyncData(true); state = const AsyncData(true);
} }
@ -181,8 +187,8 @@ class NotificationsManager extends _$NotificationsManager {
_logger.info('refreshDms'); _logger.info('refreshDms');
ref ref
.read(_NotificationsStoreProvider( .read(_NotificationsStoreProvider(
profile, NotificationType.direct_message) profile, NotificationType.direct_message)
.notifier) .notifier)
.clear(); .clear();
await _postFetchOperations( await _postFetchOperations(
[], [],
@ -205,20 +211,21 @@ class NotificationsManager extends _$NotificationsManager {
var count = 0; var count = 0;
while (hasMore && count < maxCalls) { while (hasMore && count < maxCalls) {
final result = final result =
first ? await pm.initialize(_itemsPerQuery) : await pm.nextFromEnd(); first ? await pm.initialize(_itemsPerQuery) : await pm.nextFromEnd();
first = false; first = false;
result.match( result.match(
onSuccess: (nd) => onSuccess: (nd) =>
_logger.fine('Got ${nd.data.length} notifications'), _logger.fine('Got ${nd.data.length} notifications'),
onError: (e) => _logger.severe( onError: (e) =>
_logger.severe(
'Error getting notification: $e', 'Error getting notification: $e',
Trace.current(), Trace.current(),
)); ));
final response = result.getValueOrElse(() => PagedResponse([])); final response = result.getValueOrElse(() => PagedResponse([]));
response.data response.data
.where((n) => .where((n) =>
!useActualRequests || n.type != NotificationType.follow_request) !useActualRequests || n.type != NotificationType.follow_request)
.forEach(notificationsFromRefresh.add); .forEach(notificationsFromRefresh.add);
hasMore = response.next != null; hasMore = response.next != null;
count++; count++;
@ -235,10 +242,10 @@ class NotificationsManager extends _$NotificationsManager {
} }
FutureResult<List<UserNotification>, ExecError> _postFetchOperations( FutureResult<List<UserNotification>, ExecError> _postFetchOperations(
List<UserNotification> notificationsFromRefresh, { List<UserNotification> notificationsFromRefresh, {
bool updateDms = true, bool updateDms = true,
bool updateFollowRequests = true, bool updateFollowRequests = true,
}) async { }) async {
if (updateDms) { if (updateDms) {
if (DateTime.now().difference(lastDmsUpdate) > if (DateTime.now().difference(lastDmsUpdate) >
_minimumDmsAndCrsUpdateDuration) { _minimumDmsAndCrsUpdateDuration) {
@ -266,7 +273,7 @@ class NotificationsManager extends _$NotificationsManager {
final notifications = <String, UserNotification>{}; final notifications = <String, UserNotification>{};
notificationsFromRefresh.removeWhere((n) => notificationsFromRefresh.removeWhere((n) =>
n.type == NotificationType.direct_message || n.type == NotificationType.direct_message ||
(useActualRequests && n.type == NotificationType.follow_request)); (useActualRequests && n.type == NotificationType.follow_request));
for (final n in notificationsFromRefresh) { for (final n in notificationsFromRefresh) {
notifications[n.id] = n; notifications[n.id] = n;
@ -292,24 +299,24 @@ class NotificationsManager extends _$NotificationsManager {
initialPages: hasNoNotifications initialPages: hasNoNotifications
? [] ? []
: [ : [
PagedResponse( PagedResponse(
<String>[], <String>[],
previous: PagingData( previous: PagingData(
minId: highestId, minId: highestId,
limit: _itemsPerQuery, limit: _itemsPerQuery,
), ),
) )
], ],
); );
final stillNoNotifications = final stillNoNotifications =
!ref.read(hasAnyNotificationsProvider(profile)); !ref.read(hasAnyNotificationsProvider(profile));
final result = await (stillNoNotifications final result = await (stillNoNotifications
? pm.initialize(_itemsPerQuery) ? pm.initialize(_itemsPerQuery)
: pm.previousFromBeginning()) : pm.previousFromBeginning())
.andThenAsync( .andThenAsync(
(page) async => await _postFetchOperations(page.data), (page) async => await _postFetchOperations(page.data),
) )
.withError( .withError(
(error) => _logger.info('Error getting more updates: $error')); (error) => _logger.info('Error getting more updates: $error'));
return result.mapValue((value) => value.isNotEmpty).execErrorCast(); return result.mapValue((value) => value.isNotEmpty).execErrorCast();
@ -322,8 +329,8 @@ class NotificationsManager extends _$NotificationsManager {
final nonDmAndConnectionNotifications = result final nonDmAndConnectionNotifications = result
.getValueOrElse(() => []) .getValueOrElse(() => [])
.where((n) => .where((n) =>
n.type != NotificationType.follow_request && n.type != NotificationType.follow_request &&
n.type != NotificationType.direct_message) n.type != NotificationType.direct_message)
.toList(); .toList();
if (nonDmAndConnectionNotifications.isNotEmpty) { if (nonDmAndConnectionNotifications.isNotEmpty) {
return Result.ok(true); return Result.ok(true);
@ -341,7 +348,7 @@ class NotificationsManager extends _$NotificationsManager {
.withResult((_) { .withResult((_) {
ref ref
.read( .read(
_NotificationsStoreProvider(profile, notification.type).notifier) _NotificationsStoreProvider(profile, notification.type).notifier)
.upsert(notification.copy(dismissed: true)); .upsert(notification.copy(dismissed: true));
}); });
@ -375,7 +382,7 @@ class NotificationsManager extends _$NotificationsManager {
.watch(connectionByIdProvider(profile, fromAccountId)) .watch(connectionByIdProvider(profile, fromAccountId))
.getValueOrElse(() => Connection()); .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(
id: (fromAccount.hashCode ^ t.parentUri.hashCode ^ t.title.hashCode) id: (fromAccount.hashCode ^ t.parentUri.hashCode ^ t.title.hashCode)
.toString(), .toString(),
@ -393,16 +400,17 @@ class NotificationsManager extends _$NotificationsManager {
final followRequestResult = !useActualRequests final followRequestResult = !useActualRequests
? <UserNotification>[] ? <UserNotification>[]
: ref : ref
.watch(followRequestListProvider(profile)) .watch(followRequestListProvider(profile))
.map((r) => r.toUserNotification()) .map((r) => r.toUserNotification())
.toList(); .toList();
return [...dmsResult, ...followRequestResult]; return [...dmsResult, ...followRequestResult];
} }
Future<void> _processNewNotifications( Future<void> _processNewNotifications(
Iterable<UserNotification> notifications) async { Iterable<UserNotification> notifications) async {
final st = Stopwatch()..start(); final st = Stopwatch()
..start();
for (final n in notifications) { for (final n in notifications) {
if (st.elapsedMilliseconds > maxProcessingMillis) { if (st.elapsedMilliseconds > maxProcessingMillis) {
@ -413,7 +421,7 @@ class NotificationsManager extends _$NotificationsManager {
} }
FutureResult<List<UserNotification>, ExecError> FutureResult<List<UserNotification>, ExecError>
_loadOlderUnreadNotifications() async { _loadOlderUnreadNotifications() async {
_logger.finest('Loading Older Unread Notifications'); _logger.finest('Loading Older Unread Notifications');
final (lowestId, _) = ref.read(lowHighIdProvider(profile, false)); final (lowestId, _) = ref.read(lowHighIdProvider(profile, false));
final pm = _buildPageManager( final pm = _buildPageManager(
@ -435,17 +443,19 @@ class NotificationsManager extends _$NotificationsManager {
.nextFromEnd() .nextFromEnd()
.andThenAsync( .andThenAsync(
(page) async => await _postFetchOperations(page.data), (page) async => await _postFetchOperations(page.data),
) )
.withError( .withError(
(error) => _logger.info('Error getting more updates: $error')); (error) => _logger.info('Error getting more updates: $error'));
_logger.finest( _logger.finest(
'Loaded Older Unread Notifications: ${result.getValueOrElse(() => []).length}'); 'Loaded Older Unread Notifications: ${result
.getValueOrElse(() => [])
.length}');
return result.execErrorCast(); return result.execErrorCast();
} }
FutureResult<List<UserNotification>, ExecError> FutureResult<List<UserNotification>, ExecError>
_loadOlderReadAndUnreadNotifications() async { _loadOlderReadAndUnreadNotifications() async {
_logger.finest('Loading Older Read and Unread Notifications'); _logger.finest('Loading Older Read and Unread Notifications');
final hasNoNotifications = !ref.read(hasAnyNotificationsProvider(profile)); final hasNoNotifications = !ref.read(hasAnyNotificationsProvider(profile));
final useIsRead = ref.read(hasNotificationsProvider(profile, true)); final useIsRead = ref.read(hasNotificationsProvider(profile, true));
@ -457,25 +467,27 @@ class NotificationsManager extends _$NotificationsManager {
initialPages: hasNoNotifications initialPages: hasNoNotifications
? [] ? []
: [ : [
PagedResponse( PagedResponse(
<String>[], <String>[],
next: PagingData( next: PagingData(
maxId: lowestId, maxId: lowestId,
limit: _itemsPerQuery, limit: _itemsPerQuery,
), ),
) )
], ],
); );
final result = await (hasNoNotifications final result = await (hasNoNotifications
? pm.initialize(_itemsPerQuery) ? pm.initialize(_itemsPerQuery)
: pm.nextFromEnd()) : pm.nextFromEnd())
.andThenAsync( .andThenAsync(
(page) async => await _postFetchOperations(page.data), (page) async => await _postFetchOperations(page.data),
) )
.withError( .withError(
(error) => _logger.info('Error getting more updates: $error')); (error) => _logger.info('Error getting more updates: $error'));
_logger.finest( _logger.finest(
'Loaded Older Read and Unread Notifications: ${result.getValueOrElse(() => []).length}'); 'Loaded Older Read and Unread Notifications: ${result
.getValueOrElse(() => [])
.length}');
return result.execErrorCast(); return result.execErrorCast();
} }
} }
@ -485,8 +497,8 @@ class NotificationsManager extends _$NotificationsManager {
int lowestNotificationId = 0x7FFFFFFFFFFFFFFF; int lowestNotificationId = 0x7FFFFFFFFFFFFFFF;
final ids = notifications final ids = notifications
.where((n) => .where((n) =>
n.type != NotificationType.direct_message && n.type != NotificationType.direct_message &&
n.type != NotificationType.follow_request) n.type != NotificationType.follow_request)
.map((n) => int.parse(n.id)); .map((n) => int.parse(n.id));
for (var id in ids) { for (var id in ids) {
@ -502,15 +514,15 @@ class NotificationsManager extends _$NotificationsManager {
return (lowestNotificationId, highestNotificationId); return (lowestNotificationId, highestNotificationId);
} }
PagesManager<List<UserNotification>, String> _buildPageManager( PagesManager<List<UserNotification>, String> _buildPageManager(Ref ref,
Ref ref, Profile profile,
Profile profile, bool includeAll, {
bool includeAll, { List<PagedResponse> initialPages = const [],
List<PagedResponse> initialPages = const [], }) =>
}) =>
PagesManager<List<UserNotification>, String>( PagesManager<List<UserNotification>, String>(
initialPages: initialPages, initialPages: initialPages,
idMapper: (nn) => nn.map((n) => n.id).toList(), idMapper: (nn) => nn.map((n) => n.id).toList(),
onRequest: (pd) async => await ref onRequest: (pd) async =>
await ref
.read(notificationsClientProvider(profile, pd, includeAll).future), .read(notificationsClientProvider(profile, pd, includeAll).future),
); );

Wyświetl plik

@ -2,7 +2,7 @@ name: relatica
description: A mobile and desktop client for interacting with the Friendica social network description: A mobile and desktop client for interacting with the Friendica social network
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.1.0+17 version: 1.1.1+18
environment: environment:
sdk: '>=3.2.0 <4.0.0' sdk: '>=3.2.0 <4.0.0'