From 3d690c26d8915a4ef7a4bf8977effe4eaf0d0465 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 13:27:47 -0400 Subject: [PATCH 1/9] hopefully fixup UP on linux when backgrounded --- lib/controllers/unified_push.dart | 1 + lib/main.dart | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index f637156..b9af5b2 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -68,6 +68,7 @@ class UnifiedPushController extends AsyncNotifier { await windowManager.isFocused().onError((_, _) => false) && ref.watch(KeyController.provider(KeyController.roomKey)) == event.roomId)) { + if (isInBackground) exit(0); return; } diff --git a/lib/main.dart b/lib/main.dart index 80c2649..58289f0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -88,7 +88,13 @@ void main(List args) async { FlutterError.onError = (FlutterErrorDetails details) => showError(details.exception.toString(), details.stack); - if (!isInBackground) { + if (isInBackground) { + await ProviderContainer().read(UnifiedPushController.provider.future); + + // In case it didn't exit for some reason + await Future.delayed(Duration(seconds: 20)); + exit(0); + } else { runApp( ProviderScope( retry: (_, _) => null, From 0d1ace3fd051bc3cdd5429a194f7a7b41b06a2ae Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 13:41:22 -0400 Subject: [PATCH 2/9] add more logs for notifs --- lib/controllers/notification.dart | 1 + lib/controllers/unified_push.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/controllers/notification.dart b/lib/controllers/notification.dart index 7996a47..abef40c 100644 --- a/lib/controllers/notification.dart +++ b/lib/controllers/notification.dart @@ -83,6 +83,7 @@ class NotificationController File? icon, String? payload, }) async { + debugPrint("Sending notification for $id"); final notificationDetails = NotificationDetails( android: .new( "messages", diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index b9af5b2..9575804 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -53,6 +53,7 @@ class UnifiedPushController extends AsyncNotifier { ); }, onMessage: (message, instance) async { + debugPrint("UP message received for $instance"); if (message.decrypted == false) { throw Exception( "Failed to decrypt notification. Try toggling off and on UnifiedPush in settings.", From e8fb3a85239bd336a6522dd5707264f9de6ee3ca Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 15:45:32 -0400 Subject: [PATCH 3/9] use SharedPreferencesAsync to avoid race condition in Sharedprefs This was so painful to debug... --- .vscode/launch.json | 17 +++++++++++++++++ lib/controllers/key.dart | 16 ++++++++-------- lib/controllers/member_list_opened.dart | 20 +++++++++----------- lib/controllers/push_key.dart | 13 +++++++------ lib/controllers/shared_prefs.dart | 6 +++--- lib/controllers/unified_push.dart | 13 ++++++++----- lib/main.dart | 16 +++++++++------- lib/pages/chat.dart | 4 +++- lib/widgets/room_chat.dart | 4 +++- lib/widgets/sidebar.dart | 4 ++-- 10 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b83039c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Flutter", + "type": "dart", + "request": "launch", + "program": "lib/main.dart" + }, + { + "name": "Flutter (Headless)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "env": { "FLUTTER_HEADLESS": "1" } + } + ] +} diff --git a/lib/controllers/key.dart b/lib/controllers/key.dart index 0d02d17..77b4883 100644 --- a/lib/controllers/key.dart +++ b/lib/controllers/key.dart @@ -1,28 +1,28 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/shared_prefs.dart"; -class KeyController(final String key) extends Notifier { +class KeyController(final String key) extends AsyncNotifier { static const String spaceKey = "space"; static const String roomKey = "room"; static const String pushKeyKey = "pushKey"; @override - String? build() => - ref.watch(SharedPrefsController.provider).requireValue.getString(key); + Future build() => + ref.watch(SharedPrefsController.provider).getString(key); Future set(String? value) async { - final prefs = ref.watch(SharedPrefsController.provider).requireValue; - state = value; + final prefs = ref.watch(SharedPrefsController.provider); + state = .data(value); if (value == null) { - prefs.remove(key); + await prefs.remove(key); } else { - prefs.setString(key, value); + await prefs.setString(key, value); } } static final provider = - NotifierProvider.family( + AsyncNotifierProvider.family( KeyController.new, ); } diff --git a/lib/controllers/member_list_opened.dart b/lib/controllers/member_list_opened.dart index e3509f0..f0295d8 100644 --- a/lib/controllers/member_list_opened.dart +++ b/lib/controllers/member_list_opened.dart @@ -1,22 +1,20 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/shared_prefs.dart"; -class MemberListOpenedController extends Notifier { +class MemberListOpenedController extends AsyncNotifier { static const String key = "memberListOpened"; @override - bool build() => - ref.watch(SharedPrefsController.provider).requireValue.getBool(key) ?? - true; + Future build() async => + await ref.watch(SharedPrefsController.provider).getBool(key) ?? true; Future set(bool value) async { - final prefs = ref.watch(SharedPrefsController.provider).requireValue; - state = value; - - prefs.setBool(key, value); + state = .data(value); + await ref.watch(SharedPrefsController.provider).setBool(key, value); } - static final provider = NotifierProvider( - MemberListOpenedController.new, - ); + static final provider = + AsyncNotifierProvider( + MemberListOpenedController.new, + ); } diff --git a/lib/controllers/push_key.dart b/lib/controllers/push_key.dart index 7217886..e3f6b82 100644 --- a/lib/controllers/push_key.dart +++ b/lib/controllers/push_key.dart @@ -4,18 +4,19 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/key.dart"; -class PushKeyController(final String instance) extends Notifier { +class PushKeyController(final String instance) extends AsyncNotifier { @override - String? build() => json.decode( - ref.watch(KeyController.provider(KeyController.pushKeyKey)) ?? "{}", + Future build() async => json.decode( + await ref.watch(KeyController.provider(KeyController.pushKeyKey).future) ?? + "{}", )[instance]; Future set(String? value) async { final provider = KeyController.provider(KeyController.pushKeyKey); final notifier = ref.watch(provider.notifier); - final prefs = IMap(json.decode(ref.watch(provider) ?? "{}")); + final prefs = IMap(json.decode(await ref.watch(provider.future) ?? "{}")); - state = value; + state = .data(value); notifier.set( json.encode( prefs.add(instance, value).where((_, value) => value != null).unlock, @@ -24,7 +25,7 @@ class PushKeyController(final String instance) extends Notifier { } static final provider = - NotifierProvider.family( + AsyncNotifierProvider.family( PushKeyController.new, ); } diff --git a/lib/controllers/shared_prefs.dart b/lib/controllers/shared_prefs.dart index 876fc47..9ecb34a 100644 --- a/lib/controllers/shared_prefs.dart +++ b/lib/controllers/shared_prefs.dart @@ -1,12 +1,12 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:shared_preferences/shared_preferences.dart"; -class SharedPrefsController extends AsyncNotifier { +class SharedPrefsController extends Notifier { @override - Future build() async => .getInstance(); + SharedPreferencesAsync build() => SharedPreferencesAsync(); static final provider = - AsyncNotifierProvider( + NotifierProvider( SharedPrefsController.new, ); } diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index 9575804..bc5f6e1 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -13,7 +13,6 @@ import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client_state.dart"; import "package:nexus/models/content/message.dart"; import "package:nexus/models/content/sticker.dart"; -import "package:nexus/models/requests/register_pusher.dart"; import "package:unifiedpush/unifiedpush.dart"; import "package:unifiedpush_storage_shared_preferences/storage.dart"; import "package:window_manager/window_manager.dart"; @@ -40,8 +39,8 @@ class UnifiedPushController extends AsyncNotifier { .new( appDisplayName: "Nexus", appId: "nexus.federated.nexus", - data: PusherData.webPush( - url: Uri.parse(endpoint.url), + data: .webPush( + url: .parse(endpoint.url), auth: endpoint.pubKeySet!.auth, ), deviceDisplayName: @@ -67,7 +66,9 @@ class UnifiedPushController extends AsyncNotifier { event.unreadType?.shouldNotify() != true || (!isInBackground && await windowManager.isFocused().onError((_, _) => false) && - ref.watch(KeyController.provider(KeyController.roomKey)) == + await ref.watch( + KeyController.provider(KeyController.roomKey).future, + ) == event.roomId)) { if (isInBackground) exit(0); return; @@ -146,7 +147,9 @@ class UnifiedPushController extends AsyncNotifier { Future deregister() async { final clientState = ref.watch(ClientStateController.provider); - final key = ref.watch(PushKeyController.provider(clientState!.deviceId!)); + final key = await ref.watch( + PushKeyController.provider(clientState!.deviceId!).future, + ); if (key != null) { await ref diff --git a/lib/main.dart b/lib/main.dart index 58289f0..05b840f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,10 +7,11 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:media_kit/media_kit.dart"; import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client_state.dart"; +import "package:nexus/controllers/key.dart"; +import "package:nexus/controllers/member_list_opened.dart"; import "package:nexus/controllers/multi_provider.dart"; import "package:nexus/controllers/notification.dart"; import "package:nexus/controllers/settings.dart"; -import "package:nexus/controllers/shared_prefs.dart"; import "package:nexus/controllers/unified_push.dart"; import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/scheme_to_theme.dart"; @@ -81,9 +82,9 @@ void main(List args) async { await windowManager.setMinimumSize(Size.square(500)); } - isInBackground = args.contains("--unifiedpush-bg"); + isInBackground = Platform.environment["FLUTTER_HEADLESS"] != null; - LicenseRegistry.addLicense(() => Stream.fromIterable(fontLicenses)); + LicenseRegistry.addLicense(() => .fromIterable(fontLicenses)); FlutterError.onError = (FlutterErrorDetails details) => showError(details.exception.toString(), details.stack); @@ -103,14 +104,13 @@ void main(List args) async { // ignore: dead_code if (false && kDebugMode) Logger(), ], - child: App(isInBackground), + child: App(), ), ); } } -class const App(final bool isInBackground, {super.key}) - extends StatelessWidget { +class const App({super.key}) extends StatelessWidget { @override Widget build(BuildContext context) => DynamicColorBuilder( builder: (lightDynamic, darkDynamic) => Consumer( @@ -151,10 +151,12 @@ class const App(final bool isInBackground, {super.key}) .watch( MultiProviderController.provider( IListConst([ - SharedPrefsController.provider, ClientController.provider, NotificationController.provider, UnifiedPushController.provider, + MemberListOpenedController.provider, + KeyController.provider(KeyController.roomKey), + KeyController.provider(KeyController.spaceKey), ]), ), ) diff --git a/lib/pages/chat.dart b/lib/pages/chat.dart index 9469c91..fb165d3 100644 --- a/lib/pages/chat.dart +++ b/lib/pages/chat.dart @@ -14,7 +14,9 @@ class const ChatPage({super.key}) extends ConsumerWidget { final isDesktop = constraints.maxWidth > 650; final showMembersByDefault = constraints.maxWidth > 1000; final initComplete = ref.watch(InitCompleteController.provider); - final roomId = ref.watch(KeyController.provider(KeyController.roomKey)); + final roomId = ref + .watch(KeyController.provider(KeyController.roomKey)) + .requireValue; return SafeArea( child: Scaffold( diff --git a/lib/widgets/room_chat.dart b/lib/widgets/room_chat.dart index 015bbc4..d8424c9 100644 --- a/lib/widgets/room_chat.dart +++ b/lib/widgets/room_chat.dart @@ -43,7 +43,9 @@ final class const RoomChat({ final composerSize = useState(64); final userId = ref.watch(ClientStateController.provider)?.userId; - final memberListOpened = ref.watch(MemberListOpenedController.provider); + final memberListOpened = ref + .watch(MemberListOpenedController.provider) + .requireValue; final theme = Theme.of(context); final nothing = Center( diff --git a/lib/widgets/sidebar.dart b/lib/widgets/sidebar.dart index c2a0170..b2d8295 100644 --- a/lib/widgets/sidebar.dart +++ b/lib/widgets/sidebar.dart @@ -23,13 +23,13 @@ class const Sidebar({required final bool isDesktop, super.key}) final selectedSpaceProvider = KeyController.provider( KeyController.spaceKey, ); - final selectedSpaceId = ref.watch(selectedSpaceProvider); + final selectedSpaceId = ref.watch(selectedSpaceProvider).requireValue; final selectedSpaceIdNotifier = ref.watch(selectedSpaceProvider.notifier); final selectedRoomController = KeyController.provider( KeyController.roomKey, ); - final selectedRoomId = ref.watch(selectedRoomController); + final selectedRoomId = ref.watch(selectedRoomController).requireValue; final selectedRoomIdNotifier = ref.watch(selectedRoomController.notifier); final spaces = ref.watch(SpacesController.provider); From b3023d8147dba9cd62c0cd38951043c2fdd21c29 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:00:10 -0400 Subject: [PATCH 4/9] don't auto create dbus service --- lib/controllers/unified_push.dart | 1 + pubspec.lock | 24 +++++++++++++----------- pubspec.yaml | 10 ++++++++++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index bc5f6e1..ae31cac 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -28,6 +28,7 @@ class UnifiedPushController extends AsyncNotifier { dbusName: "nexus.federated.nexus.UnifiedPush", storage: UnifiedPushStorageSharedPreferences(), background: isInBackground, + shouldWriteService: false, ), onNewEndpoint: (endpoint, instance) async { final pushKey = endpoint.pubKeySet!.pubKey; diff --git a/pubspec.lock b/pubspec.lock index 5b72591..a914165 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1501,20 +1501,22 @@ packages: source: hosted version: "3.5.0" unifiedpush_linux: - dependency: transitive + dependency: "direct overridden" description: - name: unifiedpush_linux - sha256: c062d5eedd1cec70bcd33270cc4e01ae0ff6501f33d471167c06b34a968adfeb - url: "https://pub.dev" - source: hosted - version: "1.0.0" + path: unifiedpush_linux + ref: "quad/feat/should-write-service-option" + resolved-ref: "7589b07ef4280820e4adea165d3d86b219f6022c" + url: "https://codeberg.org/Henry-Hiles/flutter-connector" + source: git + version: "1.0.1" unifiedpush_platform_interface: - dependency: transitive + dependency: "direct overridden" description: - name: unifiedpush_platform_interface - sha256: "83372bc8d794b8b12ef6993b518d7be907dcfc2191bdf6de0ece5c4445d89880" - url: "https://pub.dev" - source: hosted + path: unifiedpush_platform_interface + ref: "quad/feat/should-write-service-option" + resolved-ref: "7589b07ef4280820e4adea165d3d86b219f6022c" + url: "https://codeberg.org/Henry-Hiles/flutter-connector" + source: git version: "4.0.0" unifiedpush_storage_interface: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index 635c506..332efaf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,16 @@ environment: dependency_overrides: dynamic_color: 2.1.0 + unifiedpush_linux: + git: + url: https://codeberg.org/Henry-Hiles/flutter-connector + ref: quad/feat/should-write-service-option + path: unifiedpush_linux + unifiedpush_platform_interface: + git: + url: https://codeberg.org/Henry-Hiles/flutter-connector + ref: quad/feat/should-write-service-option + path: unifiedpush_platform_interface path_provider_android: 2.2.23 # Pinned to avoid JNI linkify: git: From 1cfea5a8196d65b8134b65c780a181a501714813 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:13:22 -0400 Subject: [PATCH 5/9] add nix module --- flake.nix | 57 +----------------- lib/controllers/unified_push.dart | 2 +- .../nexus.federated.nexus.UnifiedPush.service | 3 + linux/nix/default.nix | 59 +++++++++++++++++++ linux/nix/module.nix | 55 +++++++++++++++++ linux/nix/pkg/default.nix | 1 + 6 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 linux/nexus.federated.nexus.UnifiedPush.service create mode 100644 linux/nix/default.nix create mode 100644 linux/nix/module.nix diff --git a/flake.nix b/flake.nix index 0eedbe2..91614b5 100644 --- a/flake.nix +++ b/flake.nix @@ -16,67 +16,12 @@ ... }@inputs: flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ ./linux/nix ]; systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; - - perSystem = - { - lib, - pkgs, - system, - ... - }: - - { - _module.args.pkgs = import nixpkgs { - inherit system; - config = { - android_sdk.accept_license = true; - allowUnfree = true; - }; - }; - - packages = - let - default = pkgs.callPackage ./linux/nix/pkg { - src = self; - }; - in - { - inherit default; - - flatpak = inputs.nix2flatpak.lib.${system}.mkFlatpak { - appName = "Nexus"; - developer = "QuadRadical"; - appId = "nexus.federated.nexus"; - package = default; - runtime = "org.gnome.Platform/49"; - permissions = { - share = [ "network" ]; - sockets = [ - "pulseaudio" - "fallback-x11" - "wayland" - ]; - - talk-names = [ - "org.unifiedpush.Distributor.*" - "org.freedesktop.Notifications" - ]; - devices = [ "dri" ]; - }; - }; - - gomuks = pkgs.callPackage ./linux/nix/pkg/gomuks.nix { - src = self; - }; - }; - - devShells.default = pkgs.callPackage ./linux/nix/devshell.nix { }; - }; }; } diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index ae31cac..1016053 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -28,7 +28,7 @@ class UnifiedPushController extends AsyncNotifier { dbusName: "nexus.federated.nexus.UnifiedPush", storage: UnifiedPushStorageSharedPreferences(), background: isInBackground, - shouldWriteService: false, + shouldWriteService: true, ), onNewEndpoint: (endpoint, instance) async { final pushKey = endpoint.pubKeySet!.pubKey; diff --git a/linux/nexus.federated.nexus.UnifiedPush.service b/linux/nexus.federated.nexus.UnifiedPush.service new file mode 100644 index 0000000..663ab9b --- /dev/null +++ b/linux/nexus.federated.nexus.UnifiedPush.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=nexus.federated.nexus.UnifiedPush +Exec=/usr/bin/env FLUTTER_HEADLESS=1 nexus diff --git a/linux/nix/default.nix b/linux/nix/default.nix new file mode 100644 index 0000000..756eb0b --- /dev/null +++ b/linux/nix/default.nix @@ -0,0 +1,59 @@ +{ self, inputs, ... }: { + + perSystem = + { + pkgs, + system, + lib, + ... + }: + { + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + config = { + android_sdk.accept_license = true; + allowUnfree = true; + }; + }; + + packages = + let + default = pkgs.callPackage ./pkg { + src = self; + }; + in + { + inherit default; + + flatpak = inputs.nix2flatpak.lib.${system}.mkFlatpak { + appName = "Nexus"; + developer = "QuadRadical"; + appId = "nexus.federated.nexus"; + package = default; + runtime = "org.gnome.Platform/49"; + permissions = { + share = [ "network" ]; + sockets = [ + "pulseaudio" + "fallback-x11" + "wayland" + ]; + + talk-names = [ + "org.unifiedpush.Distributor.*" + "org.freedesktop.Notifications" + ]; + devices = [ "dri" ]; + }; + }; + + gomuks = pkgs.callPackage ./pkg/gomuks.nix { + src = self; + }; + }; + + devShells.default = pkgs.callPackage ./devshell.nix { }; + }; + + flake.nixosModules.default = import ./module.nix self; +} diff --git a/linux/nix/module.nix b/linux/nix/module.nix new file mode 100644 index 0000000..f901007 --- /dev/null +++ b/linux/nix/module.nix @@ -0,0 +1,55 @@ +self: +{ + pkgs, + lib, + config, + ... +}: + +let + inherit (lib) + mkIf + mkMerge + mkOption + mkEnableOption + mkPackageOption + types + ; + + cfg = config.programs.nexus; +in +{ + options.programs.nexus = { + enable = mkEnableOption "Nexus, a simple and user-friendly Matrix client"; + package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "nexus" { }; + + enableNotifications = mkOption { + description = '' + Whether to enable push notifications support via UnifiedPush, installing + {manpage}`kunifiedpush` and registering its systemd and D-Bus units. + ''; + type = types.bool; + default = false; + example = true; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { + environment.systemPackages = [ cfg.package ]; + } + (mkIf cfg.enableNotifications { + environment.systemPackages = [ + pkgs.kdePackages.kunifiedpush + ]; + + systemd.packages = [ + pkgs.kdePackages.kunifiedpush + ]; + + services.dbus.packages = [ + cfg.package + ]; + }) + ]); +} diff --git a/linux/nix/pkg/default.nix b/linux/nix/pkg/default.nix index 1114d43..cf1b107 100644 --- a/linux/nix/pkg/default.nix +++ b/linux/nix/pkg/default.nix @@ -37,6 +37,7 @@ flutter.buildFlutterApplication { postInstall = '' install -D assets/bundled/icon.svg $out/share/icons/hicolor/scalable/apps/nexus.svg install -Dm755 linux/nexus.federated.nexus.desktop -t $out/share/applications + install -Dm644 linux/*.service -t $out/share/dbus-1/services wrapProgram $out/bin/nexus \ --suffix LD_LIBRARY_PATH : $out/app/nexus/lib ''; From f40dd22277beb2679f2abb04d1137b4ef7a07819 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:14:56 -0400 Subject: [PATCH 6/9] use mkEnableOption for enableNotifications --- linux/nix/module.nix | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/linux/nix/module.nix b/linux/nix/module.nix index f901007..ac1b503 100644 --- a/linux/nix/module.nix +++ b/linux/nix/module.nix @@ -10,10 +10,8 @@ let inherit (lib) mkIf mkMerge - mkOption mkEnableOption mkPackageOption - types ; cfg = config.programs.nexus; @@ -23,15 +21,7 @@ in enable = mkEnableOption "Nexus, a simple and user-friendly Matrix client"; package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "nexus" { }; - enableNotifications = mkOption { - description = '' - Whether to enable push notifications support via UnifiedPush, installing - {manpage}`kunifiedpush` and registering its systemd and D-Bus units. - ''; - type = types.bool; - default = false; - example = true; - }; + enableNotifications = mkEnableOption "notifications support via UnifiedPush"; }; config = mkIf cfg.enable (mkMerge [ From 35ef82accd58a52e36e7436dc6421eb129b72af3 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:18:39 -0400 Subject: [PATCH 7/9] fixup module --- linux/nix/module.nix | 2 +- linux/nix/pkg/default.nix | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/linux/nix/module.nix b/linux/nix/module.nix index ac1b503..a8abd6c 100644 --- a/linux/nix/module.nix +++ b/linux/nix/module.nix @@ -19,7 +19,7 @@ in { options.programs.nexus = { enable = mkEnableOption "Nexus, a simple and user-friendly Matrix client"; - package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "nexus" { }; + package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "default" { }; enableNotifications = mkEnableOption "notifications support via UnifiedPush"; }; diff --git a/linux/nix/pkg/default.nix b/linux/nix/pkg/default.nix index cf1b107..36974ed 100644 --- a/linux/nix/pkg/default.nix +++ b/linux/nix/pkg/default.nix @@ -32,6 +32,8 @@ flutter.buildFlutterApplication { emoji_text_field = "sha256-3TOys09EP2GRo6pUBGPXaqBlE39O2Cmwt42Hs1cTDKo="; linkify = "sha256-TpMD6+0zyY6i9l+6d8ErnVufmepCv362rCtnbOht/z4="; navigation_rail_m3e = "sha256-+2awDTQnK58gGRY1nuHckG/jjxarsYSRu9ovR4i4TEc="; + unifiedpush_linux = "sha256-aIF/8oabSuuZo7K6qr4r7UBmf57qgoGAXyJ40fdntuQ="; + unifiedpush_platform_interface = "sha256-aIF/8oabSuuZo7K6qr4r7UBmf57qgoGAXyJ40fdntuQ="; }; postInstall = '' From 1a6a5c36ea6cbeb269f965b71444d8f362b12caa Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:21:26 -0400 Subject: [PATCH 8/9] link to module from readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9960915..b6adc87 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ If you want to try out Nexus, grab one of the following artifacts from CI: - Flatpak - [AArch64/Arm64](https://nightly.link/Henry-Hiles/nexus/workflows/flatpak/main/flatpak-aarch64.zip) - [x86_64/AMD64](https://nightly.link/Henry-Hiles/nexus/workflows/flatpak/main/flatpak-x86_64.zip) +- [NixOS Module](linux/nix/module.nix) ## Build it yourself From c0d14ac30ee4eee44298771d00469b9df1edb5d9 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Sep 2026 17:27:45 -0400 Subject: [PATCH 9/9] don't write service by default --- lib/controllers/unified_push.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index 1016053..ae31cac 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -28,7 +28,7 @@ class UnifiedPushController extends AsyncNotifier { dbusName: "nexus.federated.nexus.UnifiedPush", storage: UnifiedPushStorageSharedPreferences(), background: isInBackground, - shouldWriteService: true, + shouldWriteService: false, ), onNewEndpoint: (endpoint, instance) async { final pushKey = endpoint.pubKeySet!.pubKey;