From c07ffaa0c2a4ee37cfbfde72cd0e826951b20700 Mon Sep 17 00:00:00 2001 From: TheOneWithTheBraid Date: Tue, 15 Nov 2022 11:39:50 +0100 Subject: [PATCH] feat: implement cute events Cute events help against social distancing. You can send googly eyes, hugs and cuddles. Fixes: https://rail.chat/@AgathaSorceress@eldritch.cafe/109336005433123570 Signed-off-by: TheOneWithTheBraid --- .gitignore | 3 +- assets/js/package/.gitkeep | 0 assets/js/package/olm.js | 1 - assets/l10n/intl_en.arb | 24 ++++ lib/pages/chat/command_hints.dart | 6 + lib/pages/chat/events/cute_events.dart | 128 +++++++++++++++++++++ lib/pages/chat/events/message_content.dart | 3 + pubspec.lock | 2 +- pubspec.yaml | 2 +- 9 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 assets/js/package/.gitkeep delete mode 100644 assets/js/package/olm.js create mode 100644 lib/pages/chat/events/cute_events.dart diff --git a/.gitignore b/.gitignore index 66aa9a5d..93a8e344 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ lib/generated_plugin_registrant.dart prime # libolm package -/assets/js/package/* +/assets/js/package # IntelliJ related *.iml @@ -62,4 +62,3 @@ ios/Podfile.lock /linux/out /macos/out .vs -assets/js/package/olm.js diff --git a/assets/js/package/.gitkeep b/assets/js/package/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/assets/js/package/olm.js b/assets/js/package/olm.js deleted file mode 100644 index a0a08e3d..00000000 --- a/assets/js/package/olm.js +++ /dev/null @@ -1 +0,0 @@ -// Dummy file :-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 385936d8..7194ea14 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -103,6 +103,30 @@ "type": "text", "placeholders": {} }, + "commandHint_googly":"Send some googly eyes", + "commandHint_cuddle": "Send a cuddle", + "commandHint_hug": "Send a hug", + "googlyEyesContent": "{senderName} sends you googly eyes", + "@googlyEyesContent": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "cuddleContent": "{senderName} cuddles you", + "@cuddleContent": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "hugContent": "{senderName} hugs you", + "@hugContent": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, "answeredTheCall": "{senderName} answered the call", "@answeredTheCall": { "type": "text", diff --git a/lib/pages/chat/command_hints.dart b/lib/pages/chat/command_hints.dart index bbdf7b32..5ab49360 100644 --- a/lib/pages/chat/command_hints.dart +++ b/lib/pages/chat/command_hints.dart @@ -44,6 +44,12 @@ String commandHint(L10n l10n, String command) { return l10n.commandHint_markasdm; case 'markasgroup': return l10n.commandHint_markasgroup; + case 'googly': + return l10n.commandHint_googly; + case 'hug': + return l10n.commandHint_hug; + case 'cuddle': + return l10n.commandHint_cuddle; default: return ""; } diff --git a/lib/pages/chat/events/cute_events.dart b/lib/pages/chat/events/cute_events.dart new file mode 100644 index 00000000..1a09a9bf --- /dev/null +++ b/lib/pages/chat/events/cute_events.dart @@ -0,0 +1,128 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/config/app_config.dart'; + +class CuteContent extends StatefulWidget { + final Event event; + + const CuteContent(this.event, {Key? key}) : super(key: key); + + @override + State createState() => _CuteContentState(); +} + +class _CuteContentState extends State { + static final List overlays = []; + + @override + void initState() { + if (AppConfig.autoplayImages && overlays.isEmpty) { + addOverlay(); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: widget.event.fetchSenderUser(), + builder: (context, snapshot) { + final label = generateLabel(snapshot.data); + + return GestureDetector( + onTap: addOverlay, + child: SizedBox.square( + dimension: 300, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + widget.event.text, + style: const TextStyle(fontSize: 150), + ), + if (label != null) Text(label) + ], + ), + ), + ); + }, + ); + } + + Widget overlayBuilder(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + final position = Size( + Random().nextInt(constraints.maxWidth.round() - 64).toDouble(), + Random().nextInt(constraints.maxHeight.round() - 64).toDouble()); + + return Padding( + padding: EdgeInsets.only( + top: position.height, + left: position.width, + bottom: constraints.maxHeight - 64 - position.height, + right: constraints.maxWidth - 64 - position.width), + child: SizedBox.square( + dimension: 64, + child: GestureDetector( + onTap: removeOverlay, + child: Text( + widget.event.text, + style: const TextStyle(fontSize: 48), + ), + ), + ), + ); + }); + } + + Future addOverlay() async { + await Future.delayed(const Duration(milliseconds: 50)); + for (int i = 0; i < 5; i++) { + final overlay = OverlayEntry( + builder: overlayBuilder, + ); + Overlay.of(context)?.insert(overlay); + + Future.delayed(Duration(seconds: Random().nextInt(35))).then((_) { + overlay.remove(); + overlays.remove(overlay); + }); + overlays.add(overlay); + } + } + + void removeOverlay() { + if (overlays.isEmpty) return; + final overlay = overlays.removeLast(); + overlay.remove(); + } + + generateLabel(User? user) { + switch (widget.event.content['cute_type']) { + case 'googly_eyes': + return L10n.of(context)?.googlyEyesContent( + user?.displayName ?? + widget.event.senderFromMemoryOrFallback.displayName ?? + '', + ); + case 'cuddle': + return L10n.of(context)?.cuddleContent( + user?.displayName ?? + widget.event.senderFromMemoryOrFallback.displayName ?? + '', + ); + case 'hug': + return L10n.of(context)?.hugContent( + user?.displayName ?? + widget.event.senderFromMemoryOrFallback.displayName ?? + '', + ); + } + } +} diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 7c5710b8..70562db2 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -14,6 +14,7 @@ import '../../../utils/platform_infos.dart'; import '../../../utils/url_launcher.dart'; import '../../bootstrap/bootstrap_dialog.dart'; import 'audio_player.dart'; +import 'cute_events.dart'; import 'html_message.dart'; import 'image_bubble.dart'; import 'map_bubble.dart'; @@ -108,6 +109,8 @@ class MessageContent extends StatelessWidget { case MessageTypes.Sticker: if (event.redacted) continue textmessage; return Sticker(event); + case CuteEventContent.eventType: + return CuteContent(event); case MessageTypes.Audio: if (PlatformInfos.isMobile || PlatformInfos.isMacOS) { return AudioPlayerWidget( diff --git a/pubspec.lock b/pubspec.lock index 4bac6138..c54b48c4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -956,7 +956,7 @@ packages: name: matrix url: "https://pub.dartlang.org" source: hosted - version: "0.15.2" + version: "0.15.4" matrix_api_lite: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 741b3457..e41b6d4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,7 +60,7 @@ dependencies: just_audio: ^0.9.20 keyboard_shortcuts: ^0.1.4 latlong2: ^0.8.1 - matrix: ^0.15.2 + matrix: ^0.15.4 matrix_homeserver_recommendations: ^0.3.0 matrix_link_text: ^1.0.2 native_imaging: ^0.1.0