feat: different styling for activity plan messages (#1558)

* feat: different styling for activity plan messages
pull/1593/head
ggurdin 10 months ago committed by GitHub
parent 62d5197411
commit 1d8e68a147
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -10,6 +10,8 @@ import 'package:fluffychat/pages/chat/events/message.dart';
import 'package:fluffychat/pages/chat/seen_by_row.dart'; import 'package:fluffychat/pages/chat/seen_by_row.dart';
import 'package:fluffychat/pages/chat/typing_indicators.dart'; import 'package:fluffychat/pages/chat/typing_indicators.dart';
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart'; import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
import 'package:fluffychat/pangea/activity_planner/activity_plan_message.dart';
import 'package:fluffychat/pangea/events/extensions/pangea_event_extension.dart';
import 'package:fluffychat/pangea/instructions/instructions_enum.dart'; import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
import 'package:fluffychat/pangea/instructions/instructions_show_popup.dart'; import 'package:fluffychat/pangea/instructions/instructions_show_popup.dart';
import 'package:fluffychat/utils/account_config.dart'; import 'package:fluffychat/utils/account_config.dart';
@ -168,49 +170,64 @@ class ChatEventList extends StatelessWidget {
key: ValueKey(event.eventId), key: ValueKey(event.eventId),
index: i, index: i,
controller: controller.scrollController, controller: controller.scrollController,
child: Message( child:
event, // #Pangea
animateIn: animateIn, event.isActivityMessage
resetAnimateIn: () { ? ActivityPlanMessage(
controller.animateInEventIndex = null; event,
}, controller: controller,
onSwipe: () => controller.replyAction(replyTo: event), timeline: timeline,
// #Pangea animateIn: animateIn,
onInfoTab: (_) => {}, resetAnimateIn: () {
// onInfoTab: controller.showEventInfo, controller.animateInEventIndex = null;
// Pangea# },
onAvatarTab: (Event event) => showAdaptiveBottomSheet( )
context: context, :
builder: (c) => UserBottomSheet( // Pangea#
user: event.senderFromMemoryOrFallback, Message(
outerContext: context, event,
onMention: () => controller.sendController.text += animateIn: animateIn,
'${event.senderFromMemoryOrFallback.mention} ', resetAnimateIn: () {
), controller.animateInEventIndex = null;
), },
highlightMarker: onSwipe: () => controller.replyAction(replyTo: event),
controller.scrollToEventIdMarker == event.eventId, // #Pangea
// #Pangea onInfoTab: (_) => {},
// onSelect: controller.onSelectMessage, // onInfoTab: controller.showEventInfo,
onSelect: (_) {}, // Pangea#
// Pangea# onAvatarTab: (Event event) => showAdaptiveBottomSheet(
scrollToEventId: (String eventId) => context: context,
controller.scrollToEventId(eventId), builder: (c) => UserBottomSheet(
longPressSelect: controller.selectedEvents.isNotEmpty, user: event.senderFromMemoryOrFallback,
// #Pangea outerContext: context,
immersionMode: controller.choreographer.immersionMode, onMention: () => controller.sendController.text +=
controller: controller, '${event.senderFromMemoryOrFallback.mention} ',
isButton: event.eventId == controller.buttonEventID, ),
// Pangea# ),
selected: controller.selectedEvents highlightMarker:
.any((e) => e.eventId == event.eventId), controller.scrollToEventIdMarker == event.eventId,
timeline: timeline, // #Pangea
displayReadMarker: // onSelect: controller.onSelectMessage,
i > 0 && controller.readMarkerEventId == event.eventId, onSelect: (_) {},
nextEvent: i + 1 < events.length ? events[i + 1] : null, // Pangea#
previousEvent: i > 0 ? events[i - 1] : null, scrollToEventId: (String eventId) =>
wallpaperMode: hasWallpaper, controller.scrollToEventId(eventId),
), longPressSelect: controller.selectedEvents.isNotEmpty,
// #Pangea
immersionMode: controller.choreographer.immersionMode,
controller: controller,
isButton: event.eventId == controller.buttonEventID,
// Pangea#
selected: controller.selectedEvents
.any((e) => e.eventId == event.eventId),
timeline: timeline,
displayReadMarker: i > 0 &&
controller.readMarkerEventId == event.eventId,
nextEvent:
i + 1 < events.length ? events[i + 1] : null,
previousEvent: i > 0 ? events[i - 1] : null,
wallpaperMode: hasWallpaper,
),
); );
}, },
childCount: events.length + 2, childCount: events.length + 2,

