use xdg_desktop_portal over flutter_local_notifications on linux

This commit is contained in:
Henry Hiles 2026-09-21 15:43:01 -04:00
commit fea39e4191
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
6 changed files with 132 additions and 76 deletions

View file

@ -1,10 +1,13 @@
import "dart:io";
import "package:flutter/foundation.dart";
import "package:material_ui/material_ui.dart";
import "package:nexus/controllers/portal.dart";
import "package:nexus/main.dart";
import "package:flutter_local_notifications/flutter_local_notifications.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/pages/notifications.dart";
import "package:xdg_desktop_portal/xdg_desktop_portal.dart";
class NotificationController
extends AsyncNotifier<FlutterLocalNotificationsPlugin> {
@ -12,6 +15,7 @@ class NotificationController
Future<FlutterLocalNotificationsPlugin> build() async {
final notifications = FlutterLocalNotificationsPlugin();
if (!Platform.isLinux) {
final darwin = DarwinInitializationSettings();
await notifications.initialize(
@ -24,7 +28,6 @@ class NotificationController
android: .new("ic_launcher_foreground"),
iOS: darwin,
macOS: darwin,
linux: .new(defaultActionName: "Open"),
),
onDidReceiveNotificationResponse: (details) {
if (details.payload case final eventId?) {
@ -41,11 +44,48 @@ class NotificationController
}
},
);
}
if (Platform.isLinux) {
final portal = await ref.watch(PortalController.provider.future);
portal.notification.actionInvoked.listen((event) {
if (event.action != "app.event") {
return;
}
if (navigatorKey.currentContext case final context?) {
if (context.mounted) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => NotificationsPage(
highlightedEventId: event.id,
defaultToAllNotifications: true,
),
),
);
}
}
});
}
ref.onDispose(() {
// The portal client owns its D-Bus connection.
if (Platform.isLinux) {
ref.read(PortalController.provider.future).then((portal) {
portal.close();
});
}
});
return notifications;
}
Future<bool> requestPermissions() async {
if (Platform.isLinux) {
return true;
}
final controller = await future;
if (Platform.isIOS) {
@ -82,24 +122,33 @@ class NotificationController
String? payload,
}) async {
debugPrint("Sending notification for $id");
if (Platform.isLinux) {
final portal = await ref.read(PortalController.provider.future);
await portal.notification.addNotification(
id.toString(),
title: title,
body: body,
icon: icon == null ? null : XdgNotificationIconFile(icon.path),
defaultAction: "app.event",
);
} else {
final notificationDetails = NotificationDetails(
android: .new(
"messages",
"Messages",
largeIcon: icon == null ? null : FilePathAndroidBitmap(icon.path),
),
linux: .new(
category: LinuxNotificationCategory.imReceived,
defaultActionName: "app.event",
icon: icon == null ? null : FilePathLinuxIcon(icon.path),
),
// TODO: See if icons can be added to iOS, macOS, and Windows notifications (#68)
// TODO: See if icons can be added to iOS, macOS, and Windows
// notifications (#68)
iOS: .new(),
macOS: .new(),
windows: .new(),
);
final controller = await future;
await controller.show(
id: id,
title: title,
@ -108,6 +157,7 @@ class NotificationController
payload: payload,
);
}
}
static final provider =
AsyncNotifierProvider<

View file

@ -0,0 +1,17 @@
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:xdg_desktop_portal/xdg_desktop_portal.dart";
class PortalController extends AsyncNotifier<XdgDesktopPortalClient> {
@override
Future<XdgDesktopPortalClient> build() async {
final portal = XdgDesktopPortalClient();
await portal.registerApplication("nexus.federated.nexus");
return portal;
}
static final provider =
AsyncNotifierProvider<PortalController, XdgDesktopPortalClient>(
PortalController.new,
);
}

View file

@ -8,6 +8,4 @@ Terminal=false
Type=Application
Categories=Chat;Network;InstantMessaging;
MimeType=x-scheme-handler/nexus.federated.nexus;
StartupNotify=true
DBusActivatable=true
X-GNOME-UsesNotifications=true

View file

@ -1,3 +1,3 @@
[D-BUS Service]
Name=nexus.federated.nexus
Exec=/usr/bin/env FLUTTER_HEADLESS=1 nexus
Exec=/usr/bin/env nexus

View file

@ -495,23 +495,21 @@ packages:
source: hosted
version: "22.3.0"
flutter_local_notifications_linux:
dependency: "direct main"
dependency: transitive
description:
path: flutter_local_notifications_linux
ref: "quad/feat/xdg-portal-notifs"
resolved-ref: d853ff4997f6dd2b9ecdc53d37fb337cebe63863
url: "https://github.com/Henry-Hiles/flutter_local_notifications"
source: git
version: "9.0.0-dev.1"
name: flutter_local_notifications_linux
sha256: "9ca97e63776f29ab1b955725c09999fc2c150523269db150c39274f2a43c5a8b"
url: "https://pub.dev"
source: hosted
version: "8.0.1"
flutter_local_notifications_platform_interface:
dependency: "direct overridden"
dependency: transitive
description:
path: flutter_local_notifications_platform_interface
ref: "quad/feat/xdg-portal-notifs"
resolved-ref: d853ff4997f6dd2b9ecdc53d37fb337cebe63863
url: "https://github.com/Henry-Hiles/flutter_local_notifications"
source: git
version: "13.0.0-dev.1"
name: flutter_local_notifications_platform_interface
sha256: "43c3761d916c9bd3d5c7ebbc44d82f4990329840c0c5d62ad5260cc1b5d399bd"
url: "https://pub.dev"
source: hosted
version: "12.2.0"
flutter_local_notifications_web:
dependency: transitive
description:
@ -1745,12 +1743,13 @@ packages:
source: hosted
version: "0.5.2"
xdg_desktop_portal:
dependency: transitive
dependency: "direct main"
description:
name: xdg_desktop_portal
sha256: "4fae74b6ed63a449d4c796a74265cebdd912c390336dedc06d705142f3b939d7"
url: "https://pub.dev"
source: hosted
path: "."
ref: HEAD
resolved-ref: "6d070b677f908b01065b4dce79ddc9a208daadbf"
url: "https://github.com/Henry-Hiles/xdg_desktop_portal.dart"
source: git
version: "0.1.14"
xdg_directories:
dependency: "direct main"

View file

@ -35,16 +35,6 @@ dependency_overrides:
git:
url: https://github.com/appelladev/linkify
ref: fix/consecutive-periods-loose-url
flutter_local_notifications_linux:
git:
url: https://github.com/Henry-Hiles/flutter_local_notifications
ref: quad/feat/xdg-portal-notifs
path: flutter_local_notifications_linux
flutter_local_notifications_platform_interface:
git:
url: https://github.com/Henry-Hiles/flutter_local_notifications
ref: quad/feat/xdg-portal-notifs
path: flutter_local_notifications_platform_interface
dependencies:
flutter:
@ -99,8 +89,10 @@ dependencies:
unifiedpush: 6.2.0
unifiedpush_storage_shared_preferences: 1.0.0
flutter_local_notifications: 22.3.0
flutter_local_notifications_linux: 8.0.1
material_emoji_picker: 1.1.1
xdg_desktop_portal:
git:
url: https://github.com/Henry-Hiles/xdg_desktop_portal.dart
dev_dependencies:
build_runner: 2.16.1