Watch
1
0
Fork
You've already forked nexus
0
forked from Nexus/nexus

Compare commits

..
13 changed files with 62 additions and 142 deletions

View file

@ -1,32 +0,0 @@
name: "Build MacOS App"
on:
# TODO: Uncomment this once the MacOS workflow actually works
# push:
# branches: ["main"]
# tags: ["*"]
workflow_dispatch:
jobs:
build-app:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
- name: Lix GHA Installer Action
uses: samueldr/lix-gha-installer-action@v2026-02-22
with:
extra_nix_config: experimental-features = nix-command flakes flake-self-attrs
- name: Build app
run: nix develop --command bash -c "flutter pub get && dart scripts/generate.dart && flutter pub run build_runner build && flutter build macos --release"
- name: Upload installer artifact
uses: actions/upload-artifact@v6
with:
name: App
path: build/macos/Build/Products/Release/Nexus.app

View file

@ -127,16 +127,15 @@ If you want to try out Nexus, grab one of the following artifacts from CI:
#### Linux #### Linux
- With Nix: Either use direnv and `direnv allow`, or `nix flake develop` - With Nix: Either use direnv and `direnv allow`, or `nix flake develop`
- Without Nix: Install Flutter, Go, Git, Libclang, Libass, MPV, and Glibc. Do not use any Snap packages, they cause various compilation issues. - Without Nix: Install Flutter, Go, Git, Libclang, and Glibc. Do not use any Snap packages, they cause various compilation issues.
#### Windows #### Windows
You will need: You will need:
- Flutter - Flutter
- Android SDK + NDK
- Git - Git
- Libass
- MPV
- Go - Go
- Visual Studio 2022 (Desktop development with C++) - Visual Studio 2022 (Desktop development with C++)
- [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO) - [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO)
@ -203,7 +202,7 @@ Development instructions can be found in [DEVELOPMENT.md](./DEVELOPMENT.md).
## Community ## Community
Join the [Nexus Client Matrix room](https://matrix.to/#/#nexus:federated.nexus) for questions or help with developing or using Nexus Client. Join the [Nexus Client Matrix Room](https://matrix.to/#/#nexus:federated.nexus) for questions or help with developing or using Nexus Client.
# Credits # Credits

View file

@ -17,16 +17,18 @@ class AttachmentController extends Notifier<(String, MessageContent?)?> {
final filename = basename(file.path); final filename = basename(file.path);
state = (filename, null); state = (filename, null);
final isEncrypted = ref.read( final room = ref.watch(
RoomsController.provider.select( RoomsController.provider.select((value) => value[roomId]),
(value) =>
value[roomId]?.state[EventType.encryption.type]?.isNotEmpty == true,
),
); );
final content = await ref final content = await ref
.watch(ClientController.provider.notifier) .watch(ClientController.provider.notifier)
.uploadMedia(.new(path: file.path, encrypt: isEncrypted)); .uploadMedia(
.new(
path: file.path,
encrypt: room?.state[EventType.encryption.type]?.isNotEmpty == true,
),
);
state = (filename, content); state = (filename, content);
} }

View file

@ -1,22 +0,0 @@
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/shared_prefs.dart";
class MemberListOpenedController extends Notifier<bool> {
static const String key = "memberListOpened";
@override
bool build() =>
ref.watch(SharedPrefsController.provider).requireValue.getBool(key) ??
true;
Future<void> set(bool value) async {
final prefs = ref.watch(SharedPrefsController.provider).requireValue;
state = value;
prefs.setBool(key, value);
}
static final provider = NotifierProvider<MemberListOpenedController, bool>(
MemberListOpenedController.new,
);
}

View file