@ -0,0 +1,241 @@
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/events/message_content.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:swipe_to_action/swipe_to_action.dart';
import '../../../config/app_config.dart';
class ActivityPlanMessage extends StatelessWidget {
final Event event;
final Timeline timeline;
final bool animateIn;
final void Function()? resetAnimateIn;
final ChatController controller;
const ActivityPlanMessage(
this.event, {
required this.timeline,
this.animateIn = false,
this.resetAnimateIn,
required this.controller,
super.key,
});
@override
Widget build(BuildContext context) {
PangeaMessageEvent? pangeaMessageEvent;
if (event.type == EventTypes.Message) {
pangeaMessageEvent = PangeaMessageEvent(
event: event,
timeline: timeline,
ownMessage: event.senderId == Matrix.of(context).client.userID,
);
}
WidgetsBinding.instance.addPostFrameCallback((_) {
if (controller.pangeaEditingEvent?.eventId == event.eventId) {
pangeaMessageEvent?.updateLatestEdit();
controller.clearEditingEvent();
}
});
final theme = Theme.of(context);
final color = Color.alphaBlend(
Colors.white.withAlpha(180),
ThemeData.dark().colorScheme.primary,
);
final textColor = ThemeData.dark().colorScheme.onPrimary;
final displayEvent = event.getDisplayEvent(timeline);
const roundedCorner = Radius.circular(AppConfig.borderRadius);
const borderRadius = BorderRadius.all(roundedCorner);
final resetAnimateIn = this.resetAnimateIn;
var animateIn = this.animateIn;
final row = StatefulBuilder(
builder: (context, setState) {
if (animateIn && resetAnimateIn != null) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
animateIn = false;
if (context.mounted) {
setState(resetAnimateIn);
}
});
}
return AnimatedSize(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.none,
alignment: Alignment.bottomLeft,
child: animateIn
? const SizedBox(height: 0, width: double.infinity)
: Container(
alignment: Alignment.center,
child: AnimatedOpacity(
opacity: animateIn
? 0
: event.messageType == MessageTypes.BadEncrypted ||
event.status.isSending
? 0.5
: 1,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: Container(
decoration: BoxDecoration(
color: color,
borderRadius: borderRadius,
),
clipBehavior: Clip.antiAlias,
child: CompositedTransformTarget(
link: MatrixState.pAnyState
.layerLinkAndKey(
event.eventId,
)
.link,
child: Container(
key: MatrixState.pAnyState
.layerLinkAndKey(
event.eventId,
)
.key,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
constraints: const BoxConstraints(
maxWidth: FluffyThemes.columnWidth * 1.5,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
MessageContent(
displayEvent,
textColor: textColor,
borderRadius: borderRadius,
pangeaMessageEvent: pangeaMessageEvent,
controller: controller,
immersionMode: false,
),
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
))
Padding(
padding: const EdgeInsets.only(
top: 4.0,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
)) ...[
Icon(
Icons.edit_outlined,
color: textColor.withAlpha(164),
size: 14,
),
Text(
' - ${displayEvent.originServerTs.localizedTimeShort(context)}',
style: TextStyle(
color: textColor.withAlpha(
164,
),
fontSize: 12,
),
),
],
],
),
),
],
),
),
),
),
),
),
);
},
);
Widget container;
container = Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Center(
child: Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Material(
borderRadius: BorderRadius.circular(AppConfig.borderRadius * 2),
color: theme.colorScheme.surface.withAlpha(128),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 2.0,
),
child: Text(
event.originServerTs.localizedTime(context),
style: TextStyle(
fontSize: 12 * AppConfig.fontSizeFactor,
fontWeight: FontWeight.bold,
color: theme.colorScheme.secondary,
),
),
),
),
),
),
),
row,
],
);
container = Material(type: MaterialType.transparency, child: container);
return Center(
child: Swipeable(
key: ValueKey(event.eventId),
background: const Padding(
padding: EdgeInsets.symmetric(horizontal: 12.0),
child: Center(
child: Icon(Icons.check_outlined),
),
),
direction: AppConfig.swipeRightToLeftToReply
? SwipeDirection.endToStart
: SwipeDirection.startToEnd,
onSwipe: (_) {},
child: Container(
constraints: const BoxConstraints(
maxWidth: FluffyThemes.columnWidth * 2.5,
),
padding: const EdgeInsets.only(
left: 8.0,
right: 8.0,
top: 4.0,
bottom: 4.0,
),
child: container,
),
),
);
}
}

