Compare commits
9 changed files with 31 additions and 104 deletions
|
|
@ -13,7 +13,6 @@ import "package:nexus/models/capabilities.dart";
|
||||||
import "package:nexus/models/content/message.dart";
|
import "package:nexus/models/content/message.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/event_context.dart";
|
import "package:nexus/models/event_context.dart";
|
||||||
import "package:nexus/models/mentions_response.dart";
|
|
||||||
import "package:nexus/models/gomuks_config.dart";
|
import "package:nexus/models/gomuks_config.dart";
|
||||||
import "package:nexus/models/oauth_auth_code_response.dart";
|
import "package:nexus/models/oauth_auth_code_response.dart";
|
||||||
import "package:nexus/models/open_graph_data.dart";
|
import "package:nexus/models/open_graph_data.dart";
|
||||||
|
|
@ -215,8 +214,11 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
return .new(response?.map((event) => .fromJson(event)));
|
return .new(response?.map((event) => .fromJson(event)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<MentionsResponse> getMentions(GetMentionsRequest request) async =>
|
Future<IList<Event>> getMentions(GetMentionsRequest request) async => .new(
|
||||||
.fromJson(await _sendCommand("get_mentions", request.toJson()));
|
// TODO: Handle `related_events`
|
||||||
|
((await _sendCommand("get_mentions", request.toJson()))["events"] as List)
|
||||||
|
.map((event) => .fromJson(event)),
|
||||||
|
);
|
||||||
|
|
||||||
Future<Event?> getEvent(GetEventRequest request) async {
|
Future<Event?> getEvent(GetEventRequest request) async {
|
||||||
final json = await _sendCommand("get_event", request.toJson());
|
final json = await _sendCommand("get_event", request.toJson());
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,9 @@ class NotificationsController(final NotificationsRequest request)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
storeEvents(mentions.events.addAll(mentions.relatedEvents));
|
storeEvents(mentions);
|
||||||
|
|
||||||
return .new(mentions.events.map((event) => (event.rowId, event.roomId)));
|
return .new(mentions.map((event) => (event.rowId, event.roomId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadOlder() async {
|
Future<void> loadOlder() async {
|
||||||
|
|
@ -76,12 +76,10 @@ class NotificationsController(final NotificationsRequest request)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
storeEvents(
|
storeEvents(newNotifications);
|
||||||
newNotifications.events.addAll(newNotifications.relatedEvents),
|
|
||||||
);
|
|
||||||
|
|
||||||
return currentNotifications.addAll(
|
return currentNotifications.addAll(
|
||||||
newNotifications.events.map((event) => (event.rowId, event.roomId)),
|
newNotifications.map((event) => (event.rowId, event.roomId)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ extension SchemeToTheme on ColorScheme {
|
||||||
).textTheme;
|
).textTheme;
|
||||||
return .from(colorScheme: this).copyWith(
|
return .from(colorScheme: this).copyWith(
|
||||||
cardTheme: .new(color: primaryContainer),
|
cardTheme: .new(color: primaryContainer),
|
||||||
badgeTheme: .new(backgroundColor: primary, textColor: onPrimary),
|
|
||||||
popupMenuTheme: .new(
|
popupMenuTheme: .new(
|
||||||
shape: RoundedRectangleBorder(borderRadius: .circular(16)),
|
shape: RoundedRectangleBorder(borderRadius: .circular(16)),
|
||||||
color: surfaceContainerHigh,
|
color: surfaceContainerHigh,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
|
||||||
import "package:freezed_annotation/freezed_annotation.dart";
|
|
||||||
import "package:nexus/models/event.dart";
|
|
||||||
|
|
||||||
part "mentions_response.freezed.dart";
|
|
||||||
part "mentions_response.g.dart";
|
|
||||||
|
|
||||||
@Freezed(toJson: false, fromJson: false)
|
|
||||||
@JsonSerializable(createToJson: false)
|
|
||||||
class const MentionsResponse({
|
|
||||||
required final IList<Event> events,
|
|
||||||
final IList<Event> relatedEvents = const .empty(),
|
|
||||||
}) with _$MentionsResponse {
|
|
||||||
factory MentionsResponse.fromJson(Map<String, Object?> json) =>
|
|
||||||
_$MentionsResponseFromJson(json);
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,5 @@ abstract class const NavPage({super.key}) extends Widget {
|
||||||
String get title;
|
String get title;
|
||||||
IconData get icon;
|
IconData get icon;
|
||||||
|
|
||||||
/// Null hides the badge, and 0 shows a dot.
|
|
||||||
int? badgeCount(WidgetRef ref) => null;
|
int? badgeCount(WidgetRef ref) => null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import "package:material_ui/material_ui.dart";
|
|
||||||
|
|
||||||
/// Shows [count] in a badge on [child]: nothing if null, a dot if 0, and the
|
|
||||||
/// number otherwise.
|
|
||||||
class const CountBadge(
|
|
||||||
final int? count, {
|
|
||||||
required final Widget child,
|
|
||||||
super.key,
|
|
||||||
}) extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => switch (count) {
|
|
||||||
null => child,
|
|
||||||
0 => Badge(child: child),
|
|
||||||
final count => Badge.count(count: count, child: child),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -3,10 +3,8 @@ import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/rooms.dart";
|
import "package:nexus/controllers/rooms.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/widgets/count_badge.dart";
|
|
||||||
import "package:nexus/widgets/room_menu_button.dart";
|
import "package:nexus/widgets/room_menu_button.dart";
|
||||||
import "package:nexus/widgets/room_summary_dialog.dart";
|
import "package:nexus/widgets/room_summary_dialog.dart";
|
||||||
import "package:nexus/widgets/sidebar.dart";
|
|
||||||
|
|
||||||
final class const RoomAppbar({
|
final class const RoomAppbar({
|
||||||
required final String? roomId,
|
required final String? roomId,
|
||||||
|
|
@ -51,14 +49,7 @@ final class const RoomAppbar({
|
||||||
dimension: 24,
|
dimension: 24,
|
||||||
fallback: Icon(Icons.numbers),
|
fallback: Icon(Icons.numbers),
|
||||||
)
|
)
|
||||||
: IconButton(
|
: DrawerButton(onPressed: onOpenDrawer),
|
||||||
onPressed: onOpenDrawer,
|
|
||||||
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
|
|
||||||
icon: CountBadge(
|
|
||||||
Sidebar.totalBadgeCount(ref),
|
|
||||||
child: const DrawerButtonIcon(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
title: room == null
|
title: room == null
|
||||||
? null
|
? null
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import "package:nexus/widgets/pages/settings.dart";
|
||||||
import "package:nexus/widgets/join_dialog.dart";
|
import "package:nexus/widgets/join_dialog.dart";
|
||||||
import "package:nexus/widgets/room_menu_button.dart";
|
import "package:nexus/widgets/room_menu_button.dart";
|
||||||
import "package:nexus/controllers/key.dart";
|
import "package:nexus/controllers/key.dart";
|
||||||
import "package:nexus/controllers/rooms.dart";
|
|
||||||
import "package:nexus/controllers/spaces.dart";
|
import "package:nexus/controllers/spaces.dart";
|
||||||
import "package:collection/collection.dart";
|
import "package:collection/collection.dart";
|
||||||
|
|
||||||
|
|
@ -27,26 +26,9 @@ class const RoomList({super.key}) extends ConsumerWidget implements NavPage {
|
||||||
@override
|
@override
|
||||||
IconData get icon => Icons.list;
|
IconData get icon => Icons.list;
|
||||||
|
|
||||||
|
// TODO: Show unread badge here and on sidebar hamburger
|
||||||
@override
|
@override
|
||||||
int? badgeCount(WidgetRef ref) {
|
int? badgeCount(WidgetRef ref) => null;
|
||||||
final (notifications, hasUnread) = ref.watch(
|
|
||||||
RoomsController.provider.select(
|
|
||||||
(rooms) => rooms.values.fold(
|
|
||||||
(0, false),
|
|
||||||
(total, room) => (
|
|
||||||
total.$1 + (room.metadata?.unreadNotifications ?? 0),
|
|
||||||
total.$2 || (room.metadata?.unreadMessages ?? 0) > 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return notifications > 0
|
|
||||||
? notifications
|
|
||||||
: hasUnread
|
|
||||||
? 0
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,23 @@
|
||||||
import "package:collection/collection.dart";
|
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:nexus/controllers/sidebar_page.dart";
|
import "package:nexus/controllers/sidebar_page.dart";
|
||||||
import "package:nexus/models/nav_page.dart";
|
import "package:nexus/models/nav_page.dart";
|
||||||
import "package:nexus/models/sidebar_page.dart";
|
import "package:nexus/models/sidebar_page.dart";
|
||||||
import "package:nexus/widgets/count_badge.dart";
|
|
||||||
import "package:nexus/widgets/invites_list.dart";
|
import "package:nexus/widgets/invites_list.dart";
|
||||||
import "package:nexus/widgets/notifications_list.dart";
|
import "package:nexus/widgets/notifications_list.dart";
|
||||||
import "package:nexus/widgets/room_list.dart";
|
import "package:nexus/widgets/room_list.dart";
|
||||||
|
|
||||||
class const Sidebar({super.key}) extends ConsumerWidget {
|
class const Sidebar({super.key}) extends ConsumerWidget {
|
||||||
static NavPage pageFor(SidebarPage page) => switch (page) {
|
|
||||||
.rooms => const RoomList(),
|
|
||||||
.notifications => const NotificationsList(),
|
|
||||||
.invites => const InvitesList(),
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The badges of every tab added together, e.g. for the drawer button.
|
|
||||||
///
|
|
||||||
/// Like [NavPage.badgeCount], null means no badges and 0 means only dots.
|
|
||||||
static int? totalBadgeCount(WidgetRef ref) {
|
|
||||||
final counts = SidebarPage.values
|
|
||||||
.map((page) => pageFor(page).badgeCount(ref))
|
|
||||||
.nonNulls;
|
|
||||||
|
|
||||||
return counts.isEmpty ? null : counts.sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final selected = ref.watch(SidebarPageController.provider);
|
final selected = ref.watch(SidebarPageController.provider);
|
||||||
final pages = SidebarPage.values.map(pageFor);
|
final pages = SidebarPage.values.map<NavPage>(
|
||||||
|
(page) => switch (page) {
|
||||||
|
.rooms => const RoomList(),
|
||||||
|
.notifications => const NotificationsList(),
|
||||||
|
.invites => const InvitesList(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return Drawer(
|
return Drawer(
|
||||||
width: 330,
|
width: 330,
|
||||||
|
|
@ -40,17 +27,18 @@ class const Sidebar({super.key}) extends ConsumerWidget {
|
||||||
body: pages.elementAt(selected.index),
|
body: pages.elementAt(selected.index),
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
selectedIndex: selected.index,
|
selectedIndex: selected.index,
|
||||||
destinations: pages
|
destinations: pages.map((page) {
|
||||||
.map(
|
final badgeCount = page.badgeCount(ref);
|
||||||
(page) => NavigationDestination(
|
|
||||||
icon: CountBadge(
|
return NavigationDestination(
|
||||||
page.badgeCount(ref),
|
icon: Badge.count(
|
||||||
|
count: badgeCount ?? 0,
|
||||||
|
isLabelVisible: badgeCount != null,
|
||||||
child: Icon(page.icon),
|
child: Icon(page.icon),
|
||||||
),
|
),
|
||||||
label: page.title,
|
label: page.title,
|
||||||
),
|
);
|
||||||
)
|
}).toList(),
|
||||||
.toList(),
|
|
||||||
onDestinationSelected: (index) => ref
|
onDestinationSelected: (index) => ref
|
||||||
.read(SidebarPageController.provider.notifier)
|
.read(SidebarPageController.provider.notifier)
|
||||||
.set(SidebarPage.values[index]),
|
.set(SidebarPage.values[index]),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue