mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-21 16:48:43 +00:00
feat: live area
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -42,10 +42,13 @@ class _SelfSizedHorizontalListState extends State<SelfSizedHorizontalList> {
|
||||
}
|
||||
if (widget.itemCount == 0) return const SizedBox.shrink();
|
||||
if (isInit) {
|
||||
return Container(
|
||||
key: infoKey,
|
||||
padding: widget.padding,
|
||||
child: widget.childBuilder(0),
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
key: infoKey,
|
||||
padding: widget.padding ?? EdgeInsets.zero,
|
||||
child: widget.childBuilder(0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -802,4 +802,7 @@ class Api {
|
||||
|
||||
static const String liveFollow =
|
||||
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/following';
|
||||
|
||||
static const String liveSecondList =
|
||||
'${HttpString.liveBaseUrl}/xlive/app-interface/v2/second/getList';
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:PiliPlus/models/live/live_room/danmu_info.dart';
|
||||
import 'package:PiliPlus/models/live/live_room/item.dart';
|
||||
import 'package:PiliPlus/models/live/live_room/room_info.dart';
|
||||
import 'package:PiliPlus/models/live/live_room/room_info_h5.dart';
|
||||
import 'package:PiliPlus/models/live/live_second_list/data.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:PiliPlus/utils/wbi_sign.dart';
|
||||
@@ -172,6 +173,7 @@ class LiveHttp {
|
||||
static Future<LoadingState<LiveIndexData>> liveFeedIndex({
|
||||
required int pn,
|
||||
required bool isLogin,
|
||||
bool? moduleSelect,
|
||||
}) async {
|
||||
final params = {
|
||||
if (isLogin) 'access_key': Accounts.main.accessKey,
|
||||
@@ -185,17 +187,16 @@ class LiveHttp {
|
||||
'fnval': '912',
|
||||
'disable_rcmd': '0',
|
||||
'https_url_req': '1',
|
||||
'login_event': isLogin ? '1' : '0',
|
||||
if (moduleSelect == true) 'module_select': '1',
|
||||
'mobi_app': 'android_hd',
|
||||
'module_select': '0',
|
||||
'network': 'wifi',
|
||||
'page': pn.toString(),
|
||||
'page': pn,
|
||||
'platform': 'android',
|
||||
if (isLogin) 'relation_page': '1',
|
||||
's_locale': 'zh_CN',
|
||||
'scale': '2',
|
||||
'statistics': Constants.statistics,
|
||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
};
|
||||
Utils.appSign(
|
||||
params,
|
||||
@@ -229,4 +230,53 @@ class LiveHttp {
|
||||
return LoadingState.error(res.data['message']);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<LoadingState<LiveSecondData>> liveSecondList({
|
||||
required int pn,
|
||||
required bool isLogin,
|
||||
required int? areaId,
|
||||
required int? parentAreaId,
|
||||
}) async {
|
||||
final params = {
|
||||
if (isLogin) 'access_key': Accounts.main.accessKey,
|
||||
'appkey': Constants.appKey,
|
||||
'actionKey': 'appkey',
|
||||
if (areaId != null) 'area_id': areaId,
|
||||
if (parentAreaId != null) 'parent_area_id': parentAreaId,
|
||||
'build': '8350200',
|
||||
'c_locale': 'zh_CN',
|
||||
'device': 'pad',
|
||||
'device_name': 'vivo',
|
||||
'device_type': '0',
|
||||
'fnval': '912',
|
||||
'disable_rcmd': '0',
|
||||
'https_url_req': '1',
|
||||
'mobi_app': 'android_hd',
|
||||
'module_select': '0',
|
||||
'network': 'wifi',
|
||||
'page': pn,
|
||||
'page_size': '20',
|
||||
'platform': 'android',
|
||||
'qn': '0',
|
||||
'tag_version': '1',
|
||||
's_locale': 'zh_CN',
|
||||
'scale': '2',
|
||||
'statistics': Constants.statistics,
|
||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
||||
};
|
||||
Utils.appSign(
|
||||
params,
|
||||
Constants.appKey,
|
||||
Constants.appSec,
|
||||
);
|
||||
var res = await Request().get(
|
||||
Api.liveSecondList,
|
||||
queryParameters: params,
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return LoadingState.success(LiveSecondData.fromJson(res.data['data']));
|
||||
} else {
|
||||
return LoadingState.error(res.data['message']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
class Avatar {
|
||||
String? cover;
|
||||
String? event;
|
||||
String? text;
|
||||
int? uid;
|
||||
String? url;
|
||||
|
||||
Avatar({this.cover, this.event, this.text, this.uid, this.url});
|
||||
|
||||
factory Avatar.fromJson(Map<String, dynamic> json) => Avatar(
|
||||
cover: json['cover'] as String?,
|
||||
event: json['event'] as String?,
|
||||
text: json['text'] as String?,
|
||||
uid: json['uid'] as int?,
|
||||
url: json['url'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'cover': cover,
|
||||
'event': event,
|
||||
'text': text,
|
||||
'uid': uid,
|
||||
'url': url,
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
class CalendarButton {
|
||||
String? text;
|
||||
String? link;
|
||||
|
||||
CalendarButton({this.text, this.link});
|
||||
|
||||
factory CalendarButton.fromJson(Map<String, dynamic> json) {
|
||||
return CalendarButton(
|
||||
text: json['text'] as String?,
|
||||
link: json['link'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'text': text,
|
||||
'link': link,
|
||||
};
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import 'card_data_item.dart';
|
||||
class CardData {
|
||||
CardDataItem? bannerV2;
|
||||
CardDataItem? myIdolV1;
|
||||
CardDataItem? areaEntranceV3;
|
||||
CardLiveItem? smallCardV1;
|
||||
|
||||
CardData({
|
||||
this.bannerV2,
|
||||
this.myIdolV1,
|
||||
this.areaEntranceV3,
|
||||
this.smallCardV1,
|
||||
});
|
||||
|
||||
@@ -20,6 +22,10 @@ class CardData {
|
||||
myIdolV1: json['my_idol_v1'] == null
|
||||
? null
|
||||
: CardDataItem.fromJson(json['my_idol_v1'] as Map<String, dynamic>),
|
||||
areaEntranceV3: json['area_entrance_v3'] == null
|
||||
? null
|
||||
: CardDataItem.fromJson(
|
||||
json['area_entrance_v3'] as Map<String, dynamic>),
|
||||
smallCardV1: json['small_card_v1'] == null
|
||||
? null
|
||||
: CardLiveItem.fromJson(
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'quality_description.dart';
|
||||
import 'watched_show.dart';
|
||||
|
||||
class CardLiveItem {
|
||||
int? id;
|
||||
int? roomid;
|
||||
int? uid;
|
||||
String? uname;
|
||||
@@ -18,35 +16,14 @@ class CardLiveItem {
|
||||
int? areaV2ParentId;
|
||||
String? liveTagName;
|
||||
int? online;
|
||||
String? playUrl;
|
||||
String? playUrlH265;
|
||||
List? acceptQuality;
|
||||
int? currentQuality;
|
||||
int? pkId;
|
||||
String? link;
|
||||
int? specialAttention;
|
||||
int? broadcastType;
|
||||
String? pendentRu;
|
||||
String? pendentRuColor;
|
||||
String? pendentRuPic;
|
||||
int? officialVerify;
|
||||
int? currentQn;
|
||||
List<QualityDescription>? qualityDescription;
|
||||
String? playUrlCard;
|
||||
int? flag;
|
||||
List<dynamic>? pendentList;
|
||||
int? p2pType;
|
||||
String? sessionId;
|
||||
int? groupId;
|
||||
WatchedShow? watchedShow;
|
||||
int? isNft;
|
||||
String? nftDmark;
|
||||
String? statusText;
|
||||
String? darkFace;
|
||||
String? trackid;
|
||||
int? tagType;
|
||||
|
||||
CardLiveItem({
|
||||
this.id,
|
||||
this.roomid,
|
||||
this.uid,
|
||||
this.uname,
|
||||
@@ -62,37 +39,16 @@ class CardLiveItem {
|
||||
this.areaV2ParentId,
|
||||
this.liveTagName,
|
||||
this.online,
|
||||
this.playUrl,
|
||||
this.playUrlH265,
|
||||
this.acceptQuality,
|
||||
this.currentQuality,
|
||||
this.pkId,
|
||||
this.link,
|
||||
this.specialAttention,
|
||||
this.broadcastType,
|
||||
this.pendentRu,
|
||||
this.pendentRuColor,
|
||||
this.pendentRuPic,
|
||||
this.officialVerify,
|
||||
this.currentQn,
|
||||
this.qualityDescription,
|
||||
this.playUrlCard,
|
||||
this.flag,
|
||||
this.pendentList,
|
||||
this.p2pType,
|
||||
this.sessionId,
|
||||
this.groupId,
|
||||
this.watchedShow,
|
||||
this.isNft,
|
||||
this.nftDmark,
|
||||
this.statusText,
|
||||
this.darkFace,
|
||||
this.trackid,
|
||||
this.tagType,
|
||||
});
|
||||
|
||||
factory CardLiveItem.fromJson(Map<String, dynamic> json) => CardLiveItem(
|
||||
id: json['id'] as int?,
|
||||
roomid: json['roomid'] as int?,
|
||||
roomid: json['roomid'] ?? json['id'],
|
||||
uid: json['uid'] as int?,
|
||||
uname: json['uname'] as String?,
|
||||
face: json['face'] as String?,
|
||||
@@ -107,37 +63,15 @@ class CardLiveItem {
|
||||
areaV2ParentId: json['area_v2_parent_id'] as int?,
|
||||
liveTagName: json['live_tag_name'] as String?,
|
||||
online: json['online'] as int?,
|
||||
playUrl: json['play_url'] as String?,
|
||||
playUrlH265: json['play_url_h265'] as String?,
|
||||
acceptQuality: json['accept_quality'],
|
||||
currentQuality: json['current_quality'] as int?,
|
||||
pkId: json['pk_id'] as int?,
|
||||
link: json['link'] as String?,
|
||||
specialAttention: json['special_attention'] as int?,
|
||||
broadcastType: json['broadcast_type'] as int?,
|
||||
pendentRu: json['pendent_ru'] as String?,
|
||||
pendentRuColor: json['pendent_ru_color'] as String?,
|
||||
pendentRuPic: json['pendent_ru_pic'] as String?,
|
||||
officialVerify: json['official_verify'] as int?,
|
||||
currentQn: json['current_qn'] as int?,
|
||||
qualityDescription: (json['quality_description'] as List<dynamic>?)
|
||||
?.map((e) => QualityDescription.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
playUrlCard: json['play_url_card'] as String?,
|
||||
flag: json['flag'] as int?,
|
||||
pendentList: json['pendent_list'] as List<dynamic>?,
|
||||
p2pType: json['p2p_type'] as int?,
|
||||
sessionId: json['session_id'] as String?,
|
||||
groupId: json['group_id'] as int?,
|
||||
watchedShow: json['watched_show'] == null
|
||||
? null
|
||||
: WatchedShow.fromJson(
|
||||
json['watched_show'] as Map<String, dynamic>),
|
||||
isNft: json['is_nft'] as int?,
|
||||
nftDmark: json['nft_dmark'] as String?,
|
||||
statusText: json['status_text'] as String?,
|
||||
darkFace: json['dark_face'] as String?,
|
||||
trackid: json['trackid'] as String?,
|
||||
tagType: json['tag_type'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
@@ -156,32 +90,10 @@ class CardLiveItem {
|
||||
'area_v2_parent_id': areaV2ParentId,
|
||||
'live_tag_name': liveTagName,
|
||||
'online': online,
|
||||
'play_url': playUrl,
|
||||
'play_url_h265': playUrlH265,
|
||||
'accept_quality': acceptQuality,
|
||||
'current_quality': currentQuality,
|
||||
'pk_id': pkId,
|
||||
'link': link,
|
||||
'special_attention': specialAttention,
|
||||
'broadcast_type': broadcastType,
|
||||
'pendent_ru': pendentRu,
|
||||
'pendent_ru_color': pendentRuColor,
|
||||
'pendent_ru_pic': pendentRuPic,
|
||||
'official_verify': officialVerify,
|
||||
'current_qn': currentQn,
|
||||
'quality_description':
|
||||
qualityDescription?.map((e) => e.toJson()).toList(),
|
||||
'play_url_card': playUrlCard,
|
||||
'flag': flag,
|
||||
'pendent_list': pendentList,
|
||||
'p2p_type': p2pType,
|
||||
'session_id': sessionId,
|
||||
'group_id': groupId,
|
||||
'watched_show': watchedShow?.toJson(),
|
||||
'is_nft': isNft,
|
||||
'nft_dmark': nftDmark,
|
||||
'status_text': statusText,
|
||||
'dark_face': darkFace,
|
||||
'trackid': trackid,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ class LiveIndexData {
|
||||
int? hasMore;
|
||||
int? triggerTime;
|
||||
int? isNeedRefresh;
|
||||
LiveCardList? followItem;
|
||||
LiveCardList? areaItem;
|
||||
|
||||
LiveIndexData({
|
||||
this.cardList,
|
||||
@@ -17,14 +19,22 @@ class LiveIndexData {
|
||||
|
||||
LiveIndexData.fromJson(Map<String, dynamic> json) {
|
||||
if ((json['card_list'] as List<dynamic>?)?.isNotEmpty == true) {
|
||||
cardList = <LiveCardList>[];
|
||||
// banner_v2
|
||||
// my_idol_v1
|
||||
// area_entrance_v3
|
||||
// small_card_v1
|
||||
for (var json in json['card_list']) {
|
||||
if (const ['my_idol_v1', 'small_card_v1'].contains(json['card_type'])) {
|
||||
cardList!.add(LiveCardList.fromJson(json));
|
||||
switch (json['card_type']) {
|
||||
case 'my_idol_v1':
|
||||
followItem = LiveCardList.fromJson(json);
|
||||
break;
|
||||
case 'area_entrance_v3':
|
||||
areaItem = LiveCardList.fromJson(json);
|
||||
break;
|
||||
case 'small_card_v1':
|
||||
cardList ??= <LiveCardList>[];
|
||||
cardList!.add(LiveCardList.fromJson(json));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
class InLive {
|
||||
int? alphaLight;
|
||||
int? alphaNight;
|
||||
String? animationUrl;
|
||||
String? animationUrlHash;
|
||||
String? backgroundColorLight;
|
||||
String? backgroundColorNight;
|
||||
String? fontColor;
|
||||
String? text;
|
||||
|
||||
InLive({
|
||||
this.alphaLight,
|
||||
this.alphaNight,
|
||||
this.animationUrl,
|
||||
this.animationUrlHash,
|
||||
this.backgroundColorLight,
|
||||
this.backgroundColorNight,
|
||||
this.fontColor,
|
||||
this.text,
|
||||
});
|
||||
|
||||
factory InLive.fromJson(Map<String, dynamic> json) => InLive(
|
||||
alphaLight: json['alpha_light'] as int?,
|
||||
alphaNight: json['alpha_night'] as int?,
|
||||
animationUrl: json['animation_url'] as String?,
|
||||
animationUrlHash: json['animation_url_hash'] as String?,
|
||||
backgroundColorLight: json['background_color_light'] as String?,
|
||||
backgroundColorNight: json['background_color_night'] as String?,
|
||||
fontColor: json['font_color'] as String?,
|
||||
text: json['text'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'alpha_light': alphaLight,
|
||||
'alpha_night': alphaNight,
|
||||
'animation_url': animationUrl,
|
||||
'animation_url_hash': animationUrlHash,
|
||||
'background_color_light': backgroundColorLight,
|
||||
'background_color_night': backgroundColorNight,
|
||||
'font_color': fontColor,
|
||||
'text': text,
|
||||
};
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import 'avatar.dart';
|
||||
import 'calendar_button.dart';
|
||||
import 'player_args.dart';
|
||||
import 'right_top_live_badge.dart';
|
||||
|
||||
class InlineLive {
|
||||
Avatar? avatar;
|
||||
String? cover;
|
||||
int? inlineStartDelayTime;
|
||||
int? inlineSustainDuration;
|
||||
String? link;
|
||||
PlayerArgs? playerArgs;
|
||||
dynamic rankListInfo;
|
||||
RightTopLiveBadge? rightTopLiveBadge;
|
||||
String? title;
|
||||
dynamic topViewInfo;
|
||||
String? upName;
|
||||
String? inlinePlayUrl;
|
||||
CalendarButton? calendarButton;
|
||||
|
||||
InlineLive({
|
||||
this.avatar,
|
||||
this.cover,
|
||||
this.inlineStartDelayTime,
|
||||
this.inlineSustainDuration,
|
||||
this.link,
|
||||
this.playerArgs,
|
||||
this.rankListInfo,
|
||||
this.rightTopLiveBadge,
|
||||
this.title,
|
||||
this.topViewInfo,
|
||||
this.upName,
|
||||
this.inlinePlayUrl,
|
||||
this.calendarButton,
|
||||
});
|
||||
|
||||
factory InlineLive.fromJson(Map<String, dynamic> json) => InlineLive(
|
||||
avatar: json['avatar'] == null
|
||||
? null
|
||||
: Avatar.fromJson(json['avatar'] as Map<String, dynamic>),
|
||||
cover: json['cover'] as String?,
|
||||
inlineStartDelayTime: json['inline_start_delay_time'] as int?,
|
||||
inlineSustainDuration: json['inline_sustain_duration'] as int?,
|
||||
link: json['link'] as String?,
|
||||
playerArgs: json['player_args'] == null
|
||||
? null
|
||||
: PlayerArgs.fromJson(json['player_args'] as Map<String, dynamic>),
|
||||
rankListInfo: json['rank_list_info'] as dynamic,
|
||||
rightTopLiveBadge: json['right_top_live_badge'] == null
|
||||
? null
|
||||
: RightTopLiveBadge.fromJson(json['right_top_live_badge'] as Map<String, dynamic>),
|
||||
title: json['title'] as String?,
|
||||
topViewInfo: json['top_view_info'] as dynamic,
|
||||
upName: json['up_name'] as String?,
|
||||
inlinePlayUrl: json['inline_play_url'] as String?,
|
||||
calendarButton: json['calendar_button'] == null
|
||||
? null
|
||||
: CalendarButton.fromJson(json['calendar_button'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'avatar': avatar?.toJson(),
|
||||
'cover': cover,
|
||||
'inline_start_delay_time': inlineStartDelayTime,
|
||||
'inline_sustain_duration': inlineSustainDuration,
|
||||
'link': link,
|
||||
'player_args': playerArgs?.toJson(),
|
||||
'rank_list_info': rankListInfo,
|
||||
'right_top_live_badge': rightTopLiveBadge?.toJson(),
|
||||
'title': title,
|
||||
'top_view_info': topViewInfo,
|
||||
'up_name': upName,
|
||||
'inline_play_url': inlinePlayUrl,
|
||||
'calendar_button': calendarButton?.toJson(),
|
||||
};
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
class PlayerArgs {
|
||||
int? canPlay;
|
||||
bool? hideDanmuSwitch;
|
||||
int? liveStatus;
|
||||
int? parentAreaId;
|
||||
int? areaId;
|
||||
int? roomId;
|
||||
int? upId;
|
||||
|
||||
PlayerArgs({
|
||||
this.canPlay,
|
||||
this.hideDanmuSwitch,
|
||||
this.liveStatus,
|
||||
this.parentAreaId,
|
||||
this.areaId,
|
||||
this.roomId,
|
||||
this.upId,
|
||||
});
|
||||
|
||||
factory PlayerArgs.fromJson(Map<String, dynamic> json) => PlayerArgs(
|
||||
canPlay: json['can_play'] as int?,
|
||||
hideDanmuSwitch: json['hide_danmu_switch'] as bool?,
|
||||
liveStatus: json['live_status'] as int?,
|
||||
parentAreaId: json['parent_area_id'] as int?,
|
||||
areaId: json['area_id'] as int?,
|
||||
roomId: json['room_id'] as int?,
|
||||
upId: json['up_id'] as int?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'can_play': canPlay,
|
||||
'hide_danmu_switch': hideDanmuSwitch,
|
||||
'live_status': liveStatus,
|
||||
'parent_area_id': parentAreaId,
|
||||
'area_id': areaId,
|
||||
'room_id': roomId,
|
||||
'up_id': upId,
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
class QualityDescription {
|
||||
int? qn;
|
||||
String? desc;
|
||||
|
||||
QualityDescription({this.qn, this.desc});
|
||||
|
||||
factory QualityDescription.fromJson(Map<String, dynamic> json) {
|
||||
return QualityDescription(
|
||||
qn: json['qn'] as int?,
|
||||
desc: json['desc'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'qn': qn,
|
||||
'desc': desc,
|
||||
};
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import 'in_live.dart';
|
||||
|
||||
class RightTopLiveBadge {
|
||||
InLive? inLive;
|
||||
int? liveStatus;
|
||||
|
||||
RightTopLiveBadge({this.inLive, this.liveStatus});
|
||||
|
||||
factory RightTopLiveBadge.fromJson(Map<String, dynamic> json) {
|
||||
return RightTopLiveBadge(
|
||||
inLive: json['in_live'] == null
|
||||
? null
|
||||
: InLive.fromJson(json['in_live'] as Map<String, dynamic>),
|
||||
liveStatus: json['live_status'] as int?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'in_live': inLive?.toJson(),
|
||||
'live_status': liveStatus,
|
||||
};
|
||||
}
|
||||
23
lib/models/live/live_second_list/data.dart
Normal file
23
lib/models/live/live_second_list/data.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:PiliPlus/models/live/live_feed_index/card_data_list_item.dart';
|
||||
|
||||
class LiveSecondData {
|
||||
int? count;
|
||||
List<CardLiveItem>? cardList;
|
||||
|
||||
LiveSecondData({
|
||||
this.count,
|
||||
this.cardList,
|
||||
});
|
||||
|
||||
factory LiveSecondData.fromJson(Map<String, dynamic> json) => LiveSecondData(
|
||||
count: json['count'] as int?,
|
||||
cardList: (json['list'] as List<dynamic>?)
|
||||
?.map((e) => CardLiveItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'count': count,
|
||||
'list': cardList?.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
@@ -1,26 +1,90 @@
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/http/live.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/live/live_feed_index/card_data_list_item.dart';
|
||||
import 'package:PiliPlus/models/live/live_feed_index/card_list.dart';
|
||||
import 'package:PiliPlus/models/live/live_feed_index/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||
|
||||
class LiveController extends CommonListController<LiveIndexData, LiveCardList> {
|
||||
class LiveController extends CommonListController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
queryData();
|
||||
}
|
||||
|
||||
int? areaId;
|
||||
int? parentAreaId;
|
||||
final RxInt areaIndex = 0.obs;
|
||||
final Rx<Pair<LiveCardList?, LiveCardList?>> topState =
|
||||
Pair<LiveCardList?, LiveCardList?>(first: null, second: null).obs;
|
||||
final RxBool isLogin = Accounts.main.isLogin.obs;
|
||||
|
||||
@override
|
||||
List<LiveCardList>? getDataList(LiveIndexData response) {
|
||||
List? getDataList(response) {
|
||||
return response.cardList;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState<LiveIndexData>> customGetData() =>
|
||||
LiveHttp.liveFeedIndex(pn: currentPage, isLogin: isLogin.value);
|
||||
bool customHandleResponse(bool isRefresh, Success response) {
|
||||
if (isRefresh && areaIndex.value == 0) {
|
||||
topState.value = Pair(
|
||||
first: response.response.followItem,
|
||||
second: response.response.areaItem,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState> customGetData() {
|
||||
if (areaIndex.value != 0) {
|
||||
return LiveHttp.liveSecondList(
|
||||
pn: currentPage,
|
||||
isLogin: isLogin.value,
|
||||
areaId: areaId,
|
||||
parentAreaId: parentAreaId,
|
||||
);
|
||||
}
|
||||
return LiveHttp.liveFeedIndex(pn: currentPage, isLogin: isLogin.value);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onRefresh() async {
|
||||
currentPage = 1;
|
||||
isEnd = false;
|
||||
if (areaIndex.value != 0) {
|
||||
queryTop();
|
||||
}
|
||||
await queryData();
|
||||
}
|
||||
|
||||
Future<void> queryTop() async {
|
||||
final res = await LiveHttp.liveFeedIndex(
|
||||
pn: currentPage,
|
||||
isLogin: isLogin.value,
|
||||
moduleSelect: true,
|
||||
);
|
||||
if (res is Success) {
|
||||
final data = res.data;
|
||||
topState.value = Pair(
|
||||
first: data.followItem,
|
||||
second: data.areaItem,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void onSelectArea(int index, CardLiveItem? cardLiveItem) {
|
||||
if (index == areaIndex.value) {
|
||||
return;
|
||||
}
|
||||
areaIndex.value = index;
|
||||
areaId = cardLiveItem?.areaV2Id;
|
||||
parentAreaId = cardLiveItem?.areaV2ParentId;
|
||||
|
||||
currentPage = 1;
|
||||
isEnd = false;
|
||||
queryData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -11,7 +12,7 @@ import 'package:PiliPlus/pages/common/common_page.dart';
|
||||
import 'package:PiliPlus/pages/live/controller.dart';
|
||||
import 'package:PiliPlus/pages/live/widgets/live_item_app.dart';
|
||||
import 'package:PiliPlus/pages/live_follow/view.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||
import 'package:PiliPlus/utils/grid.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -54,7 +55,10 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
||||
top: StyleString.cardSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(controller.loadingState.value)),
|
||||
sliver: SliverMainAxisGroup(slivers: [
|
||||
Obx(() => _buildTop(controller.topState.value)),
|
||||
Obx(() => _buildBody(controller.loadingState.value)),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -62,7 +66,51 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<LiveCardList>?> loadingState) {
|
||||
Widget _buildTop(Pair<LiveCardList?, LiveCardList?> data) {
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
if (data.first != null)
|
||||
SliverToBoxAdapter(child: _buildFollowList(data.first!)),
|
||||
if (data.second?.cardData?.areaEntranceV3?.list?.isNotEmpty == true)
|
||||
SliverToBoxAdapter(
|
||||
child: SelfSizedHorizontalList(
|
||||
gapSize: 12,
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
childBuilder: (index) {
|
||||
late final item =
|
||||
data.second!.cardData!.areaEntranceV3!.list![index - 1];
|
||||
return Obx(
|
||||
() => SearchText(
|
||||
fontSize: 14,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 3,
|
||||
),
|
||||
text: index == 0 ? '推荐' : '${item.title}',
|
||||
bgColor: index == controller.areaIndex.value
|
||||
? Theme.of(context).colorScheme.secondaryContainer
|
||||
: Colors.transparent,
|
||||
textColor: index == controller.areaIndex.value
|
||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||
: null,
|
||||
onTap: (value) {
|
||||
controller.onSelectArea(
|
||||
index,
|
||||
index == 0 ? null : item,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount:
|
||||
data.second!.cardData!.areaEntranceV3!.list!.length + 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
@@ -80,47 +128,30 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? Builder(builder: (context) {
|
||||
List<LiveCardList> list = loadingState.response!;
|
||||
LiveCardList? followItem;
|
||||
if (list.first.cardType == 'my_idol_v1') {
|
||||
followItem = list.first;
|
||||
list = list.sublist(1);
|
||||
}
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
if (followItem != null)
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: _buildFollowList(followItem),
|
||||
),
|
||||
),
|
||||
if (list.isNotEmpty)
|
||||
SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent:
|
||||
MediaQuery.textScalerOf(context).scale(90),
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
return LiveCardVApp(
|
||||
item: list[index].cardData!.smallCardV1!,
|
||||
);
|
||||
},
|
||||
childCount: list.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
})
|
||||
? SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = loadingState.response![index];
|
||||
if (item is LiveCardList) {
|
||||
return LiveCardVApp(
|
||||
item: item.cardData!.smallCardV1!,
|
||||
);
|
||||
}
|
||||
return LiveCardVApp(item: item);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
)
|
||||
: HttpError(onReload: controller.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
@@ -183,22 +214,21 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
||||
),
|
||||
],
|
||||
),
|
||||
_buildFollowBody(theme, item.cardData?.myIdolV1?.list),
|
||||
if (item.cardData?.myIdolV1?.list?.isNotEmpty == true)
|
||||
_buildFollowBody(theme, item.cardData!.myIdolV1!.list!),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFollowBody(ThemeData theme, List<CardLiveItem>? list) {
|
||||
if (list.isNullOrEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
Widget _buildFollowBody(ThemeData theme, List<CardLiveItem> followList) {
|
||||
return MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeLeft: context.orientation == Orientation.landscape,
|
||||
child: SelfSizedHorizontalList(
|
||||
gapSize: 5,
|
||||
childBuilder: (index) {
|
||||
final item = list[index];
|
||||
final item = followList[index];
|
||||
return SizedBox(
|
||||
width: 65,
|
||||
child: GestureDetector(
|
||||
@@ -244,7 +274,7 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: list!.length,
|
||||
itemCount: followList.length,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ class LiveCardVApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String heroTag = Utils.makeHeroTag(item.id);
|
||||
String heroTag = Utils.makeHeroTag(item.roomid);
|
||||
return Card(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: EdgeInsets.zero,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Get.toNamed('/liveRoom?roomid=${item.id}');
|
||||
Get.toNamed('/liveRoom?roomid=${item.roomid}');
|
||||
},
|
||||
onLongPress: () => imageSaveDialog(
|
||||
title: item.title,
|
||||
|
||||
Reference in New Issue
Block a user