diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index b83039c..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "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/README.md b/README.md index b6adc87..9960915 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,6 @@ 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 diff --git a/flake.nix b/flake.nix index 91614b5..0eedbe2 100644 --- a/flake.nix +++ b/flake.nix @@ -16,12 +16,67 @@ ... }@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/key.dart b/lib/controllers/key.dart index 77b4883..0d02d17 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 AsyncNotifier { +class KeyController(final String key) extends Notifier { static const String spaceKey = "space"; static const String roomKey = "room"; static const String pushKeyKey = "pushKey"; @override - Future build() => - ref.watch(SharedPrefsController.provider).getString(key); + String? build() => + ref.watch(SharedPrefsController.provider).requireValue.getString(key); Future set(String? value) async { - final prefs = ref.watch(SharedPrefsController.provider); - state = .data(value); + final prefs = ref.watch(SharedPrefsController.provider).requireValue; + state = value; if (value == null) { - await prefs.remove(key); + prefs.remove(key); } else { - await prefs.setString(key, value); + prefs.setString(key, value); } } static final provider = - AsyncNotifierProvider.family( + NotifierProvider.family( KeyController.new, ); } diff --git a/lib/controllers/member_list_opened.dart b/lib/controllers/member_list_opened.dart index f0295d8..e3509f0 100644 --- a/lib/controllers/member_list_opened.dart +++ b/lib/controllers/member_list_opened.dart @@ -1,20 +1,22 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/shared_prefs.dart"; -class MemberListOpenedController extends AsyncNotifier { +class MemberListOpenedController extends Notifier { static const String key = "memberListOpened"; @override - Future build() async => - await ref.watch(SharedPrefsController.provider).getBool(key) ?? true; + bool build() => + ref.watch(SharedPrefsController.provider).requireValue.getBool(key) ?? + true; Future set(bool value) async { - state = .data(value); - await ref.watch(SharedPrefsController.provider).setBool(key, value); + final prefs = ref.watch(SharedPrefsController.provider).requireValue; + state = value; + + prefs.setBool(key, value); } - static final provider = - AsyncNotifierProvider( - MemberListOpenedController.new, - ); + static final provider = NotifierProvider( + MemberListOpenedController.new, + ); } diff --git a/lib/controllers/notification.dart b/lib/controllers/notification.dart index abef40c..7996a47 100644 --- a/lib/controllers/notification.dart +++ b/lib/controllers/notification.dart @@ -83,7 +83,6 @@ class NotificationController File? icon, String? payload, }) async { - debugPrint("Sending notification for $id"); final notificationDetails = NotificationDetails( android: .new( "messages", diff --git a/lib/controllers/push_key.dart b/lib/controllers/push_key.dart index e3f6b82..7217886 100644 --- a/lib/controllers/push_key.dart +++ b/lib/controllers/push_key.dart @@ -4,19 +4,18 @@ 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 AsyncNotifier { +class PushKeyController(final String instance) extends Notifier { @override - Future build() async => json.decode( - await ref.watch(KeyController.provider(KeyController.pushKeyKey).future) ?? - "{}", + String? build() => json.decode( + ref.watch(KeyController.provider(KeyController.pushKeyKey)) ?? "{}", )[instance]; Future set(String? value) async { final provider = KeyController.provider(KeyController.pushKeyKey); final notifier = ref.watch(provider.notifier); - final prefs = IMap(json.decode(await ref.watch(provider.future) ?? "{}")); + final prefs = IMap(json.decode(ref.watch(provider) ?? "{}")); - state = .data(value); + state = value; notifier.set( json.encode( prefs.add(instance, value).where((_, value) => value != null).unlock, @@ -25,7 +24,7 @@ class PushKeyController(final String instance) extends AsyncNotifier { } static final provider = - AsyncNotifierProvider.family( + NotifierProvider.family( PushKeyController.new, ); } diff --git a/lib/controllers/shared_prefs.dart b/lib/controllers/shared_prefs.dart index 9ecb34a..876fc47 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 Notifier { +class SharedPrefsController extends AsyncNotifier { @override - SharedPreferencesAsync build() => SharedPreferencesAsync(); + Future build() async => .getInstance(); static final provider = - NotifierProvider( + AsyncNotifierProvider( SharedPrefsController.new, ); } diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index ae31cac..f637156 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -13,6 +13,7 @@ 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"; @@ -28,7 +29,6 @@ class UnifiedPushController extends AsyncNotifier { dbusName: "nexus.federated.nexus.UnifiedPush", storage: UnifiedPushStorageSharedPreferences(), background: isInBackground, - shouldWriteService: false, ), onNewEndpoint: (endpoint, instance) async { final pushKey = endpoint.pubKeySet!.pubKey; @@ -40,8 +40,8 @@ class UnifiedPushController extends AsyncNotifier { .new( appDisplayName: "Nexus", appId: "nexus.federated.nexus", - data: .webPush( - url: .parse(endpoint.url), + data: PusherData.webPush( + url: Uri.parse(endpoint.url), auth: endpoint.pubKeySet!.auth, ), deviceDisplayName: @@ -53,7 +53,6 @@ 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.", @@ -67,11 +66,8 @@ class UnifiedPushController extends AsyncNotifier { event.unreadType?.shouldNotify() != true || (!isInBackground && await windowManager.isFocused().onError((_, _) => false) && - await ref.watch( - KeyController.provider(KeyController.roomKey).future, - ) == + ref.watch(KeyController.provider(KeyController.roomKey)) == event.roomId)) { - if (isInBackground) exit(0); return; } @@ -148,9 +144,7 @@ class UnifiedPushController extends AsyncNotifier { Future deregister() async { final clientState = ref.watch(ClientStateController.provider); - final key = await ref.watch( - PushKeyController.provider(clientState!.deviceId!).future, - ); + final key = ref.watch(PushKeyController.provider(clientState!.deviceId!)); if (key != null) { await ref diff --git a/lib/main.dart b/lib/main.dart index 05b840f..80c2649 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,11 +7,10 @@ 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"; @@ -82,20 +81,14 @@ void main(List args) async { await windowManager.setMinimumSize(Size.square(500)); } - isInBackground = Platform.environment["FLUTTER_HEADLESS"] != null; + isInBackground = args.contains("--unifiedpush-bg"); - LicenseRegistry.addLicense(() => .fromIterable(fontLicenses)); + LicenseRegistry.addLicense(() => Stream.fromIterable(fontLicenses)); FlutterError.onError = (FlutterErrorDetails details) => showError(details.exception.toString(), details.stack); - 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 { + if (!isInBackground) { runApp( ProviderScope( retry: (_, _) => null, @@ -104,13 +97,14 @@ void main(List args) async { // ignore: dead_code if (false && kDebugMode) Logger(), ], - child: App(), + child: App(isInBackground), ), ); } } -class const App({super.key}) extends StatelessWidget { +class const App(final bool isInBackground, {super.key}) + extends StatelessWidget { @override Widget build(BuildContext context) => DynamicColorBuilder( builder: (lightDynamic, darkDynamic) => Consumer( @@ -151,12 +145,10 @@ class const App({super.key}) extends StatelessWidget { .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 fb165d3..9469c91 100644 --- a/lib/pages/chat.dart +++ b/lib/pages/chat.dart @@ -14,9 +14,7 @@ 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)) - .requireValue; + final roomId = ref.watch(KeyController.provider(KeyController.roomKey)); return SafeArea( child: Scaffold( diff --git a/lib/widgets/room_chat.dart b/lib/widgets/room_chat.dart index d8424c9..015bbc4 100644 --- a/lib/widgets/room_chat.dart +++ b/lib/widgets/room_chat.dart @@ -43,9 +43,7 @@ final class const RoomChat({ final composerSize = useState(64); final userId = ref.watch(ClientStateController.provider)?.userId; - final memberListOpened = ref - .watch(MemberListOpenedController.provider) - .requireValue; + final memberListOpened = ref.watch(MemberListOpenedController.provider); final theme = Theme.of(context); final nothing = Center( diff --git a/lib/widgets/sidebar.dart b/lib/widgets/sidebar.dart index b2d8295..c2a0170 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).requireValue; + final selectedSpaceId = ref.watch(selectedSpaceProvider); final selectedSpaceIdNotifier = ref.watch(selectedSpaceProvider.notifier); final selectedRoomController = KeyController.provider( KeyController.roomKey, ); - final selectedRoomId = ref.watch(selectedRoomController).requireValue; + final selectedRoomId = ref.watch(selectedRoomController); final selectedRoomIdNotifier = ref.watch(selectedRoomController.notifier); final spaces = ref.watch(SpacesController.provider); diff --git a/linux/nexus.federated.nexus.UnifiedPush.service b/linux/nexus.federated.nexus.UnifiedPush.service deleted file mode 100644 index 663ab9b..0000000 --- a/linux/nexus.federated.nexus.UnifiedPush.service +++ /dev/null @@ -1,3 +0,0 @@ -[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 deleted file mode 100644 index 756eb0b..0000000 --- a/linux/nix/default.nix +++ /dev/null @@ -1,59 +0,0 @@ -{ 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 deleted file mode 100644 index a8abd6c..0000000 --- a/linux/nix/module.nix +++ /dev/null @@ -1,45 +0,0 @@ -self: -{ - pkgs, - lib, - config, - ... -}: - -let - inherit (lib) - mkIf - mkMerge - mkEnableOption - mkPackageOption - ; - - 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} "default" { }; - - enableNotifications = mkEnableOption "notifications support via UnifiedPush"; - }; - - 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 36974ed..1114d43 100644 --- a/linux/nix/pkg/default.nix +++ b/linux/nix/pkg/default.nix @@ -32,14 +32,11 @@ 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 = '' 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 ''; diff --git a/pubspec.lock b/pubspec.lock index a914165..5b72591 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1501,22 +1501,20 @@ packages: source: hosted version: "3.5.0" unifiedpush_linux: - dependency: "direct overridden" + dependency: transitive description: - 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" + name: unifiedpush_linux + sha256: c062d5eedd1cec70bcd33270cc4e01ae0ff6501f33d471167c06b34a968adfeb + url: "https://pub.dev" + source: hosted + version: "1.0.0" unifiedpush_platform_interface: - dependency: "direct overridden" + dependency: transitive description: - path: unifiedpush_platform_interface - ref: "quad/feat/should-write-service-option" - resolved-ref: "7589b07ef4280820e4adea165d3d86b219f6022c" - url: "https://codeberg.org/Henry-Hiles/flutter-connector" - source: git + name: unifiedpush_platform_interface + sha256: "83372bc8d794b8b12ef6993b518d7be907dcfc2191bdf6de0ece5c4445d89880" + url: "https://pub.dev" + source: hosted version: "4.0.0" unifiedpush_storage_interface: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index 332efaf..635c506 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,16 +20,6 @@ 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: