add notification page filter

This commit is contained in:
Henry Hiles 2026-09-11 22:34:43 -04:00
commit 6ca9b2a948
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 89 additions and 44 deletions

View file

@ -33,7 +33,10 @@ class NotificationController
if (navigatorKey.currentContext case final context?) { if (navigatorKey.currentContext case final context?) {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => NotificationsPage(eventId: eventId), builder: (_) => NotificationsPage(
eventId: eventId,
defaultToAllNotifications: true,
),
), ),
); );
} }

View file

@ -1,7 +1,9 @@
import "package:m3e_buttons/m3e_buttons.dart";
import "package:material_ui/material_ui.dart"; import "package:material_ui/material_ui.dart";
import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/notifications.dart"; import "package:nexus/controllers/notifications.dart";
import "package:nexus/models/event.dart";
import "package:nexus/widgets/appbar.dart"; import "package:nexus/widgets/appbar.dart";
import "package:nexus/widgets/error_dialog.dart"; import "package:nexus/widgets/error_dialog.dart";
import "package:nexus/widgets/highlight_wrapper.dart"; import "package:nexus/widgets/highlight_wrapper.dart";
@ -9,11 +11,29 @@ import "package:nexus/widgets/loading.dart";
import "package:nexus/widgets/renderers/event.dart"; import "package:nexus/widgets/renderers/event.dart";
import "package:super_sliver_list/super_sliver_list.dart"; import "package:super_sliver_list/super_sliver_list.dart";
class const NotificationsPage({final String? eventId, super.key}) class const NotificationsPage({
extends HookConsumerWidget { final String? eventId,
final bool defaultToAllNotifications = false,
super.key,
}) extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final provider = NotificationsController.provider(null); final options = <M3EToggleButtonGroupAction, UnreadType>{
M3EToggleButtonGroupAction(
label: Text("Mentions"),
icon: Icon(Icons.alternate_email),
): .highlight,
M3EToggleButtonGroupAction(
label: Text("All Notifications"),
icon: Icon(Icons.notifications),
): .notify,
};
final unreadTypeIndex = useState(defaultToAllNotifications ? 1 : 0);
final provider = NotificationsController.provider((
options.values.toList()[unreadTypeIndex.value],
null,
));
final notifications = ref.watch(provider); final notifications = ref.watch(provider);
final notifier = ref.watch(provider.notifier); final notifier = ref.watch(provider.notifier);
@ -35,49 +55,71 @@ class const NotificationsPage({final String? eventId, super.key})
return Scaffold( return Scaffold(
appBar: Appbar(title: Text("Notifications")), appBar: Appbar(title: Text("Notifications")),
body: Column( body: Stack(
children: [ children: [
if (notifications is AsyncLoading && notifications.value != null) Column(
const LinearProgressIndicator(minHeight: 2), children: [
Expanded( if (notifications is AsyncLoading && notifications.value != null)
child: switch (notifications) { const LinearProgressIndicator(minHeight: 2),
AsyncData(:final value) || AsyncLoading(:final value?) => Expanded(
value.isEmpty child: switch (notifications) {
? Center( AsyncData(:final value) || AsyncLoading(:final value?) =>
child: Text( value.isEmpty
"No notifications yet", ? Center(
style: Theme.of(context).textTheme.headlineMedium, child: Text(
), "No notifications yet",
) style: Theme.of(context).textTheme.headlineMedium,
: SuperListView.builder(
controller: scrollController,
itemCount: value.length,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 12,
),
reverse: true,
itemBuilder: (context, index) {
final event = value[index];
final isHighlighted = event.eventId == eventId;
return HighlightWrapper(
InkWell(
onTap: () {
//TODO
},
child: EventRenderer(event),
), ),
isHighlighted: isHighlighted, )
); : SuperListView.builder(
}, controller: scrollController,
), itemCount: value.length,
AsyncLoading() => const Loading(), padding: const EdgeInsets.symmetric(
AsyncError(:final error, :final stackTrace) => ErrorDialog( horizontal: 8,
error, vertical: 12,
stackTrace, ),
reverse: true,
itemBuilder: (context, index) {
final event = value[index];
final isHighlighted = event.eventId == eventId;
return Padding(
padding: .only(top: 8),
child: HighlightWrapper(
InkWell(
onTap: () {
//TODO
},
child: EventRenderer(event),
),
isHighlighted: isHighlighted,
),
);
},
),
AsyncLoading() => const Loading(),
AsyncError(:final error, :final stackTrace) => ErrorDialog(
error,
stackTrace,
),
},
), ),
}, ],
),
Align(
alignment: .topRight,
child: Card(
color: Theme.of(context).colorScheme.surfaceContainer,
child: Padding(
padding: .all(12),
child: M3EToggleButtonGroup(
selectedIndex: unreadTypeIndex.value,
onSelectedIndexChanged: (index) =>
unreadTypeIndex.value = index ?? unreadTypeIndex.value,
actions: options.keys.toList(),
),
),
),
), ),
], ],
), ),