feat: allow sending of lemma emojis as reactions, remove emoji picker to simplify selected view

This commit is contained in:
wcjord 2025-06-06 17:42:47 -04:00
parent c8fdcda3fb
commit fc98b90736
10 changed files with 187 additions and 68 deletions

View file

@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
abstract class AppConfig {
// #Pangea

View file

@ -4,22 +4,9 @@ import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:collection/collection.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
import 'package:matrix/matrix.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
@ -66,6 +53,18 @@ import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart'
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/share_scaffold_dialog.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
import 'package:matrix/matrix.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
import '../../utils/account_bundles.dart';
import '../../utils/localized_exception_extension.dart';
import 'send_file_dialog.dart';
@ -1542,6 +1541,7 @@ class ChatController extends State<ChatPageWithRoom>
// setState(() => selectedEvents.clear());
// Pangea#
for (final event in events) {
// if reaction already exists, don't send it again
await room.sendReaction(
event.eventId,
emoji!,

View file

@ -1,11 +1,5 @@
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:swipe_to_action/swipe_to_action.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart';
@ -17,6 +11,11 @@ import 'package:fluffychat/utils/string_color.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:swipe_to_action/swipe_to_action.dart';
import '../../../config/app_config.dart';
import 'message_content.dart';
import 'message_reactions.dart';
@ -614,7 +613,12 @@ class Message extends StatelessWidget {
crossAxisAlignment:
ownMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
if (displayTime || selected)
// #Pangea
if (displayTime)
// we don't need to display the time if the message is selected
// we have the background blotted out so you can't see the time anyway
// if (displayTime || selected)
// Pangea#
Padding(
padding: displayTime
? const EdgeInsets.symmetric(vertical: 8.0)

View file

@ -1,13 +1,12 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/chat_emoji_picker.dart';
import 'package:fluffychat/pages/chat/reply_display.dart';
import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart';
import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart';
import 'package:flutter/material.dart';
class ChatInputBar extends StatefulWidget {
final ChatController controller;

View file

@ -0,0 +1,65 @@
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart';
import 'package:flutter/material.dart';
class LemmaReactionPicker extends StatefulWidget {
final ConstructIdentifier cId;
final ChatController controller;
final double? iconSize;
const LemmaReactionPicker({
super.key,
required this.cId,
required this.controller,
this.iconSize,
});
@override
LemmaReactionPickerState createState() => LemmaReactionPickerState();
}
class LemmaReactionPickerState extends State<LemmaReactionPicker> {
List<String> displayEmoji = [];
@override
void initState() {
super.initState();
widget.cId.getLemmaInfo().then((info) {
setState(() => displayEmoji = info.emoji);
}).catchError((e, s) {
ErrorHandler.logError(data: widget.cId.toJson(), e: e, s: s);
});
}
// @override
// didUpdateWidget(LemmaReactionPicker oldWidget) {
// if (oldWidget.isSelected != widget.isSelected ||
// widget.cId.userSetEmoji != oldWidget.cId.userSetEmoji) {
// setState(() => displayEmoji = widget.cId.userSetEmoji.firstOrNull);
// }
// super.didUpdateWidget(oldWidget);
// }
void setEmoji(String emoji) => widget.controller.sendEmojiAction(emoji);
@override
Widget build(BuildContext context) {
return Container(
height: 50,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: displayEmoji
.map(
(emoji) => LemmaEmojiChoiceItem(
content: emoji,
onTap: () => setEmoji(emoji),
),
)
.toList(),
),
);
}
}

View file

@ -0,0 +1,53 @@
import 'package:fluffychat/config/app_config.dart';
import 'package:flutter/material.dart';
class LemmaEmojiChoiceItem extends StatefulWidget {
const LemmaEmojiChoiceItem({
super.key,
required this.content,
required this.onTap,
});
final String content;
final Function onTap;
@override
LemmaEmojiChoiceItemState createState() => LemmaEmojiChoiceItemState();
}
class LemmaEmojiChoiceItemState extends State<LemmaEmojiChoiceItem> {
bool _isHovered = false;
Color color(BuildContext context) {
if (_isHovered) {
return Theme.of(context).colorScheme.primaryContainer;
}
return Colors.transparent;
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: color(context).withAlpha((0.4 * 255).toInt()),
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
child: InkWell(
onHover: (isHovered) => setState(() => _isHovered = isHovered),
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
onTap: () {
if (!mounted) {
return;
}
widget.onTap();
},
child: Text(
widget.content,
style: Theme.of(context).textTheme.headlineSmall,
),
),
);
}
}

View file

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/chat.dart';
@ -7,6 +5,7 @@ import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart';
import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_mode_buttons.dart';
import 'package:flutter/material.dart';
class OverlayFooter extends StatelessWidget {
final ChatController controller;

View file

@ -1,7 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/reactions_picker.dart';
@ -11,6 +7,8 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_mode_locked_card.dart'
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_translation_card.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
const double minContentHeight = 120;
@ -27,7 +25,8 @@ class ReadingAssistanceInputBar extends StatelessWidget {
Widget barContent(BuildContext context) {
if (overlayController.readingAssistanceMode !=
ReadingAssistanceMode.practiceMode) {
return ReactionsPicker(controller);
return const SizedBox();
// return ReactionsPicker(controller);
}
Widget? content;

View file

@ -1,10 +1,6 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
@ -24,6 +20,8 @@ import 'package:fluffychat/pangea/toolbar/widgets/overlay_header.dart';
import 'package:fluffychat/pangea/toolbar/widgets/select_mode_buttons.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
/// Controls positioning of the message overlay.
class MessageSelectionPositioner extends StatefulWidget {
@ -149,10 +147,11 @@ class MessageSelectionPositionerState extends State<MessageSelectionPositioner>
_centeredMessageOffset = Offset(
offset.dx - _columnWidth - _horizontalPadding - 2.0,
_mediaQuery!.size.height -
(offset.dy -
((AppConfig.practiceModeInputBarHeight -
AppConfig.selectModeInputBarHeight) *
0.75)) -
offset.dy -
// (offset.dy -
// ((AppConfig.practiceModeInputBarHeight -
// AppConfig.selectModeInputBarHeight) *
// 0.75)) -
renderBox.size.height -
_reactionsHeight,
);
@ -485,6 +484,7 @@ class MessageSelectionPositionerState extends State<MessageSelectionPositioner>
}
double get _footerHeight {
return 0;
return _inputBarSize + (_mediaQuery?.padding.bottom ?? 0);
}

View file

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
@ -7,16 +5,16 @@ import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dar
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart';
import 'package:fluffychat/pangea/lemmas/lemma_emoji_row.dart';
import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.dart';
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart';
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart';
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_widget.dart';
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/morphological_list_item.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
class WordZoomWidget extends StatelessWidget {
final PangeaToken token;
@ -108,30 +106,34 @@ class WordZoomWidget extends StatelessWidget {
const SizedBox(
height: 8.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
constraints: const BoxConstraints(
minHeight: 40,
),
alignment: Alignment.center,
child: LemmaEmojiRow(
cId: _selectedToken.vocabConstructID,
onTapOverride: overlayController.hideWordCardContent &&
hasEmojiActivity
? () => overlayController.updateToolbarMode(
MessageMode.wordEmoji,
)
: null,
isSelected:
overlayController.toolbarMode == MessageMode.wordEmoji,
emojiSetCallback: () => overlayController.setState(() {}),
shouldShowEmojis: !hasEmojiActivity,
),
),
],
LemmaReactionPicker(
cId: _selectedToken.vocabConstructID,
controller: overlayController.widget.chatController,
),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Container(
// constraints: const BoxConstraints(
// minHeight: 40,
// ),
// alignment: Alignment.center,
// child: LemmaEmojiRow(
// cId: _selectedToken.vocabConstructID,
// onTapOverride: overlayController.hideWordCardContent &&
// hasEmojiActivity
// ? () => overlayController.updateToolbarMode(
// MessageMode.wordEmoji,
// )
// : null,
// isSelected:
// overlayController.toolbarMode == MessageMode.wordEmoji,
// emojiSetCallback: () => overlayController.setState(() {}),
// shouldShowEmojis: !hasEmojiActivity,
// ),
// ),
// ],
// ),
const SizedBox(
height: 8.0,
),