From 313dc377ecd6f03ab5166ac0b894041b659297b7 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Mon, 13 Apr 2026 22:44:22 -0400 Subject: [PATCH 1/5] fetch emoji list from gemoji for a more complete emoji list --- lib/controllers/emoji_controller.dart | 88 +++++++++++++++++++ lib/models/emoji.dart | 17 ++++ .../chat_page/emoji_picker_button.dart | 43 +++++---- pubspec.lock | 2 +- 4 files changed, 131 insertions(+), 19 deletions(-) create mode 100644 lib/controllers/emoji_controller.dart create mode 100644 lib/models/emoji.dart diff --git a/lib/controllers/emoji_controller.dart b/lib/controllers/emoji_controller.dart new file mode 100644 index 0000000..358f98b --- /dev/null +++ b/lib/controllers/emoji_controller.dart @@ -0,0 +1,88 @@ +import "dart:convert"; +import "package:emoji_text_field/models/emoji_category.dart"; +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:http/http.dart"; +import "package:nexus/models/emoji.dart"; + +typedef EmojiTuple = (IMap, IMap>); + +class EmojiController extends AsyncNotifier { + @override + Future build() async { + final response = await get( + Uri.https( + "github.com", + "github/gemoji/raw/refs/heads/master/db/emoji.json", + ), + ); + + if (response.statusCode != 200) { + throw Exception("Failed to load emoji data"); + } + + final data = json.decode(response.body); + + final entries = (data as List) + .cast>() + .map(Emoji.fromJson) + .toIList(); + + final categoryMap = entries.fold>>( + const IMap.empty(), + (acc, entry) => acc.update( + entry.category, + (list) => list.add(entry.emoji), + ifAbsent: () => IList([entry.emoji]), + ), + ); + + final keywordMap = entries.fold>>( + const IMap.empty(), + (acc, entry) => acc.add( + entry.emoji, + IList([...entry.tags, ...entry.aliases, entry.description]), + ), + ); + + final customCategories = IMap.fromEntries( + categoryMap.entries.map( + (entry) => MapEntry( + entry.key, + EmojiCategory( + name: entry.key, + icon: switch (entry.key) { + "Smileys & Emotion" => Icons.emoji_emotions, + "People & Body" => Icons.emoji_people, + "Animals & Nature" => Icons.emoji_nature, + "Food & Drink" => Icons.emoji_food_beverage, + "Travel & Places" => Icons.travel_explore, + "Activities" => Icons.sports_soccer, + "Objects" => Icons.emoji_objects, + "Symbols" => Icons.emoji_symbols, + "Flags" => Icons.emoji_flags, + _ => Icons.category, + }, + emojis: entry.value.toList(growable: false), + ), + ), + ), + ); + + final customKeywords = IMap( + Map.fromEntries( + keywordMap.entries.map( + (e) => MapEntry(e.key, e.value.toList(growable: false)), + ), + ), + ); + + return (customCategories, customKeywords); + } + + static final provider = + AsyncNotifierProvider.autoDispose( + EmojiController.new, + ); +} diff --git a/lib/models/emoji.dart b/lib/models/emoji.dart new file mode 100644 index 0000000..8e4eac6 --- /dev/null +++ b/lib/models/emoji.dart @@ -0,0 +1,17 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:freezed_annotation/freezed_annotation.dart"; +part "emoji.freezed.dart"; +part "emoji.g.dart"; + +@freezed +abstract class Emoji with _$Emoji { + const factory Emoji({ + required String emoji, + required String category, + required IList aliases, + required String description, + required IList tags, + }) = _Emoji; + + factory Emoji.fromJson(Map json) => _$EmojiFromJson(json); +} diff --git a/lib/widgets/chat_page/emoji_picker_button.dart b/lib/widgets/chat_page/emoji_picker_button.dart index 0c43c48..dc2518e 100644 --- a/lib/widgets/chat_page/emoji_picker_button.dart +++ b/lib/widgets/chat_page/emoji_picker_button.dart @@ -1,8 +1,9 @@ import "package:emoji_text_field/emoji_text_field.dart"; import "package:flutter/material.dart"; -import "package:flutter_hooks/flutter_hooks.dart"; +import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:nexus/controllers/emoji_controller.dart"; -class EmojiPickerButton extends HookWidget { +class EmojiPickerButton extends HookConsumerWidget { final TextEditingController? controller; final void Function(String emoji)? onSelection; final VoidCallback? onPressed; @@ -16,25 +17,31 @@ class EmojiPickerButton extends HookWidget { }); @override - Widget build(_) => IconButton( - onPressed: () { + Widget build(_, WidgetRef ref) => IconButton( + onPressed: () async { onPressed?.call(); final controller = this.controller ?? TextEditingController(); - showModalBottomSheet( - context: context, - builder: (context) => EmojiKeyboardView( - config: EmojiViewConfig( - showRecentTab: false, - backgroundColor: Theme.of(context).colorScheme.surfaceContainer, - height: 600, + + final emojis = await ref.watch(EmojiController.provider.future); + if (context.mounted) { + showModalBottomSheet( + context: context, + builder: (context) => EmojiKeyboardView( + config: EmojiViewConfig( + showRecentTab: false, + customCategories: emojis.$1.unlock, + customKeywords: emojis.$2.unlock, + backgroundColor: Theme.of(context).colorScheme.surfaceContainer, + height: 600, + ), + textController: controller + ..addListener(() async { + Navigator.of(context).pop(); + onSelection?.call(controller.text); + }), ), - textController: controller - ..addListener(() async { - Navigator.of(context).pop(); - onSelection?.call(controller.text); - }), - ), - ); + ); + } }, icon: Icon(Icons.emoji_emotions), ); diff --git a/pubspec.lock b/pubspec.lock index ef7fcd9..984341b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -359,7 +359,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "0e90703a6e876939be70bd1816c49cf14474de61" + resolved-ref: "5f7baaf8a6f059ec3ab8ff0f5d02339b00bf6997" url: "https://github.com/Henry-Hiles/emoji_text_field" source: git version: "1.0.0" From 82dab26fd478aba8a3ea84924187940b6c80993b Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Mon, 13 Apr 2026 23:18:01 -0400 Subject: [PATCH 2/5] fix emoji dep hash --- linux/nix/pkg/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/nix/pkg/default.nix b/linux/nix/pkg/default.nix index 26f2a17..adaeb15 100644 --- a/linux/nix/pkg/default.nix +++ b/linux/nix/pkg/default.nix @@ -26,7 +26,7 @@ flutter.buildFlutterApplication { dynamic_system_colors = "sha256-es6rjMK1drkqZBKYUP77yw/q5+0uLwWOEDOXRawy3Dc="; flutter_chat_ui = "sha256-4fuag7lRH5cMBFD3fUzj2K541JwXLoz8HF/4OMr3uhk="; flutter_link_previewer = "sha256-4fuag7lRH5cMBFD3fUzj2K541JwXLoz8HF/4OMr3uhk="; - emoji_text_field = "sha256-F0QbIHP3wpKoL6QbJ20Oun0SsOdwnXe84IqsK2ad85w="; + emoji_text_field = "sha256-3TOys09EP2GRo6pUBGPXaqBlE39O2Cmwt42Hs1cTDKo="; }; postInstall = '' From ad8d4f36d915be60583e68a06eb28824b7f4a922 Mon Sep 17 00:00:00 2001 From: Zach Russell Date: Mon, 13 Apr 2026 21:44:25 -0600 Subject: [PATCH 3/5] Update windows build chain docs --- README.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0fe2a1b..890c11a 100644 --- a/README.md +++ b/README.md @@ -156,9 +156,39 @@ Or, try the Nix package: `nix run git+https://git.federated.nexus/Henry-Hiles/ne - With Nix: Either use direnv and `direnv allow`, or `nix flake develop` - Without Nix: Install Flutter, Go, Git, Libclang, and Glibc. Do not use any Snap packages, they cause various compilation issues. -#### Windows / MacOS +#### Windows -I don't really know. You will need Flutter, Git, Go, and Visual Studio tools, and otherwise I guess just keep installing stuff until there aren't any errors. I will look into this sometimeTM. +You will need: + +- Flutter +- Android SDK + NDK +- Git +- Go +- Visual Studio 2022 (Desktop development with C++) +- [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO) +- [LLVM/Clang + libclang](https://clang.llvm.org/get_started.html) (for `ffigen`) + +On Windows, make sure these are available in your shell `PATH`: + +- `C:\msys64\ucrt64\bin` (or your MinGW bin path containing `x86_64-w64-mingw32-gcc.exe`) +- `C:\Program Files\LLVM\bin` (contains `clang.exe` and `libclang.dll`) + +Also make sure Go build cache env vars are present (PowerShell): + +```powershell +$env:LOCALAPPDATA = "C:\Users\\AppData\Local" +$env:GOCACHE = "$env:LOCALAPPDATA\go-build" +``` + +For `dart scripts/generate.dart`, you may also need: + +```powershell +$env:CPATH = "C:\msys64\ucrt64\include" +``` + +#### MacOS + +Similar prerequisites apply (Flutter, Git, Go, C toolchain, LLVM/libclang), but exact setup has not been fully documented yet. ### Clone repo From 50e1a8e4c70f6871f272b10f6b385e94e4b59853 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 14 Apr 2026 10:58:25 -0400 Subject: [PATCH 4/5] remove un-needed async --- lib/widgets/chat_page/emoji_picker_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/chat_page/emoji_picker_button.dart b/lib/widgets/chat_page/emoji_picker_button.dart index dc2518e..d96594f 100644 --- a/lib/widgets/chat_page/emoji_picker_button.dart +++ b/lib/widgets/chat_page/emoji_picker_button.dart @@ -35,7 +35,7 @@ class EmojiPickerButton extends HookConsumerWidget { height: 600, ), textController: controller - ..addListener(() async { + ..addListener(() { Navigator.of(context).pop(); onSelection?.call(controller.text); }), From f4b2dcb8246ef621661d30185a41342a5d4bc2db Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 14 Apr 2026 18:09:31 -0400 Subject: [PATCH 5/5] hopefully fix debugLocked error --- lib/widgets/chat_page/emoji_picker_button.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/widgets/chat_page/emoji_picker_button.dart b/lib/widgets/chat_page/emoji_picker_button.dart index d96594f..e8805ca 100644 --- a/lib/widgets/chat_page/emoji_picker_button.dart +++ b/lib/widgets/chat_page/emoji_picker_button.dart @@ -36,7 +36,10 @@ class EmojiPickerButton extends HookConsumerWidget { ), textController: controller ..addListener(() { - Navigator.of(context).pop(); + // Without this, there will sometimes be a debugLocked is not true error sometimes + Future.delayed(Duration.zero, () { + if (context.mounted) Navigator.of(context).pop(); + }); onSelection?.call(controller.text); }), ),