mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-03 17:59:45 +01:00
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 <the-one@with-the-braid.cf>
This commit is contained in:
parent
ad185f4a95
commit
c07ffaa0c2
3
.gitignore
vendored
3
.gitignore
vendored
@ -14,7 +14,7 @@ lib/generated_plugin_registrant.dart
|
|||||||
prime
|
prime
|
||||||
|
|
||||||
# libolm package
|
# libolm package
|
||||||
/assets/js/package/*
|
/assets/js/package
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
*.iml
|
*.iml
|
||||||
@ -62,4 +62,3 @@ ios/Podfile.lock
|
|||||||
/linux/out
|
/linux/out
|
||||||
/macos/out
|
/macos/out
|
||||||
.vs
|
.vs
|
||||||
assets/js/package/olm.js
|
|
||||||
|
0
assets/js/package/.gitkeep
Normal file
0
assets/js/package/.gitkeep
Normal file
@ -1 +0,0 @@
|
|||||||
// Dummy file :-)
|
|
@ -103,6 +103,30 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"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": "{senderName} answered the call",
|
||||||
"@answeredTheCall": {
|
"@answeredTheCall": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -44,6 +44,12 @@ String commandHint(L10n l10n, String command) {
|
|||||||
return l10n.commandHint_markasdm;
|
return l10n.commandHint_markasdm;
|
||||||
case 'markasgroup':
|
case 'markasgroup':
|
||||||
return l10n.commandHint_markasgroup;
|
return l10n.commandHint_markasgroup;
|
||||||
|
case 'googly':
|
||||||
|
return l10n.commandHint_googly;
|
||||||
|
case 'hug':
|
||||||
|
return l10n.commandHint_hug;
|
||||||
|
case 'cuddle':
|
||||||
|
return l10n.commandHint_cuddle;
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
128
lib/pages/chat/events/cute_events.dart
Normal file
128
lib/pages/chat/events/cute_events.dart
Normal file
@ -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<CuteContent> createState() => _CuteContentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CuteContentState extends State<CuteContent> {
|
||||||
|
static final List<OverlayEntry> overlays = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
if (AppConfig.autoplayImages && overlays.isEmpty) {
|
||||||
|
addOverlay();
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder<User?>(
|
||||||
|
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<void> 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 ??
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import '../../../utils/platform_infos.dart';
|
|||||||
import '../../../utils/url_launcher.dart';
|
import '../../../utils/url_launcher.dart';
|
||||||
import '../../bootstrap/bootstrap_dialog.dart';
|
import '../../bootstrap/bootstrap_dialog.dart';
|
||||||
import 'audio_player.dart';
|
import 'audio_player.dart';
|
||||||
|
import 'cute_events.dart';
|
||||||
import 'html_message.dart';
|
import 'html_message.dart';
|
||||||
import 'image_bubble.dart';
|
import 'image_bubble.dart';
|
||||||
import 'map_bubble.dart';
|
import 'map_bubble.dart';
|
||||||
@ -108,6 +109,8 @@ class MessageContent extends StatelessWidget {
|
|||||||
case MessageTypes.Sticker:
|
case MessageTypes.Sticker:
|
||||||
if (event.redacted) continue textmessage;
|
if (event.redacted) continue textmessage;
|
||||||
return Sticker(event);
|
return Sticker(event);
|
||||||
|
case CuteEventContent.eventType:
|
||||||
|
return CuteContent(event);
|
||||||
case MessageTypes.Audio:
|
case MessageTypes.Audio:
|
||||||
if (PlatformInfos.isMobile || PlatformInfos.isMacOS) {
|
if (PlatformInfos.isMobile || PlatformInfos.isMacOS) {
|
||||||
return AudioPlayerWidget(
|
return AudioPlayerWidget(
|
||||||
|
@ -956,7 +956,7 @@ packages:
|
|||||||
name: matrix
|
name: matrix
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.2"
|
version: "0.15.4"
|
||||||
matrix_api_lite:
|
matrix_api_lite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -60,7 +60,7 @@ dependencies:
|
|||||||
just_audio: ^0.9.20
|
just_audio: ^0.9.20
|
||||||
keyboard_shortcuts: ^0.1.4
|
keyboard_shortcuts: ^0.1.4
|
||||||
latlong2: ^0.8.1
|
latlong2: ^0.8.1
|
||||||
matrix: ^0.15.2
|
matrix: ^0.15.4
|
||||||
matrix_homeserver_recommendations: ^0.3.0
|
matrix_homeserver_recommendations: ^0.3.0
|
||||||
matrix_link_text: ^1.0.2
|
matrix_link_text: ^1.0.2
|
||||||
native_imaging: ^0.1.0
|
native_imaging: ^0.1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user