kopia lustrzana https://gitlab.com/mysocialportal/relatica
Merge branch 'notifications-comments-version-updates' into 'main'
Remove unused withListenerNotifications Notifications service methods. See merge request mysocialportal/relatica!70merge-requests/71/merge
commit
44568c2141
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,5 +1,31 @@
|
|||
# Relatica Change Log
|
||||
|
||||
## Version 1.1.0
|
||||
|
||||
* Changes
|
||||
* Streamlined the Notifications screen loading/reloading to make it less quirky.
|
||||
* Fixes
|
||||
* Fix drop shadow on comments bubbles being rendered instead of the base background color.
|
||||
* New Features
|
||||
|
||||
## Version 1.0.1
|
||||
|
||||
* Changes
|
||||
* Fixes
|
||||
* New Features
|
||||
* Adds ability to report a post/comment by redirecting to a WebView browser session on the Friendica website for
|
||||
that user. Currently, Friendica doesn't support the reporting API endpoint.
|
||||
* User can toggle on whether to confirm reporting a post/comment confirmation dialog box. Default is on.
|
||||
* Requires users to agree to abide by the server rules for the account's server when signing in as their respective
|
||||
user.
|
||||
|
||||
## Version 1.0.0
|
||||
|
||||
* Changes
|
||||
* Fixes
|
||||
* Fix control overflows on Settings Screen
|
||||
* New Features
|
||||
|
||||
## Version 0.16.0 (beta)
|
||||
|
||||
* Changes
|
||||
|
|
|
@ -166,7 +166,7 @@ SPEC CHECKSUMS:
|
|||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_file_dialog: 4c014a45b105709a27391e266c277d7e588e9299
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
flutter_web_auth_2: 051cf9f5dc366f31b5dcc4e2952c2b954767be8a
|
||||
flutter_web_auth_2: 06d500582775790a0d4c323222fcb6d7990f9603
|
||||
image_gallery_saver_plus: 782ade975fe6a4600b53e7c1983e3a2979d1e9e5
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
@ -43,6 +44,7 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -27,9 +27,7 @@ class AppBottomNavBar extends ConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final profile = ref.watch(activeProfileProvider);
|
||||
ref.watch(notificationsManagerProvider(profile));
|
||||
final hasNotifications = ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.hasNotifications;
|
||||
final hasNotifications = ref.read(hasNotificationsProvider(profile, false));
|
||||
|
||||
return BottomNavigationBar(
|
||||
onTap: (index) {
|
||||
|
|
|
@ -95,7 +95,7 @@ class _StatusControlState extends ConsumerState<FlattenedTreeEntryControl> {
|
|||
otherPadding + (min(maxDepth, widget.originalItem.level) * 15.0);
|
||||
final color = widget.originalItem.level.isOdd
|
||||
? Theme.of(context).secondaryHeaderColor
|
||||
: Theme.of(context).dialogTheme.backgroundColor;
|
||||
: Theme.of(context).scaffoldBackgroundColor;
|
||||
|
||||
if (filteringInfo.isFiltered &&
|
||||
filteringInfo.action == TimelineEntryFilterAction.hide) {
|
||||
|
|
|
@ -111,6 +111,21 @@ class UserNotification implements Comparable<UserNotification> {
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool exactlyEqual(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is UserNotification &&
|
||||
runtimeType == other.runtimeType &&
|
||||
id == other.id &&
|
||||
type == other.type &&
|
||||
fromId == other.fromId &&
|
||||
fromName == other.fromName &&
|
||||
fromUrl == other.fromUrl &&
|
||||
timestamp == other.timestamp &&
|
||||
iid == other.iid &&
|
||||
dismissed == other.dismissed &&
|
||||
content == other.content &&
|
||||
link == other.link;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
|
|
|
@ -13,12 +13,12 @@ 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 '../utils/list_utils.dart';
|
||||
import 'connection_manager_services.dart';
|
||||
import 'direct_message_services.dart';
|
||||
import 'feature_checker_services.dart';
|
||||
import 'follow_requests_services.dart';
|
||||
import 'networking/friendica_notifications_client_services.dart';
|
||||
import 'settings_services.dart';
|
||||
|
||||
part 'notification_services.g.dart';
|
||||
|
||||
|
@ -26,45 +26,145 @@ const _itemsPerQuery = 50;
|
|||
const _minimumDmsAndCrsUpdateDuration = Duration(seconds: 30);
|
||||
final _logger = Logger('NotificationManager');
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class _NotificationsStore extends _$NotificationsStore {
|
||||
final _values = <UserNotification>{};
|
||||
|
||||
@override
|
||||
List<UserNotification> build(Profile profile, NotificationType type) {
|
||||
_logger.fine('Build _NotificationStoreProvider($profile) for $type');
|
||||
return _rval;
|
||||
}
|
||||
|
||||
void upsert(UserNotification notification) {
|
||||
_values.remove(notification);
|
||||
_values.add(notification);
|
||||
state = _rval;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_values.clear();
|
||||
state = _rval;
|
||||
}
|
||||
|
||||
void markAllRead() {
|
||||
final updated = _values.map((n) => n.copy(dismissed: true)).toList();
|
||||
_values.clear();
|
||||
_values.addAll(updated);
|
||||
state = _rval;
|
||||
}
|
||||
|
||||
List<UserNotification> get _rval => _values.toList()..sort();
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(
|
||||
List<UserNotification> previous, List<UserNotification> next) {
|
||||
final rval = !listEqualsWithComparer(
|
||||
previous,
|
||||
next,
|
||||
equals: (u1, u2) => u1.exactlyEqual(u2),
|
||||
);
|
||||
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
List<UserNotification> userNotificationsByType(
|
||||
Ref ref, Profile profile, NotificationType type, bool isRead) {
|
||||
_logger.fine('Build userNotificationsByTypeProvider($type,$isRead,$profile)');
|
||||
final notifications = ref.watch(_NotificationsStoreProvider(profile, type));
|
||||
return notifications.where((n) => n.dismissed == isRead).toList();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
List<UserNotification> allNotifications(Ref ref, Profile profile, bool isRead) {
|
||||
_logger.fine('Build allNotificationsProvider($profile)');
|
||||
|
||||
final notifications = <UserNotification>[];
|
||||
for (NotificationType type in NotificationType.values) {
|
||||
notifications.addAll(
|
||||
ref.watch(userNotificationsByTypeProvider(profile, type, isRead)));
|
||||
}
|
||||
|
||||
return notifications..sort();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
bool hasNotifications(Ref ref, Profile profile, bool isRead) {
|
||||
_logger.info('Build hasNotifications($profile)');
|
||||
|
||||
var hasNotifications = false;
|
||||
// Go through all to watch all for changes
|
||||
for (NotificationType type in NotificationType.values) {
|
||||
hasNotifications |= ref
|
||||
.watch(userNotificationsByTypeProvider(profile, type, isRead))
|
||||
.isNotEmpty;
|
||||
}
|
||||
|
||||
return hasNotifications;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
bool hasAnyNotifications(Ref ref, Profile profile) {
|
||||
_logger.info('Build hasNotifications($profile)');
|
||||
final hasRead = ref.watch(hasNotificationsProvider(profile, true));
|
||||
final hasUnread = ref.watch(hasNotificationsProvider(profile, false));
|
||||
return hasRead || hasUnread;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
(int low, int high) lowHighId(Ref ref, Profile profile, bool isRead) {
|
||||
_logger.fine('Build lowHighIdProvider($profile) for isRead? $isRead');
|
||||
final notifications = <UserNotification>[];
|
||||
for (NotificationType type in NotificationType.values) {
|
||||
notifications.addAll(
|
||||
ref.watch(userNotificationsByTypeProvider(profile, type, isRead)));
|
||||
}
|
||||
|
||||
final result = calcLowHigh(notifications);
|
||||
_logger.finest(
|
||||
'Result lowHighIdProvider($profile) for isRead? $isRead: $result');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class NotificationsManager extends _$NotificationsManager {
|
||||
final dms = <UserNotification>[];
|
||||
final connectionRequests = <UserNotification>[];
|
||||
final unread = <UserNotification>[];
|
||||
final read = <UserNotification>[];
|
||||
var lastDmsUpdate = DateTime(1900);
|
||||
var lastCrUpdate = DateTime(1900);
|
||||
|
||||
bool get hasNotifications =>
|
||||
dms.isNotEmpty || connectionRequests.isNotEmpty || unread.isNotEmpty;
|
||||
|
||||
List<UserNotification> get notifications =>
|
||||
[...connectionRequests, ...dms, ...unread, ...read];
|
||||
|
||||
@override
|
||||
Future<Result<List<UserNotification>, ExecError>> build(
|
||||
Profile profile) async {
|
||||
Future<bool> build(Profile profile) async {
|
||||
_logger.info('Building');
|
||||
|
||||
await _initialize();
|
||||
return Result.ok(notifications);
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _initialize() async {
|
||||
final result = await loadUnreadNotifications(false);
|
||||
if (result.isSuccess && unread.isEmpty && read.isEmpty) {
|
||||
await loadOlderNotifications(withListenerNotification: false);
|
||||
final result = await loadUnreadNotifications();
|
||||
final hasNoNotifications = !ref.read(hasAnyNotificationsProvider(profile));
|
||||
if (result.isSuccess && hasNoNotifications) {
|
||||
await loadOlderNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
void refreshNotifications() async {
|
||||
clear(withListenerNotification: true);
|
||||
for (final t in NotificationType.values) {
|
||||
ref.read(_NotificationsStoreProvider(profile, t).notifier).clear();
|
||||
}
|
||||
_initialize();
|
||||
}
|
||||
|
||||
Future<void> clearConnectionRequestNotifications() async {
|
||||
_logger.info('clearConnectionRequestNotifications');
|
||||
connectionRequests.clear();
|
||||
state = AsyncData(Result.ok(notifications));
|
||||
ref
|
||||
.read(_NotificationsStoreProvider(
|
||||
profile, NotificationType.follow_request)
|
||||
.notifier)
|
||||
.clear();
|
||||
state = const AsyncData(true);
|
||||
}
|
||||
|
||||
Future<void> refreshConnectionRequestNotifications() async {
|
||||
|
@ -72,7 +172,6 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
clearConnectionRequestNotifications();
|
||||
await _postFetchOperations(
|
||||
[],
|
||||
true,
|
||||
updateDms: false,
|
||||
updateFollowRequests: true,
|
||||
);
|
||||
|
@ -80,25 +179,19 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
|
||||
Future<void> refreshDms() async {
|
||||
_logger.info('refreshDms');
|
||||
dms.clear();
|
||||
ref
|
||||
.read(_NotificationsStoreProvider(
|
||||
profile, NotificationType.direct_message)
|
||||
.notifier)
|
||||
.clear();
|
||||
await _postFetchOperations(
|
||||
[],
|
||||
true,
|
||||
updateDms: true,
|
||||
updateFollowRequests: false,
|
||||
);
|
||||
}
|
||||
|
||||
void clear({bool withListenerNotification = true}) {
|
||||
dms.clear();
|
||||
connectionRequests.clear();
|
||||
unread.clear();
|
||||
read.clear();
|
||||
_initialize();
|
||||
}
|
||||
|
||||
FutureResult<bool, ExecError> loadUnreadNotifications(
|
||||
bool withListenerNotification) async {
|
||||
FutureResult<bool, ExecError> loadUnreadNotifications() async {
|
||||
final notificationsFromRefresh = <UserNotification>[];
|
||||
|
||||
final pm = _buildPageManager(ref, profile, false);
|
||||
|
@ -138,13 +231,11 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
// query unread notifications in increments of 25 after the latest ID
|
||||
return await _postFetchOperations(
|
||||
notificationsFromRefresh,
|
||||
withListenerNotification,
|
||||
).mapValue((value) => value.isNotEmpty);
|
||||
}
|
||||
|
||||
FutureResult<List<UserNotification>, ExecError> _postFetchOperations(
|
||||
List<UserNotification> notificationsFromRefresh,
|
||||
bool withListenerNotification, {
|
||||
List<UserNotification> notificationsFromRefresh, {
|
||||
bool updateDms = true,
|
||||
bool updateFollowRequests = true,
|
||||
}) async {
|
||||
|
@ -190,16 +281,15 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
return Result.ok(notifications.values.toList());
|
||||
}
|
||||
|
||||
FutureResult<bool, ExecError> loadNewerNotifications({
|
||||
bool withListenerNotification = true,
|
||||
}) async {
|
||||
final (_, highestId) =
|
||||
unread.isNotEmpty ? calcLowHigh(unread) : calcLowHigh(read);
|
||||
FutureResult<bool, ExecError> loadNewerNotifications() async {
|
||||
final hasNoNotifications = !ref.read(hasAnyNotificationsProvider(profile));
|
||||
final useIsRead = !ref.read(hasNotificationsProvider(profile, false));
|
||||
final (_, highestId) = ref.read(lowHighIdProvider(profile, useIsRead));
|
||||
final pm = _buildPageManager(
|
||||
ref,
|
||||
profile,
|
||||
true,
|
||||
initialPages: read.isEmpty && unread.isEmpty
|
||||
initialPages: hasNoNotifications
|
||||
? []
|
||||
: [
|
||||
PagedResponse(
|
||||
|
@ -212,23 +302,23 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
],
|
||||
);
|
||||
|
||||
final result = await (unread.isEmpty && read.isEmpty
|
||||
final stillNoNotifications =
|
||||
!ref.read(hasAnyNotificationsProvider(profile));
|
||||
final result = await (stillNoNotifications
|
||||
? pm.initialize(_itemsPerQuery)
|
||||
: pm.previousFromBeginning())
|
||||
.andThenAsync(
|
||||
(page) async =>
|
||||
await _postFetchOperations(page.data, withListenerNotification),
|
||||
(page) async => await _postFetchOperations(page.data),
|
||||
)
|
||||
.withError(
|
||||
(error) => _logger.info('Error getting more updates: $error'));
|
||||
return result.mapValue((value) => value.isNotEmpty).execErrorCast();
|
||||
}
|
||||
|
||||
FutureResult<bool, ExecError> loadOlderNotifications(
|
||||
{bool withListenerNotification = true}) async {
|
||||
if (unread.isNotEmpty) {
|
||||
final result =
|
||||
await _loadOlderUnreadNotifications(withListenerNotification);
|
||||
FutureResult<bool, ExecError> loadOlderNotifications() async {
|
||||
final hasUnread = ref.read(hasNotificationsProvider(profile, false));
|
||||
if (hasUnread) {
|
||||
final result = await _loadOlderUnreadNotifications();
|
||||
final nonDmAndConnectionNotifications = result
|
||||
.getValueOrElse(() => [])
|
||||
.where((n) =>
|
||||
|
@ -240,18 +330,19 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
}
|
||||
}
|
||||
|
||||
return _loadOlderReadAndUnreadNotifications(withListenerNotification)
|
||||
return _loadOlderReadAndUnreadNotifications()
|
||||
.mapValue((value) => value.isNotEmpty);
|
||||
}
|
||||
|
||||
FutureResult<bool, ExecError> markSeen(UserNotification notification) async {
|
||||
_logger.fine('Marking Notification Seen: $notification');
|
||||
final result = await ref
|
||||
.read(clearNotificationProvider(profile, notification).future)
|
||||
.withResult((_) {
|
||||
unread.remove(notification);
|
||||
read.add(notification.copy(dismissed: true));
|
||||
read.sort();
|
||||
state = AsyncData(Result.ok(notifications));
|
||||
ref
|
||||
.read(
|
||||
_NotificationsStoreProvider(profile, notification.type).notifier)
|
||||
.upsert(notification.copy(dismissed: true));
|
||||
});
|
||||
|
||||
return result.execErrorCast();
|
||||
|
@ -261,10 +352,11 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
final result = await ref
|
||||
.read(clearNotificationsProvider(profile).future)
|
||||
.withResult((_) {
|
||||
unread.map((n) => n.copy(dismissed: true)).forEach(read.add);
|
||||
unread.clear();
|
||||
read.sort();
|
||||
state = AsyncData(Result.ok(notifications));
|
||||
for (final t in NotificationType.values) {
|
||||
ref
|
||||
.read(_NotificationsStoreProvider(profile, t).notifier)
|
||||
.markAllRead();
|
||||
}
|
||||
});
|
||||
|
||||
return result.execErrorCast();
|
||||
|
@ -275,7 +367,7 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
final myId = profile.userId;
|
||||
final dmsResult = ref
|
||||
.watch(directMessageThreadIdsProvider(profile))
|
||||
.map((id) => ref.watch(directMessageThreadServiceProvider(profile, id)))
|
||||
.map((id) => ref.read(directMessageThreadServiceProvider(profile, id)))
|
||||
.where((t) => !t.allSeen)
|
||||
.map((t) {
|
||||
final fromAccountId = t.participantIds.firstWhere((pid) => pid != myId);
|
||||
|
@ -310,93 +402,20 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
|
||||
Future<void> _processNewNotifications(
|
||||
Iterable<UserNotification> notifications) async {
|
||||
final groupNotifications = ref.watch(notificationGroupingSettingProvider);
|
||||
final dmsMap = <String, UserNotification>{};
|
||||
final crMap = <String, UserNotification>{};
|
||||
final unreadMap = <String, UserNotification>{};
|
||||
final readMap = <String, UserNotification>{};
|
||||
|
||||
final st = Stopwatch()..start();
|
||||
|
||||
for (int i = 0; i < dms.length; i++) {
|
||||
dmsMap[dms[i].id] = dms[i];
|
||||
}
|
||||
|
||||
if (st.elapsedMilliseconds > maxProcessingMillis) {
|
||||
await Future.delayed(processingSleep, () => st.reset());
|
||||
}
|
||||
|
||||
for (int i = 0; i < connectionRequests.length; i++) {
|
||||
crMap[connectionRequests[i].id] = connectionRequests[i];
|
||||
}
|
||||
|
||||
if (st.elapsedMilliseconds > maxProcessingMillis) {
|
||||
await Future.delayed(processingSleep, () => st.reset());
|
||||
}
|
||||
|
||||
for (int i = 0; i < unread.length; i++) {
|
||||
unreadMap[unread[i].id] = unread[i];
|
||||
}
|
||||
|
||||
if (st.elapsedMilliseconds > maxProcessingMillis) {
|
||||
await Future.delayed(processingSleep, () => st.reset());
|
||||
}
|
||||
|
||||
for (int i = 0; i < read.length; i++) {
|
||||
readMap[read[i].id] = read[i];
|
||||
}
|
||||
|
||||
dms.clear();
|
||||
connectionRequests.clear();
|
||||
unread.clear();
|
||||
read.clear();
|
||||
|
||||
for (final n in notifications) {
|
||||
if (st.elapsedMilliseconds > maxProcessingMillis) {
|
||||
await Future.delayed(processingSleep, () => st.reset());
|
||||
}
|
||||
dmsMap.remove(n.id);
|
||||
crMap.remove(n.id);
|
||||
unreadMap.remove(n.id);
|
||||
readMap.remove(n.id);
|
||||
if (n.dismissed) {
|
||||
readMap[n.id] = n;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (n.type) {
|
||||
case NotificationType.direct_message:
|
||||
dmsMap[n.id] = n;
|
||||
break;
|
||||
case NotificationType.follow_request:
|
||||
crMap[n.id] = n;
|
||||
break;
|
||||
default:
|
||||
unreadMap[n.id] = n;
|
||||
}
|
||||
ref.read(_NotificationsStoreProvider(profile, n.type).notifier).upsert(n);
|
||||
}
|
||||
|
||||
dms
|
||||
..addAll(dmsMap.values)
|
||||
..sort();
|
||||
connectionRequests
|
||||
..addAll(crMap.values)
|
||||
..sort();
|
||||
unread
|
||||
..addAll(unreadMap.values)
|
||||
..sort(
|
||||
(n1, n2) => _compareByTypeStatusAndDate(n1, n2, groupNotifications));
|
||||
read
|
||||
..addAll(readMap.values)
|
||||
..sort(
|
||||
(n1, n2) => _compareByTypeStatusAndDate(n1, n2, groupNotifications));
|
||||
state = AsyncData(Result.ok(this.notifications));
|
||||
}
|
||||
|
||||
FutureResult<List<UserNotification>, ExecError> _loadOlderUnreadNotifications(
|
||||
bool withListenerNotification) async {
|
||||
FutureResult<List<UserNotification>, ExecError>
|
||||
_loadOlderUnreadNotifications() async {
|
||||
_logger.finest('Loading Older Unread Notifications');
|
||||
final (lowestId, _) = calcLowHigh(unread);
|
||||
final (lowestId, _) = ref.read(lowHighIdProvider(profile, false));
|
||||
final pm = _buildPageManager(
|
||||
ref,
|
||||
profile,
|
||||
|
@ -415,8 +434,7 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
final result = await pm
|
||||
.nextFromEnd()
|
||||
.andThenAsync(
|
||||
(page) async =>
|
||||
await _postFetchOperations(page.data, withListenerNotification),
|
||||
(page) async => await _postFetchOperations(page.data),
|
||||
)
|
||||
.withError(
|
||||
(error) => _logger.info('Error getting more updates: $error'));
|
||||
|
@ -427,16 +445,16 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
}
|
||||
|
||||
FutureResult<List<UserNotification>, ExecError>
|
||||
_loadOlderReadAndUnreadNotifications(
|
||||
bool withListenerNotification) async {
|
||||
_loadOlderReadAndUnreadNotifications() async {
|
||||
_logger.finest('Loading Older Read and Unread Notifications');
|
||||
final (lowestId, _) =
|
||||
read.isNotEmpty ? calcLowHigh(read) : calcLowHigh(unread);
|
||||
final hasNoNotifications = !ref.read(hasAnyNotificationsProvider(profile));
|
||||
final useIsRead = ref.read(hasNotificationsProvider(profile, true));
|
||||
final (lowestId, _) = ref.read(lowHighIdProvider(profile, useIsRead));
|
||||
final pm = _buildPageManager(
|
||||
ref,
|
||||
profile,
|
||||
true,
|
||||
initialPages: read.isEmpty && unread.isEmpty
|
||||
initialPages: hasNoNotifications
|
||||
? []
|
||||
: [
|
||||
PagedResponse(
|
||||
|
@ -448,12 +466,11 @@ class NotificationsManager extends _$NotificationsManager {
|
|||
)
|
||||
],
|
||||
);
|
||||
final result = await (read.isEmpty && unread.isEmpty
|
||||
final result = await (hasNoNotifications
|
||||
? pm.initialize(_itemsPerQuery)
|
||||
: pm.nextFromEnd())
|
||||
.andThenAsync(
|
||||
(page) async =>
|
||||
await _postFetchOperations(page.data, withListenerNotification),
|
||||
(page) async => await _postFetchOperations(page.data),
|
||||
)
|
||||
.withError(
|
||||
(error) => _logger.info('Error getting more updates: $error'));
|
||||
|
@ -497,28 +514,3 @@ PagesManager<List<UserNotification>, String> _buildPageManager(
|
|||
onRequest: (pd) async => await ref
|
||||
.read(notificationsClientProvider(profile, pd, includeAll).future),
|
||||
);
|
||||
|
||||
int _compareByTypeStatusAndDate(
|
||||
UserNotification n1, UserNotification n2, bool groupNotifications) {
|
||||
final n1Weight = _notificationTypeToWeight(n1.type);
|
||||
final n2Weight = _notificationTypeToWeight(n2.type);
|
||||
if (!groupNotifications || n1Weight == n2Weight) {
|
||||
return n1.compareTo(n2);
|
||||
}
|
||||
|
||||
return (n2Weight - n1Weight).sign.toInt();
|
||||
}
|
||||
|
||||
num _notificationTypeToWeight(NotificationType type) {
|
||||
return switch (type) {
|
||||
NotificationType.follow_request => 1000,
|
||||
NotificationType.follow => 100,
|
||||
NotificationType.direct_message => 50,
|
||||
NotificationType.mention => 10,
|
||||
NotificationType.status => 4,
|
||||
NotificationType.reshare => 3,
|
||||
NotificationType.reblog => 3,
|
||||
NotificationType.favourite => 2,
|
||||
NotificationType.unknown => 1,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ part of 'notification_services.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$notificationsManagerHash() =>
|
||||
r'c92bf43255b0c2b6b4a94c4239e545ee1c9bf90f';
|
||||
String _$userNotificationsByTypeHash() =>
|
||||
r'fe1e04eab091d6e92de866a9888c389024ca3da3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@ -30,11 +30,920 @@ class _SystemHash {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class _$NotificationsManager
|
||||
extends BuildlessAsyncNotifier<Result<List<UserNotification>, ExecError>> {
|
||||
/// See also [userNotificationsByType].
|
||||
@ProviderFor(userNotificationsByType)
|
||||
const userNotificationsByTypeProvider = UserNotificationsByTypeFamily();
|
||||
|
||||
/// See also [userNotificationsByType].
|
||||
class UserNotificationsByTypeFamily extends Family<List<UserNotification>> {
|
||||
/// See also [userNotificationsByType].
|
||||
const UserNotificationsByTypeFamily();
|
||||
|
||||
/// See also [userNotificationsByType].
|
||||
UserNotificationsByTypeProvider call(
|
||||
Profile profile,
|
||||
NotificationType type,
|
||||
bool isRead,
|
||||
) {
|
||||
return UserNotificationsByTypeProvider(
|
||||
profile,
|
||||
type,
|
||||
isRead,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
UserNotificationsByTypeProvider getProviderOverride(
|
||||
covariant UserNotificationsByTypeProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.type,
|
||||
provider.isRead,
|
||||
);
|
||||
}
|
||||
|
||||
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'userNotificationsByTypeProvider';
|
||||
}
|
||||
|
||||
/// See also [userNotificationsByType].
|
||||
class UserNotificationsByTypeProvider
|
||||
extends AutoDisposeProvider<List<UserNotification>> {
|
||||
/// See also [userNotificationsByType].
|
||||
UserNotificationsByTypeProvider(
|
||||
Profile profile,
|
||||
NotificationType type,
|
||||
bool isRead,
|
||||
) : this._internal(
|
||||
(ref) => userNotificationsByType(
|
||||
ref as UserNotificationsByTypeRef,
|
||||
profile,
|
||||
type,
|
||||
isRead,
|
||||
),
|
||||
from: userNotificationsByTypeProvider,
|
||||
name: r'userNotificationsByTypeProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$userNotificationsByTypeHash,
|
||||
dependencies: UserNotificationsByTypeFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
UserNotificationsByTypeFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
type: type,
|
||||
isRead: isRead,
|
||||
);
|
||||
|
||||
UserNotificationsByTypeProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final NotificationType type;
|
||||
final bool isRead;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
List<UserNotification> Function(UserNotificationsByTypeRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: UserNotificationsByTypeProvider._internal(
|
||||
(ref) => create(ref as UserNotificationsByTypeRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
type: type,
|
||||
isRead: isRead,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<List<UserNotification>> createElement() {
|
||||
return _UserNotificationsByTypeProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is UserNotificationsByTypeProvider &&
|
||||
other.profile == profile &&
|
||||
other.type == type &&
|
||||
other.isRead == isRead;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, type.hashCode);
|
||||
hash = _SystemHash.combine(hash, isRead.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin UserNotificationsByTypeRef
|
||||
on AutoDisposeProviderRef<List<UserNotification>> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `type` of this provider.
|
||||
NotificationType get type;
|
||||
|
||||
/// The parameter `isRead` of this provider.
|
||||
bool get isRead;
|
||||
}
|
||||
|
||||
class _UserNotificationsByTypeProviderElement
|
||||
extends AutoDisposeProviderElement<List<UserNotification>>
|
||||
with UserNotificationsByTypeRef {
|
||||
_UserNotificationsByTypeProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as UserNotificationsByTypeProvider).profile;
|
||||
@override
|
||||
NotificationType get type => (origin as UserNotificationsByTypeProvider).type;
|
||||
@override
|
||||
bool get isRead => (origin as UserNotificationsByTypeProvider).isRead;
|
||||
}
|
||||
|
||||
String _$allNotificationsHash() => r'b353d331c19ca184cb47b221b88be98ebf7b365d';
|
||||
|
||||
/// See also [allNotifications].
|
||||
@ProviderFor(allNotifications)
|
||||
const allNotificationsProvider = AllNotificationsFamily();
|
||||
|
||||
/// See also [allNotifications].
|
||||
class AllNotificationsFamily extends Family<List<UserNotification>> {
|
||||
/// See also [allNotifications].
|
||||
const AllNotificationsFamily();
|
||||
|
||||
/// See also [allNotifications].
|
||||
AllNotificationsProvider call(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) {
|
||||
return AllNotificationsProvider(
|
||||
profile,
|
||||
isRead,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AllNotificationsProvider getProviderOverride(
|
||||
covariant AllNotificationsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.isRead,
|
||||
);
|
||||
}
|
||||
|
||||
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'allNotificationsProvider';
|
||||
}
|
||||
|
||||
/// See also [allNotifications].
|
||||
class AllNotificationsProvider
|
||||
extends AutoDisposeProvider<List<UserNotification>> {
|
||||
/// See also [allNotifications].
|
||||
AllNotificationsProvider(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) : this._internal(
|
||||
(ref) => allNotifications(
|
||||
ref as AllNotificationsRef,
|
||||
profile,
|
||||
isRead,
|
||||
),
|
||||
from: allNotificationsProvider,
|
||||
name: r'allNotificationsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$allNotificationsHash,
|
||||
dependencies: AllNotificationsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AllNotificationsFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
);
|
||||
|
||||
AllNotificationsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.isRead,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final bool isRead;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
List<UserNotification> Function(AllNotificationsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: AllNotificationsProvider._internal(
|
||||
(ref) => create(ref as AllNotificationsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<List<UserNotification>> createElement() {
|
||||
return _AllNotificationsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AllNotificationsProvider &&
|
||||
other.profile == profile &&
|
||||
other.isRead == isRead;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, isRead.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin AllNotificationsRef on AutoDisposeProviderRef<List<UserNotification>> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `isRead` of this provider.
|
||||
bool get isRead;
|
||||
}
|
||||
|
||||
class _AllNotificationsProviderElement
|
||||
extends AutoDisposeProviderElement<List<UserNotification>>
|
||||
with AllNotificationsRef {
|
||||
_AllNotificationsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as AllNotificationsProvider).profile;
|
||||
@override
|
||||
bool get isRead => (origin as AllNotificationsProvider).isRead;
|
||||
}
|
||||
|
||||
String _$hasNotificationsHash() => r'75fd7e12fef88aee9bfabb94ca30959a13b600f2';
|
||||
|
||||
/// See also [hasNotifications].
|
||||
@ProviderFor(hasNotifications)
|
||||
const hasNotificationsProvider = HasNotificationsFamily();
|
||||
|
||||
/// See also [hasNotifications].
|
||||
class HasNotificationsFamily extends Family<bool> {
|
||||
/// See also [hasNotifications].
|
||||
const HasNotificationsFamily();
|
||||
|
||||
/// See also [hasNotifications].
|
||||
HasNotificationsProvider call(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) {
|
||||
return HasNotificationsProvider(
|
||||
profile,
|
||||
isRead,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
HasNotificationsProvider getProviderOverride(
|
||||
covariant HasNotificationsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.isRead,
|
||||
);
|
||||
}
|
||||
|
||||
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'hasNotificationsProvider';
|
||||
}
|
||||
|
||||
/// See also [hasNotifications].
|
||||
class HasNotificationsProvider extends AutoDisposeProvider<bool> {
|
||||
/// See also [hasNotifications].
|
||||
HasNotificationsProvider(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) : this._internal(
|
||||
(ref) => hasNotifications(
|
||||
ref as HasNotificationsRef,
|
||||
profile,
|
||||
isRead,
|
||||
),
|
||||
from: hasNotificationsProvider,
|
||||
name: r'hasNotificationsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$hasNotificationsHash,
|
||||
dependencies: HasNotificationsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
HasNotificationsFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
);
|
||||
|
||||
HasNotificationsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.isRead,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final bool isRead;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
bool Function(HasNotificationsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: HasNotificationsProvider._internal(
|
||||
(ref) => create(ref as HasNotificationsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<bool> createElement() {
|
||||
return _HasNotificationsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is HasNotificationsProvider &&
|
||||
other.profile == profile &&
|
||||
other.isRead == isRead;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, isRead.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin HasNotificationsRef on AutoDisposeProviderRef<bool> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `isRead` of this provider.
|
||||
bool get isRead;
|
||||
}
|
||||
|
||||
class _HasNotificationsProviderElement extends AutoDisposeProviderElement<bool>
|
||||
with HasNotificationsRef {
|
||||
_HasNotificationsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as HasNotificationsProvider).profile;
|
||||
@override
|
||||
bool get isRead => (origin as HasNotificationsProvider).isRead;
|
||||
}
|
||||
|
||||
String _$hasAnyNotificationsHash() =>
|
||||
r'02f8ed9e0dc829753d60c81ada195d909e223104';
|
||||
|
||||
/// See also [hasAnyNotifications].
|
||||
@ProviderFor(hasAnyNotifications)
|
||||
const hasAnyNotificationsProvider = HasAnyNotificationsFamily();
|
||||
|
||||
/// See also [hasAnyNotifications].
|
||||
class HasAnyNotificationsFamily extends Family<bool> {
|
||||
/// See also [hasAnyNotifications].
|
||||
const HasAnyNotificationsFamily();
|
||||
|
||||
/// See also [hasAnyNotifications].
|
||||
HasAnyNotificationsProvider call(
|
||||
Profile profile,
|
||||
) {
|
||||
return HasAnyNotificationsProvider(
|
||||
profile,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
HasAnyNotificationsProvider getProviderOverride(
|
||||
covariant HasAnyNotificationsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
);
|
||||
}
|
||||
|
||||
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'hasAnyNotificationsProvider';
|
||||
}
|
||||
|
||||
/// See also [hasAnyNotifications].
|
||||
class HasAnyNotificationsProvider extends AutoDisposeProvider<bool> {
|
||||
/// See also [hasAnyNotifications].
|
||||
HasAnyNotificationsProvider(
|
||||
Profile profile,
|
||||
) : this._internal(
|
||||
(ref) => hasAnyNotifications(
|
||||
ref as HasAnyNotificationsRef,
|
||||
profile,
|
||||
),
|
||||
from: hasAnyNotificationsProvider,
|
||||
name: r'hasAnyNotificationsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$hasAnyNotificationsHash,
|
||||
dependencies: HasAnyNotificationsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
HasAnyNotificationsFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
);
|
||||
|
||||
HasAnyNotificationsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
bool Function(HasAnyNotificationsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: HasAnyNotificationsProvider._internal(
|
||||
(ref) => create(ref as HasAnyNotificationsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<bool> createElement() {
|
||||
return _HasAnyNotificationsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is HasAnyNotificationsProvider && other.profile == profile;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin HasAnyNotificationsRef on AutoDisposeProviderRef<bool> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
}
|
||||
|
||||
class _HasAnyNotificationsProviderElement
|
||||
extends AutoDisposeProviderElement<bool> with HasAnyNotificationsRef {
|
||||
_HasAnyNotificationsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as HasAnyNotificationsProvider).profile;
|
||||
}
|
||||
|
||||
String _$lowHighIdHash() => r'822098121e657a46ec5dc57ed5cee245354c0bd0';
|
||||
|
||||
/// See also [lowHighId].
|
||||
@ProviderFor(lowHighId)
|
||||
const lowHighIdProvider = LowHighIdFamily();
|
||||
|
||||
/// See also [lowHighId].
|
||||
class LowHighIdFamily extends Family<(int low, int high)> {
|
||||
/// See also [lowHighId].
|
||||
const LowHighIdFamily();
|
||||
|
||||
/// See also [lowHighId].
|
||||
LowHighIdProvider call(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) {
|
||||
return LowHighIdProvider(
|
||||
profile,
|
||||
isRead,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
LowHighIdProvider getProviderOverride(
|
||||
covariant LowHighIdProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.isRead,
|
||||
);
|
||||
}
|
||||
|
||||
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'lowHighIdProvider';
|
||||
}
|
||||
|
||||
/// See also [lowHighId].
|
||||
class LowHighIdProvider extends AutoDisposeProvider<(int low, int high)> {
|
||||
/// See also [lowHighId].
|
||||
LowHighIdProvider(
|
||||
Profile profile,
|
||||
bool isRead,
|
||||
) : this._internal(
|
||||
(ref) => lowHighId(
|
||||
ref as LowHighIdRef,
|
||||
profile,
|
||||
isRead,
|
||||
),
|
||||
from: lowHighIdProvider,
|
||||
name: r'lowHighIdProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$lowHighIdHash,
|
||||
dependencies: LowHighIdFamily._dependencies,
|
||||
allTransitiveDependencies: LowHighIdFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
);
|
||||
|
||||
LowHighIdProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.isRead,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final bool isRead;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
(int low, int high) Function(LowHighIdRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: LowHighIdProvider._internal(
|
||||
(ref) => create(ref as LowHighIdRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
isRead: isRead,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<(int low, int high)> createElement() {
|
||||
return _LowHighIdProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LowHighIdProvider &&
|
||||
other.profile == profile &&
|
||||
other.isRead == isRead;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, isRead.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin LowHighIdRef on AutoDisposeProviderRef<(int low, int high)> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `isRead` of this provider.
|
||||
bool get isRead;
|
||||
}
|
||||
|
||||
class _LowHighIdProviderElement
|
||||
extends AutoDisposeProviderElement<(int low, int high)> with LowHighIdRef {
|
||||
_LowHighIdProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as LowHighIdProvider).profile;
|
||||
@override
|
||||
bool get isRead => (origin as LowHighIdProvider).isRead;
|
||||
}
|
||||
|
||||
String _$notificationsStoreHash() =>
|
||||
r'f0fd5f5bfdf129fe805d0d2cbb753fde83106cb6';
|
||||
|
||||
abstract class _$NotificationsStore
|
||||
extends BuildlessNotifier<List<UserNotification>> {
|
||||
late final Profile profile;
|
||||
late final NotificationType type;
|
||||
|
||||
List<UserNotification> build(
|
||||
Profile profile,
|
||||
NotificationType type,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [_NotificationsStore].
|
||||
@ProviderFor(_NotificationsStore)
|
||||
const _notificationsStoreProvider = _NotificationsStoreFamily();
|
||||
|
||||
/// See also [_NotificationsStore].
|
||||
class _NotificationsStoreFamily extends Family<List<UserNotification>> {
|
||||
/// See also [_NotificationsStore].
|
||||
const _NotificationsStoreFamily();
|
||||
|
||||
/// See also [_NotificationsStore].
|
||||
_NotificationsStoreProvider call(
|
||||
Profile profile,
|
||||
NotificationType type,
|
||||
) {
|
||||
return _NotificationsStoreProvider(
|
||||
profile,
|
||||
type,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
_NotificationsStoreProvider getProviderOverride(
|
||||
covariant _NotificationsStoreProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.profile,
|
||||
provider.type,
|
||||
);
|
||||
}
|
||||
|
||||
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'_notificationsStoreProvider';
|
||||
}
|
||||
|
||||
/// See also [_NotificationsStore].
|
||||
class _NotificationsStoreProvider
|
||||
extends NotifierProviderImpl<_NotificationsStore, List<UserNotification>> {
|
||||
/// See also [_NotificationsStore].
|
||||
_NotificationsStoreProvider(
|
||||
Profile profile,
|
||||
NotificationType type,
|
||||
) : this._internal(
|
||||
() => _NotificationsStore()
|
||||
..profile = profile
|
||||
..type = type,
|
||||
from: _notificationsStoreProvider,
|
||||
name: r'_notificationsStoreProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$notificationsStoreHash,
|
||||
dependencies: _NotificationsStoreFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
_NotificationsStoreFamily._allTransitiveDependencies,
|
||||
profile: profile,
|
||||
type: type,
|
||||
);
|
||||
|
||||
_NotificationsStoreProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.profile,
|
||||
required this.type,
|
||||
}) : super.internal();
|
||||
|
||||
final Profile profile;
|
||||
final NotificationType type;
|
||||
|
||||
@override
|
||||
List<UserNotification> runNotifierBuild(
|
||||
covariant _NotificationsStore notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
profile,
|
||||
type,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(_NotificationsStore Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: _NotificationsStoreProvider._internal(
|
||||
() => create()
|
||||
..profile = profile
|
||||
..type = type,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
profile: profile,
|
||||
type: type,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
NotifierProviderElement<_NotificationsStore, List<UserNotification>>
|
||||
createElement() {
|
||||
return _NotificationsStoreProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is _NotificationsStoreProvider &&
|
||||
other.profile == profile &&
|
||||
other.type == type;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||
hash = _SystemHash.combine(hash, type.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin _NotificationsStoreRef on NotifierProviderRef<List<UserNotification>> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
|
||||
/// The parameter `type` of this provider.
|
||||
NotificationType get type;
|
||||
}
|
||||
|
||||
class _NotificationsStoreProviderElement
|
||||
extends NotifierProviderElement<_NotificationsStore, List<UserNotification>>
|
||||
with _NotificationsStoreRef {
|
||||
_NotificationsStoreProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Profile get profile => (origin as _NotificationsStoreProvider).profile;
|
||||
@override
|
||||
NotificationType get type => (origin as _NotificationsStoreProvider).type;
|
||||
}
|
||||
|
||||
String _$notificationsManagerHash() =>
|
||||
r'e6946d8411c01f8e5d6dbdbbff612f552eea2c03';
|
||||
|
||||
abstract class _$NotificationsManager extends BuildlessAsyncNotifier<bool> {
|
||||
late final Profile profile;
|
||||
|
||||
FutureOr<Result<List<UserNotification>, ExecError>> build(
|
||||
FutureOr<bool> build(
|
||||
Profile profile,
|
||||
);
|
||||
}
|
||||
|
@ -44,8 +953,7 @@ abstract class _$NotificationsManager
|
|||
const notificationsManagerProvider = NotificationsManagerFamily();
|
||||
|
||||
/// See also [NotificationsManager].
|
||||
class NotificationsManagerFamily
|
||||
extends Family<AsyncValue<Result<List<UserNotification>, ExecError>>> {
|
||||
class NotificationsManagerFamily extends Family<AsyncValue<bool>> {
|
||||
/// See also [NotificationsManager].
|
||||
const NotificationsManagerFamily();
|
||||
|
||||
|
@ -83,8 +991,8 @@ class NotificationsManagerFamily
|
|||
}
|
||||
|
||||
/// See also [NotificationsManager].
|
||||
class NotificationsManagerProvider extends AsyncNotifierProviderImpl<
|
||||
NotificationsManager, Result<List<UserNotification>, ExecError>> {
|
||||
class NotificationsManagerProvider
|
||||
extends AsyncNotifierProviderImpl<NotificationsManager, bool> {
|
||||
/// See also [NotificationsManager].
|
||||
NotificationsManagerProvider(
|
||||
Profile profile,
|
||||
|
@ -115,7 +1023,7 @@ class NotificationsManagerProvider extends AsyncNotifierProviderImpl<
|
|||
final Profile profile;
|
||||
|
||||
@override
|
||||
FutureOr<Result<List<UserNotification>, ExecError>> runNotifierBuild(
|
||||
FutureOr<bool> runNotifierBuild(
|
||||
covariant NotificationsManager notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
|
@ -140,8 +1048,7 @@ class NotificationsManagerProvider extends AsyncNotifierProviderImpl<
|
|||
}
|
||||
|
||||
@override
|
||||
AsyncNotifierProviderElement<NotificationsManager,
|
||||
Result<List<UserNotification>, ExecError>> createElement() {
|
||||
AsyncNotifierProviderElement<NotificationsManager, bool> createElement() {
|
||||
return _NotificationsManagerProviderElement(this);
|
||||
}
|
||||
|
||||
|
@ -161,15 +1068,14 @@ class NotificationsManagerProvider extends AsyncNotifierProviderImpl<
|
|||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin NotificationsManagerRef
|
||||
on AsyncNotifierProviderRef<Result<List<UserNotification>, ExecError>> {
|
||||
mixin NotificationsManagerRef on AsyncNotifierProviderRef<bool> {
|
||||
/// The parameter `profile` of this provider.
|
||||
Profile get profile;
|
||||
}
|
||||
|
||||
class _NotificationsManagerProviderElement extends AsyncNotifierProviderElement<
|
||||
NotificationsManager,
|
||||
Result<List<UserNotification>, ExecError>> with NotificationsManagerRef {
|
||||
class _NotificationsManagerProviderElement
|
||||
extends AsyncNotifierProviderElement<NotificationsManager, bool>
|
||||
with NotificationsManagerRef {
|
||||
_NotificationsManagerProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
|
|
|
@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../controls/app_bottom_nav_bar.dart';
|
||||
import '../controls/async_value_widget.dart';
|
||||
import '../controls/error_message_widget.dart';
|
||||
import '../controls/notifications_control.dart';
|
||||
import '../controls/padding.dart';
|
||||
import '../controls/responsive_max_width.dart';
|
||||
|
@ -13,9 +11,11 @@ import '../controls/standard_appbar.dart';
|
|||
import '../controls/status_and_refresh_button.dart';
|
||||
import '../globals.dart';
|
||||
import '../models/auth/profile.dart';
|
||||
import '../models/user_notification.dart';
|
||||
import '../riverpod_controllers/account_services.dart';
|
||||
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||
import '../riverpod_controllers/notification_services.dart';
|
||||
import '../riverpod_controllers/settings_services.dart';
|
||||
import '../utils/snackbar_builder.dart';
|
||||
|
||||
class NotificationsScreen extends ConsumerWidget {
|
||||
|
@ -28,13 +28,8 @@ class NotificationsScreen extends ConsumerWidget {
|
|||
_logger.finer('Building');
|
||||
final profile = ref.watch(activeProfileProvider);
|
||||
const title = 'Notifications';
|
||||
final loading = ref.watch(notificationsLoadingProvider(profile));
|
||||
late final Widget body;
|
||||
final notificationsValue = ref.watch(notificationsManagerProvider(profile));
|
||||
final loading = ref.watch(notificationsLoadingProvider(profile)) ||
|
||||
switch (notificationsValue) {
|
||||
AsyncData() => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
final actions = [
|
||||
if (platformIsDesktop)
|
||||
|
@ -50,96 +45,78 @@ class NotificationsScreen extends ConsumerWidget {
|
|||
),
|
||||
];
|
||||
|
||||
body = AsyncValueWidget(notificationsValue,
|
||||
valueBuilder: (context, ref, result) {
|
||||
if (result.isFailure) {
|
||||
return ErrorMessageWidget(
|
||||
message: 'Error getting notifications: ${result.error.message}');
|
||||
}
|
||||
final hasNoNotifications = !ref.watch(hasAnyNotificationsProvider(profile));
|
||||
if (hasNoNotifications) {
|
||||
body = RefreshIndicator(
|
||||
onRefresh: () async => ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.refreshNotifications(),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: loading
|
||||
? [
|
||||
const Center(child: Text('Loading Notifications')),
|
||||
]
|
||||
: [
|
||||
const Center(child: Text('No notifications')),
|
||||
const VerticalPadding(),
|
||||
ElevatedButton(
|
||||
onPressed: () => ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.refreshNotifications(),
|
||||
child: const Text('Load Notifications'),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
final groupNotifications = ref.watch(notificationGroupingSettingProvider);
|
||||
final notificationEntries = groupNotifications
|
||||
? [
|
||||
...orderedNotificationTypes.map((type) =>
|
||||
_NotificationsByTypeListElement(
|
||||
profile: profile, type: type, isRead: false)),
|
||||
_NotificationsByReadStatusListElement(
|
||||
profile: profile, isRead: true),
|
||||
]
|
||||
: [
|
||||
_NotificationsByReadStatusListElement(
|
||||
profile: profile, isRead: false),
|
||||
_NotificationsByReadStatusListElement(
|
||||
profile: profile, isRead: true),
|
||||
];
|
||||
|
||||
final notifications = result.value;
|
||||
final allEntries = [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.loadNewerNotifications();
|
||||
},
|
||||
child: const Text('Load newer notifications')),
|
||||
...notificationEntries,
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.loadOlderNotifications();
|
||||
},
|
||||
child: const Text('Load older notifications'))
|
||||
];
|
||||
|
||||
if (notifications.isEmpty) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async => ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.refreshNotifications(),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: loading
|
||||
? [
|
||||
const Center(child: Text('Loading Notifications')),
|
||||
]
|
||||
: [
|
||||
const Center(child: Text('No notifications')),
|
||||
const VerticalPadding(),
|
||||
ElevatedButton(
|
||||
onPressed: () => ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.refreshNotifications(),
|
||||
child: const Text('Load Notifications'),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
return RefreshIndicator(
|
||||
body = RefreshIndicator(
|
||||
onRefresh: () async => ref
|
||||
.read(notificationsManagerProvider(profile).notifier)
|
||||
.refreshNotifications(),
|
||||
child: ResponsiveMaxWidth(
|
||||
child: ListView.separated(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
final result = await ref
|
||||
.read(notificationsManagerProvider(profile)
|
||||
.notifier)
|
||||
.loadNewerNotifications();
|
||||
final noMore = result.fold(
|
||||
onSuccess: (value) => !value,
|
||||
onError: (_) => true);
|
||||
if (context.mounted && noMore) {
|
||||
buildSnackbar(
|
||||
context, 'No newer notifications to load');
|
||||
}
|
||||
},
|
||||
child: const Text('Load newer notifications'));
|
||||
}
|
||||
if (index == notifications.length + 1) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
final result = await ref
|
||||
.read(notificationsManagerProvider(profile)
|
||||
.notifier)
|
||||
.loadOlderNotifications();
|
||||
final noMore = result.fold(
|
||||
onSuccess: (value) => !value,
|
||||
onError: (_) => true);
|
||||
if (context.mounted && noMore) {
|
||||
buildSnackbar(
|
||||
context, 'No older notifications to load');
|
||||
}
|
||||
},
|
||||
child: const Text('Load older notifications'));
|
||||
}
|
||||
return NotificationControl(
|
||||
notification: notifications[index - 1]);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return const Divider(
|
||||
color: Colors.black54,
|
||||
height: 0.0,
|
||||
);
|
||||
},
|
||||
itemCount: notifications.length + 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
itemBuilder: (_, index) => allEntries[index],
|
||||
separatorBuilder: (_, __) => _standardDivider,
|
||||
itemCount: allEntries.length,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: StandardAppBar.build(
|
||||
|
@ -183,3 +160,64 @@ class NotificationsScreen extends ConsumerWidget {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _NotificationsByTypeListElement extends ConsumerWidget {
|
||||
final Profile profile;
|
||||
final NotificationType type;
|
||||
final bool isRead;
|
||||
|
||||
const _NotificationsByTypeListElement(
|
||||
{required this.profile, required this.type, required this.isRead});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final notifications =
|
||||
ref.watch(userNotificationsByTypeProvider(profile, type, isRead));
|
||||
return ListView.separated(
|
||||
primary: false,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (_, index) =>
|
||||
NotificationControl(notification: notifications[index]),
|
||||
separatorBuilder: (_, __) => _standardDivider,
|
||||
itemCount: notifications.length,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NotificationsByReadStatusListElement extends ConsumerWidget {
|
||||
final Profile profile;
|
||||
final bool isRead;
|
||||
|
||||
const _NotificationsByReadStatusListElement(
|
||||
{required this.profile, required this.isRead});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final notifications = ref.watch(allNotificationsProvider(profile, isRead));
|
||||
return ListView.separated(
|
||||
primary: false,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (_, index) =>
|
||||
NotificationControl(notification: notifications[index]),
|
||||
separatorBuilder: (_, __) => _standardDivider,
|
||||
itemCount: notifications.length,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final orderedNotificationTypes = [
|
||||
NotificationType.follow_request,
|
||||
NotificationType.follow,
|
||||
NotificationType.direct_message,
|
||||
NotificationType.mention,
|
||||
NotificationType.status,
|
||||
NotificationType.reshare,
|
||||
NotificationType.reblog,
|
||||
NotificationType.favourite,
|
||||
NotificationType.unknown,
|
||||
];
|
||||
|
||||
const _standardDivider = Divider(
|
||||
color: Colors.black54,
|
||||
height: 0.0,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
bool listEqualsWithComparer<T>(List<T> a, List<T> b,
|
||||
{required bool Function(T i1, T i2) equals}) {
|
||||
if (identical(a, b)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < a.length; index++) {
|
||||
if (!equals(a[index], b[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <desktop_window/desktop_window_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
|
@ -16,6 +17,9 @@
|
|||
#include <window_to_front/window_to_front_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
|
||||
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
|
||||
g_autoptr(FlPluginRegistrar) desktop_window_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWindowPlugin");
|
||||
desktop_window_plugin_register_with_registrar(desktop_window_registrar);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
desktop_window
|
||||
file_selector_linux
|
||||
flutter_secure_storage_linux
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import desktop_webview_window
|
||||
import desktop_window
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
|
@ -24,6 +25,7 @@ import wakelock_plus
|
|||
import window_to_front
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||
DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
PODS:
|
||||
- desktop_webview_window (0.0.1):
|
||||
- FlutterMacOS
|
||||
- desktop_window (0.0.1):
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
|
@ -44,6 +46,7 @@ PODS:
|
|||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`)
|
||||
- desktop_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_window/macos`)
|
||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||
|
@ -69,6 +72,8 @@ SPEC REPOS:
|
|||
- ObjectBox
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
desktop_webview_window:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos
|
||||
desktop_window:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_window/macos
|
||||
device_info_plus:
|
||||
|
@ -109,6 +114,7 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
desktop_webview_window: d4365e71bcd4e1aa0c14cf0377aa24db0c16a7e2
|
||||
desktop_window: fb7c4f12c1129f947ac482296b6f14059d57a3c3
|
||||
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
|
||||
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
|
||||
|
|
40
pubspec.lock
40
pubspec.lock
|
@ -50,10 +50,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -310,6 +310,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
desktop_webview_window:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: desktop_webview_window
|
||||
sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.3"
|
||||
desktop_window:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -338,10 +346,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -540,18 +548,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_web_auth_2
|
||||
sha256: "4d3d2fd3d26bf1a26b3beafd4b4b899c0ffe10dc99af25abc58ffe24e991133c"
|
||||
sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "4.1.0"
|
||||
flutter_web_auth_2_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_web_auth_2_platform_interface
|
||||
sha256: e8669e262005a8354389ba2971f0fc1c36188481234ff50d013aaf993f30f739
|
||||
sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "4.1.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -609,10 +617,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e
|
||||
sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "4.3.0"
|
||||
html:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -657,10 +665,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: image_gallery_saver_plus
|
||||
sha256: "05a5dfd60b0ecd9f990f578f4ff55fe2b6df57a03bb34e3d0963639584d76153"
|
||||
sha256: "199b9e24f8d85e98f11e3d35571ab68ae50626ad40e2bb85c84383f69a6950ad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "4.0.1"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -769,10 +777,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1654,10 +1662,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.0"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -2,7 +2,7 @@ name: relatica
|
|||
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
|
||||
version: 1.0.0+15
|
||||
version: 1.1.0+17
|
||||
|
||||
environment:
|
||||
sdk: '>=3.2.0 <4.0.0'
|
||||
|
@ -23,14 +23,14 @@ dependencies:
|
|||
flutter_riverpod: ^2.5.1
|
||||
flutter_secure_storage: ^9.2.2
|
||||
flutter_svg: ^2.0.10+1
|
||||
flutter_web_auth_2: ^3.1.2
|
||||
flutter_web_auth_2: ^4.1.0
|
||||
flutter_widget_from_html_core: ^0.15.2
|
||||
go_router: ^14.1.2
|
||||
html: ^0.15.4
|
||||
http: any
|
||||
http_parser: any
|
||||
image: ^4.2.0
|
||||
image_gallery_saver_plus: ^3.0.5
|
||||
image_gallery_saver_plus: ^4.0.1
|
||||
image_picker: ^1.1.2
|
||||
logging: ^1.2.0
|
||||
markdown: ^7.2.2
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <desktop_window/desktop_window_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
|
@ -17,6 +18,8 @@
|
|||
#include <window_to_front/window_to_front_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||
DesktopWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopWindowPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
desktop_window
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
|
|
Ładowanie…
Reference in New Issue