feat: super chat

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-09-01 21:15:29 +08:00
parent e6af0ef15b
commit 80fa0240e9
20 changed files with 896 additions and 261 deletions

View File

@@ -0,0 +1,149 @@
import 'dart:async';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class SuperChatCard extends StatefulWidget {
const SuperChatCard({
super.key,
required this.item,
required this.onRemove,
});
final SuperChatItem item;
final VoidCallback onRemove;
@override
State<SuperChatCard> createState() => _SuperChatCardState();
}
class _SuperChatCardState extends State<SuperChatCard> {
Timer? _timer;
RxInt _remains = 0.obs;
@override
void initState() {
super.initState();
if (widget.item.expired) {
_onRemove();
return;
}
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final offset = widget.item.endTime - now;
if (offset > 0) {
_remains = offset.obs;
_timer = Timer.periodic(const Duration(seconds: 1), _callback);
} else {
_onRemove();
}
}
void _onRemove() {
widget
..item.expired = true
..onRemove();
}
void _callback(_) {
final remains = _remains.value;
if (remains > 0) {
_remains.value = remains - 1;
} else {
_cancelTimer();
_onRemove();
}
}
void _cancelTimer() {
_timer?.cancel();
_timer = null;
}
@override
void dispose() {
_cancelTimer();
super.dispose();
}
@override
Widget build(BuildContext context) {
final item = widget.item;
final bottomColor = Utils.parseColor(item.backgroundBottomColor);
final border = BorderSide(color: bottomColor);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
color: Utils.parseColor(item.backgroundColor),
border: Border(top: border, left: border, right: border),
),
padding: const EdgeInsets.all(8),
child: Row(
spacing: 12,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${item.uid}'),
child: NetworkImgLayer(
src: item.userInfo.face,
width: 45,
height: 45,
type: ImageType.avatar,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.userInfo.uname,
style: TextStyle(
color: Utils.parseColor(item.userInfo.nameColor),
),
),
Text(
"${item.price}",
style: TextStyle(
fontSize: 12,
color: Utils.parseColor(item.backgroundPriceColor),
),
),
],
),
),
Obx(
() => Text(
_remains.toString(),
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
),
],
),
),
Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
color: bottomColor,
),
padding: const EdgeInsets.all(8),
child: SelectableText(
item.message,
style: TextStyle(color: Utils.parseColor(item.messageFontColor)),
),
),
],
);
}
}

View File

@@ -0,0 +1,45 @@
import 'package:PiliPlus/pages/live_room/controller.dart';
import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
import 'package:PiliPlus/pages/search/controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
class SuperChatPanel extends StatefulWidget {
const SuperChatPanel({
super.key,
required this.controller,
});
final LiveRoomController controller;
@override
State<SuperChatPanel> createState() => _SuperChatPanelState();
}
class _SuperChatPanelState extends DebounceStreamState<SuperChatPanel, bool> {
@override
Duration get duration => const Duration(milliseconds: 300);
@override
Widget build(BuildContext context) {
return Obx(
() => ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 12),
physics: const ClampingScrollPhysics(),
itemCount: widget.controller.superChatMsg.length,
itemBuilder: (context, index) {
final item = widget.controller.superChatMsg[index];
return SuperChatCard(
key: Key(item.id.toString()),
item: item,
onRemove: () => ctr?.add(true),
);
},
separatorBuilder: (_, _) => const SizedBox(height: 12),
),
);
}
@override
void onValueChanged(value) => widget.controller.clearSC();
}