mirror of
https://github.com/nostrlabs-io/zap-stream-flutter.git
synced 2025-06-15 03:46:33 +00:00
@ -139,7 +139,6 @@ class _StreamPage extends State<StreamPage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Expanded(child: ChatWidget(stream: widget.stream)),
|
||||
],
|
||||
);
|
||||
|
@ -17,18 +17,20 @@ class ChatWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
reverse: true,
|
||||
child: RxFilter<Nip01Event>(
|
||||
filters: [
|
||||
Filter(kinds: [1311, 9735], limit: 200, aTags: [stream.aTag]),
|
||||
],
|
||||
builder: (ctx, state) {
|
||||
return Column(
|
||||
return RxFilter<Nip01Event>(
|
||||
filters: [
|
||||
Filter(kinds: [1311, 9735], limit: 200, aTags: [stream.aTag]),
|
||||
],
|
||||
builder: (ctx, state) {
|
||||
return Column(
|
||||
spacing: 8,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_TopZappersWidget(events: state ?? []),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
reverse: true,
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children:
|
||||
@ -37,43 +39,95 @@ class ChatWidget extends StatelessWidget {
|
||||
.map(
|
||||
(c) => switch (c.kind) {
|
||||
1311 => ChatMessageWidget(stream: stream, msg: c),
|
||||
9735 => ChatZapWidget(stream: stream, zap: c),
|
||||
9735 => _ChatZapWidget(stream: stream, zap: c),
|
||||
_ => SizedBox.shrink(),
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (stream.info.status == StreamStatus.live)
|
||||
WriteMessageWidget(stream: stream),
|
||||
if (stream.info.status == StreamStatus.ended)
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
margin: EdgeInsets.symmetric(vertical: 8),
|
||||
width: double.maxFinite,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: PRIMARY_1,
|
||||
borderRadius: DEFAULT_BR,
|
||||
),
|
||||
child: Text(
|
||||
"STREAM ENDED",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (stream.info.status == StreamStatus.live)
|
||||
WriteMessageWidget(stream: stream),
|
||||
if (stream.info.status == StreamStatus.ended)
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
margin: EdgeInsets.symmetric(vertical: 8),
|
||||
width: double.maxFinite,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(borderRadius: DEFAULT_BR),
|
||||
child: Text(
|
||||
"STREAM ENDED",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatZapWidget extends StatelessWidget {
|
||||
class _TopZappersWidget extends StatelessWidget {
|
||||
final List<Nip01Event> events;
|
||||
|
||||
const _TopZappersWidget({required this.events});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final topZaps =
|
||||
events
|
||||
.where((e) => e.kind == 9735)
|
||||
.map((e) => ZapReceipt.fromEvent(e))
|
||||
.fold(<String, int>{}, (acc, e) {
|
||||
if (e.sender != null) {
|
||||
acc[e.sender!] = (acc[e.sender!] ?? 0) + e.amountSats!;
|
||||
}
|
||||
return acc;
|
||||
})
|
||||
.entries
|
||||
.sortedBy((e) => e.value)
|
||||
.reversed
|
||||
.take(10)
|
||||
.toList();
|
||||
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
primary: false,
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children:
|
||||
topZaps
|
||||
.map(
|
||||
(v) => Container(
|
||||
padding: EdgeInsets.only(left: 4, right: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: DEFAULT_BR,
|
||||
border: Border.all(color: LAYER_3),
|
||||
),
|
||||
child: ProfileWidget.pubkey(
|
||||
v.key,
|
||||
showName: false,
|
||||
size: 20,
|
||||
spacing: 0,
|
||||
children: [
|
||||
Icon(Icons.bolt, color: ZAP_1),
|
||||
Text(formatSats(v.value)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ChatZapWidget extends StatelessWidget {
|
||||
final StreamEvent stream;
|
||||
final Nip01Event zap;
|
||||
|
||||
const ChatZapWidget({super.key, required this.stream, required this.zap});
|
||||
const _ChatZapWidget({required this.stream, required this.zap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -125,6 +179,7 @@ class ChatZapWidget extends StatelessWidget {
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: AvatarWidget(profile: profile, size: 20),
|
||||
),
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
),
|
||||
TextSpan(text: name),
|
||||
TextSpan(text: " zapped ", style: TextStyle(color: FONT_COLOR)),
|
||||
|
@ -64,19 +64,34 @@ class ProfileWidget extends StatelessWidget {
|
||||
final Metadata profile;
|
||||
final TextStyle? style;
|
||||
final double? size;
|
||||
final List<Widget>? children;
|
||||
final bool? showName;
|
||||
final double? spacing;
|
||||
|
||||
const ProfileWidget({
|
||||
super.key,
|
||||
required this.profile,
|
||||
this.style,
|
||||
this.size,
|
||||
this.children,
|
||||
this.showName,
|
||||
this.spacing,
|
||||
});
|
||||
|
||||
static Widget pubkey(String pubkey, {double? size}) {
|
||||
static Widget pubkey(
|
||||
String pubkey, {
|
||||
double? size,
|
||||
List<Widget>? children,
|
||||
bool? showName,
|
||||
double? spacing,
|
||||
}) {
|
||||
return ProfileLoaderWidget(pubkey, (ctx, state) {
|
||||
return ProfileWidget(
|
||||
profile: state.data ?? Metadata(pubKey: pubkey),
|
||||
size: size,
|
||||
showName: showName,
|
||||
spacing: spacing,
|
||||
children: children,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -84,10 +99,11 @@ class ProfileWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
spacing: 8,
|
||||
spacing: spacing ?? 8,
|
||||
children: [
|
||||
AvatarWidget(profile: profile, size: size),
|
||||
ProfileNameWidget(profile: profile),
|
||||
if (showName ?? true) ProfileNameWidget(profile: profile),
|
||||
...(children ?? []),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user