@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart'; import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
import 'package:fluffychat/pangea/events/extensions/pangea_event_extension.dart';
import 'package:fluffychat/pangea/events/models/representation_content_model.dart'; import 'package:fluffychat/pangea/events/models/representation_content_model.dart';
import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/spaces/models/space_model.dart'; import 'package:fluffychat/pangea/spaces/models/space_model.dart';
@ -689,4 +690,6 @@ class PangeaMessageEvent {
/// Returns a list of [PracticeActivityEvent] for the user's active l2. /// Returns a list of [PracticeActivityEvent] for the user's active l2.
List<PracticeActivityEvent> get practiceActivities => List<PracticeActivityEvent> get practiceActivities =>
l2Code == null ? [] : practiceActivitiesByLangCode(l2Code!); l2Code == null ? [] : practiceActivitiesByLangCode(l2Code!);
bool get shouldShowToolbar => !event.isActivityMessage;
} }

@ -88,4 +88,7 @@ extension PangeaEvent on Event {
waveform: waveform, waveform: waveform,
); );
} }
bool get isActivityMessage =>
content[ModelKey.messageTags] == ModelKey.messageTagActivityPlan;
} }

@ -252,6 +252,7 @@ class MessageSelectionPositionerState extends State<MessageSelectionPositioner>
bool get showToolbarButtons => bool get showToolbarButtons =>
widget.pangeaMessageEvent != null && widget.pangeaMessageEvent != null &&
widget.pangeaMessageEvent!.shouldShowToolbar &&
widget.pangeaMessageEvent!.event.messageType == MessageTypes.Text; widget.pangeaMessageEvent!.event.messageType == MessageTypes.Text;
double get _toolbarButtonsHeight => double get _toolbarButtonsHeight =>
@ -374,6 +375,7 @@ class MessageSelectionPositionerState extends State<MessageSelectionPositioner>
overlayController: widget.overlayController, overlayController: widget.overlayController,
chatController: widget.chatController, chatController: widget.chatController,
hasReactions: _hasReactions, hasReactions: _hasReactions,
shouldShowToolbarButtons: showToolbarButtons,
), ),
); );
}, },
@ -436,6 +438,8 @@ class ToolbarOverlay extends StatelessWidget {
final Event? prevEvent; final Event? prevEvent;
final bool hasReactions; final bool hasReactions;
final bool shouldShowToolbarButtons;
final PangeaMessageEvent? pangeaMessageEvent; final PangeaMessageEvent? pangeaMessageEvent;
final MessageOverlayController overlayController; final MessageOverlayController overlayController;
final ChatController chatController; final ChatController chatController;
@ -449,6 +453,7 @@ class ToolbarOverlay extends StatelessWidget {
required this.overlayController, required this.overlayController,
required this.chatController, required this.chatController,
required this.hasReactions, required this.hasReactions,
required this.shouldShowToolbarButtons,
this.pangeaMessageEvent, this.pangeaMessageEvent,
this.nextEvent, this.nextEvent,
this.prevEvent, this.prevEvent,
@ -466,7 +471,8 @@ class ToolbarOverlay extends StatelessWidget {
? CrossAxisAlignment.end ? CrossAxisAlignment.end
: CrossAxisAlignment.start, : CrossAxisAlignment.start,
children: [ children: [
if (pangeaMessageEvent != null) if (pangeaMessageEvent != null &&
pangeaMessageEvent!.shouldShowToolbar)
MessageToolbar( MessageToolbar(
pangeaMessageEvent: pangeaMessageEvent!, pangeaMessageEvent: pangeaMessageEvent!,
overlayController: overlayController, overlayController: overlayController,
@ -498,10 +504,11 @@ class ToolbarOverlay extends StatelessWidget {
), ),
), ),
), ),
ToolbarButtons( if (shouldShowToolbarButtons)
event: event, ToolbarButtons(
overlayController: overlayController, event: event,
), overlayController: overlayController,
),
], ],
), ),
), ),

Loading…
Cancel
Save