Files
Client/lib/view/pages/talk/widgets/chat_bubble_reactions.dart
T

105 lines
4.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import '../../../../api/marianumcloud/talk/chat/get_chat_response.dart';
import '../../../../api/marianumcloud/talk/delete_react_message/delete_react_message.dart';
import '../../../../api/marianumcloud/talk/delete_react_message/delete_react_message_params.dart';
import '../../../../api/marianumcloud/talk/react_message/react_message.dart';
import '../../../../api/marianumcloud/talk/react_message/react_message_params.dart';
import '../../../../api/marianumcloud/talk/room/get_room_response.dart';
import '../../../../widget/a11y/a11y_labels.dart';
import '../../../../widget/async_action_button.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/emoji_text.dart';
/// Reactions wrap shown beneath a chat bubble. Tapping a reaction toggles
/// the user's own reaction via the Talk API and notifies via [onChanged].
class ChatBubbleReactions extends StatelessWidget {
final GetChatResponseObject bubbleData;
final GetRoomResponseObject chatData;
final bool isSender;
final void Function({bool renew}) onChanged;
const ChatBubbleReactions({
required this.bubbleData,
required this.chatData,
required this.isSender,
required this.onChanged,
super.key,
});
@override
Widget build(BuildContext context) {
final reactions = bubbleData.reactions;
if (reactions == null) return const SizedBox.shrink();
return Transform.translate(
offset: const Offset(0, -10),
child: Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Wrap(
alignment: isSender ? WrapAlignment.end : WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
children: reactions.entries.map<Widget>((e) {
final hasSelfReacted =
bubbleData.reactionsSelf?.contains(e.key) ?? false;
void toggle() {
if (guardDemoAction(context)) return;
runWithErrorDialog(context, () async {
if (hasSelfReacted) {
await DeleteReactMessage(
chatToken: chatData.token,
messageId: bubbleData.id,
params: DeleteReactMessageParams(e.key),
).run();
} else {
await ReactMessage(
chatToken: chatData.token,
messageId: bubbleData.id,
params: ReactMessageParams(e.key),
).run();
}
onChanged(renew: true);
});
}
// Ownership (eigene Reaktion) wird visuell nur über die
// Hintergrundfarbe transportiert für den Screenreader ins Label.
final label = hasSelfReacted
? '${e.key} ${e.value}, ${A11yLabels.yourReaction}'
: '${e.key} ${e.value}';
return Container(
margin: const EdgeInsets.only(right: 2.5, left: 2.5),
child: Semantics(
button: true,
label: label,
onTap: toggle,
child: ExcludeSemantics(
child: ActionChip(
label: Row(
mainAxisSize: MainAxisSize.min,
children: [
EmojiText(e.key, size: EmojiText.sizeInline),
const SizedBox(width: 4),
Text('${e.value}'),
],
),
visualDensity: const VisualDensity(
vertical: VisualDensity.minimumDensity,
horizontal: VisualDensity.minimumDensity,
),
padding: EdgeInsets.zero,
backgroundColor: hasSelfReacted
? Theme.of(context).primaryColor
: null,
onPressed: toggle,
),
),
),
);
}).toList(),
),
),
);
}
}