reorganize and rename widgets

This commit is contained in:
Henry Hiles 2026-11-09 17:25:02 -05:00
commit d5f29dc344
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
3 changed files with 568 additions and 547 deletions

View file

@ -0,0 +1,84 @@
import "dart:async";
import "package:collection/collection.dart";
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:material_emoji_picker/material_emoji_picker.dart" as upstream;
import "package:material_ui/material_ui.dart";
import "package:nexus/controllers/all_emoji.dart";
import "package:nexus/controllers/image_packs.dart";
import "package:nexus/controllers/recent_emoji.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/image_pack_emoji.dart";
import "package:nexus/main.dart";
import "package:nexus/models/content/image_pack.dart";
class const EmojiPicker({
required final String roomId,
/// Has the [shortcode] and [description] of images from packs.
required final FutureOr<void> Function(
String value, {
String? shortcode,
String? description,
})
onSelection,
final bool allowFreeText = false,
super.key,
}) extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final recentEmoji = ref.watch(RecentEmojiController.provider);
return ref
.watch(AllEmojiController.provider(roomId))
.betterWhen(
data: (categories) {
final allEmoji = categories.expand((category) => category.emojis);
final customCategories =
ref
.watch(ImagePacksController.provider(roomId))
.value
?.map((pack) => pack.emojiCategory)
.nonNulls
.toIList() ??
const .empty();
return upstream.EmojiPicker(
onSelection: (emoji) async {
final image = switch (emoji.data) {
final PackImage image => image,
_ => null,
};
await onSelection(
emoji.value,
shortcode: image == null ? null : emoji.aliases.first,
description: image?.body,
);
await ref
.read(RecentEmojiController.provider.notifier)
.add(emoji.value)
.onError(showError);
},
onFreeText: allowFreeText ? (text) => onSelection(text) : null,
prependCategories: IList<upstream.EmojiCategory>([
.new(
icon: Icon(Icons.history),
name: "Recent",
emojis: .new(
recentEmoji
.map(
(recent) => allEmoji.firstWhereOrNull(
(element) => element.value == recent.emoji,
),
)
.nonNulls,
),
),
]).addAll(customCategories),
);
},
);
}
}

View file

@ -0,0 +1,16 @@
import "package:material_ui/material_ui.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/helpers/mxc_image.dart";
/// A custom emoji or sticker from an image pack, scaled to fit its parent.
class const MxcEmoji(final Uri url, {final String? label, super.key})
extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) => Image(
image: MxcImage(ref, .new(mxc: url)),
semanticLabel: label,
fit: .contain,
errorBuilder: (context, _, _) =>
Icon(Icons.broken_image, color: Theme.of(context).colorScheme.error),
);
}

View file

@ -0,0 +1,47 @@
import "dart:async";
import "package:fast_immutable_collections/fast_immutable_collections.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/controllers/image_packs.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/image_pack_emoji.dart";
import "package:nexus/models/content/image_pack.dart";
/// Stickers from the image packs available in [roomId], grouped by pack.
class const StickerPicker({
required final String roomId,
required final FutureOr<void> Function(String shortcode, PackImage image)
onSelection,
super.key,
}) extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) => ref
.watch(ImagePacksController.provider(roomId))
.betterWhen(
data: (packs) {
final categories = packs
.map((pack) => pack.stickerCategory)
.nonNulls
.toIList();
return categories.isEmpty
? Padding(
padding: .all(16),
child: Center(child: Text("No sticker packs available")),
)
: EmojiPicker(
prependCategories: categories,
includeDefaultEmoji: false,
itemSize: 96,
searchHint: "Search stickers",
onSelection: (sticker) {
if (sticker.data case final PackImage image) {
return onSelection(sticker.aliases.first, image);
}
},
);
},
);
}