@ -125,9 +125,11 @@ class RoomChatController extends AsyncNotifier<IList<Event>?> {
if (relationType == .edit) { if (relationType == .edit) {
baseContent = relation?.content; baseContent = relation?.content;
} else { } else {
final provider = AttachmentController.provider(roomId); final attachment = ref.watch(AttachmentController.provider(roomId));
baseContent = ref.watch(provider)?.$2; if (attachment != null && attachment.$2 == null) return;
ref.invalidate(provider);
baseContent = attachment?.$2;
ref.invalidate(AttachmentController.provider(roomId));
} }
var taggedMessage = text; var taggedMessage = text;

View file

@ -59,10 +59,7 @@ class Composer extends HookConsumerWidget {
final attachment = ref.watch(AttachmentController.provider(roomId)); final attachment = ref.watch(AttachmentController.provider(roomId));
void send() { void send() {
if (controller.value.text.isEmpty && attachment == null || if (controller.value.text.isEmpty && attachment == null) return;
attachment != null && attachment.$2 == null) {
return;
}
onSend( onSend(
controller.value.formattedText, controller.value.formattedText,
shouldMention: shouldMention.value, shouldMention: shouldMention.value,

View file

@ -216,15 +216,12 @@ class EventRenderer extends HookConsumerWidget {
if (event.content is! MessageContent) ReactionRow(event), if (event.content is! MessageContent) ReactionRow(event),
if (event.sendError != null && event.sendError != "not sent") if (event.sendError != null && event.sendError != "not sent")
Padding( Text(
padding: .only(bottom: 4),
child: Text(
event.sendError!, event.sendError!,
style: theme.textTheme.labelSmall?.copyWith( style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.error, color: theme.colorScheme.error,
), ),
), ),
),
].map((child) => Padding(padding: .only(left: 4), child: child)), ].map((child) => Padding(padding: .only(left: 4), child: child)),
], ],
] else if (textOnly) ] else if (textOnly)

View file

@ -286,8 +286,9 @@ class MessageRenderer extends ConsumerWidget {
"This message is redacted", "This message is redacted",
style: errorStyle, style: errorStyle,
) )
: Wrap( : Row(
spacing: 8, spacing: 8,
mainAxisSize: .min,
children: [ children: [
Text( Text(
"Unknown message type:", "Unknown message type:",

View file

@ -7,7 +7,6 @@ import "package:measure_size/measure_size.dart";
import "package:nexus/controllers/account_data.dart"; import "package:nexus/controllers/account_data.dart";
import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client.dart";
import "package:nexus/controllers/client_state.dart"; import "package:nexus/controllers/client_state.dart";
import "package:nexus/controllers/member_list_opened.dart";
import "package:nexus/controllers/pinned_ids.dart"; import "package:nexus/controllers/pinned_ids.dart";
import "package:nexus/controllers/power_level.dart"; import "package:nexus/controllers/power_level.dart";
import "package:nexus/controllers/rooms.dart"; import "package:nexus/controllers/rooms.dart";
@ -47,8 +46,9 @@ class RoomChat extends HookConsumerWidget {
final composerSize = useState<double>(64); final composerSize = useState<double>(64);
final memberListOpened = useState<bool>(showMembersByDefault);
final userId = ref.watch(ClientStateController.provider)?.userId; final userId = ref.watch(ClientStateController.provider)?.userId;
final memberListOpened = ref.watch(MemberListOpenedController.provider);
final theme = Theme.of(context); final theme = Theme.of(context);
final nothing = Center( final nothing = Center(
@ -448,9 +448,7 @@ class RoomChat extends HookConsumerWidget {
isDesktop: isDesktop, isDesktop: isDesktop,
onOpenDrawer: Scaffold.of(context).openDrawer, onOpenDrawer: Scaffold.of(context).openDrawer,
onOpenMemberList: (thisContext) { onOpenMemberList: (thisContext) {
ref memberListOpened.value = !memberListOpened.value;
.watch(MemberListOpenedController.provider.notifier)
.set(!memberListOpened);
Scaffold.of(thisContext).openEndDrawer(); Scaffold.of(thisContext).openEndDrawer();
}, },
onOpenPinnedMessagesList: () { onOpenPinnedMessagesList: () {
@ -555,7 +553,7 @@ class RoomChat extends HookConsumerWidget {
), ),
), ),
if (memberListOpened == true && showMembersByDefault) if (memberListOpened.value == true && showMembersByDefault)
MemberList(roomId), MemberList(roomId),
], ],
), ),

View file

@ -18,13 +18,12 @@ let
}; };
in in
pkgs.mkShell { pkgs.mkShell {
packages = packages = with pkgs; [
with pkgs;
[
go go
git git
jdk17 jdk17
libGL libGL
wayland
(flutter.override { (flutter.override {
extraPkgConfigPackages = [ extraPkgConfigPackages = [
mpv-unwrapped mpv-unwrapped
@ -32,11 +31,12 @@ pkgs.mkShell {
]; ];
}) })
android.platform-tools android.platform-tools
] ];
++ lib.optional pkgs.stdenv.isLinux wayland;
env = rec { env = rec {
LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.libclang ]; LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.libclang ];
LD_LIBRARY_PATH = "./build/native_assets/linux:${lib.makeLibraryPath [ pkgs.zlib ]}";
CPATH = lib.makeSearchPath "include" [ pkgs.glibc.dev ];
ANDROID_HOME = "${android.androidsdk}/libexec/android-sdk"; ANDROID_HOME = "${android.androidsdk}/libexec/android-sdk";
ANDROID_SDK_ROOT = ANDROID_HOME; ANDROID_SDK_ROOT = ANDROID_HOME;
@ -44,9 +44,5 @@ pkgs.mkShell {
TOOLS = "${ANDROID_HOME}/build-tools/${"36.0.0"}"; TOOLS = "${ANDROID_HOME}/build-tools/${"36.0.0"}";
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${TOOLS}/aapt2"; GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${TOOLS}/aapt2";
}
// lib.optionalAttrs pkgs.stdenv.isLinux {
CPATH = lib.makeSearchPath "include" [ pkgs.glibc.dev ];
LD_LIBRARY_PATH = "./build/native_assets/linux:${lib.makeLibraryPath [ pkgs.zlib ]}";
}; };
} }

View file

@ -44,7 +44,7 @@ flutter.buildFlutterApplication {
meta = { meta = {
description = "A simple and user-friendly Matrix client"; description = "A simple and user-friendly Matrix client";
mainProgram = "nexus"; mainProgram = "nexus";
platforms = lib.platforms.unix; platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ quadradical ]; maintainers = with lib.maintainers; [ quadradical ];
}; };
} }

