Browse Source
feat(live): 添加礼物产品功能并实现直播间结束页面
feat(live): 添加礼物产品功能并实现直播间结束页面
- 新增礼物产品模型 GiftProductModel - 在 RoomController 中集成礼物产品列表加载逻辑 - 实现直播间结束页面 LiveEndPage - 添加获取礼物产品列表的 API 接口 - 更新网络服务以支持礼物产品相关请求ios
6 changed files with 343 additions and 0 deletions
Unified View
Diff Options
-
22lib/controller/discover/room_controller.dart
-
66lib/model/live/gift_product_model.dart
-
2lib/network/api_urls.dart
-
5lib/network/rtc_api.dart
-
41lib/network/rtc_api.g.dart
-
207lib/pages/discover/live_end_page.dart
@ -0,0 +1,66 @@ |
|||||
|
/// 礼物产品模型 |
||||
|
class GiftProductModel { |
||||
|
final String productId; |
||||
|
final String productSpecId; |
||||
|
final int mainCategory; |
||||
|
final int subCategory; |
||||
|
final String productTitle; |
||||
|
final String productDesc; |
||||
|
final String? detailDesc; |
||||
|
final double unitOriginalPrice; |
||||
|
final double unitSellingPrice; |
||||
|
final String mainPic; |
||||
|
final String svgaFile; |
||||
|
|
||||
|
GiftProductModel({ |
||||
|
required this.productId, |
||||
|
required this.productSpecId, |
||||
|
required this.mainCategory, |
||||
|
required this.subCategory, |
||||
|
required this.productTitle, |
||||
|
required this.productDesc, |
||||
|
this.detailDesc, |
||||
|
required this.unitOriginalPrice, |
||||
|
required this.unitSellingPrice, |
||||
|
required this.mainPic, |
||||
|
required this.svgaFile, |
||||
|
}); |
||||
|
|
||||
|
factory GiftProductModel.fromJson(Map<String, dynamic> json) { |
||||
|
return GiftProductModel( |
||||
|
productId: json['productId']?.toString() ?? '', |
||||
|
productSpecId: json['productSpecId']?.toString() ?? '', |
||||
|
mainCategory: json['mainCategory'] as int? ?? 0, |
||||
|
subCategory: json['subCategory'] as int? ?? 0, |
||||
|
productTitle: json['productTitle']?.toString() ?? '', |
||||
|
productDesc: json['productDesc']?.toString() ?? '', |
||||
|
detailDesc: json['detailDesc']?.toString(), |
||||
|
unitOriginalPrice: (json['unitOriginalPrice'] as num?)?.toDouble() ?? 0.0, |
||||
|
unitSellingPrice: (json['unitSellingPrice'] as num?)?.toDouble() ?? 0.0, |
||||
|
mainPic: json['mainPic']?.toString() ?? '', |
||||
|
svgaFile: json['svgaFile']?.toString() ?? '', |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'productId': productId, |
||||
|
'productSpecId': productSpecId, |
||||
|
'mainCategory': mainCategory, |
||||
|
'subCategory': subCategory, |
||||
|
'productTitle': productTitle, |
||||
|
'productDesc': productDesc, |
||||
|
'detailDesc': detailDesc, |
||||
|
'unitOriginalPrice': unitOriginalPrice, |
||||
|
'unitSellingPrice': unitSellingPrice, |
||||
|
'mainPic': mainPic, |
||||
|
'svgaFile': svgaFile, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
String toString() { |
||||
|
return 'GiftProductModel(productId: $productId, productTitle: $productTitle, unitSellingPrice: $unitSellingPrice)'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,207 @@ |
|||||
|
import 'package:cached_network_image/cached_network_image.dart'; |
||||
|
import 'package:dating_touchme_app/controller/discover/room_controller.dart'; |
||||
|
import 'package:dating_touchme_app/extension/ex_widget.dart'; |
||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:dating_touchme_app/pages/main/main_page.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
|
||||
|
class LiveEndPage extends StatelessWidget { |
||||
|
const LiveEndPage({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final roomController = Get.find<RoomController>(); |
||||
|
final anchorInfo = roomController.rtcChannelDetail.value?.anchorInfo; |
||||
|
|
||||
|
return Scaffold( |
||||
|
body: Container( |
||||
|
decoration: BoxDecoration( |
||||
|
gradient: LinearGradient( |
||||
|
begin: Alignment.topCenter, |
||||
|
end: Alignment.bottomCenter, |
||||
|
colors: [ |
||||
|
const Color.fromRGBO(19, 16, 47, 1), |
||||
|
const Color.fromRGBO(19, 16, 47, 1).withOpacity(0.8), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: SafeArea( |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
// 顶部返回按钮 |
||||
|
Padding( |
||||
|
padding: EdgeInsets.only(left: 16.w, top: 10.w), |
||||
|
child: Align( |
||||
|
alignment: Alignment.centerLeft, |
||||
|
child: IconButton( |
||||
|
icon: Icon( |
||||
|
Icons.arrow_back_ios, |
||||
|
color: Colors.white, |
||||
|
size: 20.w, |
||||
|
), |
||||
|
onPressed: () { |
||||
|
Get.back(); |
||||
|
}, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
// 主要内容区域 |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
// 头像 |
||||
|
Container( |
||||
|
width: 120.w, |
||||
|
height: 120.w, |
||||
|
decoration: BoxDecoration( |
||||
|
shape: BoxShape.circle, |
||||
|
border: Border.all( |
||||
|
color: Colors.white.withOpacity(0.3), |
||||
|
width: 2.w, |
||||
|
), |
||||
|
), |
||||
|
child: ClipOval( |
||||
|
child: anchorInfo?.profilePhoto != null && |
||||
|
anchorInfo!.profilePhoto.isNotEmpty |
||||
|
? CachedNetworkImage( |
||||
|
imageUrl: |
||||
|
"${anchorInfo.profilePhoto}?x-oss-process=image/format,webp/resize,w_240", |
||||
|
width: 120.w, |
||||
|
height: 120.w, |
||||
|
fit: BoxFit.cover, |
||||
|
placeholder: (context, url) => Container( |
||||
|
color: Colors.grey.withOpacity(0.3), |
||||
|
child: Center( |
||||
|
child: CircularProgressIndicator( |
||||
|
strokeWidth: 2.w, |
||||
|
color: Colors.white.withOpacity(0.5), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
errorWidget: (context, url, error) => |
||||
|
Image.asset( |
||||
|
Assets.imagesUserAvatar, |
||||
|
width: 120.w, |
||||
|
height: 120.w, |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
) |
||||
|
: Image.asset( |
||||
|
Assets.imagesUserAvatar, |
||||
|
width: 120.w, |
||||
|
height: 120.w, |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 20.w), |
||||
|
// 用户名和关注按钮 |
||||
|
Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||
|
children: [ |
||||
|
Text( |
||||
|
anchorInfo?.nickName ?? '用户', |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.w, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
// 关注按钮 |
||||
|
Container( |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
horizontal: 16.w, |
||||
|
vertical: 6.w, |
||||
|
), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(20.w), |
||||
|
border: Border.all( |
||||
|
color: Colors.white, |
||||
|
width: 1.w, |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
'关注', |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.w, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
).onTap(() { |
||||
|
// TODO: 实现关注功能 |
||||
|
print('点击关注'); |
||||
|
}), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 60.w), |
||||
|
// 状态消息(带横线) |
||||
|
Row( |
||||
|
children: [ |
||||
|
Expanded( |
||||
|
child: Container( |
||||
|
height: 1.w, |
||||
|
color: Colors.white.withOpacity(0.3), |
||||
|
), |
||||
|
), |
||||
|
Padding( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w), |
||||
|
child: Text( |
||||
|
'当前相亲已结束', |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.w, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Expanded( |
||||
|
child: Container( |
||||
|
height: 1.w, |
||||
|
color: Colors.white.withOpacity(0.3), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
// 底部返回首页按钮 |
||||
|
Padding( |
||||
|
padding: EdgeInsets.only( |
||||
|
left: 20.w, |
||||
|
right: 20.w, |
||||
|
bottom: 40.w + MediaQuery.of(context).padding.bottom, |
||||
|
), |
||||
|
child: Container( |
||||
|
width: double.infinity, |
||||
|
height: 50.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(25.w), |
||||
|
color: const Color.fromRGBO(108, 105, 244, 1), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
'返回首页', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.w, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
).onTap(() { |
||||
|
Get.offAll(() => const MainPage()); |
||||
|
}), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save