diff --git a/lib/pangea/chat/widgets/pangea_chat_input_row.dart b/lib/pangea/chat/widgets/pangea_chat_input_row.dart index a243b86a3..2419c466d 100644 --- a/lib/pangea/chat/widgets/pangea_chat_input_row.dart +++ b/lib/pangea/chat/widgets/pangea_chat_input_row.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:animations/animations.dart'; -import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; @@ -12,21 +11,15 @@ import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/input_bar.dart'; import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart'; import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart'; -import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; -import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/utils/error_reporter.dart'; import 'package:fluffychat/utils/platform_infos.dart'; class PangeaChatInputRow extends StatefulWidget { final ChatController controller; - final MessageOverlayController? overlayController; const PangeaChatInputRow({ required this.controller, - this.overlayController, super.key, }); @@ -74,305 +67,203 @@ class PangeaChatInputRowState extends State { : L10n.of(context).writeAMessage; } - void _deleteErrorEventsAction() async { - try { - if (widget.overlayController == null || - widget.overlayController!.event.status != EventStatus.error) { - throw Exception( - 'Tried to delete failed to send events but one event is not failed to sent', - ); - } - await widget.overlayController!.event.cancelSend(); - _controller.clearSelectedEvents(); - } catch (e, s) { - ErrorReporter( - context, - 'Error while delete error events action', - ).onErrorCallback(e, s); - } - } - - void _sendAgainAction() { - if (widget.overlayController == null) { - ErrorHandler.logError( - e: "No selected events in send again action", - s: StackTrace.current, - data: {"roomId": _controller.room.id}, - ); - _controller.clearSelectedEvents(); - return; - } - - final event = widget.overlayController!.event; - if (event.status.isError) { - event.sendAgain(); - } - - final allEditEvents = event - .aggregatedEvents( - _controller.timeline!, - RelationshipTypes.edit, - ) - .where((e) => e.status.isError); - for (final e in allEditEvents) { - e.sendAgain(); - } - - _controller.clearSelectedEvents(); - } - @override Widget build(BuildContext context) { final theme = Theme.of(context); const height = 48.0; + if (widget.controller.selectMode) { + return const SizedBox(height: height); + } + return Column( children: [ - // if (!controller.selectMode) WritingAssistanceInputRow(controller), CompositedTransformTarget( link: _controller.choreographer.inputLayerLinkAndKey.link, child: Container( - padding: EdgeInsets.all( - widget.overlayController != null - ? AppConfig.chatInputRowOverlayPadding - : 0.0, - ), - decoration: BoxDecoration( - color: widget.overlayController != null - ? Theme.of(context).cardColor - : null, - borderRadius: const BorderRadius.all( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all( Radius.circular(8.0), ), ), child: Row( - key: widget.overlayController != null - ? null - : _controller.choreographer.inputLayerLinkAndKey.key, + key: _controller.choreographer.inputLayerLinkAndKey.key, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: widget.overlayController != null - ? [ - if (widget.overlayController!.event.status == - EventStatus.error) - SizedBox( - height: height, - child: TextButton( - style: TextButton.styleFrom( - foregroundColor: theme.colorScheme.error, - ), - onPressed: _deleteErrorEventsAction, - child: Row( - children: [ - const Icon(Icons.delete), - Text(L10n.of(context).delete), - ], - ), + children: [ + const SizedBox(width: 4), + AnimatedContainer( + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + height: height, + width: _controller.sendController.text.isEmpty ? height : 0, + alignment: Alignment.center, + clipBehavior: Clip.hardEdge, + decoration: const BoxDecoration(), + child: PopupMenuButton( + useRootNavigator: true, + icon: const Icon(Icons.add_outlined), + onSelected: _controller.onAddPopupMenuButtonSelected, + itemBuilder: (BuildContext context) => + >[ + PopupMenuItem( + value: 'file', + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + child: Icon(Icons.attachment_outlined), ), - ), - if (widget.overlayController!.event - .getDisplayEvent(_controller.timeline!) - .status - .isSent) - ReadingAssistanceInputBar( - _controller, - widget.overlayController!, - ), - if (widget.overlayController!.event - .getDisplayEvent(_controller.timeline!) - .status - .isError) - SizedBox( - height: height, - child: TextButton( - onPressed: _sendAgainAction, - child: Row( - children: [ - Text(L10n.of(context).tryToSendAgain), - const SizedBox(width: 4), - const Icon(Icons.send_outlined, size: 16), - ], - ), - ), - ), - ] - : [ - const SizedBox(width: 4), - AnimatedContainer( - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - height: height, - width: _controller.sendController.text.isEmpty - ? height - : 0, - alignment: Alignment.center, - clipBehavior: Clip.hardEdge, - decoration: const BoxDecoration(), - child: PopupMenuButton( - useRootNavigator: true, - icon: const Icon(Icons.add_outlined), - onSelected: _controller.onAddPopupMenuButtonSelected, - itemBuilder: (BuildContext context) => - >[ - PopupMenuItem( - value: 'file', - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.green, - foregroundColor: Colors.white, - child: Icon(Icons.attachment_outlined), - ), - title: Text(L10n.of(context).sendFile), - contentPadding: const EdgeInsets.all(0), - ), - ), - PopupMenuItem( - value: 'image', - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - child: Icon(Icons.image_outlined), - ), - title: Text(L10n.of(context).sendImage), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (PlatformInfos.isMobile) - PopupMenuItem( - value: 'camera', - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.purple, - foregroundColor: Colors.white, - child: Icon(Icons.camera_alt_outlined), - ), - title: Text(L10n.of(context).openCamera), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (PlatformInfos.isMobile) - PopupMenuItem( - value: 'camera-video', - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - child: Icon(Icons.videocam_outlined), - ), - title: Text(L10n.of(context).openVideoCamera), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (PlatformInfos.isMobile) - PopupMenuItem( - value: 'location', - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.brown, - foregroundColor: Colors.white, - child: Icon(Icons.gps_fixed_outlined), - ), - title: Text(L10n.of(context).shareLocation), - contentPadding: const EdgeInsets.all(0), - ), - ), - ], + title: Text(L10n.of(context).sendFile), + contentPadding: const EdgeInsets.all(0), ), ), - if (FluffyThemes.isColumnMode(context)) - Container( - height: height, - width: height, - alignment: Alignment.center, - child: IconButton( - tooltip: L10n.of(context).emojis, - icon: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: - SharedAxisTransitionType.scaled, - fillColor: Colors.transparent, - child: child, - ); - }, - child: Icon( - _controller.showEmojiPicker - ? Icons.keyboard - : Icons.add_reaction_outlined, - key: ValueKey(_controller.showEmojiPicker), - ), - ), - onPressed: _controller.emojiPickerAction, - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 0.0), - child: InputBar( - room: _controller.room, - minLines: 1, - maxLines: 8, - autofocus: !PlatformInfos.isMobile, - keyboardType: TextInputType.multiline, - textInputAction: AppConfig.sendOnEnter == true && - PlatformInfos.isMobile - ? TextInputAction.send - : null, - onSubmitted: (String value) => - _controller.onInputBarSubmitted(value, context), - onSubmitImage: _controller.sendImageFromClipBoard, - focusNode: _controller.inputFocus, - controller: _controller.sendController, - decoration: const InputDecoration( - contentPadding: EdgeInsets.only( - left: 6.0, - right: 6.0, - bottom: 6.0, - top: 3.0, - ), - disabledBorder: InputBorder.none, - hintMaxLines: 1, - border: InputBorder.none, - enabledBorder: InputBorder.none, - filled: false, - ), - onChanged: _controller.onInputBarChanged, - hintText: hintText(), + PopupMenuItem( + value: 'image', + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + child: Icon(Icons.image_outlined), ), + title: Text(L10n.of(context).sendImage), + contentPadding: const EdgeInsets.all(0), ), ), - StartIGCButton( - controller: _controller, - ), - Container( - height: height, - width: height, - alignment: Alignment.center, - child: PlatformInfos.platformCanRecord && - _controller.sendController.text.isEmpty && - !_controller.choreographer.itController.willOpen - ? FloatingActionButton.small( - tooltip: L10n.of(context).voiceMessage, - onPressed: _controller.voiceMessageAction, - elevation: 0, - heroTag: null, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(height), - ), - backgroundColor: theme.bubbleColor, - foregroundColor: theme.onBubbleColor, - child: const Icon(Icons.mic_none_outlined), - ) - : ChoreographerSendButton(controller: _controller), - ), + if (PlatformInfos.isMobile) + PopupMenuItem( + value: 'camera', + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.purple, + foregroundColor: Colors.white, + child: Icon(Icons.camera_alt_outlined), + ), + title: Text(L10n.of(context).openCamera), + contentPadding: const EdgeInsets.all(0), + ), + ), + if (PlatformInfos.isMobile) + PopupMenuItem( + value: 'camera-video', + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + child: Icon(Icons.videocam_outlined), + ), + title: Text(L10n.of(context).openVideoCamera), + contentPadding: const EdgeInsets.all(0), + ), + ), + if (PlatformInfos.isMobile) + PopupMenuItem( + value: 'location', + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.brown, + foregroundColor: Colors.white, + child: Icon(Icons.gps_fixed_outlined), + ), + title: Text(L10n.of(context).shareLocation), + contentPadding: const EdgeInsets.all(0), + ), + ), ], + ), + ), + if (FluffyThemes.isColumnMode(context)) + Container( + height: height, + width: height, + alignment: Alignment.center, + child: IconButton( + tooltip: L10n.of(context).emojis, + icon: PageTransitionSwitcher( + transitionBuilder: ( + Widget child, + Animation primaryAnimation, + Animation secondaryAnimation, + ) { + return SharedAxisTransition( + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + transitionType: SharedAxisTransitionType.scaled, + fillColor: Colors.transparent, + child: child, + ); + }, + child: Icon( + _controller.showEmojiPicker + ? Icons.keyboard + : Icons.add_reaction_outlined, + key: ValueKey(_controller.showEmojiPicker), + ), + ), + onPressed: _controller.emojiPickerAction, + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 0.0), + child: InputBar( + room: _controller.room, + minLines: 1, + maxLines: 8, + autofocus: !PlatformInfos.isMobile, + keyboardType: TextInputType.multiline, + textInputAction: AppConfig.sendOnEnter == true && + PlatformInfos.isMobile + ? TextInputAction.send + : null, + onSubmitted: (String value) => + _controller.onInputBarSubmitted(value, context), + onSubmitImage: _controller.sendImageFromClipBoard, + focusNode: _controller.inputFocus, + controller: _controller.sendController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.only( + left: 6.0, + right: 6.0, + bottom: 6.0, + top: 3.0, + ), + disabledBorder: InputBorder.none, + hintMaxLines: 1, + border: InputBorder.none, + enabledBorder: InputBorder.none, + filled: false, + ), + onChanged: _controller.onInputBarChanged, + hintText: hintText(), + ), + ), + ), + StartIGCButton( + controller: _controller, + ), + Container( + height: height, + width: height, + alignment: Alignment.center, + child: PlatformInfos.platformCanRecord && + _controller.sendController.text.isEmpty && + !_controller.choreographer.itController.willOpen + ? FloatingActionButton.small( + tooltip: L10n.of(context).voiceMessage, + onPressed: _controller.voiceMessageAction, + elevation: 0, + heroTag: null, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(height), + ), + backgroundColor: theme.bubbleColor, + foregroundColor: theme.onBubbleColor, + child: const Icon(Icons.mic_none_outlined), + ) + : ChoreographerSendButton(controller: _controller), + ), + ], ), ), ), diff --git a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart index 8f7b0ec62..3511f23ac 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart @@ -51,7 +51,6 @@ class OverlayFooter extends StatelessWidget { ), child: PangeaChatInputRow( controller: controller, - overlayController: overlayController, ), ), ], diff --git a/lib/pangea/toolbar/widgets/message_selection_overlay.dart b/lib/pangea/toolbar/widgets/message_selection_overlay.dart index 440558bd8..cc6997d66 100644 --- a/lib/pangea/toolbar/widgets/message_selection_overlay.dart +++ b/lib/pangea/toolbar/widgets/message_selection_overlay.dart @@ -459,6 +459,11 @@ class MessageOverlayController extends State transcription != null || transcriptionError != null; + bool get showLanguageAssistance => + event.status.isSent && + event.type == EventTypes.Message && + event.messageType == MessageTypes.Text; + /////////////////////////////////// /// Functions ///////////////////////////////////// diff --git a/lib/pangea/toolbar/widgets/message_selection_positioner.dart b/lib/pangea/toolbar/widgets/message_selection_positioner.dart index 3c3727950..948109db4 100644 --- a/lib/pangea/toolbar/widgets/message_selection_positioner.dart +++ b/lib/pangea/toolbar/widgets/message_selection_positioner.dart @@ -627,7 +627,14 @@ class MessageSelectionPositionerState extends State double? get _availableSpaceAboveContent { if (_contentHeight == null || _mediaQuery == null) return null; - return max(0, (_mediaQuery!.size.height - _contentHeight!) / 2); + return max( + 0, + (_mediaQuery!.size.height - + _mediaQuery!.padding.top - + _mediaQuery!.padding.bottom - + _contentHeight!) / + 2, + ); } double? get _wordCardTopOffset { @@ -660,123 +667,129 @@ class MessageSelectionPositionerState extends State } widget.overlayController.maxWidth = _toolbarMaxWidth; - return Row( - children: [ - Column( - children: [ - Expanded( - child: SizedBox( - width: _mediaQuery!.size.width - - _columnWidth - - (_showDetails ? FluffyThemes.columnWidth : 0), - child: Stack( - alignment: _ownMessage - ? Alignment.centerRight - : Alignment.centerLeft, - children: [ - GestureDetector( - onTap: widget.chatController.clearSelectedEvents, - child: SingleChildScrollView( - controller: _scrollController, - padding: EdgeInsets.only( - left: _messageLeftOffset ?? 0.0, - right: _messageRightOffset ?? 0.0, - ), - child: Column( - crossAxisAlignment: _ownMessage - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - if (_contentHeight != null && - _mediaQuery != null && - _availableSpaceAboveContent != null && - _availableSpaceAboveContent! < - _overheadContentHeight) - AnimatedContainer( - duration: FluffyThemes.animationDuration, - height: - _contentHeight! + _overheadContentHeight > - _mediaQuery!.size.height - ? _overheadContentHeight - : (_overheadContentHeight - - _availableSpaceAboveContent!) * - 2, + return SafeArea( + child: Row( + children: [ + Column( + children: [ + Expanded( + child: SizedBox( + width: _mediaQuery!.size.width - + _columnWidth - + (_showDetails ? FluffyThemes.columnWidth : 0), + child: Stack( + alignment: _ownMessage + ? Alignment.centerRight + : Alignment.centerLeft, + children: [ + GestureDetector( + onTap: widget.chatController.clearSelectedEvents, + child: SingleChildScrollView( + controller: _scrollController, + padding: EdgeInsets.only( + left: _messageLeftOffset ?? 0.0, + right: _messageRightOffset ?? 0.0, + ), + child: Column( + crossAxisAlignment: _ownMessage + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (_contentHeight != null && + _mediaQuery != null && + _availableSpaceAboveContent != null && + _availableSpaceAboveContent! < + _overheadContentHeight) + AnimatedContainer( + duration: FluffyThemes.animationDuration, + height: _contentHeight! + + _overheadContentHeight > + _mediaQuery!.size.height + ? _overheadContentHeight + : (_overheadContentHeight - + _availableSpaceAboveContent!) * + 2, + ), + CompositedTransformTarget( + link: MatrixState.pAnyState + .layerLinkAndKey( + 'overlay_message_${widget.event.eventId}', + ) + .link, + child: OverlayCenterContent( + event: widget.event, + messageHeight: _originalMessageSize.height, + messageWidth: widget + .overlayController.showingExtraContent + ? max(_originalMessageSize.width, 150) + : _originalMessageSize.width, + overlayController: widget.overlayController, + chatController: widget.chatController, + nextEvent: widget.nextEvent, + prevEvent: widget.prevEvent, + hasReactions: _hasReactions, + // sizeAnimation: _messageSizeAnimation, + isTransitionAnimation: true, + readingAssistanceMode: widget + .overlayController.readingAssistanceMode, + ), ), - CompositedTransformTarget( - link: MatrixState.pAnyState - .layerLinkAndKey( - 'overlay_message_${widget.event.eventId}', - ) - .link, - child: OverlayCenterContent( - event: widget.event, - messageHeight: _originalMessageSize.height, - messageWidth: - widget.overlayController.showingExtraContent - ? max(_originalMessageSize.width, 150) - : _originalMessageSize.width, + const SizedBox(height: 4.0), + SelectModeButtons( + controller: widget.chatController, overlayController: widget.overlayController, - chatController: widget.chatController, - nextEvent: widget.nextEvent, - prevEvent: widget.prevEvent, - hasReactions: _hasReactions, - // sizeAnimation: _messageSizeAnimation, - isTransitionAnimation: true, - readingAssistanceMode: widget - .overlayController.readingAssistanceMode, + lauchPractice: () {}, + // lauchPractice: () { + // _setReadingAssistanceMode( + // ReadingAssistanceMode.practiceMode, + // ); + // widget.overlayController + // .updateSelectedSpan(null); + // }, ), - ), - const SizedBox(height: 4.0), - SelectModeButtons( - controller: widget.chatController, - overlayController: widget.overlayController, - lauchPractice: () {}, - // lauchPractice: () { - // _setReadingAssistanceMode( - // ReadingAssistanceMode.practiceMode, - // ); - // widget.overlayController - // .updateSelectedSpan(null); - // }, - ), - ], + ], + ), ), ), - ), - AnimatedPositioned( - top: _wordCardTopOffset, - left: _wordCardLeftOffset, - right: _messageRightOffset, - duration: FluffyThemes.animationDuration, - child: AnimatedSize( + AnimatedPositioned( + top: _wordCardTopOffset, + left: _wordCardLeftOffset, + right: _messageRightOffset, duration: FluffyThemes.animationDuration, - child: _wordCardTopOffset == null - ? const SizedBox() - : widget.pangeaMessageEvent != null && - widget.overlayController.selectedToken != - null - ? ReadingAssistanceContent( - pangeaMessageEvent: - widget.pangeaMessageEvent!, - overlayController: widget.overlayController, - ) - : MessageReactionPicker( - chatController: widget.chatController, - ), + child: AnimatedSize( + alignment: _ownMessage + ? Alignment.bottomRight + : Alignment.bottomLeft, + duration: FluffyThemes.animationDuration, + child: _wordCardTopOffset == null + ? const SizedBox() + : widget.pangeaMessageEvent != null && + widget.overlayController.selectedToken != + null + ? ReadingAssistanceContent( + pangeaMessageEvent: + widget.pangeaMessageEvent!, + overlayController: + widget.overlayController, + ) + : MessageReactionPicker( + chatController: widget.chatController, + ), + ), ), - ), - ], + ], + ), ), ), - ), - ], - ), - if (_showDetails) - const SizedBox( - width: FluffyThemes.columnWidth, + ], ), - ], + if (_showDetails) + const SizedBox( + width: FluffyThemes.columnWidth, + ), + ], + ), ); } } @@ -824,108 +837,111 @@ class MessageReactionPicker extends StatelessWidget { shadowColor: theme.colorScheme.surface.withAlpha(128), child: SingleChildScrollView( scrollDirection: Axis.horizontal, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ...AppConfig.defaultReactions.map( - (emoji) => IconButton( - padding: EdgeInsets.zero, - icon: Center( - child: Opacity( - opacity: sentReactions.contains( - emoji, - ) - ? 0.33 - : 1, - child: Text( - emoji, - style: const TextStyle( - fontSize: 20, + child: SizedBox( + height: 40.0, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ...AppConfig.defaultReactions.map( + (emoji) => IconButton( + padding: EdgeInsets.zero, + icon: Center( + child: Opacity( + opacity: sentReactions.contains( + emoji, + ) + ? 0.33 + : 1, + child: Text( + emoji, + style: const TextStyle( + fontSize: 20, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, ), ), + onPressed: sentReactions.contains(emoji) + ? null + : () => event.room.sendReaction( + event.eventId, + emoji, + ), ), - onPressed: sentReactions.contains(emoji) - ? null - : () => event.room.sendReaction( - event.eventId, - emoji, + ), + IconButton( + icon: const Icon( + Icons.add_reaction_outlined, + ), + tooltip: L10n.of(context).customReaction, + onPressed: () async { + final emoji = await showAdaptiveBottomSheet( + context: context, + builder: (context) => Scaffold( + appBar: AppBar( + title: Text( + L10n.of(context).customReaction, ), - ), - ), - IconButton( - icon: const Icon( - Icons.add_reaction_outlined, - ), - tooltip: L10n.of(context).customReaction, - onPressed: () async { - final emoji = await showAdaptiveBottomSheet( - context: context, - builder: (context) => Scaffold( - appBar: AppBar( - title: Text( - L10n.of(context).customReaction, - ), - leading: CloseButton( - onPressed: () => Navigator.of( - context, - ).pop( - null, + leading: CloseButton( + onPressed: () => Navigator.of( + context, + ).pop( + null, + ), ), ), - ), - body: SizedBox( - height: double.infinity, - child: EmojiPicker( - onEmojiSelected: ( - _, - emoji, - ) => - Navigator.of( - context, - ).pop( - emoji.emoji, - ), - config: Config( - emojiViewConfig: const EmojiViewConfig( - backgroundColor: Colors.transparent, + body: SizedBox( + height: double.infinity, + child: EmojiPicker( + onEmojiSelected: ( + _, + emoji, + ) => + Navigator.of( + context, + ).pop( + emoji.emoji, ), - bottomActionBarConfig: const BottomActionBarConfig( - enabled: false, - ), - categoryViewConfig: CategoryViewConfig( - initCategory: Category.SMILEYS, - backspaceColor: theme.colorScheme.primary, - iconColor: theme.colorScheme.primary.withAlpha( - 128, + config: Config( + emojiViewConfig: const EmojiViewConfig( + backgroundColor: Colors.transparent, + ), + bottomActionBarConfig: const BottomActionBarConfig( + enabled: false, + ), + categoryViewConfig: CategoryViewConfig( + initCategory: Category.SMILEYS, + backspaceColor: theme.colorScheme.primary, + iconColor: theme.colorScheme.primary.withAlpha( + 128, + ), + iconColorSelected: theme.colorScheme.primary, + indicatorColor: theme.colorScheme.primary, + backgroundColor: theme.colorScheme.surface, + ), + skinToneConfig: SkinToneConfig( + dialogBackgroundColor: Color.lerp( + theme.colorScheme.surface, + theme.colorScheme.primaryContainer, + 0.75, + )!, + indicatorColor: theme.colorScheme.onSurface, ), - iconColorSelected: theme.colorScheme.primary, - indicatorColor: theme.colorScheme.primary, - backgroundColor: theme.colorScheme.surface, - ), - skinToneConfig: SkinToneConfig( - dialogBackgroundColor: Color.lerp( - theme.colorScheme.surface, - theme.colorScheme.primaryContainer, - 0.75, - )!, - indicatorColor: theme.colorScheme.onSurface, ), ), ), ), - ), - ); - if (emoji == null) return; - if (sentReactions.contains(emoji)) return; - await event.room.sendReaction( - event.eventId, - emoji, - ); - }, - ), - ], + ); + if (emoji == null) return; + if (sentReactions.contains(emoji)) return; + await event.room.sendReaction( + event.eventId, + emoji, + ); + }, + ), + ], + ), ), ), ); diff --git a/lib/pangea/toolbar/widgets/select_mode_buttons.dart b/lib/pangea/toolbar/widgets/select_mode_buttons.dart index 91ded7d9f..efe1e61a4 100644 --- a/lib/pangea/toolbar/widgets/select_mode_buttons.dart +++ b/lib/pangea/toolbar/widgets/select_mode_buttons.dart @@ -55,7 +55,9 @@ enum MessageActions { download, pin, report, - info; + info, + deleteOnError, + sendAgain; IconData get icon { switch (this) { @@ -77,6 +79,10 @@ enum MessageActions { return Icons.shield_outlined; case MessageActions.info: return Icons.info_outlined; + case MessageActions.deleteOnError: + return Icons.delete; + case MessageActions.sendAgain: + return Icons.send_outlined; } } @@ -101,6 +107,10 @@ enum MessageActions { return l10n.reportMessage; case MessageActions.info: return l10n.messageInfo; + case MessageActions.deleteOnError: + return l10n.delete; + case MessageActions.sendAgain: + return l10n.tryToSendAgain; } } } @@ -539,20 +549,34 @@ class SelectModeButtonsState extends State { bool _messageActionEnabled(MessageActions action) { if (messageEvent == null) return false; + if (widget.controller.selectedEvents.isEmpty) return false; + final events = widget.controller.selectedEvents; + + if (events.any((e) => !e.status.isSent)) { + if (action == MessageActions.sendAgain) { + return true; + } + + if (events.every((e) => e.status.isError) && + action == MessageActions.deleteOnError) { + return true; + } + + return false; + } switch (action) { case MessageActions.reply: - return widget.controller.selectedEvents.length == 1 && + return events.length == 1 && widget.controller.room.canSendDefaultMessages; case MessageActions.edit: return widget.controller.canEditSelectedEvents && - !widget.controller.selectedEvents.first.isActivityMessage; + !events.first.isActivityMessage; case MessageActions.delete: return widget.controller.canRedactSelectedEvents; case MessageActions.copy: - return widget.controller.selectedEvents.length == 1 && - widget.controller.selectedEvents.single.messageType == - MessageTypes.Text; + return events.length == 1 && + events.single.messageType == MessageTypes.Text; case MessageActions.download: return widget.controller.canSaveSelectedEvent; case MessageActions.pin: @@ -560,7 +584,10 @@ class SelectModeButtonsState extends State { case MessageActions.forward: case MessageActions.report: case MessageActions.info: - return widget.controller.selectedEvents.length == 1; + return events.length == 1; + case MessageActions.deleteOnError: + case MessageActions.sendAgain: + return false; } } @@ -600,13 +627,23 @@ class SelectModeButtonsState extends State { widget.controller.showEventInfo(); widget.controller.clearSelectedEvents(); break; + case MessageActions.deleteOnError: + widget.controller.deleteErrorEventsAction(); + break; + case MessageActions.sendAgain: + widget.controller.sendAgainAction(); + break; } } @override Widget build(BuildContext context) { final theme = Theme.of(context); - final modes = messageEvent?.isAudioMessage == true ? audioModes : textModes; + final modes = widget.overlayController.showLanguageAssistance + ? messageEvent?.isAudioMessage == true + ? audioModes + : textModes + : []; final actions = MessageActions.values.where(_messageActionEnabled); return Material( @@ -637,7 +674,9 @@ class SelectModeButtonsState extends State { ), ); } else if (index == modes.length) { - return const Divider(height: 1.0); + return modes.isNotEmpty + ? const Divider(height: 1.0) + : const SizedBox(); } else { final action = actions.elementAt(index - modes.length - 1); return SizedBox(