diff --git a/README.md b/README.md index b165d7a..dfe10f7 100644 --- a/README.md +++ b/README.md @@ -55,10 +55,10 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend. - [x] Per message profiles - [x] Attachments - [ ] Commands with [MSC4391](https://github.com/matrix-org/matrix-spec-proposals/pull/4391) - - [x] Mentions + - [x] Tags - [x] Users - [x] Rooms - - [ ] Inline emoji picker (Putting this here since it'll be implemented the same way as mentions) + - [x] Emojis - [ ] Custom emojis/stickers - [ ] GIFs using Gomuks' GIF proxies - [x] Receiving diff --git a/lib/widgets/composer/overlays/emoji_overlay.dart b/lib/widgets/composer/overlays/emoji_overlay.dart new file mode 100644 index 0000000..e537927 --- /dev/null +++ b/lib/widgets/composer/overlays/emoji_overlay.dart @@ -0,0 +1,44 @@ +import "package:collection/collection.dart"; +import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:material_emoji_picker/material_emoji_picker.dart"; +import "package:material_ui/material_ui.dart"; +import "package:nexus/helpers/extensions/better_when.dart"; + +class const EmojiOverlay( + final String query, { + required final String roomId, + required final void Function({required String id, required String name}) + addTag, + super.key, +}) extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) => ref + .watch(EmojiController.provider) + .betterWhen( + data: (emojis) => ListView( + children: emojis + .map((element) => element.emojis) + .flattened + .where( + (emoji) => + emoji.aliases.join().contains(query) || + emoji.description.contains(query) || + emoji.tags.join().contains(query), + ) + .map( + (emoji) => ListTile( + leading: emoji.widget, + title: Text(emoji.aliases.first), + subtitle: Text(emoji.description), + onTap: () => addTag( + id: Uri.tryParse(emoji.value)?.scheme == "mxc" + ? "" // TODO: Handle custom emotes + : emoji.value, + name: emoji.aliases.first, + ), + ), + ) + .toList(), + ), + ); +} diff --git a/lib/widgets/composer/overlays/room_overlay.dart b/lib/widgets/composer/overlays/room_overlay.dart index db74fc0..b5af177 100644 --- a/lib/widgets/composer/overlays/room_overlay.dart +++ b/lib/widgets/composer/overlays/room_overlay.dart @@ -28,31 +28,28 @@ class const RoomOverlay( room.metadata?.canonicalAlias ?? room.metadata?.id ?? "Unknown Room"; - return Material( - color: Colors.transparent, - child: ListTile( - leading: AvatarOrHash( - room.metadata?.avatar, - name, - fallback: Icon(Icons.numbers), - ), - title: Text(name), - subtitle: room.metadata?.topic == null - ? null - : Text(room.metadata!.topic!, maxLines: 1), - onTap: () { - final vias = ref.watch(ViaController.provider(room)); - addTag( - id: "[#$name](matrix:roomid/${room.metadata?.id.substring(1)}$vias)", - name: - (room.metadata?.canonicalAlias ?? room.metadata?.id) - ?.substring(1) - .split(":") - .first ?? - "", - ); - }, + return ListTile( + leading: AvatarOrHash( + room.metadata?.avatar, + name, + fallback: Icon(Icons.numbers), ), + title: Text(name), + subtitle: room.metadata?.topic == null + ? null + : Text(room.metadata!.topic!, maxLines: 1), + onTap: () { + final vias = ref.watch(ViaController.provider(room)); + addTag( + id: "[#$name](matrix:roomid/${room.metadata?.id.substring(1)}$vias)", + name: + (room.metadata?.canonicalAlias ?? room.metadata?.id) + ?.substring(1) + .split(":") + .first ?? + "", + ); + }, ); }) .toList(), diff --git a/lib/widgets/composer/overlays/tagger_overlay.dart b/lib/widgets/composer/overlays/tagger_overlay.dart index dda9043..7d973dc 100644 --- a/lib/widgets/composer/overlays/tagger_overlay.dart +++ b/lib/widgets/composer/overlays/tagger_overlay.dart @@ -2,6 +2,7 @@ import "package:material_ui/material_ui.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:nexus/widgets/composer/overlays/room_overlay.dart"; import "package:nexus/widgets/composer/overlays/user_overlay.dart"; +import "package:nexus/widgets/composer/overlays/emoji_overlay.dart"; import "package:nexus/widgets/loading.dart"; class const TaggerOverlay( @@ -21,12 +22,16 @@ class const TaggerOverlay( child: Container( color: Theme.of(context).colorScheme.surfaceContainerHigh, padding: .all(8), - child: switch (triggerCharacter) { - "@" => UserOverlay(query, roomId: roomId, addTag: addTag), - "#" => RoomOverlay(query, addTag: addTag), + child: Material( + color: Colors.transparent, + child: switch (triggerCharacter) { + "@" => UserOverlay(query, roomId: roomId, addTag: addTag), + "#" => RoomOverlay(query, addTag: addTag), + ":" => EmojiOverlay(query, roomId: roomId, addTag: addTag), - _ => Loading(), - }, + _ => Loading(), + }, + ), ), ), ); diff --git a/lib/widgets/composer/overlays/user_overlay.dart b/lib/widgets/composer/overlays/user_overlay.dart index ba23c1e..fe4f70f 100644 --- a/lib/widgets/composer/overlays/user_overlay.dart +++ b/lib/widgets/composer/overlays/user_overlay.dart @@ -41,21 +41,18 @@ class const UserOverlay( .map( (member) => switch (member.content) { MembershipContent(:final displayName, :final avatarUrl) => - Material( - color: Colors.transparent, - child: ListTile( - leading: AvatarOrHash( - avatarUrl, - displayName ?? member.stateKey!.localpart, - ), - title: Text( - displayName ?? member.stateKey!.localpart, - ), - subtitle: Text(member.stateKey!), - onTap: () => addTag( - id: "[@$displayName](matrix:u/${member.stateKey!.substring(1)})", - name: member.stateKey!.localpart, - ), + ListTile( + leading: AvatarOrHash( + avatarUrl, + displayName ?? member.stateKey!.localpart, + ), + title: Text( + displayName ?? member.stateKey!.localpart, + ), + subtitle: Text(member.stateKey!), + onTap: () => addTag( + id: "[@$displayName](matrix:u/${member.stateKey!.substring(1)})", + name: member.stateKey!.localpart, ), ), _ => SizedBox.shrink(),