mirror of
https://github.com/nostrlabs-io/zap-stream-flutter.git
synced 2025-06-17 12:28:49 +00:00
feat: custom emoji in chat
This commit is contained in:
@ -1,14 +1,12 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:ndk/ndk.dart';
|
import 'package:ndk/ndk.dart';
|
||||||
import 'package:zap_stream_flutter/imgproxy.dart';
|
|
||||||
import 'package:zap_stream_flutter/main.dart';
|
import 'package:zap_stream_flutter/main.dart';
|
||||||
import 'package:zap_stream_flutter/rx_filter.dart';
|
import 'package:zap_stream_flutter/rx_filter.dart';
|
||||||
import 'package:zap_stream_flutter/theme.dart';
|
import 'package:zap_stream_flutter/theme.dart';
|
||||||
import 'package:zap_stream_flutter/utils.dart';
|
import 'package:zap_stream_flutter/utils.dart';
|
||||||
import 'package:zap_stream_flutter/widgets/avatar.dart';
|
import 'package:zap_stream_flutter/widgets/avatar.dart';
|
||||||
import 'package:zap_stream_flutter/widgets/chat_modal.dart';
|
import 'package:zap_stream_flutter/widgets/chat_modal.dart';
|
||||||
|
import 'package:zap_stream_flutter/widgets/custom_emoji.dart';
|
||||||
import 'package:zap_stream_flutter/widgets/nostr_text.dart';
|
import 'package:zap_stream_flutter/widgets/nostr_text.dart';
|
||||||
import 'package:zap_stream_flutter/widgets/profile.dart';
|
import 'package:zap_stream_flutter/widgets/profile.dart';
|
||||||
|
|
||||||
@ -132,33 +130,11 @@ class ChatReactions extends StatelessWidget {
|
|||||||
borderRadius: DEFAULT_BR,
|
borderRadius: DEFAULT_BR,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: _rectionContent(context, v.key, v.value.first),
|
child: CustomEmoji(emoji: v.key, tags: v.value.first.tags),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _rectionContent(
|
|
||||||
BuildContext context,
|
|
||||||
String reaction,
|
|
||||||
Nip01Event event,
|
|
||||||
) {
|
|
||||||
final customEmoji =
|
|
||||||
event.tags.firstWhereOrNull(
|
|
||||||
(t) =>
|
|
||||||
t[0] == "emoji" &&
|
|
||||||
t[1] == reaction.substring(1, reaction.length - 1),
|
|
||||||
)?[2];
|
|
||||||
if (customEmoji != null) {
|
|
||||||
return CachedNetworkImage(
|
|
||||||
imageUrl: proxyImg(context, customEmoji),
|
|
||||||
height: 15,
|
|
||||||
width: 15,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Text(reaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
39
lib/widgets/custom_emoji.dart
Normal file
39
lib/widgets/custom_emoji.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:zap_stream_flutter/imgproxy.dart';
|
||||||
|
|
||||||
|
class CustomEmoji extends StatelessWidget {
|
||||||
|
final List<List<String>> tags;
|
||||||
|
final String emoji;
|
||||||
|
final double? size;
|
||||||
|
|
||||||
|
const CustomEmoji({
|
||||||
|
super.key,
|
||||||
|
required this.tags,
|
||||||
|
required this.emoji,
|
||||||
|
this.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final cleanedEmojiName =
|
||||||
|
emoji.startsWith(":") && emoji.endsWith(":")
|
||||||
|
? emoji.substring(1, emoji.length - 1)
|
||||||
|
: emoji;
|
||||||
|
|
||||||
|
final customEmoji =
|
||||||
|
tags.firstWhereOrNull(
|
||||||
|
(t) => t[0] == "emoji" && t[1] == cleanedEmojiName,
|
||||||
|
)?[2];
|
||||||
|
if (customEmoji != null) {
|
||||||
|
return CachedNetworkImage(
|
||||||
|
imageUrl: proxyImg(context, customEmoji),
|
||||||
|
height: size ?? 16,
|
||||||
|
width: size ?? 16,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Text(emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import 'package:ndk/shared/nips/nip19/nip19.dart';
|
|||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:zap_stream_flutter/theme.dart';
|
import 'package:zap_stream_flutter/theme.dart';
|
||||||
import 'package:zap_stream_flutter/utils.dart';
|
import 'package:zap_stream_flutter/utils.dart';
|
||||||
|
import 'package:zap_stream_flutter/widgets/custom_emoji.dart';
|
||||||
import 'package:zap_stream_flutter/widgets/profile.dart';
|
import 'package:zap_stream_flutter/widgets/profile.dart';
|
||||||
|
|
||||||
class NoteText extends StatelessWidget {
|
class NoteText extends StatelessWidget {
|
||||||
@ -30,12 +31,12 @@ List<InlineSpan> textToSpans(
|
|||||||
List<List<String>> tags,
|
List<List<String>> tags,
|
||||||
String pubkey,
|
String pubkey,
|
||||||
) {
|
) {
|
||||||
return _buildContentSpans(content);
|
return _buildContentSpans(content, tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Content parser from camelus
|
/// Content parser from camelus
|
||||||
/// https://github.com/leo-lox/camelus/blob/f58455a0ac07fcc780bdc69b8f4544fd5ea4a46d/lib/presentation_layer/components/note_card/note_card_build_split_content.dart#L262
|
/// https://github.com/leo-lox/camelus/blob/f58455a0ac07fcc780bdc69b8f4544fd5ea4a46d/lib/presentation_layer/components/note_card/note_card_build_split_content.dart#L262
|
||||||
List<InlineSpan> _buildContentSpans(String content) {
|
List<InlineSpan> _buildContentSpans(String content, List<List<String>> tags) {
|
||||||
List<InlineSpan> spans = [];
|
List<InlineSpan> spans = [];
|
||||||
RegExp exp = RegExp(
|
RegExp exp = RegExp(
|
||||||
r'nostr:(nprofile|npub)[a-zA-Z0-9]+|'
|
r'nostr:(nprofile|npub)[a-zA-Z0-9]+|'
|
||||||
@ -62,7 +63,23 @@ List<InlineSpan> _buildContentSpans(String content) {
|
|||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
onNonMatch: (String text) {
|
onNonMatch: (String text) {
|
||||||
spans.add(TextSpan(text: text));
|
final textTrim = text.trim();
|
||||||
|
if (textTrim.startsWith(":") &&
|
||||||
|
textTrim.endsWith(":") &&
|
||||||
|
tags.any(
|
||||||
|
(t) =>
|
||||||
|
t[0] == "emoji" &&
|
||||||
|
t[1] == textTrim.substring(1, textTrim.length - 1),
|
||||||
|
)) {
|
||||||
|
spans.add(
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: CustomEmoji(emoji: textTrim, tags: tags, size: 24),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
spans.add(TextSpan(text: text));
|
||||||
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user