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

Compare commits

..
25 changed files with 239 additions and 493 deletions

View file

@ -48,7 +48,7 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] Replies - [x] Replies
- [x] Choose ping on/off - [x] Choose ping on/off
- [x] Per message profiles - [x] Per message profiles
- [x] Attachments - [ ] Attachments
- [ ] Commands with [MSC4391](https://github.com/matrix-org/matrix-spec-proposals/pull/4391) - [ ] Commands with [MSC4391](https://github.com/matrix-org/matrix-spec-proposals/pull/4391)
- [x] Mentions - [x] Mentions
- [x] Users - [x] Users

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

2
gomuks

@ -1 +1 @@
Subproject commit c06eb1cbda2d49ff199a351e2d55df6ff7ab602b Subproject commit 3c759ba03a5235deb82cb1559ebc42c36ee0e874

View file

@ -1,40 +0,0 @@
import "package:file_selector/file_selector.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/client.dart";
import "package:nexus/controllers/rooms.dart";
import "package:nexus/models/content/content.dart";
import "package:nexus/models/content/message.dart";
import "package:path/path.dart";
class AttachmentController extends Notifier<(String, MessageContent?)?> {
final String roomId;
AttachmentController(this.roomId);
@override
Null build() => null;
Future<void> add(XFile file) async {
final filename = basename(file.path);
state = (filename, null);
final room = ref.watch(
RoomsController.provider.select((value) => value[roomId]),
);
final content = await ref
.watch(ClientController.provider.notifier)
.uploadMedia(
.new(
path: file.path,
encrypt: room?.state[EventType.encryption.type]?.isNotEmpty == true,
),
);
state = (filename, content);
}
static final provider = NotifierProvider.family
.autoDispose<AttachmentController, (String, MessageContent?)?, String>(
AttachmentController.new,
);
}

View file

@ -23,8 +23,10 @@ class AuthUrlController extends AsyncNotifier<OAuthAuthCodeResponse> {
), ),
); );
static final provider = AsyncNotifierProvider.family static final provider =
.autoDispose<AuthUrlController, OAuthAuthCodeResponse, Uri>( AsyncNotifierProvider.family<
AuthUrlController.new, AuthUrlController,
); OAuthAuthCodeResponse,
Uri
>(AuthUrlController.new);
} }

View file

