refa: coin/like arc

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-06-06 21:33:55 +08:00
parent 77e418e4b7
commit db4283af4a
10 changed files with 220 additions and 121 deletions

View File

@@ -876,4 +876,8 @@ class Api {
static const String favFavFolder = '/x/v3/fav/folder/fav';
static const String unfavFavFolder = '/x/v3/fav/folder/unfav';
static const String coinArc = '${HttpString.appBaseUrl}/x/v2/space/coinarc';
static const String likeArc = '${HttpString.appBaseUrl}/x/v2/space/likearc';
}

View File

@@ -8,11 +8,11 @@ import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/member/contribute_type.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/models/member/info.dart';
import 'package:PiliPlus/models/member/tags.dart';
import 'package:PiliPlus/models_new/follow/data.dart';
import 'package:PiliPlus/models_new/follow/list.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/data.dart';
import 'package:PiliPlus/models_new/member/search_archive/data.dart';
import 'package:PiliPlus/models_new/space/space/data.dart';
import 'package:PiliPlus/models_new/space/space_archive/data.dart';
@@ -605,62 +605,6 @@ class MemberHttp {
}
}
// 最近投币
static Future<LoadingState<List<MemberCoinsDataModel>?>> getRecentCoinVideo(
{required int mid}) async {
Map params = await WbiSign.makSign({
'mid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
});
var res = await Request().get(
Api.getRecentCoinVideoApi,
queryParameters: {
'vmid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
'w_rid': params['w_rid'],
'wts': params['wts'],
},
);
if (res.data['code'] == 0) {
List<MemberCoinsDataModel>? list = (res.data['data'] as List?)
?.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList();
return Success(list);
} else {
return Error(res.data['message']);
}
}
// 最近点赞
static Future<LoadingState<List<MemberCoinsDataModel>?>> getRecentLikeVideo(
{required int mid}) async {
Map params = await WbiSign.makSign({
'mid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
});
var res = await Request().get(
Api.getRecentLikeVideoApi,
queryParameters: {
'vmid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
'w_rid': params['w_rid'],
'wts': params['wts'],
},
);
if (res.data['code'] == 0) {
List<MemberCoinsDataModel>? list = (res.data['data']?['list'] as List?)
?.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList();
return Success(list);
} else {
return Error(res.data['message']);
}
}
// 获取up播放数、点赞数
static Future memberView({required int mid}) async {
var res = await Request()
@@ -748,4 +692,42 @@ class MemberHttp {
return Error(res.data['message']);
}
}
static Future<LoadingState<CoinLikeArcData>> coinArc({
required int mid,
required int page,
}) async {
var res = await Request().get(
Api.coinArc,
queryParameters: {
'pn': page,
'ps': 20,
'vmid': mid,
},
);
if (res.data['code'] == 0) {
return Success(CoinLikeArcData.fromJson(res.data['data']));
} else {
return Error(res.data['message']);
}
}
static Future<LoadingState<CoinLikeArcData>> likeArc({
required int mid,
required int page,
}) async {
var res = await Request().get(
Api.likeArc,
queryParameters: {
'pn': page,
'ps': 20,
'vmid': mid,
},
);
if (res.data['code'] == 0) {
return Success(CoinLikeArcData.fromJson(res.data['data']));
} else {
return Error(res.data['message']);
}
}
}

View File

@@ -1,17 +0,0 @@
import 'package:PiliPlus/models/model_hot_video_item.dart';
class MemberCoinsDataModel extends HotVideoItemModel {
String? subtitle;
int? coins;
int? time;
String? resourceType;
MemberCoinsDataModel.fromJson(Map<String, dynamic> json)
: super.fromJson(json) {
coins = json['coins'];
subtitle = json['subtitle'];
time = json['time'];
resourceType = json['resource_type'];
redirectUrl = json['redirect_url'];
}
}

View File

@@ -0,0 +1,16 @@
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
class CoinLikeArcData {
int? count;
List<CoinLikeArcItem>? item;
CoinLikeArcData({this.count, this.item});
factory CoinLikeArcData.fromJson(Map<String, dynamic> json) =>
CoinLikeArcData(
count: json['count'] as int?,
item: (json['item'] as List<dynamic>?)
?.map((e) => CoinLikeArcItem.fromJson(e as Map<String, dynamic>))
.toList(),
);
}

View File

