Browse Source
feat(live): 添加直播间相关组件- 新增礼物弹窗组件 (LiveGiftPopup),支持礼物选择与数量调整
feat(live): 添加直播间相关组件- 新增礼物弹窗组件 (LiveGiftPopup),支持礼物选择与数量调整
- 新增充值弹窗组件 (LiveRechargePopup),包含支付选项与协议确认- 新增直播间底部操作栏 (LiveRoomActionBar),集成聊天输入与功能按钮- 新增活跃用户展示组件 (LiveRoomActiveSpeaker) - 新增主播展示区组件 (LiveRoomAnchorShowcase),包含主持与侧边主播卡片 - 新增聊天消息项组件 (LiveRoomChatItem) - 新增礼物选项组件 (LiveRoomGiftItem),支持选中状态 - 新增公告与聊天面板组件 (LiveRoomNoticeChatPanel) - 新增充值选项组件 (LiveRoomPayItem),支持标签与选中状态 - 新增座位列表组件 (LiveRoomSeatList),展示用户座位与麦克风状态 - 新增直播间顶部用户信息组件 (LiveRoomUserHeader),包含关注与关闭功能ios
12 changed files with 1559 additions and 1853 deletions
Unified View
Diff Options
-
1912lib/pages/discover/live_room_page.dart
-
326lib/widget/live/live_gift_popup.dart
-
227lib/widget/live/live_recharge_popup.dart
-
121lib/widget/live/live_room_action_bar.dart
-
54lib/widget/live/live_room_active_speaker.dart
-
195lib/widget/live/live_room_anchor_showcase.dart
-
44lib/widget/live/live_room_chat_item.dart
-
72lib/widget/live/live_room_gift_item.dart
-
53lib/widget/live/live_room_notice_chat_panel.dart
-
152lib/widget/live/live_room_pay_item.dart
-
128lib/widget/live/live_room_seat_list.dart
-
128lib/widget/live/live_room_user_header.dart
1912
lib/pages/discover/live_room_page.dart
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,326 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:dating_touchme_app/widget/live/live_room_gift_item.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart'; |
||||
|
import 'package:tdesign_flutter/tdesign_flutter.dart'; |
||||
|
|
||||
|
class LiveGiftPopup extends StatelessWidget { |
||||
|
const LiveGiftPopup({ |
||||
|
super.key, |
||||
|
required this.activeGift, |
||||
|
required this.giftNum, |
||||
|
required this.giftList, |
||||
|
required this.changeActive, |
||||
|
}); |
||||
|
|
||||
|
final ValueNotifier<int?> activeGift; |
||||
|
final ValueNotifier<int> giftNum; |
||||
|
final List<Map> giftList; |
||||
|
final void Function(int) changeActive; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Material( |
||||
|
color: Colors.transparent, |
||||
|
child: Container( |
||||
|
color: const Color.fromRGBO(41, 31, 61, 1), |
||||
|
height: 363.w, |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
_buildHeader(), |
||||
|
Expanded( |
||||
|
child: Container( |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), |
||||
|
color: const Color.fromRGBO(22, 19, 28, 1), |
||||
|
), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
_buildTab(), |
||||
|
_buildGiftSwiper(), |
||||
|
_buildBottomBar(), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildHeader() { |
||||
|
return Container( |
||||
|
height: 53.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"送给: ", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
SizedBox(width: 6.w), |
||||
|
...List.generate(3, (index) { |
||||
|
return Padding( |
||||
|
padding: EdgeInsets.only(right: 10.w), |
||||
|
child: Stack( |
||||
|
children: [ |
||||
|
ClipRRect( |
||||
|
borderRadius: BorderRadius.all( |
||||
|
Radius.circular(index == 0 ? 68.w : 34.w), |
||||
|
), |
||||
|
child: Container( |
||||
|
width: 34.w, |
||||
|
height: 34.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all( |
||||
|
Radius.circular(index == 0 ? 68.w : 34.w), |
||||
|
), |
||||
|
border: Border.all( |
||||
|
width: index == 0 ? 2 : 1, |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
), |
||||
|
child: Image.asset( |
||||
|
Assets.imagesUserAvatar, |
||||
|
width: 32.w, |
||||
|
height: 32.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: 0, |
||||
|
right: 2.w, |
||||
|
child: Container( |
||||
|
width: 12.w, |
||||
|
height: 12.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(12.w)), |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesCheck, |
||||
|
width: 6.w, |
||||
|
height: 4.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}), |
||||
|
], |
||||
|
), |
||||
|
Container( |
||||
|
width: 63.w, |
||||
|
height: 30.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(30.w)), |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"全选", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildTab() { |
||||
|
return Container( |
||||
|
height: 47.w, |
||||
|
padding: EdgeInsets.only(left: 29.w), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"互动", |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 40.w), |
||||
|
Text( |
||||
|
"礼物", |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w700, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildGiftSwiper() { |
||||
|
return Expanded( |
||||
|
child: ValueListenableBuilder<int?>( |
||||
|
valueListenable: activeGift, |
||||
|
builder: (context, active, _) { |
||||
|
return Swiper( |
||||
|
autoplay: false, |
||||
|
itemCount: 6, |
||||
|
loop: true, |
||||
|
pagination: const SwiperPagination( |
||||
|
alignment: Alignment.bottomCenter, |
||||
|
builder: TDSwiperDotsPagination( |
||||
|
color: Color.fromRGBO(144, 144, 144, 1), |
||||
|
activeColor: Color.fromRGBO(77, 77, 77, 1), |
||||
|
), |
||||
|
), |
||||
|
itemBuilder: (context, index) { |
||||
|
return Align( |
||||
|
alignment: Alignment.topCenter, |
||||
|
child: Wrap( |
||||
|
children: [ |
||||
|
...giftList.asMap().entries.map( |
||||
|
(entry) => LiveRoomGiftItem( |
||||
|
item: entry.value, |
||||
|
active: active ?? 0, |
||||
|
index: entry.key, |
||||
|
changeActive: changeActive, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildBottomBar() { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Row( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesRoseGift, |
||||
|
width: 21.w, |
||||
|
height: 21.w, |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
Text( |
||||
|
"9", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Image.asset( |
||||
|
Assets.imagesRoseGift, |
||||
|
width: 68.w, |
||||
|
height: 33.w, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
ValueListenableBuilder<int>( |
||||
|
valueListenable: giftNum, |
||||
|
builder: (context, num, _) { |
||||
|
return Row( |
||||
|
children: [ |
||||
|
_buildAdjustButton( |
||||
|
label: "-", |
||||
|
enabled: num > 1, |
||||
|
onTap: () { |
||||
|
if (giftNum.value <= 1) return; |
||||
|
giftNum.value -= 1; |
||||
|
}, |
||||
|
), |
||||
|
SizedBox( |
||||
|
width: 23.w, |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"$num", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
_buildAdjustButton( |
||||
|
label: "+", |
||||
|
enabled: true, |
||||
|
onTap: () { |
||||
|
giftNum.value += 1; |
||||
|
}, |
||||
|
), |
||||
|
SizedBox(width: 9.w), |
||||
|
Container( |
||||
|
width: 63.w, |
||||
|
height: 30.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(30.w)), |
||||
|
gradient: const LinearGradient( |
||||
|
begin: Alignment.centerLeft, |
||||
|
end: Alignment.centerRight, |
||||
|
colors: [ |
||||
|
Color.fromRGBO(61, 138, 224, 1), |
||||
|
Color.fromRGBO(131, 89, 255, 1), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"赠送", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildAdjustButton({ |
||||
|
required String label, |
||||
|
required bool enabled, |
||||
|
required VoidCallback onTap, |
||||
|
}) { |
||||
|
return InkWell( |
||||
|
onTap: enabled ? onTap : null, |
||||
|
child: Container( |
||||
|
width: 14.w, |
||||
|
height: 14.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(14.w)), |
||||
|
color: enabled |
||||
|
? const Color.fromRGBO(117, 98, 249, 1) |
||||
|
: Colors.transparent, |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
label, |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: enabled |
||||
|
? Colors.white |
||||
|
: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
height: 1, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,227 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:dating_touchme_app/widget/live/live_room_pay_item.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRechargePopup extends StatelessWidget { |
||||
|
const LiveRechargePopup({ |
||||
|
super.key, |
||||
|
required this.activePay, |
||||
|
required this.payChecked, |
||||
|
required this.payList, |
||||
|
required this.changePayActive, |
||||
|
}); |
||||
|
|
||||
|
final ValueNotifier<int?> activePay; |
||||
|
final ValueNotifier<bool> payChecked; |
||||
|
final List<Map> payList; |
||||
|
final void Function(int) changePayActive; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Material( |
||||
|
color: Colors.transparent, |
||||
|
child: Container( |
||||
|
color: Colors.white, |
||||
|
height: 440.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
_buildHeader(context), |
||||
|
_buildBalanceInfo(), |
||||
|
_buildPayOptions(), |
||||
|
_buildAgreementRow(), |
||||
|
SizedBox(height: 23.w), |
||||
|
_buildSubmitButton(), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildHeader(BuildContext context) { |
||||
|
return Container( |
||||
|
height: 48.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
InkWell( |
||||
|
onTap: () => Navigator.maybePop(context), |
||||
|
child: Icon( |
||||
|
Icons.close, |
||||
|
size: 14.w, |
||||
|
color: const Color.fromRGBO(114, 114, 114, 1), |
||||
|
), |
||||
|
), |
||||
|
Text( |
||||
|
"玫瑰充值", |
||||
|
style: TextStyle( |
||||
|
fontSize: 17.w, |
||||
|
color: const Color.fromRGBO(51, 51, 51, 1), |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
Icon( |
||||
|
Icons.close, |
||||
|
size: 14.w, |
||||
|
color: Colors.transparent, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildBalanceInfo() { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w), |
||||
|
margin: EdgeInsets.only(bottom: 15.w), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"余额:9玫瑰", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildPayOptions() { |
||||
|
return ValueListenableBuilder<int?>( |
||||
|
valueListenable: activePay, |
||||
|
builder: (context, active, _) { |
||||
|
return Wrap( |
||||
|
spacing: 7.w, |
||||
|
runSpacing: 7.w, |
||||
|
children: [ |
||||
|
...payList.asMap().entries.map( |
||||
|
(entry) { |
||||
|
return LiveRoomPayItem( |
||||
|
item: entry.value, |
||||
|
active: active ?? 0, |
||||
|
index: entry.key, |
||||
|
changeActive: changePayActive, |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildAgreementRow() { |
||||
|
return Padding( |
||||
|
padding: EdgeInsets.only(top: 10.w, bottom: 15.w), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Container( |
||||
|
height: 1, |
||||
|
color: const Color.fromRGBO(219, 219, 219, 1), |
||||
|
), |
||||
|
SizedBox(height: 15.w), |
||||
|
Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Row( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesAliPay, |
||||
|
width: 17.w, |
||||
|
height: 17.w, |
||||
|
), |
||||
|
SizedBox(width: 6.w), |
||||
|
Text( |
||||
|
"支付宝支付", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(51, 51, 51, 1), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
ValueListenableBuilder<bool>( |
||||
|
valueListenable: payChecked, |
||||
|
builder: (context, checked, _) { |
||||
|
return GestureDetector( |
||||
|
onTap: () => payChecked.value = !payChecked.value, |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 14.w, |
||||
|
height: 14.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(2.w)), |
||||
|
color: checked |
||||
|
? const Color.fromRGBO(239, 19, 46, 1) |
||||
|
: Colors.white, |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: checked |
||||
|
? const Color.fromRGBO(239, 19, 46, 1) |
||||
|
: const Color.fromRGBO(188, 188, 188, 1), |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesCheck, |
||||
|
width: 6.w, |
||||
|
height: 4.w, |
||||
|
color: checked ? Colors.white : Colors.transparent, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 6.w), |
||||
|
Text( |
||||
|
"我已阅读并同意《充值协议》", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildSubmitButton() { |
||||
|
return Container( |
||||
|
width: double.infinity, |
||||
|
height: 44.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(44.w)), |
||||
|
gradient: const LinearGradient( |
||||
|
begin: Alignment.centerLeft, |
||||
|
end: Alignment.centerRight, |
||||
|
colors: [ |
||||
|
Color.fromRGBO(239, 19, 46, 1), |
||||
|
Color.fromRGBO(255, 183, 22, 1), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"立即充值", |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,121 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomActionBar extends StatelessWidget { |
||||
|
const LiveRoomActionBar({ |
||||
|
super.key, |
||||
|
required this.messageController, |
||||
|
required this.onMessageChanged, |
||||
|
required this.onGiftTap, |
||||
|
required this.onChargeTap, |
||||
|
}); |
||||
|
|
||||
|
final TextEditingController messageController; |
||||
|
final ValueChanged<String> onMessageChanged; |
||||
|
final VoidCallback onGiftTap; |
||||
|
final VoidCallback onChargeTap; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
margin: EdgeInsets.only(left: 16.w), |
||||
|
child: InkWell( |
||||
|
onTap: onGiftTap, |
||||
|
child: Container( |
||||
|
width: 38.w, |
||||
|
height: 38.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(38.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesGiftIcon, |
||||
|
width: 28.w, |
||||
|
height: 28.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 9.w), |
||||
|
Expanded( |
||||
|
child: Container( |
||||
|
height: 38.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(38.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: TextField( |
||||
|
controller: messageController, |
||||
|
keyboardType: TextInputType.number, |
||||
|
style: TextStyle( |
||||
|
fontSize: ScreenUtil().setWidth(14), |
||||
|
height: 1, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
decoration: InputDecoration( |
||||
|
contentPadding: EdgeInsets.symmetric( |
||||
|
vertical: 0, |
||||
|
horizontal: 37.w, |
||||
|
), |
||||
|
hintText: "聊点什么吧~", |
||||
|
hintStyle: TextStyle( |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
), |
||||
|
border: InputBorder.none, |
||||
|
), |
||||
|
onChanged: onMessageChanged, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
Container( |
||||
|
width: 38.w, |
||||
|
height: 38.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(38.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesArrowR, |
||||
|
width: 16.w, |
||||
|
height: 16.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
InkWell( |
||||
|
onTap: onChargeTap, |
||||
|
child: Container( |
||||
|
width: 38.w, |
||||
|
height: 38.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(38.w)), |
||||
|
gradient: const LinearGradient( |
||||
|
begin: Alignment.topLeft, |
||||
|
end: Alignment.bottomRight, |
||||
|
colors: [ |
||||
|
Color.fromRGBO(255, 43, 110, 1), |
||||
|
Color.fromRGBO(255, 52, 26, 1), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesRoseWhite, |
||||
|
width: 14.w, |
||||
|
height: 25.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,54 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomActiveSpeaker extends StatelessWidget { |
||||
|
const LiveRoomActiveSpeaker({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.start, |
||||
|
children: [ |
||||
|
Stack( |
||||
|
clipBehavior: Clip.none, |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 34.w, |
||||
|
height: 34.w, |
||||
|
margin: EdgeInsets.only(left: 13.w), |
||||
|
child: ClipRRect( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(34.w)), |
||||
|
child: Image.asset( |
||||
|
Assets.imagesUserAvatar, |
||||
|
width: 34.w, |
||||
|
height: 34.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: -3.w, |
||||
|
left: 20.w, |
||||
|
child: Container( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(4.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .65), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesMicClose, |
||||
|
width: 10.w, |
||||
|
height: 11.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,195 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomAnchorShowcase extends StatelessWidget { |
||||
|
const LiveRoomAnchorShowcase({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Column( |
||||
|
children: [ |
||||
|
Stack( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 177.w, |
||||
|
height: 175.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(9.w)), |
||||
|
color: const Color.fromRGBO(47, 10, 94, 1), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
top: 5.w, |
||||
|
left: 5.w, |
||||
|
child: Container( |
||||
|
width: 42.w, |
||||
|
height: 13.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(13.w)), |
||||
|
color: const Color.fromRGBO(142, 20, 186, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"主持人", |
||||
|
style: TextStyle( |
||||
|
fontSize: 9.w, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
top: 5.w, |
||||
|
right: 5.w, |
||||
|
child: Container( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(20.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesGiftIcon, |
||||
|
width: 19.w, |
||||
|
height: 19.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: 5.w, |
||||
|
right: 5.w, |
||||
|
child: Container( |
||||
|
width: 47.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(20.w)), |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"加好友", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 5.w), |
||||
|
Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
_buildSideAnchorCard( |
||||
|
isLeft: true, |
||||
|
micIcon: Assets.imagesMicClose, |
||||
|
), |
||||
|
_buildSideAnchorCard( |
||||
|
isLeft: false, |
||||
|
micIcon: Assets.imagesMicOpen, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildSideAnchorCard({ |
||||
|
required bool isLeft, |
||||
|
required String micIcon, |
||||
|
}) { |
||||
|
return Stack( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 177.w, |
||||
|
height: 175.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: isLeft |
||||
|
? BorderRadius.horizontal(left: Radius.circular(18.w)) |
||||
|
: BorderRadius.horizontal(right: Radius.circular(18.w)), |
||||
|
color: const Color.fromRGBO(47, 10, 94, 1), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
top: 5.w, |
||||
|
right: 5.w, |
||||
|
child: Container( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(20.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesGiftIcon, |
||||
|
width: 19.w, |
||||
|
height: 19.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: 5.w, |
||||
|
right: 5.w, |
||||
|
child: Container( |
||||
|
width: 47.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(20.w)), |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"加好友", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
left: 5.w, |
||||
|
bottom: 5.w, |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(4.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .65), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
micIcon, |
||||
|
width: 10.w, |
||||
|
height: 11.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 5.w), |
||||
|
Text( |
||||
|
"飞翔的企鹅", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,44 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomChatItem extends StatelessWidget { |
||||
|
const LiveRoomChatItem({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Container( |
||||
|
width: 260.w, |
||||
|
margin: EdgeInsets.only(bottom: 15.w), |
||||
|
child: Row( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Image.asset(Assets.imagesUserAvatar, width: 25.w, height: 25.w), |
||||
|
SizedBox(width: 10.w), |
||||
|
SizedBox( |
||||
|
width: 224.w, |
||||
|
child: RichText( |
||||
|
text: TextSpan( |
||||
|
children: [ |
||||
|
TextSpan( |
||||
|
text: "沙发沙发:", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(155, 138, 246, 1), |
||||
|
), |
||||
|
), |
||||
|
TextSpan( |
||||
|
text: |
||||
|
"大家好啊!大家好啊!大家好啊!大家好啊!大家好啊!大家好啊!大家好啊!大家好啊!大家好啊!", |
||||
|
style: TextStyle(fontSize: 11.w, color: Colors.white), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,72 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomGiftItem extends StatefulWidget { |
||||
|
final Map item; |
||||
|
final int active; |
||||
|
final int index; |
||||
|
final void Function(int) changeActive; |
||||
|
const LiveRoomGiftItem({ |
||||
|
super.key, |
||||
|
required this.item, |
||||
|
required this.active, |
||||
|
required this.index, |
||||
|
required this.changeActive, |
||||
|
}); |
||||
|
|
||||
|
@override |
||||
|
State<LiveRoomGiftItem> createState() => _LiveRoomGiftItemState(); |
||||
|
} |
||||
|
|
||||
|
class _LiveRoomGiftItemState extends State<LiveRoomGiftItem> { |
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return InkWell( |
||||
|
onTap: () { |
||||
|
widget.changeActive(widget.index); |
||||
|
}, |
||||
|
child: Container( |
||||
|
width: 83.w, |
||||
|
height: 94.w, |
||||
|
padding: EdgeInsets.only(top: 10.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(9.w)), |
||||
|
color: Color.fromRGBO( |
||||
|
117, |
||||
|
98, |
||||
|
249, |
||||
|
widget.active == widget.index ? .2 : 0, |
||||
|
), |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: Color.fromRGBO( |
||||
|
117, |
||||
|
98, |
||||
|
249, |
||||
|
widget.active == widget.index ? 1 : 0, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Image.asset(widget.item["icon"], width: 41.w, height: 41.w), |
||||
|
SizedBox(height: 7.w), |
||||
|
Text( |
||||
|
widget.item["title"], |
||||
|
style: TextStyle(fontSize: 11.w, color: Colors.white), |
||||
|
), |
||||
|
SizedBox(height: 1.w), |
||||
|
Text( |
||||
|
"${widget.item["price"]}支", |
||||
|
style: TextStyle( |
||||
|
fontSize: 7.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,53 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:dating_touchme_app/widget/live/live_room_chat_item.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomNoticeChatPanel extends StatelessWidget { |
||||
|
const LiveRoomNoticeChatPanel({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Container( |
||||
|
height: 230.w, |
||||
|
padding: EdgeInsets.only(left: 13.w, right: 9.w), |
||||
|
child: Row( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Expanded( |
||||
|
child: SingleChildScrollView( |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"欢迎来到直播间!严禁未成年人直播或礼物消费。严禁违法违规、低俗色情、吸烟酗酒、人身伤害等直播内容。理性消费如主播在直播中以不当方式诱导消费,请谨慎辨别。切勿私下交易,以防人身财产损失,谨防网络诈骗。", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(155, 138, 246, 1), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 15.w), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
const LiveRoomChatItem(), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 18.w), |
||||
|
Image.asset( |
||||
|
Assets.imagesAd, |
||||
|
width: 73.w, |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,152 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomPayItem extends StatefulWidget { |
||||
|
final Map item; |
||||
|
final int active; |
||||
|
final int index; |
||||
|
final void Function(int) changeActive; |
||||
|
const LiveRoomPayItem({ |
||||
|
super.key, |
||||
|
required this.item, |
||||
|
required this.active, |
||||
|
required this.index, |
||||
|
required this.changeActive, |
||||
|
}); |
||||
|
|
||||
|
@override |
||||
|
State<LiveRoomPayItem> createState() => _LiveRoomPayItemState(); |
||||
|
} |
||||
|
|
||||
|
class _LiveRoomPayItemState extends State<LiveRoomPayItem> { |
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return InkWell( |
||||
|
onTap: () { |
||||
|
widget.changeActive(widget.index); |
||||
|
}, |
||||
|
child: Stack( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 113.w, |
||||
|
height: 55.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(9.w)), |
||||
|
color: widget.active == widget.index |
||||
|
? const Color.fromRGBO(239, 19, 46, .05) |
||||
|
: const Color.fromRGBO(247, 247, 247, 1), |
||||
|
border: widget.active == widget.index |
||||
|
? Border.all( |
||||
|
width: 1, |
||||
|
color: const Color.fromRGBO(239, 19, 46, 1), |
||||
|
) |
||||
|
: null, |
||||
|
), |
||||
|
child: Column( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
RichText( |
||||
|
text: TextSpan( |
||||
|
children: [ |
||||
|
TextSpan( |
||||
|
text: "${widget.item["num"]}", |
||||
|
style: TextStyle( |
||||
|
fontSize: 17.w, |
||||
|
color: const Color.fromRGBO(51, 51, 51, 1), |
||||
|
fontWeight: FontWeight.w700, |
||||
|
), |
||||
|
), |
||||
|
TextSpan( |
||||
|
text: "玫瑰", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(51, 51, 51, 1), |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Text( |
||||
|
"${widget.item["price"]}元", |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 144), |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
if (widget.item["hasTag"]) |
||||
|
Positioned( |
||||
|
top: 0, |
||||
|
left: 0, |
||||
|
child: Container( |
||||
|
width: 53.w, |
||||
|
height: 11.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.only( |
||||
|
topLeft: Radius.circular(9.w), |
||||
|
bottomRight: Radius.circular(9.w), |
||||
|
), |
||||
|
color: widget.active == widget.index |
||||
|
? null |
||||
|
: const Color.fromRGBO(238, 24, 50, .1), |
||||
|
gradient: widget.active == widget.index |
||||
|
? LinearGradient( |
||||
|
begin: Alignment.centerLeft, |
||||
|
end: Alignment.centerRight, |
||||
|
colors: const [ |
||||
|
Color.fromRGBO(238, 24, 50, 1), |
||||
|
Color.fromRGBO(250, 101, 64, 1), |
||||
|
Color.fromRGBO(255, 131, 69, 1), |
||||
|
], |
||||
|
stops: const [0.0, 0.7216, 1.0], |
||||
|
) |
||||
|
: null, |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"送新人大礼包", |
||||
|
style: TextStyle( |
||||
|
fontSize: 6.w, |
||||
|
color: widget.active == widget.index |
||||
|
? Colors.white |
||||
|
: const Color.fromRGBO(237, 23, 50, 1), |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
if (widget.active == widget.index) |
||||
|
Positioned( |
||||
|
right: 0, |
||||
|
bottom: 0, |
||||
|
child: Container( |
||||
|
width: 17.w, |
||||
|
height: 13.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.only( |
||||
|
topLeft: Radius.circular(9.w), |
||||
|
bottomRight: Radius.circular(9.w), |
||||
|
), |
||||
|
color: const Color.fromRGBO(239, 19, 46, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesCheck, |
||||
|
width: 6.w, |
||||
|
height: 4.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,128 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class LiveRoomSeatList extends StatelessWidget { |
||||
|
const LiveRoomSeatList({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final seatLabelWidths = [ |
||||
|
23.w, |
||||
|
23.w, |
||||
|
28.w, |
||||
|
28.w, |
||||
|
28.w, |
||||
|
28.w, |
||||
|
28.w, |
||||
|
28.w, |
||||
|
]; |
||||
|
|
||||
|
return Container( |
||||
|
width: 375.w, |
||||
|
height: 55.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 6.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(9.w)), |
||||
|
gradient: LinearGradient( |
||||
|
begin: Alignment.topLeft, |
||||
|
end: Alignment.bottomRight, |
||||
|
colors: const [ |
||||
|
Color.fromRGBO(46, 19, 79, 1), |
||||
|
Color.fromRGBO(61, 67, 130, 1), |
||||
|
Color.fromRGBO(64, 23, 115, 1), |
||||
|
Color.fromRGBO(26, 28, 86, 1), |
||||
|
], |
||||
|
stops: const [0.0, 0.3153, 0.7209, 1.0], |
||||
|
), |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: const Color.fromRGBO(117, 102, 255, 1), |
||||
|
), |
||||
|
), |
||||
|
child: SingleChildScrollView( |
||||
|
scrollDirection: Axis.horizontal, |
||||
|
child: Row( |
||||
|
children: seatLabelWidths |
||||
|
.map( |
||||
|
(labelWidth) => Padding( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 7.w), |
||||
|
child: _SeatItem(labelWidth: labelWidth), |
||||
|
), |
||||
|
) |
||||
|
.toList(), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class _SeatItem extends StatelessWidget { |
||||
|
const _SeatItem({required this.labelWidth}); |
||||
|
|
||||
|
final double labelWidth; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesSeat, |
||||
|
width: 35.w, |
||||
|
height: 35.w, |
||||
|
), |
||||
|
Positioned( |
||||
|
bottom: 0, |
||||
|
left: 3.w, |
||||
|
child: Container( |
||||
|
width: labelWidth, |
||||
|
height: 12.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(4.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .65), |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Expanded( |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"1", |
||||
|
style: TextStyle( |
||||
|
fontSize: 8.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Container( |
||||
|
width: 12.w, |
||||
|
height: 12.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(12.w)), |
||||
|
gradient: const LinearGradient( |
||||
|
begin: Alignment.centerLeft, |
||||
|
end: Alignment.centerRight, |
||||
|
colors: [ |
||||
|
Color.fromRGBO(131, 89, 255, 1), |
||||
|
Color.fromRGBO(61, 138, 224, 1), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
Assets.imagesMicClose, |
||||
|
width: 6.w, |
||||
|
height: 7.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,128 @@ |
|||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
/// 直播间顶部用户信息与操作区域 |
||||
|
class LiveRoomUserHeader extends StatelessWidget { |
||||
|
const LiveRoomUserHeader({ |
||||
|
super.key, |
||||
|
required this.userName, |
||||
|
required this.popularityText, |
||||
|
this.avatarAsset = Assets.imagesUserAvatar, |
||||
|
this.fireIconAsset = Assets.imagesFireIcon, |
||||
|
this.closeIconAsset = Assets.imagesCloseArrow, |
||||
|
this.onFollowTap, |
||||
|
this.onCloseTap, |
||||
|
}); |
||||
|
|
||||
|
final String userName; |
||||
|
final String popularityText; |
||||
|
final String avatarAsset; |
||||
|
final String fireIconAsset; |
||||
|
final String closeIconAsset; |
||||
|
final VoidCallback? onFollowTap; |
||||
|
final VoidCallback? onCloseTap; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Container( |
||||
|
height: 40.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 3.w), |
||||
|
margin: EdgeInsets.only(left: 10.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(40.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .25), |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
avatarAsset, |
||||
|
width: 34.w, |
||||
|
height: 34.w, |
||||
|
), |
||||
|
SizedBox(width: 7.w), |
||||
|
Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
Text( |
||||
|
userName, |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 2.w), |
||||
|
Row( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
fireIconAsset, |
||||
|
width: 10.w, |
||||
|
height: 12.w, |
||||
|
), |
||||
|
SizedBox(width: 4.w), |
||||
|
Text( |
||||
|
popularityText, |
||||
|
style: TextStyle( |
||||
|
fontSize: 10.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(width: 15.w), |
||||
|
GestureDetector( |
||||
|
onTap: onFollowTap, |
||||
|
child: Container( |
||||
|
width: 47.w, |
||||
|
height: 27.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(27.w)), |
||||
|
color: const Color.fromRGBO(253, 43, 84, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
'关注', |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
height: 1, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
GestureDetector( |
||||
|
onTap: onCloseTap, |
||||
|
child: Container( |
||||
|
width: 30.w, |
||||
|
height: 30.w, |
||||
|
margin: EdgeInsets.only(right: 15.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(30.w)), |
||||
|
color: const Color.fromRGBO(0, 0, 0, .3), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Image.asset( |
||||
|
closeIconAsset, |
||||
|
width: 14.w, |
||||
|
height: 14.w, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save