@ -14,7 +14,6 @@ import "package:nexus/controllers/sync_status.dart";
import "package:nexus/controllers/top_level_spaces.dart"; import "package:nexus/controllers/top_level_spaces.dart";
import "package:nexus/helpers/extensions/gomuks_buffer.dart"; import "package:nexus/helpers/extensions/gomuks_buffer.dart";
import "package:nexus/main.dart"; import "package:nexus/main.dart";
import "package:nexus/models/content/message.dart";
import "package:nexus/models/event.dart"; import "package:nexus/models/event.dart";
import "package:nexus/models/oauth_auth_code_response.dart"; import "package:nexus/models/oauth_auth_code_response.dart";
import "package:nexus/models/paginate.dart"; import "package:nexus/models/paginate.dart";
@ -33,7 +32,6 @@ import "package:nexus/models/requests/send_event.dart";
import "package:nexus/models/requests/send_message.dart"; import "package:nexus/models/requests/send_message.dart";
import "package:nexus/models/requests/set_membership.dart"; import "package:nexus/models/requests/set_membership.dart";
import "package:nexus/models/requests/set_state.dart"; import "package:nexus/models/requests/set_state.dart";
import "package:nexus/models/requests/upload_media.dart";
import "package:nexus/models/room.dart"; import "package:nexus/models/room.dart";
import "package:nexus/models/sync_data.dart"; import "package:nexus/models/sync_data.dart";
import "package:nexus/src/third_party/gomuks.g.dart"; import "package:nexus/src/third_party/gomuks.g.dart";
@ -268,9 +266,6 @@ class ClientController extends AsyncNotifier<int> {
Future<void> setMembership(SetMembershipRequest request) => Future<void> setMembership(SetMembershipRequest request) =>
_sendCommand("set_membership", request.toJson()); _sendCommand("set_membership", request.toJson());
Future<MessageContent> uploadMedia(UploadMediaRequest request) async =>
.fromJson(await _sendCommand("upload_media", request.toJson()));
Future<void> logout() => _sendCommand("logout"); Future<void> logout() => _sendCommand("logout");
Future<void> markRead(Room room) async { Future<void> markRead(Room room) async {

View file

@ -1,11 +0,0 @@
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:image_picker/image_picker.dart";
class ImagePickerController extends Notifier<ImagePicker> {
@override
ImagePicker build() => .new();
static final provider = NotifierProvider<ImagePickerController, ImagePicker>(
ImagePickerController.new,
);
}

View file

@ -4,7 +4,6 @@ import "package:collection/collection.dart";
import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:fluttertagger/fluttertagger.dart"; import "package:fluttertagger/fluttertagger.dart";
import "package:nexus/controllers/attachment.dart";
import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client.dart";
import "package:nexus/controllers/rooms.dart"; import "package:nexus/controllers/rooms.dart";
import "package:nexus/models/content/content.dart"; import "package:nexus/models/content/content.dart";
@ -121,10 +120,6 @@ class RoomChatController extends AsyncNotifier<IList<Event>?> {
required RelationType relationType, required RelationType relationType,
Event? relation, Event? relation,
}) async { }) async {
final attachment = ref.watch(AttachmentController.provider(roomId));
if (attachment != null && attachment.$2 == null) return;
var taggedMessage = text; var taggedMessage = text;
for (final tag in tags) { for (final tag in tags) {
@ -141,7 +136,6 @@ class RoomChatController extends AsyncNotifier<IList<Event>?> {
final event = await client.sendMessage( final event = await client.sendMessage(
SendMessageRequest( SendMessageRequest(
roomId: roomId, roomId: roomId,
baseContent: attachment?.$2,
mentions: Mentions( mentions: Mentions(
userIds: [ userIds: [
if (shouldMention == true && if (shouldMention == true &&
@ -158,8 +152,6 @@ class RoomChatController extends AsyncNotifier<IList<Event>?> {
), ),
); );
ref.invalidate(AttachmentController.provider(roomId));
ref ref
.watch(RoomsController.provider.notifier) .watch(RoomsController.provider.notifier)
.update( .update(

View file

@ -5,7 +5,6 @@ import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:intl/intl.dart"; import "package:intl/intl.dart";
import "package:m3e_buttons/m3e_buttons.dart"; import "package:m3e_buttons/m3e_buttons.dart";
import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client.dart";
import "package:nexus/controllers/client_state.dart";
import "package:nexus/controllers/settings.dart"; import "package:nexus/controllers/settings.dart";
import "package:nexus/models/settings_category.dart"; import "package:nexus/models/settings_category.dart";
import "package:nexus/main.dart"; import "package:nexus/main.dart";
@ -90,7 +89,6 @@ class SettingsSectionsController
]), ]),
), ),
]), ]),
if (ref.watch(ClientStateController.provider)?.isLoggedIn == true)
"Account": .new([ "Account": .new([
.new(title: "Profile", icon: Icons.person, settings: .new([])), .new(title: "Profile", icon: Icons.person, settings: .new([])),
.new( .new(
@ -106,15 +104,10 @@ class SettingsSectionsController
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
return M3EButton.icon( return M3EButton.icon(
onPressed: () async { onPressed: () async {
Navigator.of(
context,
).popUntil((route) => route.isFirst);
await WidgetsBinding.instance.endOfFrame;
await ref await ref
.watch(ClientController.provider.notifier) .watch(ClientController.provider.notifier)
.logout(); .logout();
if (context.mounted) Navigator.of(context).pop();
}, },
label: Text(title), label: Text(title),
icon: Icon(icon), icon: Icon(icon),

View file

@ -1,12 +1,7 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
extension SchemeToTheme on ColorScheme { extension SchemeToTheme on ColorScheme {
ThemeData get theme { ThemeData get theme => .from(colorScheme: this).copyWith(
final textTheme = ThemeData(
fontFamilyFallback: ["sans", "emoji", "fallback-sans", "fallback-emoji"],
brightness: brightness,
).textTheme;
return .from(colorScheme: this).copyWith(
cardTheme: .new(color: primaryContainer), cardTheme: .new(color: primaryContainer),
popupMenuTheme: .new( popupMenuTheme: .new(
shape: RoundedRectangleBorder(borderRadius: .circular(16)), shape: RoundedRectangleBorder(borderRadius: .circular(16)),
@ -16,21 +11,12 @@ extension SchemeToTheme on ColorScheme {
titleSpacing: 0, titleSpacing: 0,
backgroundColor: surfaceContainerLow, backgroundColor: surfaceContainerLow,
), ),
tooltipTheme: .new( textTheme: ThemeData(
textStyle: textTheme.labelLarge?.copyWith( fontFamilyFallback: ["sans", "emoji", "fallback-sans", "fallback-emoji"],
fontSize: 16, brightness: brightness,
fontWeight: .w600, ).textTheme,
),
padding: .all(8),
decoration: BoxDecoration(
color: surfaceContainerHighest,
borderRadius: .circular(8),
),
),
textTheme: textTheme,
inputDecorationTheme: const InputDecorationTheme( inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
); );
}
} }

View file

@ -38,16 +38,11 @@ New Value: ${newValue is AsyncData ? newValue.value : newValue}
} }
void showError(Object error, [StackTrace? stackTrace]) { void showError(Object error, [StackTrace? stackTrace]) {
if (error.toString().contains("DioException") || if (error.toString().contains("DioException")) return;
error.toString().contains( if (error.toString().contains("Invalid source")) return;
"setState() or markNeedsBuild() called during build.", if (error.toString().contains("UTF-16")) return;
) || if (error.toString().contains("HTTP request failed")) return;
error.toString().contains("Invalid source") || if (error.toString().contains("Invalid image data")) return;
error.toString().contains("UTF-16") ||
error.toString().contains("HTTP request failed") ||
error.toString().contains("Invalid image data")) {
return;
}
debugPrintStack(stackTrace: stackTrace, label: error.toString()); debugPrintStack(stackTrace: stackTrace, label: error.toString());
if (navigatorKey.currentContext != null) { if (navigatorKey.currentContext != null) {
@ -84,7 +79,7 @@ void main() async {
runApp( runApp(
ProviderScope( ProviderScope(
retry: (_, _) => null, retry: null,
observers: [ observers: [
// Change false to true if you want debug information on provider reloads // Change false to true if you want debug information on provider reloads
// ignore: dead_code // ignore: dead_code

View file

@ -7,8 +7,6 @@ import "package:nexus/models/info/video.dart";
part "message.freezed.dart"; part "message.freezed.dart";
part "message.g.dart"; part "message.g.dart";
typedef EncryptedFile = Map<String, dynamic>;
@Freezed(unionKey: "msgtype", fallbackUnion: "default") @Freezed(unionKey: "msgtype", fallbackUnion: "default")
abstract class MessageContent extends Content with _$MessageContent { abstract class MessageContent extends Content with _$MessageContent {
MessageContent._(); MessageContent._();
@ -40,7 +38,7 @@ abstract class MessageContent extends Content with _$MessageContent {
required String body, required String body,
MessageFormat? format, MessageFormat? format,
String? formattedBody, String? formattedBody,
EncryptedFile? file, // EncryptedFile? file
String? filename, String? filename,
ImageInfo? info, ImageInfo? info,
Uri? url, Uri? url,
@ -51,7 +49,7 @@ abstract class MessageContent extends Content with _$MessageContent {
required String body, required String body,
MessageFormat? format, MessageFormat? format,
String? formattedBody, String? formattedBody,
EncryptedFile? file, // EncryptedFile? file
String? filename, String? filename,
FileInfo? info, FileInfo? info,
Uri? url, Uri? url,
@ -62,7 +60,7 @@ abstract class MessageContent extends Content with _$MessageContent {
required String body, required String body,
MessageFormat? format, MessageFormat? format,
String? formattedBody, String? formattedBody,
EncryptedFile? file, // EncryptedFile? file
String? filename, String? filename,
AudioInfo? info, AudioInfo? info,
Uri? url, Uri? url,
@ -73,7 +71,7 @@ abstract class MessageContent extends Content with _$MessageContent {
required String body, required String body,
MessageFormat? format, MessageFormat? format,
String? formattedBody, String? formattedBody,
EncryptedFile? file, // EncryptedFile? file
String? filename, String? filename,
VideoInfo? info, VideoInfo? info,
Uri? url, Uri? url,

View file

@ -1,6 +1,5 @@
import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:freezed_annotation/freezed_annotation.dart"; import "package:freezed_annotation/freezed_annotation.dart";
import "package:nexus/models/content/content.dart";
import "package:nexus/models/relation_type.dart"; import "package:nexus/models/relation_type.dart";
part "send_message.freezed.dart"; part "send_message.freezed.dart";
part "send_message.g.dart"; part "send_message.g.dart";
@ -10,7 +9,6 @@ abstract class SendMessageRequest with _$SendMessageRequest {
const factory SendMessageRequest({ const factory SendMessageRequest({
required String roomId, required String roomId,
required String text, required String text,
Content? baseContent,
@Default(Mentions()) @JsonKey(name: "mentions") Mentions mentions, @Default(Mentions()) @JsonKey(name: "mentions") Mentions mentions,
@JsonKey(name: "relates_to") Relation? relation, @JsonKey(name: "relates_to") Relation? relation,
}) = _SendMessageRequest; }) = _SendMessageRequest;

View file

@ -1,24 +0,0 @@
import "package:freezed_annotation/freezed_annotation.dart";
part "upload_media.freezed.dart";
part "upload_media.g.dart";
@freezed
abstract class UploadMediaRequest with _$UploadMediaRequest {
const factory UploadMediaRequest({
required String path,
required bool encrypt,
String? filename,
@Default(false) @JsonKey(name: "voice_message") bool isVoiceMessage,
@Default(false) bool forceFile,
// Below params only work if encodeTo is set
String? encodeTo,
int? resizeWidth,
int? resizeHeight,
int? resizePercent,
@Default(80) int quality,
}) = _UploadMediaRequest;
factory UploadMediaRequest.fromJson(Map<String, Object?> json) =>
_$UploadMediaRequestFromJson(json);
}

View file

@ -9,7 +9,6 @@ import "package:nexus/controllers/client_id.dart";
import "package:nexus/helpers/launch_helper.dart"; import "package:nexus/helpers/launch_helper.dart";
import "package:nexus/main.dart"; import "package:nexus/main.dart";
import "package:nexus/models/homeserver.dart"; import "package:nexus/models/homeserver.dart";
import "package:nexus/pages/settings.dart";
import "package:nexus/widgets/appbar.dart"; import "package:nexus/widgets/appbar.dart";
import "package:nexus/widgets/divider_text.dart"; import "package:nexus/widgets/divider_text.dart";
@ -58,9 +57,6 @@ class SelectServerPage extends HookConsumerWidget {
await ref.watch(LaunchHelper.provider).launchUrl(codeResponse.url); await ref.watch(LaunchHelper.provider).launchUrl(codeResponse.url);
AppLinks().uriLinkStream.listen((encodedUri) async { AppLinks().uriLinkStream.listen((encodedUri) async {
final state = encodedUri.queryParameters["state"];
if (state != codeResponse.state) return;
final code = encodedUri.queryParameters["code"]; final code = encodedUri.queryParameters["code"];
if (code != null) { if (code != null) {
@ -83,6 +79,9 @@ class SelectServerPage extends HookConsumerWidget {
.onError(showError); .onError(showError);
} }
}); });
// await Navigator.of(context).push(
// MaterialPageRoute(builder: (_) => LoginPage(homeserver: newUrl)),
// );
} }
} }
} catch (error, stackTrace) { } catch (error, stackTrace) {
@ -93,15 +92,7 @@ class SelectServerPage extends HookConsumerWidget {
} }
return Scaffold( return Scaffold(
appBar: Appbar( appBar: Appbar(),
actions: .new([
IconButton(
onPressed: () =>
showDialog(context: context, builder: (_) => SettingsPage()),
icon: Icon(Icons.settings),
),
]),
),
body: SafeArea( body: SafeArea(
child: Center( child: Center(
child: ConstrainedBox( child: ConstrainedBox(

View file

@ -127,13 +127,13 @@ class SettingsPage extends ConsumerWidget {
), ),
...sections ...sections
.mapTo( .mapTo(
(section, categories) => [ (categoryGroup, categories) => [
SliverToBoxAdapter( SliverToBoxAdapter(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 16, horizontal: 16,
).copyWith(bottom: 4), ).copyWith(bottom: 4),
child: DividerText(section), child: DividerText(categoryGroup),
), ),
), ),
SliverM3ECardList( SliverM3ECardList(
@ -150,14 +150,7 @@ class SettingsPage extends ConsumerWidget {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) =>
SettingsCategoryPage( SettingsCategoryPage(index),
sections
.values
.flattenedToList
.indexOf(
categories[index],
),
),
), ),
), ),
itemBuilder: (context, index) => ListTile( itemBuilder: (context, index) => ListTile(

View file

@ -2,7 +2,6 @@ import "package:flutter/material.dart";
import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/client.dart"; import "package:nexus/controllers/client.dart";
import "package:nexus/pages/settings.dart";
import "package:nexus/widgets/appbar.dart"; import "package:nexus/widgets/appbar.dart";
import "package:nexus/helpers/required_validator_helper.dart"; import "package:nexus/helpers/required_validator_helper.dart";
@ -33,15 +32,7 @@ class VerifyPage extends HookConsumerWidget {
} }
return Scaffold( return Scaffold(
appBar: Appbar( appBar: Appbar(),
actions: .new([
IconButton(
onPressed: () =>
showDialog(context: context, builder: (_) => SettingsPage()),
icon: Icon(Icons.settings),
),
]),
),
body: AlertDialog( body: AlertDialog(
title: Text("Verify"), title: Text("Verify"),
content: Form( content: Form(

View file

@ -1,13 +1,9 @@
import "dart:io";
import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:file_selector/file_selector.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter/services.dart"; import "package:flutter/services.dart";
import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_hooks/flutter_hooks.dart";
import "package:fluttertagger/fluttertagger.dart"; import "package:fluttertagger/fluttertagger.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/attachment.dart";
import "package:nexus/controllers/image_picker.dart";
import "package:nexus/controllers/power_level.dart"; import "package:nexus/controllers/power_level.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";
@ -15,7 +11,6 @@ import "package:nexus/models/relation_type.dart";
import "package:nexus/widgets/composer/mention_overlay.dart"; import "package:nexus/widgets/composer/mention_overlay.dart";
import "package:nexus/widgets/composer/relation_preview.dart"; import "package:nexus/widgets/composer/relation_preview.dart";
import "package:nexus/widgets/emoji_picker_button.dart"; import "package:nexus/widgets/emoji_picker_button.dart";
import "package:nexus/main.dart";
class Composer extends HookConsumerWidget { class Composer extends HookConsumerWidget {
final String roomId; final String roomId;
@ -56,10 +51,8 @@ class Composer extends HookConsumerWidget {
}; };
} }
final attachment = ref.watch(AttachmentController.provider(roomId));
void send() { void send() {
if (controller.value.text.isEmpty && attachment == null) return; if (controller.value.text.isEmpty) return;
onSend( onSend(
controller.value.formattedText, controller.value.formattedText,
shouldMention: shouldMention.value, shouldMention: shouldMention.value,
@ -77,28 +70,7 @@ class Composer extends HookConsumerWidget {
return Padding( return Padding(
padding: .all(12), padding: .all(12),
child: Column( child: ClipRRect(
children: [
if (attachment != null)
Card(
margin: .only(bottom: 8),
child: ListTile(
leading: attachment.$2 == null
? SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(),
)
: Icon(Icons.file_copy),
title: Text(attachment.$1),
trailing: IconButton(
onPressed: () =>
ref.invalidate(AttachmentController.provider(roomId)),
icon: Icon(Icons.close),
),
),
),
ClipRRect(
borderRadius: .all(.circular(12)), borderRadius: .all(.circular(12)),
child: Column( child: Column(
children: [ children: [
@ -130,58 +102,20 @@ class Composer extends HookConsumerWidget {
), ),
PopupMenuButton( PopupMenuButton(
tooltip: "Add media", tooltip: "Add media",
enabled: attachment == null,
itemBuilder: (context) => [ itemBuilder: (context) => [
if (Platform.isAndroid || Platform.isIOS)
PopupMenuItem( PopupMenuItem(
child: ListTile( child: ListTile(
title: Text("Camera"), title: Text("Camera"),
leading: Icon(Icons.add_a_photo), leading: Icon(Icons.add_a_photo),
), ),
onTap: () async => ref
.watch(
AttachmentController.provider(
roomId,
).notifier,
)
.add(
(await ref
.watch(
ImagePickerController.provider,
)
.pickImage(source: .camera))!,
)
.onError(showError),
), ),
PopupMenuItem( PopupMenuItem(
child: ListTile( child: ListTile(
title: Text("Gallery"), title: Text("Gallery"),
leading: Icon(Icons.add_photo_alternate), leading: Icon(Icons.add_photo_alternate),
), ),
onTap: () async => ref
.watch(
AttachmentController.provider(
roomId,
).notifier,
)
.add(
(await ref
.watch(
ImagePickerController.provider,
)
.pickImage(source: .gallery))!,
)
.onError(showError),
), ),
PopupMenuItem( PopupMenuItem(
onTap: () async => ref
.watch(
AttachmentController.provider(
roomId,
).notifier,
)
.add((await openFile())!)
.onError(showError),
child: ListTile( child: ListTile(
title: Text("Files"), title: Text("Files"),
leading: Icon(Icons.attachment), leading: Icon(Icons.attachment),
@ -207,18 +141,14 @@ class Composer extends HookConsumerWidget {
triggerCharacter.value = newTriggerCharacter; triggerCharacter.value = newTriggerCharacter;
query.value = newQuery; query.value = newQuery;
}, },
triggerCharacterAndStyles: { triggerCharacterAndStyles: {"@": style, "#": style},
"@": style,
"#": style,
},
builder: (context, key) => Focus( builder: (context, key) => Focus(
onKeyEvent: (_, event) { onKeyEvent: (_, event) {
if (event is KeyDownEvent && if (event is KeyDownEvent &&
event.logicalKey == event.logicalKey ==
LogicalKeyboardKey.enter) { LogicalKeyboardKey.enter) {
final shiftPressed = HardwareKeyboard final shiftPressed =
.instance HardwareKeyboard.instance.isShiftPressed;
.isShiftPressed;
if (!shiftPressed) { if (!shiftPressed) {
send(); send();
@ -244,10 +174,7 @@ class Composer extends HookConsumerWidget {
), ),
), ),
IconButton( IconButton(
onPressed: onPressed: send,
attachment != null && attachment.$2 == null
? null
: send,
icon: Icon(Icons.send), icon: Icon(Icons.send),
tooltip: "Send message", tooltip: "Send message",
), ),
@ -255,10 +182,7 @@ class Composer extends HookConsumerWidget {
: [ : [
Expanded( Expanded(
child: Padding( child: Padding(
padding: .symmetric( padding: .symmetric(horizontal: 8, vertical: 12),
horizontal: 8,
vertical: 12,
),
child: Text( child: Text(
"You don't have permission to send messages in this room...", "You don't have permission to send messages in this room...",
), ),
@ -270,8 +194,6 @@ class Composer extends HookConsumerWidget {
], ],
), ),
), ),
],
),
); );
} }
} }

View file

@ -73,9 +73,7 @@ class MentionOverlay extends ConsumerWidget {
:final displayName, :final displayName,
:final avatarUrl, :final avatarUrl,
) => ) =>
Material( ListTile(
color: Colors.transparent,
child: ListTile(
leading: AvatarOrHash( leading: AvatarOrHash(
avatarUrl, avatarUrl,
displayName ?? displayName ??
@ -91,7 +89,6 @@ class MentionOverlay extends ConsumerWidget {
name: member.stateKey!.localpart, name: member.stateKey!.localpart,
), ),
), ),
),
_ => SizedBox.shrink(), _ => SizedBox.shrink(),
}, },
) )
@ -104,21 +101,16 @@ class MentionOverlay extends ConsumerWidget {
? rooms.values ? rooms.values
: rooms.values.where( : rooms.values.where(
(room) => (room) =>
(room.metadata?.name ?? (room.metadata?.name ?? room.metadata!.id)
room.metadata?.id ??
"")
.toLowerCase() .toLowerCase()
.contains(query.toLowerCase()), .contains(query.toLowerCase()),
)) ))
.map((room) { .map((room) {
final name = final name =
room.metadata?.name ?? room.metadata?.name ??
room.metadata?.canonicalAlias ?? room.metadata!.canonicalAlias ??
room.metadata?.id ?? room.metadata!.id;
"Unknown Room"; return ListTile(
return Material(
color: Colors.transparent,
child: ListTile(
leading: AvatarOrHash( leading: AvatarOrHash(
room.metadata?.avatar, room.metadata?.avatar,
name, name,
@ -143,7 +135,6 @@ class MentionOverlay extends ConsumerWidget {
"", "",
); );
}, },
),
); );
}) })
.toList(), .toList(),

View file

@ -7,6 +7,7 @@ import Foundation
import app_links import app_links
import dynamic_color import dynamic_color
import file_picker
import file_selector_macos import file_selector_macos
import media_kit_libs_macos_video import media_kit_libs_macos_video
import media_kit_video import media_kit_video
@ -20,6 +21,7 @@ import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))

View file

@ -10,7 +10,5 @@
<true/> <true/>
<key>com.apple.security.network.server</key> <key>com.apple.security.network.server</key>
<true/> <true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict> </dict>
</plist> </plist>

View file

@ -6,7 +6,5 @@
<true/> <true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict> </dict>
</plist> </plist>

View file

@ -402,30 +402,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
file_selector: file_picker:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_selector name: file_picker
sha256: bd15e43e9268db636b53eeaca9f56324d1622af30e5c34d6e267649758c84d9a sha256: fdc6a37f715d19f35b131decf1ce39242eeed5ddae18c0818c3eccb731ab76be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "12.0.0-beta.7"
file_selector_android:
dependency: transitive
description:
name: file_selector_android
sha256: "6a26687fa65cbc28a5345c7ae6f227e89f0b47740978a4c475b1a625da7a331b"
url: "https://pub.dev"
source: hosted
version: "0.5.2+8"
file_selector_ios:
dependency: transitive
description:
name: file_selector_ios
sha256: e2ecf2885c121691ce13b60db3508f53c01f869fb6e8dc5c1cfa771e4c46aeca
url: "https://pub.dev"
source: hosted
version: "0.5.3+5"
file_selector_linux: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@ -450,14 +434,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.7.0" version: "2.7.0"
file_selector_web:
dependency: transitive
description:
name: file_selector_web
sha256: "73181fbc5257776d8ecaa6a94ab3c8e920ad143b9132a6d984a9271dfc6928d3"
url: "https://pub.dev"
source: hosted
version: "0.9.5"
file_selector_windows: file_selector_windows:
dependency: transitive dependency: transitive
description: description:

View file

@ -37,7 +37,8 @@ dependencies:
path_provider: 2.1.6 path_provider: 2.1.6
url_launcher: 6.3.2 url_launcher: 6.3.2
freezed_annotation: 3.1.0 freezed_annotation: 3.1.0
image_picker: ^1.2.3 image_picker: 1.2.3
file_picker: 12.0.0-beta.7
path: 1.9.1 path: 1.9.1
dynamic_color: 1.8.1 dynamic_color: 1.8.1
collection: 1.19.1 collection: 1.19.1
@ -77,7 +78,6 @@ dependencies:
xdg_directories: 1.1.0 xdg_directories: 1.1.0
package_info_plus: 10.2.1 package_info_plus: 10.2.1
app_links: 7.2.1 app_links: 7.2.1
file_selector: ^1.1.0
dev_dependencies: dev_dependencies:
build_runner: ^2.15.1 build_runner: ^2.15.1