@@ -0,0 +1,96 @@
class CoinLikeArcItem {
String? title;
String? subtitle;
String? tname;
String? cover;
String? coverIcon;
String? uri;
String? param;
String? goto;
String? length;
int? duration;
bool? isPopular;
bool? isSteins;
bool? isUgcpay;
bool? isCooperation;
bool? isPgc;
bool? isLivePlayback;
bool? isPugv;
bool? isFold;
bool? isOneself;
int? play;
int? danmaku;
int? ctime;
int? ugcPay;
String? author;
bool? state;
int? videos;
String? viewContent;
int? iconType;
String? publishTimeText;
CoinLikeArcItem({
this.title,
this.subtitle,
this.tname,
this.cover,
this.coverIcon,
this.uri,
this.param,
this.goto,
this.length,
this.duration,
this.isPopular,
this.isSteins,
this.isUgcpay,
this.isCooperation,
this.isPgc,
this.isLivePlayback,
this.isPugv,
this.isFold,
this.isOneself,
this.play,
this.danmaku,
this.ctime,
this.ugcPay,
this.author,
this.state,
this.videos,
this.viewContent,
this.iconType,
this.publishTimeText,
});
factory CoinLikeArcItem.fromJson(Map<String, dynamic> json) =>
CoinLikeArcItem(
title: json['title'] as String?,
subtitle: json['subtitle'] as String?,
tname: json['tname'] as String?,
cover: json['cover'] as String?,
coverIcon: json['cover_icon'] as String?,
uri: json['uri'] as String?,
param: json['param'] as String?,
goto: json['goto'] as String?,
length: json['length'] as String?,
duration: json['duration'] as int?,
isPopular: json['is_popular'] as bool?,
isSteins: json['is_steins'] as bool?,
isUgcpay: json['is_ugcpay'] as bool?,
isCooperation: json['is_cooperation'] as bool?,
isPgc: json['is_pgc'] as bool?,
isLivePlayback: json['is_live_playback'] as bool?,
isPugv: json['is_pugv'] as bool?,
isFold: json['is_fold'] as bool?,
isOneself: json['is_oneself'] as bool?,
play: json['play'] as int?,
danmaku: json['danmaku'] as int?,
ctime: json['ctime'] as int?,
ugcPay: json['ugc_pay'] as int?,
author: json['author'] as String?,
state: json['state'] as bool?,
videos: json['videos'] as int?,
viewContent: json['view_content'] as String?,
iconType: json['icon_type'] as int?,
publishTimeText: json['publish_time_text'] as String?,
);
}

View File

@@ -1,10 +1,11 @@
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/member.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/data.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart';
class MemberCoinController extends CommonListController<
List<MemberCoinsDataModel>?, MemberCoinsDataModel> {
class MemberCoinController
extends CommonListController<CoinLikeArcData, CoinLikeArcItem> {
final dynamic mid;
MemberCoinController({this.mid});
@@ -15,6 +16,11 @@ class MemberCoinController extends CommonListController<
}
@override
Future<LoadingState<List<MemberCoinsDataModel>?>> customGetData() =>
MemberHttp.getRecentCoinVideo(mid: mid);
List<CoinLikeArcItem>? getDataList(CoinLikeArcData response) {
return response.item;
}
@override
Future<LoadingState<CoinLikeArcData>> customGetData() =>
MemberHttp.coinArc(mid: mid, page: page);
}

View File

