11 changed files with 987 additions and 527 deletions
Split View
Diff Options
-
384lib/controller/discover/room_controller.dart
-
116lib/model/discover/task_data.dart
-
3lib/network/api_urls.dart
-
6lib/network/user_api.dart
-
33lib/network/user_api.g.dart
-
81lib/widget/live/audience_item.dart
-
43lib/widget/live/disconnect_mic_dialog.dart
-
189lib/widget/live/kick_list.dart
-
313lib/widget/live/live_room_invitation_list.dart
-
181lib/widget/live/live_room_notice_chat_panel.dart
-
165lib/widget/live/live_room_user_header.dart
@ -0,0 +1,116 @@ |
|||
class TaskData { |
|||
String? userTaskCompleteId; |
|||
int? taskGroup; |
|||
int? taskType; |
|||
int? stageCode; |
|||
String? taskName; |
|||
String? taskDesc; |
|||
String? taskStartDate; |
|||
String? taskEndDate; |
|||
String? rewardValue; |
|||
bool? completeStatus; |
|||
int? rewardReceiveStatus; |
|||
String? completeTime; |
|||
List<SubList>? subList; |
|||
|
|||
TaskData( |
|||
{this.userTaskCompleteId, |
|||
this.taskGroup, |
|||
this.taskType, |
|||
this.stageCode, |
|||
this.taskName, |
|||
this.taskDesc, |
|||
this.taskStartDate, |
|||
this.taskEndDate, |
|||
this.rewardValue, |
|||
this.completeStatus, |
|||
this.rewardReceiveStatus, |
|||
this.completeTime, |
|||
this.subList}); |
|||
|
|||
TaskData.fromJson(Map<String, dynamic> json) { |
|||
userTaskCompleteId = json['userTaskCompleteId']; |
|||
taskGroup = json['taskGroup']; |
|||
taskType = json['taskType']; |
|||
stageCode = json['stageCode']; |
|||
taskName = json['taskName']; |
|||
taskDesc = json['taskDesc']; |
|||
taskStartDate = json['taskStartDate']; |
|||
taskEndDate = json['taskEndDate']; |
|||
rewardValue = json['rewardValue']; |
|||
completeStatus = json['completeStatus']; |
|||
rewardReceiveStatus = json['rewardReceiveStatus']; |
|||
completeTime = json['completeTime']; |
|||
if (json['subList'] != null) { |
|||
subList = <SubList>[]; |
|||
json['subList'].forEach((v) { |
|||
subList!.add(new SubList.fromJson(v)); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
data['userTaskCompleteId'] = this.userTaskCompleteId; |
|||
data['taskGroup'] = this.taskGroup; |
|||
data['taskType'] = this.taskType; |
|||
data['stageCode'] = this.stageCode; |
|||
data['taskName'] = this.taskName; |
|||
data['taskDesc'] = this.taskDesc; |
|||
data['taskStartDate'] = this.taskStartDate; |
|||
data['taskEndDate'] = this.taskEndDate; |
|||
data['rewardValue'] = this.rewardValue; |
|||
data['completeStatus'] = this.completeStatus; |
|||
data['rewardReceiveStatus'] = this.rewardReceiveStatus; |
|||
data['completeTime'] = this.completeTime; |
|||
if (this.subList != null) { |
|||
data['subList'] = this.subList!.map((v) => v.toJson()).toList(); |
|||
} |
|||
return data; |
|||
} |
|||
} |
|||
|
|||
class SubList { |
|||
String? subTaskName; |
|||
int? subTaskType; |
|||
String? subTaskDesc; |
|||
int? requiredCount; |
|||
int? completeCount; |
|||
bool? completeStatus; |
|||
String? completeTime; |
|||
int? sort; |
|||
|
|||
SubList( |
|||
{this.subTaskName, |
|||
this.subTaskType, |
|||
this.subTaskDesc, |
|||
this.requiredCount, |
|||
this.completeCount, |
|||
this.completeStatus, |
|||
this.completeTime, |
|||
this.sort}); |
|||
|
|||
SubList.fromJson(Map<String, dynamic> json) { |
|||
subTaskName = json['subTaskName']; |
|||
subTaskType = json['subTaskType']; |
|||
subTaskDesc = json['subTaskDesc']; |
|||
requiredCount = json['requiredCount']; |
|||
completeCount = json['completeCount']; |
|||
completeStatus = json['completeStatus']; |
|||
completeTime = json['completeTime']; |
|||
sort = json['sort']; |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
data['subTaskName'] = this.subTaskName; |
|||
data['subTaskType'] = this.subTaskType; |
|||
data['subTaskDesc'] = this.subTaskDesc; |
|||
data['requiredCount'] = this.requiredCount; |
|||
data['completeCount'] = this.completeCount; |
|||
data['completeStatus'] = this.completeStatus; |
|||
data['completeTime'] = this.completeTime; |
|||
data['sort'] = this.sort; |
|||
return data; |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
|
|||
|
|||
import 'package:cached_network_image/cached_network_image.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|||
|
|||
import '../../model/discover/audience_list_data.dart'; |
|||
|
|||
class AudienceItem extends StatefulWidget { |
|||
final Records item; |
|||
final List<String> selectUserId; |
|||
final Function(String) selectChange; |
|||
const AudienceItem({super.key, required this.item, required this.selectUserId, required this.selectChange}); |
|||
|
|||
@override |
|||
State<AudienceItem> createState() => _AudienceItemState(); |
|||
} |
|||
|
|||
class _AudienceItemState extends State<AudienceItem> { |
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Container( |
|||
margin: EdgeInsets.symmetric(vertical: 10.w), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Row( |
|||
children: [ |
|||
ClipRRect( |
|||
borderRadius: BorderRadius.all(Radius.circular(40.w)), |
|||
child: CachedNetworkImage( |
|||
imageUrl: "${widget.item.profilePhoto ?? ""}?x-oss-process=image/format,webp/resize,w_120", |
|||
|
|||
width: 40.w, |
|||
height: 40.w, |
|||
imageBuilder: (context, imageProvider) => Container( |
|||
decoration: BoxDecoration( |
|||
image: DecorationImage( |
|||
image: imageProvider, |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
), |
|||
), |
|||
), |
|||
SizedBox(width: 5.w,), |
|||
Column( |
|||
children: [ |
|||
Text( |
|||
widget.item.nickName ?? "", |
|||
style: TextStyle( |
|||
fontSize: 12.w |
|||
), |
|||
), |
|||
Text( |
|||
"${widget.item.age ?? ""}岁", |
|||
style: TextStyle( |
|||
fontSize: 12.w, |
|||
color: const Color.fromRGBO(121, 121, 121, 1) |
|||
), |
|||
), |
|||
], |
|||
) |
|||
], |
|||
), |
|||
|
|||
Checkbox( |
|||
value: widget.selectUserId.contains(widget.item.userId), |
|||
onChanged: (value) { |
|||
widget.selectChange(widget.item.userId ?? ""); |
|||
}, |
|||
activeColor: const Color.fromRGBO(117, 98, 249, 1), |
|||
side: const BorderSide(color: Colors.grey), |
|||
shape: const CircleBorder(), |
|||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,189 @@ |
|||
import 'package:dating_touchme_app/controller/discover/room_controller.dart'; |
|||
import 'package:dating_touchme_app/extension/ex_widget.dart'; |
|||
import 'package:easy_refresh/easy_refresh.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
import 'audience_item.dart'; |
|||
|
|||
class KickList extends StatefulWidget { |
|||
const KickList({super.key}); |
|||
|
|||
@override |
|||
State<KickList> createState() => _KickListState(); |
|||
} |
|||
|
|||
class _KickListState extends State<KickList> { |
|||
|
|||
final RoomController _roomController = Get.find<RoomController>(); |
|||
|
|||
|
|||
|
|||
List<String> selectUserId = []; |
|||
|
|||
selectChange(String userId){ |
|||
if (selectUserId.contains(userId)) { |
|||
selectUserId.remove(userId); |
|||
} else { |
|||
selectUserId.add(userId); |
|||
} |
|||
setState(() { |
|||
|
|||
}); |
|||
} |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Material( |
|||
borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), |
|||
color: Colors.white, |
|||
child: Container( |
|||
width: 375.w, |
|||
height: 300.w, |
|||
padding: EdgeInsets.all(10.w), |
|||
child: Column( |
|||
children: [ |
|||
Text( |
|||
"在线用户", |
|||
style: TextStyle( |
|||
fontSize: 16.w, |
|||
fontWeight: FontWeight.w700 |
|||
), |
|||
), |
|||
Expanded( |
|||
child: EasyRefresh( |
|||
|
|||
controller: _roomController.listRefreshController, |
|||
header: const ClassicHeader( |
|||
dragText: '下拉刷新', |
|||
armedText: '释放刷新', |
|||
readyText: '刷新中...', |
|||
processingText: '刷新中...', |
|||
processedText: '刷新完成', |
|||
failedText: '刷新失败', |
|||
noMoreText: '没有更多数据', |
|||
showMessage: false |
|||
), |
|||
footer: ClassicFooter( |
|||
dragText: '上拉加载', |
|||
armedText: '释放加载', |
|||
readyText: '加载中...', |
|||
processingText: '加载中...', |
|||
processedText: '加载完成', |
|||
failedText: '加载失败', |
|||
noMoreText: '没有更多数据', |
|||
showMessage: false |
|||
), |
|||
// 下拉刷新 |
|||
onRefresh: () async { |
|||
print('推荐列表下拉刷新被触发'); |
|||
_roomController.page.value = 1; |
|||
_roomController.audienceList.clear(); |
|||
await _roomController.getAudienceList(); |
|||
_roomController.listRefreshController.finishRefresh(IndicatorResult.success); |
|||
_roomController.listRefreshController.finishLoad(IndicatorResult.none); |
|||
}, |
|||
// 上拉加载更多 |
|||
onLoad: () async { |
|||
print('推荐列表上拉加载被触发, hasMore: '); |
|||
_roomController.page.value += 1; |
|||
await _roomController.getAudienceList(); |
|||
}, |
|||
child: ListView.separated( |
|||
// 关键:始终允许滚动,即使内容不足 |
|||
// 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 |
|||
padding: EdgeInsets.only(left: 12, right: 12), |
|||
itemBuilder: (context, index) { |
|||
// 空数据状态 |
|||
if (_roomController.audienceList.isEmpty && index == 0) { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
Text('暂无数据'), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
// 数据项 |
|||
final item = _roomController.audienceList[index]; |
|||
return AudienceItem(item: item, selectUserId: selectUserId, selectChange: selectChange,); |
|||
}, |
|||
separatorBuilder: (context, index) { |
|||
// 空状态或加载状态时不显示分隔符 |
|||
if (_roomController.audienceList.isEmpty) { |
|||
return const SizedBox.shrink(); |
|||
} |
|||
return const SizedBox(height: 12); |
|||
}, |
|||
// 至少显示一个 item(用于显示加载或空状态) |
|||
itemCount: _roomController.audienceList.isEmpty ? 1 : _roomController.audienceList.length, |
|||
), |
|||
), |
|||
), |
|||
Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Container( |
|||
width: 170.w, |
|||
height: 42.w, |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.all(Radius.circular(42.w)), |
|||
color: const Color.fromRGBO(237, 237, 237, 1) |
|||
), |
|||
child: Center( |
|||
child: Text( |
|||
"取消", |
|||
style: TextStyle( |
|||
fontSize: 14.w, |
|||
fontWeight: FontWeight.w500 |
|||
), |
|||
), |
|||
), |
|||
).onTap((){ |
|||
// 隐藏键盘 |
|||
FocusScope.of(context).unfocus(); |
|||
// 隐藏 overlay |
|||
SmartDialog.dismiss(); |
|||
_roomController.setDialogDismiss(false); |
|||
}), |
|||
Container( |
|||
width: 170.w, |
|||
height: 42.w, |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.all(Radius.circular(42.w)), |
|||
color: const Color.fromRGBO(117, 98, 249, 1) |
|||
), |
|||
child: Center( |
|||
child: Text( |
|||
"确认", |
|||
style: TextStyle( |
|||
fontSize: 14.w, |
|||
color: Colors.white, |
|||
fontWeight: FontWeight.w500 |
|||
), |
|||
), |
|||
), |
|||
).onTap(() async { |
|||
final selectedA = _roomController.audienceList.where((item) => selectUserId.contains(item.userId)).toList(); |
|||
final List<String> dList = |
|||
selectedA.map((item) => item.userManagementId.toString()).toList(); |
|||
await _roomController.kickUser(dList); |
|||
|
|||
// 隐藏键盘 |
|||
FocusScope.of(context).unfocus(); |
|||
// 隐藏 overlay |
|||
SmartDialog.dismiss(); |
|||
_roomController.setDialogDismiss(false); |
|||
selectUserId.clear(); |
|||
}) |
|||
], |
|||
) |
|||
], |
|||
), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save