View file

@ -1,15 +1,9 @@
{ {
src, src,
stdenv,
buildGoModule, buildGoModule,
}: }:
buildGoModule ( buildGoModule (finalAttrs: {
finalAttrs:
let
filename = "libgomuks${stdenv.hostPlatform.extensions.sharedLibrary}";
in
{
pname = "gomuks-ffi"; pname = "gomuks-ffi";
version = "submodule"; version = "submodule";
@ -22,7 +16,7 @@ buildGoModule (
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
go build -buildmode=c-shared -o ${filename} -tags goolm,noheic,sqlite_fts5 ./pkg/ffi go build -buildmode=c-shared -o libgomuks.so -tags goolm,noheic,sqlite_fts5 ./pkg/ffi
runHook postBuild runHook postBuild
''; '';
@ -30,9 +24,8 @@ buildGoModule (
installPhase = '' installPhase = ''
runHook preInstall runHook preInstall
install -Dm0644 ${filename} -t $out/lib install -Dm0644 libgomuks.so -t $out/lib
runHook postInstall runHook postInstall
''; '';
} })
)

View file

@ -24,18 +24,7 @@ void main(List<String> args) async {
).generate( ).generate(
libclangDylib: libclangPath == null libclangDylib: libclangPath == null
? null ? null
: Uri.file( : Uri.file(join(libclangPath, "libclang.so")),
join(
libclangPath,
"libclang.${(Platform.isLinux || Platform.isAndroid)
? "so"
: Platform.isMacOS
? "dylib"
: Platform.isWindows
? "dll"
: throw UnsupportedError("Unsupported Platform")}",
),
),
); );
print("Done!"); print("Done!");
} }