@@ -2,7 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
import 'package:PiliPlus/pages/member_coin/controller.dart';
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
import 'package:PiliPlus/utils/grid.dart';
@@ -59,7 +59,7 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
);
}
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
Widget _buildBody(LoadingState<List<CoinLikeArcItem>?> loadingState) {
return switch (loadingState) {
Loading() => SliverGrid.builder(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
@@ -85,7 +85,10 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
),
itemCount: response!.length,
itemBuilder: (context, index) {
return MemberCoinsItem(coinItem: response[index]);
if (index == response.length - 1) {
_ctr.onLoadMore();
}
return MemberCoinLikeItem(item: response[index]);
},
)
: HttpError(onReload: _ctr.onReload),

View File

@@ -6,18 +6,18 @@ import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/models/common/badge_type.dart';
import 'package:PiliPlus/models/common/stat_type.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
class MemberCoinsItem extends StatelessWidget {
final MemberCoinsDataModel coinItem;
class MemberCoinLikeItem extends StatelessWidget {
final CoinLikeArcItem item;
const MemberCoinsItem({
const MemberCoinLikeItem({
super.key,
required this.coinItem,
required this.item,
});
@override
@@ -27,29 +27,29 @@ class MemberCoinsItem extends StatelessWidget {
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async {
if (coinItem.resourceType != 'ugc') {
if (coinItem.redirectUrl?.isNotEmpty == true) {
if (await PiliScheme.routePushFromUrl(coinItem.redirectUrl!,
selfHandle: true)) {
return;
}
if (item.isPgc == true) {
if (item.uri?.isNotEmpty == true) {
PageUtils.viewPgcFromUri(item.uri!);
}
return;
}
int? cid =
await SearchHttp.ab2c(aid: coinItem.aid, bvid: coinItem.bvid);
if (cid != null) {
PageUtils.toVideoPage(
'bvid=${coinItem.bvid}&cid=$cid',
arguments: {
'videoItem': coinItem,
'heroTag': Utils.makeHeroTag(coinItem.aid)
},
);
if (item.param != null) {
int? cid = await SearchHttp.ab2c(aid: item.param);
if (cid != null) {
PageUtils.toVideoPage(
'bvid=${IdUtils.av2bv(int.parse(item.param!))}&cid=$cid',
arguments: {
'videoItem': item,
'heroTag': Utils.makeHeroTag(item.param)
},
);
}
}
},
onLongPress: () => imageSaveDialog(
title: coinItem.title,
cover: coinItem.cover,
title: item.title,
cover: item.cover,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -63,16 +63,16 @@ class MemberCoinsItem extends StatelessWidget {
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: coinItem.cover,
src: item.cover,
width: maxWidth,
height: maxHeight,
),
if (coinItem.duration > 0)
if (item.duration != null && item.duration! > 0)
PBadge(
bottom: 6,
right: 6,
type: PBadgeType.gray,
text: Utils.timeFormat(coinItem.duration),
text: Utils.timeFormat(item.duration),
)
],
);
@@ -85,7 +85,7 @@ class MemberCoinsItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${coinItem.title}\n',
'${item.title}\n',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
@@ -94,17 +94,17 @@ class MemberCoinsItem extends StatelessWidget {
children: [
StatWidget(
type: StatType.play,
value: coinItem.stat.view,
value: item.play,
),
const SizedBox(width: 8),
StatWidget(
type: StatType.danmaku,
value: coinItem.stat.danmu,
value: item.danmaku,
),
const Spacer(),
Text(
Utils.customStampStr(
timestamp: coinItem.pubdate, date: 'MM-DD'),
timestamp: item.ctime, date: 'MM-DD'),
style: TextStyle(
fontSize: 11,
color: Theme.of(context).colorScheme.outline,

View File

@@ -1,10 +1,11 @@
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/member.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/data.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart';
class MemberLikeController extends CommonListController<
List<MemberCoinsDataModel>?, MemberCoinsDataModel> {
class MemberLikeController
extends CommonListController<CoinLikeArcData, CoinLikeArcItem> {
final dynamic mid;
MemberLikeController({this.mid});
@@ -15,6 +16,11 @@ class MemberLikeController extends CommonListController<
}
@override
Future<LoadingState<List<MemberCoinsDataModel>?>> customGetData() =>
MemberHttp.getRecentLikeVideo(mid: mid);
List<CoinLikeArcItem>? getDataList(CoinLikeArcData response) {
return response.item;
}
@override
Future<LoadingState<CoinLikeArcData>> customGetData() =>
MemberHttp.likeArc(mid: mid, page: page);
}

View File

@@ -2,7 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/member/coin.dart';
import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart';
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
import 'package:PiliPlus/pages/member_like/controller.dart';
import 'package:PiliPlus/utils/grid.dart';
@@ -59,7 +59,7 @@ class _MemberLikePageState extends State<MemberLikePage> {
);
}
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
Widget _buildBody(LoadingState<List<CoinLikeArcItem>?> loadingState) {
return switch (loadingState) {
Loading() => SliverGrid.builder(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
@@ -85,7 +85,10 @@ class _MemberLikePageState extends State<MemberLikePage> {
),
itemCount: response!.length,
itemBuilder: (context, index) {
return MemberCoinsItem(coinItem: response[index]);
if (index == response.length - 1) {
_ctr.onLoadMore();
}
return MemberCoinLikeItem(item: response[index]);
},
)
: HttpError(onReload: _ctr.onReload),