diff --git a/lib/controllers/recent_emoji.dart b/lib/controllers/recent_emoji.dart new file mode 100644 index 0000000..6cf57f7 --- /dev/null +++ b/lib/controllers/recent_emoji.dart @@ -0,0 +1,44 @@ +import "package:collection/collection.dart"; +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:nexus/controllers/account_data.dart"; +import "package:nexus/controllers/client.dart"; +import "package:nexus/models/account_data.dart"; + +class RecentEmojiController extends Notifier> { + @override + IList build() => ref.watch( + AccountDataController.provider.select( + (value) => value.recentEmoji.recentEmoji, + ), + ); + + Future add(String emoji) => ref + .watch(ClientController.provider.notifier) + .setAccountData( + .new( + type: AccountData.recentEmojiKey, + content: RecentEmojiData( + recentEmoji: .new([ + .new( + emoji: emoji, + total: + (state + .firstWhereOrNull( + (element) => element.emoji == emoji, + ) + ?.total ?? + 0) + + 1, + ), + ...state.whereNot((element) => element.emoji == emoji), + ]), + ), + ), + ); + + static final provider = + NotifierProvider.autoDispose>( + RecentEmojiController.new, + ); +} diff --git a/lib/models/account_data.dart b/lib/models/account_data.dart index 53b4ff2..955d8d1 100644 --- a/lib/models/account_data.dart +++ b/lib/models/account_data.dart @@ -14,22 +14,9 @@ class const AccountData({ @JsonKey(name: AccountData.directKey) final IMap> directMessages = const IMap.empty(), - @JsonKey( - name: AccountData.recentEmojiKey, - readValue: AccountData.readRecentEmojiValue, - toJson: AccountData.recentEmojiToJson, - ) - final IList recentEmoji = const IList.empty(), + @JsonKey(name: AccountData.recentEmojiKey) + final RecentEmojiData recentEmoji = const RecentEmojiData(), }) with _$AccountData { - static List? readRecentEmojiValue( - Map json, - String key, - ) => json[key]?["recent_emoji"]; - - static Map>? recentEmojiToJson( - IList recentEmoji, - ) => {"recent_emoji": recentEmoji.map((emoji) => emoji.toJson()).toList()}; - static const invitePermissionConfigKey = "m.invite_permission_config"; static const directKey = "m.direct"; static const recentEmojiKey = "m.recent_emoji"; @@ -40,6 +27,17 @@ class const AccountData({ _$AccountDataFromJson(json); } +@Freezed(toJson: false, fromJson: false) +@JsonSerializable() +class const RecentEmojiData({ + final IList recentEmoji = const IList.empty(), +}) with _$RecentEmojiData { + Map toJson() => _$RecentEmojiDataToJson(this); + + factory RecentEmojiData.fromJson(Map json) => + _$RecentEmojiDataFromJson(json); +} + @Freezed(toJson: false, fromJson: false) @JsonSerializable() class const InvitePermissionConfig({ diff --git a/lib/widgets/emoji_picker.dart b/lib/widgets/emoji_picker.dart index 144d9bc..a0c691a 100644 --- a/lib/widgets/emoji_picker.dart +++ b/lib/widgets/emoji_picker.dart @@ -1,12 +1,12 @@ 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/account_data.dart"; +import "package:nexus/controllers/recent_emoji.dart"; import "package:nexus/helpers/extensions/better_when.dart"; +import "package:nexus/main.dart"; class const EmojiPicker({ required final FutureOr Function(String value) onSelection, @@ -14,40 +14,40 @@ class const EmojiPicker({ super.key, }) extends ConsumerWidget { @override - Widget build(BuildContext context, WidgetRef ref) => ref - .watch(upstream.EmojiController.provider) - .betterWhen( - data: (categories) => upstream.EmojiPicker( - onSelection: (value) async { - // - await onSelection(value); - }, - allowFreeText: allowFreeText, - prependCategories: .new([ - .new( - icon: Icon(Icons.history), - name: "Recent", - emojis: .new( - ref - .watch( - AccountDataController.provider.select( - (value) => value.recentEmoji - .map((entry) => entry.emoji) - .toIList(), - ), - ) - .map( - (emoji) => categories - .map((element) => element.emojis) - .flattened - .firstWhereOrNull( - (element) => element.value == emoji, - ), - ) - .nonNulls, + Widget build(BuildContext context, WidgetRef ref) { + final recentEmoji = ref.watch(RecentEmojiController.provider); + + return ref + .watch(upstream.EmojiController.provider) + .betterWhen( + data: (categories) => upstream.EmojiPicker( + onSelection: (emoji) async { + await onSelection(emoji); + await ref + .watch(RecentEmojiController.provider.notifier) + .add(emoji) + .onError(showError); + }, + allowFreeText: allowFreeText, + prependCategories: .new([ + .new( + icon: Icon(Icons.history), + name: "Recent", + emojis: .new( + recentEmoji + .map( + (recent) => categories + .map((element) => element.emojis) + .flattened + .firstWhereOrNull( + (element) => element.value == recent.emoji, + ), + ) + .nonNulls, + ), ), - ), - ]), - ), - ); + ]), + ), + ); + } } diff --git a/lib/widgets/room_chat.dart b/lib/widgets/room_chat.dart index 6161cde..015bbc4 100644 --- a/lib/widgets/room_chat.dart +++ b/lib/widgets/room_chat.dart @@ -4,12 +4,12 @@ import "package:flutter/services.dart"; import "package:flutter_hooks/flutter_hooks.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:measure_size/measure_size.dart"; -import "package:nexus/controllers/account_data.dart"; import "package:nexus/controllers/client.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/power_level.dart"; +import "package:nexus/controllers/recent_emoji.dart"; import "package:nexus/controllers/rooms.dart"; import "package:nexus/controllers/room_chat.dart"; import "package:nexus/controllers/via.dart"; @@ -196,6 +196,8 @@ final class const RoomChat({ final danger = theme.colorScheme.error; final isSentByMe = event.sender == userId; + final recentEmoji = ref.watch(RecentEmojiController.provider); + return [ if (ref.watch( PowerLevelController.provider( @@ -209,13 +211,7 @@ final class const RoomChat({ child: Row( children: [ ...{ - ...ref.watch( - AccountDataController.provider.select( - (value) => value.recentEmoji - .map((entry) => entry.emoji) - .toIList(), - ), - ), + ...recentEmoji.map((entry) => entry.emoji), "👍", "🤣", "😭", @@ -230,6 +226,11 @@ final class const RoomChat({ await notifier .sendReaction(emoji, event) .onError(showError); + + ref + .watch(RecentEmojiController.provider.notifier) + .add(emoji) + .onError(showError); }, icon: Text(emoji), ),