mirror of
https://github.com/nostrlabs-io/zap-stream-flutter.git
synced 2025-06-16 11:58:50 +00:00
refactor: performance
This commit is contained in:
136
lib/widgets/chat_message.dart
Normal file
136
lib/widgets/chat_message.dart
Normal file
@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ndk/ndk.dart';
|
||||
import 'package:zap_stream_flutter/main.dart';
|
||||
import 'package:zap_stream_flutter/rx_filter.dart';
|
||||
import 'package:zap_stream_flutter/theme.dart';
|
||||
import 'package:zap_stream_flutter/utils.dart';
|
||||
import 'package:zap_stream_flutter/widgets/avatar.dart';
|
||||
import 'package:zap_stream_flutter/widgets/chat_modal.dart';
|
||||
import 'package:zap_stream_flutter/widgets/nostr_text.dart';
|
||||
import 'package:zap_stream_flutter/widgets/profile.dart';
|
||||
|
||||
class ChatMessageWidget extends StatelessWidget {
|
||||
final StreamEvent stream;
|
||||
final Nip01Event msg;
|
||||
|
||||
const ChatMessageWidget({super.key, required this.stream, required this.msg});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ProfileLoaderWidget(msg.pubKey, (ctx, state) {
|
||||
final profile = state.data ?? Metadata(pubKey: msg.pubKey);
|
||||
return GestureDetector(
|
||||
onLongPress: () {
|
||||
if (ndk.accounts.canSign) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
constraints: BoxConstraints.expand(),
|
||||
builder: (ctx) => ChatModalWidget(profile: profile, event: msg),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
|
||||
child: Column(
|
||||
spacing: 2,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [_chatText(profile), ChatReactions(msg: msg)],
|
||||
),
|
||||
),
|
||||
);
|
||||
}, key: Key("chat:${msg.id}:profile"));
|
||||
}
|
||||
|
||||
Widget _chatText(Metadata profile) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: AvatarWidget(profile: profile, size: 24),
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
),
|
||||
TextSpan(text: " "),
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: ProfileNameWidget(
|
||||
profile: profile,
|
||||
style: TextStyle(
|
||||
color: msg.pubKey == stream.info.host ? PRIMARY_1 : SECONDARY_1,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(text: " "),
|
||||
...textToSpans(msg.content, msg.tags, msg.pubKey),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatReactions extends StatelessWidget {
|
||||
final Nip01Event msg;
|
||||
|
||||
const ChatReactions({super.key, required this.msg});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RxFilter<Nip01Event>(
|
||||
Key("chat:${msg.id}:reactions"),
|
||||
filters: [
|
||||
Filter(kinds: [9735, 7], eTags: [msg.id]),
|
||||
],
|
||||
builder: (ctx, data) => _chatReactions(data),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chatReactions(List<Nip01Event>? events) {
|
||||
if ((events?.length ?? 0) == 0) return SizedBox.shrink();
|
||||
|
||||
// reactions must have e tag pointing to msg
|
||||
final filteredEvents = events!.where((e) => e.getEId() == msg.id);
|
||||
final zaps = filteredEvents
|
||||
.where((e) => e.kind == 9735)
|
||||
.map((e) => ZapReceipt.fromEvent(e));
|
||||
final reactions = filteredEvents.where((e) => e.kind == 7);
|
||||
|
||||
return Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
if (zaps.isNotEmpty)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(color: LAYER_2, borderRadius: DEFAULT_BR),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.bolt, color: ZAP_1, size: 16),
|
||||
Text(
|
||||
formatSats(
|
||||
zaps.fold(0, (acc, v) => acc + (v.amountSats ?? 0)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (reactions.isNotEmpty)
|
||||
...reactions
|
||||
.fold(<String, Set<String>>{}, (acc, v) {
|
||||
// ignore: prefer_collection_literals
|
||||
acc[v.content] ??= Set();
|
||||
acc[v.content]!.add(v.pubKey);
|
||||
return acc;
|
||||
})
|
||||
.entries
|
||||
.map(
|
||||
(v) => Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: LAYER_2,
|
||||
borderRadius: DEFAULT_BR,
|
||||
),
|
||||
child: Center(child: Text(v.key)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user