mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
refa: query data (#659)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -50,7 +50,7 @@ class BangumiHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> bangumiList({
|
static Future<LoadingState<List<BangumiListItemModel>?>> bangumiList({
|
||||||
int? page,
|
int? page,
|
||||||
int? indexType,
|
int? indexType,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -67,7 +67,7 @@ class BangumiHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> bangumiFollowList({
|
static Future<LoadingState<BangumiListDataModel>> bangumiFollowList({
|
||||||
required dynamic mid,
|
required dynamic mid,
|
||||||
required int type,
|
required int type,
|
||||||
required int pn,
|
required int pn,
|
||||||
@@ -80,12 +80,8 @@ class BangumiHttp {
|
|||||||
'pn': pn,
|
'pn': pn,
|
||||||
});
|
});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
BangumiListDataModel data =
|
return LoadingState.success(
|
||||||
BangumiListDataModel.fromJson(res.data['data']);
|
BangumiListDataModel.fromJson(res.data['data']));
|
||||||
if (followStatus != null) {
|
|
||||||
return LoadingState.success(data.list);
|
|
||||||
}
|
|
||||||
return LoadingState.success(data);
|
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import '../models/user/black.dart';
|
|||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class BlackHttp {
|
class BlackHttp {
|
||||||
static Future<LoadingState> blackList({required int pn, int? ps}) async {
|
static Future<LoadingState<BlackListDataModel>> blackList(
|
||||||
|
{required int pn, int? ps}) async {
|
||||||
var res = await Request().get(Api.blackLst, queryParameters: {
|
var res = await Request().get(Api.blackLst, queryParameters: {
|
||||||
'pn': pn,
|
'pn': pn,
|
||||||
'ps': ps ?? 50,
|
'ps': ps ?? 50,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import '../models/dynamics/up.dart';
|
|||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class DynamicsHttp {
|
class DynamicsHttp {
|
||||||
static Future<LoadingState> followDynamic({
|
static Future<LoadingState<DynamicsDataModel>> followDynamic({
|
||||||
String? type,
|
String? type,
|
||||||
String? offset,
|
String? offset,
|
||||||
int? mid,
|
int? mid,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import '../models/fans/result.dart';
|
|||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class FanHttp {
|
class FanHttp {
|
||||||
static Future<LoadingState> fans(
|
static Future<LoadingState<FansDataModel>> fans(
|
||||||
{int? vmid, int? pn, int? ps, String? orderType}) async {
|
{int? vmid, int? pn, int? ps, String? orderType}) async {
|
||||||
var res = await Request().get(Api.fans, queryParameters: {
|
var res = await Request().get(Api.fans, queryParameters: {
|
||||||
'vmid': vmid,
|
'vmid': vmid,
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ import 'api.dart';
|
|||||||
import 'init.dart';
|
import 'init.dart';
|
||||||
|
|
||||||
class LiveHttp {
|
class LiveHttp {
|
||||||
static Future<LoadingState> liveList(
|
static Future<LoadingState<List<LiveItemModel>?>> liveList(
|
||||||
{int? vmid, int? pn, int? ps, String? orderType}) async {
|
{int? vmid, int? pn, int? ps, String? orderType}) async {
|
||||||
var res = await Request().get(Api.liveList,
|
var res = await Request().get(Api.liveList,
|
||||||
queryParameters: {'page': pn, 'page_size': 30, 'platform': 'web'});
|
queryParameters: {'page': pn, 'page_size': 30, 'platform': 'web'});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
List<LiveItemModel> list = res.data['data']['list']
|
List<LiveItemModel>? list = (res.data['data']?['list'] as List?)
|
||||||
.map<LiveItemModel>((e) => LiveItemModel.fromJson(e))
|
?.map<LiveItemModel>((e) => LiveItemModel.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
return LoadingState.success(list);
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import 'package:PiliPlus/grpc/grpc_repo.dart';
|
|||||||
import 'package:PiliPlus/http/constants.dart';
|
import 'package:PiliPlus/http/constants.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/space/data.dart';
|
import 'package:PiliPlus/models/space/data.dart';
|
||||||
|
import 'package:PiliPlus/models/space_archive/data.dart' as space_archive;
|
||||||
|
import 'package:PiliPlus/models/space_article/data.dart' as space_article;
|
||||||
|
import 'package:PiliPlus/models/space/data.dart' as space_;
|
||||||
import 'package:PiliPlus/models/space_fav/space_fav.dart';
|
import 'package:PiliPlus/models/space_fav/space_fav.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
||||||
show ContributeType;
|
show ContributeType;
|
||||||
@@ -62,7 +65,7 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> spaceArticle({
|
static Future<LoadingState<space_article.Data>> spaceArticle({
|
||||||
required int mid,
|
required int mid,
|
||||||
required int page,
|
required int page,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -138,13 +141,13 @@ class MemberHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return LoadingState.success(res.data['data']['items_lists']);
|
return LoadingState.success(res.data['data']?['items_lists']);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> spaceArchive({
|
static Future<LoadingState<space_archive.Data>> spaceArchive({
|
||||||
required ContributeType type,
|
required ContributeType type,
|
||||||
required int? mid,
|
required int? mid,
|
||||||
String? aid,
|
String? aid,
|
||||||
@@ -241,7 +244,7 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> space({
|
static Future<LoadingState<space_.Data>> space({
|
||||||
int? mid,
|
int? mid,
|
||||||
dynamic fromViewAid,
|
dynamic fromViewAid,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -391,7 +394,7 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 用户动态
|
// 用户动态
|
||||||
static Future<LoadingState> memberDynamic({
|
static Future<LoadingState<DynamicsDataModel>> memberDynamic({
|
||||||
String? offset,
|
String? offset,
|
||||||
int? mid,
|
int? mid,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -601,7 +604,8 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 最近投币
|
// 最近投币
|
||||||
static Future<LoadingState> getRecentCoinVideo({required int mid}) async {
|
static Future<LoadingState<List<MemberCoinsDataModel>?>> getRecentCoinVideo(
|
||||||
|
{required int mid}) async {
|
||||||
Map params = await WbiSign.makSign({
|
Map params = await WbiSign.makSign({
|
||||||
'mid': mid,
|
'mid': mid,
|
||||||
'gaia_source': 'main_web',
|
'gaia_source': 'main_web',
|
||||||
@@ -618,16 +622,18 @@ class MemberHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return LoadingState.success(res.data['data']
|
List<MemberCoinsDataModel>? list = (res.data['data'] as List?)
|
||||||
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
|
?.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
|
||||||
.toList());
|
.toList();
|
||||||
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 最近点赞
|
// 最近点赞
|
||||||
static Future<LoadingState> getRecentLikeVideo({required int mid}) async {
|
static Future<LoadingState<List<MemberCoinsDataModel>?>> getRecentLikeVideo(
|
||||||
|
{required int mid}) async {
|
||||||
Map params = await WbiSign.makSign({
|
Map params = await WbiSign.makSign({
|
||||||
'mid': mid,
|
'mid': mid,
|
||||||
'gaia_source': 'main_web',
|
'gaia_source': 'main_web',
|
||||||
@@ -644,9 +650,10 @@ class MemberHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return LoadingState.success(res.data['data']['list']
|
List<MemberCoinsDataModel>? list = (res.data['data']?['list'] as List?)
|
||||||
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
|
?.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
|
||||||
.toList());
|
.toList();
|
||||||
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import 'api.dart';
|
|||||||
import 'init.dart';
|
import 'init.dart';
|
||||||
|
|
||||||
class MsgHttp {
|
class MsgHttp {
|
||||||
static Future<LoadingState> msgFeedReplyMe(
|
static Future<LoadingState<MsgFeedReplyMe>> msgFeedReplyMe(
|
||||||
{int cursor = -1, int cursorTime = -1}) async {
|
{int cursor = -1, int cursorTime = -1}) async {
|
||||||
var res = await Request().get(Api.msgFeedReply, queryParameters: {
|
var res = await Request().get(Api.msgFeedReply, queryParameters: {
|
||||||
'id': cursor == -1 ? null : cursor,
|
'id': cursor == -1 ? null : cursor,
|
||||||
@@ -34,7 +34,7 @@ class MsgHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> msgFeedAtMe(
|
static Future<LoadingState<MsgFeedAtMe>> msgFeedAtMe(
|
||||||
{int cursor = -1, int cursorTime = -1}) async {
|
{int cursor = -1, int cursorTime = -1}) async {
|
||||||
var res = await Request().get(Api.msgFeedAt, queryParameters: {
|
var res = await Request().get(Api.msgFeedAt, queryParameters: {
|
||||||
'id': cursor == -1 ? null : cursor,
|
'id': cursor == -1 ? null : cursor,
|
||||||
@@ -51,7 +51,7 @@ class MsgHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> msgFeedLikeMe(
|
static Future<LoadingState<MsgFeedLikeMe>> msgFeedLikeMe(
|
||||||
{int cursor = -1, int cursorTime = -1}) async {
|
{int cursor = -1, int cursorTime = -1}) async {
|
||||||
var res = await Request().get(Api.msgFeedLike, queryParameters: {
|
var res = await Request().get(Api.msgFeedLike, queryParameters: {
|
||||||
'id': cursor == -1 ? null : cursor,
|
'id': cursor == -1 ? null : cursor,
|
||||||
@@ -68,7 +68,7 @@ class MsgHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> msgFeedNotify(
|
static Future<LoadingState<List<SystemNotifyList>?>> msgFeedNotify(
|
||||||
{int cursor = -1, int pageSize = 20}) async {
|
{int cursor = -1, int pageSize = 20}) async {
|
||||||
var res = await Request().get(Api.msgSysNotify, queryParameters: {
|
var res = await Request().get(Api.msgSysNotify, queryParameters: {
|
||||||
'cursor': cursor == -1 ? null : cursor,
|
'cursor': cursor == -1 ? null : cursor,
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class ReplyHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> replyListGrpc({
|
static Future<LoadingState<MainListReply>> replyListGrpc({
|
||||||
int type = 1,
|
int type = 1,
|
||||||
required int oid,
|
required int oid,
|
||||||
required CursorReq cursor,
|
required CursorReq cursor,
|
||||||
@@ -387,7 +387,8 @@ class ReplyHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> getEmoteList({String? business}) async {
|
static Future<LoadingState<List<Packages>?>> getEmoteList(
|
||||||
|
{String? business}) async {
|
||||||
var res = await Request().get(Api.myEmote, queryParameters: {
|
var res = await Request().get(Api.myEmote, queryParameters: {
|
||||||
'business': business ?? 'reply',
|
'business': business ?? 'reply',
|
||||||
'web_location': '333.1245',
|
'web_location': '333.1245',
|
||||||
|
|||||||
@@ -160,7 +160,8 @@ class SearchHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> bangumiInfoNew({int? seasonId, int? epId}) async {
|
static Future<LoadingState<BangumiInfoModel>> bangumiInfoNew(
|
||||||
|
{int? seasonId, int? epId}) async {
|
||||||
final dynamic res = await Request().get(
|
final dynamic res = await Request().get(
|
||||||
Api.bangumiInfo,
|
Api.bangumiInfo,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 收藏夹
|
// 收藏夹
|
||||||
static Future<LoadingState> userfavFolder({
|
static Future<LoadingState<FavFolderData>> userfavFolder({
|
||||||
required int pn,
|
required int pn,
|
||||||
required int ps,
|
required int ps,
|
||||||
required dynamic mid,
|
required dynamic mid,
|
||||||
@@ -170,7 +170,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> userFavFolderDetail(
|
static Future<LoadingState<FavDetailData>> userFavFolderDetail(
|
||||||
{required int mediaId,
|
{required int mediaId,
|
||||||
required int pn,
|
required int pn,
|
||||||
required int ps,
|
required int ps,
|
||||||
@@ -195,7 +195,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 稍后再看
|
// 稍后再看
|
||||||
static Future<LoadingState> seeYouLater() async {
|
static Future<LoadingState<Map>> seeYouLater() async {
|
||||||
var res = await Request().get(Api.seeYouLater);
|
var res = await Request().get(Api.seeYouLater);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
if (res.data['data']['count'] == 0) {
|
if (res.data['data']['count'] == 0) {
|
||||||
@@ -220,7 +220,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 观看历史
|
// 观看历史
|
||||||
static Future<LoadingState> historyList({
|
static Future<LoadingState<HistoryData>> historyList({
|
||||||
required String type,
|
required String type,
|
||||||
int? max,
|
int? max,
|
||||||
int? viewAt,
|
int? viewAt,
|
||||||
@@ -426,7 +426,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 我的订阅
|
// 我的订阅
|
||||||
static Future<LoadingState> userSubFolder({
|
static Future<LoadingState<List<SubFolderItemData>?>> userSubFolder({
|
||||||
required int mid,
|
required int mid,
|
||||||
required int pn,
|
required int pn,
|
||||||
required int ps,
|
required int ps,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:developer';
|
|||||||
import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card;
|
import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card;
|
||||||
import 'package:PiliPlus/grpc/grpc_repo.dart';
|
import 'package:PiliPlus/grpc/grpc_repo.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/member/article.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@@ -145,7 +146,7 @@ class VideoHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 最热视频
|
// 最热视频
|
||||||
static Future<LoadingState> hotVideoList(
|
static Future<LoadingState<List<HotVideoItemModel>>> hotVideoList(
|
||||||
{required int pn, required int ps}) async {
|
{required int pn, required int ps}) async {
|
||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
Api.hotList,
|
Api.hotList,
|
||||||
@@ -345,15 +346,16 @@ class VideoHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 相关视频
|
// 相关视频
|
||||||
static Future<LoadingState> relatedVideoList({required String bvid}) async {
|
static Future<LoadingState<List<HotVideoItemModel>?>> relatedVideoList(
|
||||||
|
{required String bvid}) async {
|
||||||
var res =
|
var res =
|
||||||
await Request().get(Api.relatedList, queryParameters: {'bvid': bvid});
|
await Request().get(Api.relatedList, queryParameters: {'bvid': bvid});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
final items =
|
final items = (res.data['data'] as List?)
|
||||||
(res.data['data'] as List).map((i) => HotVideoItemModel.fromJson(i));
|
?.map((i) => HotVideoItemModel.fromJson(i));
|
||||||
final list = RecommendFilter.applyFilterToRelatedVideos
|
final list = RecommendFilter.applyFilterToRelatedVideos
|
||||||
? items.where((i) => !RecommendFilter.filterAll(i)).toList()
|
? items?.where((i) => !RecommendFilter.filterAll(i)).toList()
|
||||||
: items.toList();
|
: items?.toList();
|
||||||
return LoadingState.success(list);
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
@@ -1046,7 +1048,8 @@ class VideoHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 视频排行
|
// 视频排行
|
||||||
static Future<LoadingState> getRankVideoList(int rid) async {
|
static Future<LoadingState<List<HotVideoItemModel>>> getRankVideoList(
|
||||||
|
int rid) async {
|
||||||
var rankApi = "${Api.getRankApi}?rid=$rid&type=all";
|
var rankApi = "${Api.getRankApi}?rid=$rid&type=all";
|
||||||
var res = await Request().get(rankApi);
|
var res = await Request().get(rankApi);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
@@ -1094,7 +1097,7 @@ class VideoHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> noteList({
|
static Future<LoadingState<List<FavArticleModel>?>> noteList({
|
||||||
required int page,
|
required int page,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
@@ -1106,13 +1109,16 @@ class VideoHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return LoadingState.success(res.data['data']?['list']);
|
List<FavArticleModel>? list = (res.data['data']?['list'] as List?)
|
||||||
|
?.map((e) => FavArticleModel.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState> userNoteList({
|
static Future<LoadingState<List<FavArticleModel>?>> userNoteList({
|
||||||
required int page,
|
required int page,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
@@ -1124,7 +1130,10 @@ class VideoHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return LoadingState.success(res.data['data']?['list']);
|
List<FavArticleModel>? list = (res.data['data']?['list'] as List?)
|
||||||
|
?.map((e) => FavArticleModel.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart'
|
||||||
|
show MultiSelectData;
|
||||||
|
|
||||||
class BangumiListDataModel {
|
class BangumiListDataModel {
|
||||||
BangumiListDataModel({
|
BangumiListDataModel({
|
||||||
this.hasNext,
|
this.hasNext,
|
||||||
@@ -24,7 +27,7 @@ class BangumiListDataModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BangumiListItemModel {
|
class BangumiListItemModel with MultiSelectData {
|
||||||
BangumiListItemModel({
|
BangumiListItemModel({
|
||||||
this.badge,
|
this.badge,
|
||||||
this.badgeType,
|
this.badgeType,
|
||||||
@@ -66,8 +69,6 @@ class BangumiListItemModel {
|
|||||||
Map? newEp;
|
Map? newEp;
|
||||||
String? progress;
|
String? progress;
|
||||||
|
|
||||||
bool? checked;
|
|
||||||
|
|
||||||
BangumiListItemModel.fromJson(Map<String, dynamic> json) {
|
BangumiListItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
badge = json['badge'] == '' ? null : json['badge'];
|
badge = json['badge'] == '' ? null : json['badge'];
|
||||||
badgeType = json['badge_type'];
|
badgeType = json['badge_type'];
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ class LiveFollowingModel {
|
|||||||
count = json['count'];
|
count = json['count'];
|
||||||
list = (json['list'] as List?)
|
list = (json['list'] as List?)
|
||||||
?.map((item) => LiveFollowingItemModel.fromJson(item))
|
?.map((item) => LiveFollowingItemModel.fromJson(item))
|
||||||
.toList() ??
|
.toList();
|
||||||
<LiveFollowingItemModel>[];
|
|
||||||
liveCount = json['live_count'];
|
liveCount = json['live_count'];
|
||||||
neverLivedCount = json['never_lived_count'];
|
neverLivedCount = json['never_lived_count'];
|
||||||
neverLivedFaces = json['never_lived_faces'];
|
neverLivedFaces = json['never_lived_faces'];
|
||||||
|
|||||||
31
lib/models/member/article.dart
Normal file
31
lib/models/member/article.dart
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||||
|
|
||||||
|
class FavArticleModel with MultiSelectData {
|
||||||
|
FavArticleModel({
|
||||||
|
this.webUrl,
|
||||||
|
this.title,
|
||||||
|
this.summary,
|
||||||
|
this.message,
|
||||||
|
this.pic,
|
||||||
|
this.cvid,
|
||||||
|
this.noteId,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? webUrl;
|
||||||
|
String? title;
|
||||||
|
String? summary;
|
||||||
|
String? message;
|
||||||
|
String? pic;
|
||||||
|
dynamic cvid;
|
||||||
|
dynamic noteId;
|
||||||
|
|
||||||
|
FavArticleModel.fromJson(Map json) {
|
||||||
|
webUrl = json['web_url'];
|
||||||
|
title = json['title'];
|
||||||
|
summary = json['summary'];
|
||||||
|
message = json['message'];
|
||||||
|
pic = json['arc']?['pic'];
|
||||||
|
cvid = json['cvid'];
|
||||||
|
noteId = json['note_id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
class MemberTagItemModel {
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart'
|
||||||
|
show MultiSelectData;
|
||||||
|
|
||||||
|
class MemberTagItemModel with MultiSelectData {
|
||||||
MemberTagItemModel({
|
MemberTagItemModel({
|
||||||
this.count,
|
this.count,
|
||||||
this.name,
|
this.name,
|
||||||
this.tagid,
|
this.tagid,
|
||||||
this.tip,
|
this.tip,
|
||||||
this.checked,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
int? count;
|
int? count;
|
||||||
String? name;
|
String? name;
|
||||||
int? tagid;
|
int? tagid;
|
||||||
String? tip;
|
String? tip;
|
||||||
bool? checked;
|
|
||||||
|
|
||||||
MemberTagItemModel.fromJson(Map<String, dynamic> json) {
|
MemberTagItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
count = json['count'];
|
count = json['count'];
|
||||||
name = json['name'];
|
name = json['name'];
|
||||||
tagid = json['tagid'];
|
tagid = json['tagid'];
|
||||||
tip = json['tip'];
|
tip = json['tip'];
|
||||||
checked = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart'
|
||||||
|
show MultiSelectData;
|
||||||
import 'model_owner.dart';
|
import 'model_owner.dart';
|
||||||
import 'model_rec_video_item.dart';
|
import 'model_rec_video_item.dart';
|
||||||
import 'model_video.dart';
|
import 'model_video.dart';
|
||||||
|
|
||||||
// 稍后再看, 排行榜等网页返回也使用该类
|
// 稍后再看, 排行榜等网页返回也使用该类
|
||||||
class HotVideoItemModel extends BaseRecVideoItemModel {
|
class HotVideoItemModel extends BaseRecVideoItemModel with MultiSelectData {
|
||||||
int? videos;
|
int? videos;
|
||||||
int? tid;
|
int? tid;
|
||||||
String? tname;
|
String? tname;
|
||||||
@@ -16,8 +18,6 @@ class HotVideoItemModel extends BaseRecVideoItemModel {
|
|||||||
String? pgcLabel;
|
String? pgcLabel;
|
||||||
String? redirectUrl;
|
String? redirectUrl;
|
||||||
|
|
||||||
bool? checked; // 手动设置的
|
|
||||||
|
|
||||||
num? progress;
|
num? progress;
|
||||||
|
|
||||||
HotVideoItemModel.fromJson(Map<String, dynamic> json) {
|
HotVideoItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart'
|
||||||
|
show MultiSelectData;
|
||||||
|
|
||||||
import '../model_owner.dart';
|
import '../model_owner.dart';
|
||||||
import '../model_video.dart';
|
import '../model_video.dart';
|
||||||
import 'fav_folder.dart';
|
import 'fav_folder.dart';
|
||||||
@@ -18,7 +21,7 @@ class FavDetailData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FavDetailItemData extends BaseVideoItemModel {
|
class FavDetailItemData extends BaseVideoItemModel with MultiSelectData {
|
||||||
int? id;
|
int? id;
|
||||||
int? type;
|
int? type;
|
||||||
int? page;
|
int? page;
|
||||||
@@ -31,7 +34,6 @@ class FavDetailItemData extends BaseVideoItemModel {
|
|||||||
int? favTime;
|
int? favTime;
|
||||||
Map? ogv;
|
Map? ogv;
|
||||||
String? epId;
|
String? epId;
|
||||||
bool? checked;
|
|
||||||
|
|
||||||
FavDetailItemData.fromJson(Map<String, dynamic> json) {
|
FavDetailItemData.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
id = json['id'];
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart'
|
||||||
|
show MultiSelectData;
|
||||||
|
|
||||||
class HistoryData {
|
class HistoryData {
|
||||||
HistoryData({
|
HistoryData({
|
||||||
this.cursor,
|
this.cursor,
|
||||||
@@ -59,7 +62,7 @@ class HisTabItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HisListItem {
|
class HisListItem with MultiSelectData {
|
||||||
late String title;
|
late String title;
|
||||||
String? longTitle;
|
String? longTitle;
|
||||||
String? cover;
|
String? cover;
|
||||||
@@ -84,7 +87,6 @@ class HisListItem {
|
|||||||
int? kid;
|
int? kid;
|
||||||
String? tagName;
|
String? tagName;
|
||||||
int? liveStatus;
|
int? liveStatus;
|
||||||
bool? checked;
|
|
||||||
dynamic isFullScreen;
|
dynamic isFullScreen;
|
||||||
|
|
||||||
HisListItem.fromJson(Map<String, dynamic> json) {
|
HisListItem.fromJson(Map<String, dynamic> json) {
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/bangumi/list.dart';
|
import 'package:PiliPlus/models/bangumi/list.dart';
|
||||||
import 'package:PiliPlus/models/common/tab_type.dart';
|
import 'package:PiliPlus/models/common/tab_type.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/http/bangumi.dart';
|
import 'package:PiliPlus/http/bangumi.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
|
||||||
class BangumiController extends CommonController {
|
class BangumiController extends CommonListController<
|
||||||
|
List<BangumiListItemModel>?, BangumiListItemModel> {
|
||||||
BangumiController({required this.tabType});
|
BangumiController({required this.tabType});
|
||||||
final TabType tabType;
|
final TabType tabType;
|
||||||
|
|
||||||
@@ -75,7 +76,8 @@ class BangumiController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => BangumiHttp.bangumiList(
|
Future<LoadingState<List<BangumiListItemModel>?>> customGetData() =>
|
||||||
|
BangumiHttp.bangumiList(
|
||||||
page: currentPage,
|
page: currentPage,
|
||||||
indexType: tabType == TabType.cinema ? 102 : null, // TODO: sort
|
indexType: tabType == TabType.cinema ? 102 : null, // TODO: sort
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'dart:convert';
|
|||||||
import 'package:PiliPlus/http/init.dart';
|
import 'package:PiliPlus/http/init.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart';
|
import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart';
|
||||||
import 'package:PiliPlus/pages/video/detail/introduction/controller.dart';
|
import 'package:PiliPlus/pages/video/detail/introduction/controller.dart';
|
||||||
import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart';
|
import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart';
|
||||||
@@ -26,7 +26,8 @@ import 'package:PiliPlus/utils/storage.dart';
|
|||||||
import 'package:html/parser.dart' as html_parser;
|
import 'package:html/parser.dart' as html_parser;
|
||||||
import 'package:html/dom.dart' as dom;
|
import 'package:html/dom.dart' as dom;
|
||||||
|
|
||||||
class BangumiIntroController extends CommonController {
|
class BangumiIntroController
|
||||||
|
extends CommonDataController<BangumiInfoModel, BangumiInfoModel> {
|
||||||
// 视频bvid
|
// 视频bvid
|
||||||
String bvid = Get.parameters['bvid'] ?? '';
|
String bvid = Get.parameters['bvid'] ?? '';
|
||||||
var seasonId = Get.parameters['seasonId'] != null
|
var seasonId = Get.parameters['seasonId'] != null
|
||||||
@@ -125,14 +126,15 @@ class BangumiIntroController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(
|
||||||
epId ??= response.response.episodes!.first.id;
|
bool isRefresh, Success<BangumiInfoModel> response) {
|
||||||
|
epId ??= response.response.episodes?.firstOrNull?.id;
|
||||||
loadingState.value = response;
|
loadingState.value = response;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<BangumiInfoModel>> customGetData() =>
|
||||||
SearchHttp.bangumiInfoNew(seasonId: seasonId, epId: epId);
|
SearchHttp.bangumiInfoNew(seasonId: seasonId, epId: epId);
|
||||||
|
|
||||||
// 获取点赞/投币/收藏状态
|
// 获取点赞/投币/收藏状态
|
||||||
@@ -147,40 +149,15 @@ class BangumiIntroController extends CommonController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取点赞状态
|
|
||||||
// Future queryHasLikeVideo() async {
|
|
||||||
// var result = await VideoHttp.hasLikeVideo(bvid: bvid);
|
|
||||||
// // data num 被点赞标志 0:未点赞 1:已点赞
|
|
||||||
// hasLike.value = result["data"] == 1 ? true : false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取投币状态
|
|
||||||
// Future queryHasCoinVideo() async {
|
|
||||||
// var result = await VideoHttp.hasCoinVideo(bvid: bvid);
|
|
||||||
// hasCoin.value = result["data"]['multiply'] == 0 ? false : true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 获取收藏状态
|
|
||||||
// Future queryHasFavVideo() async {
|
|
||||||
// var result = await VideoHttp.hasFavVideo(aid: IdUtils.bv2av(bvid));
|
|
||||||
// if (result['status']) {
|
|
||||||
// hasFav.value = result["data"]['favoured'];
|
|
||||||
// } else {
|
|
||||||
// hasFav.value = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// (取消)点赞
|
// (取消)点赞
|
||||||
Future actionLikeVideo() async {
|
Future actionLikeVideo() async {
|
||||||
var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value);
|
var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
SmartDialog.showToast(!hasLike.value ? result['data']['toast'] : '取消赞');
|
SmartDialog.showToast(!hasLike.value ? result['data']['toast'] : '取消赞');
|
||||||
hasLike.value = !hasLike.value;
|
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response;
|
||||||
dynamic bangumiDetail = (loadingState.value as Success).response;
|
|
||||||
bangumiDetail.stat!['likes'] =
|
bangumiDetail.stat!['likes'] =
|
||||||
bangumiDetail.stat!['likes'] + (!hasLike.value ? 1 : -1);
|
bangumiDetail.stat!['likes'] + (!hasLike.value ? 1 : -1);
|
||||||
loadingState.value = LoadingState.success(bangumiDetail);
|
hasLike.value = !hasLike.value;
|
||||||
hasLike.refresh();
|
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
@@ -194,14 +171,13 @@ class BangumiIntroController extends CommonController {
|
|||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast('投币成功');
|
SmartDialog.showToast('投币成功');
|
||||||
hasCoin.value = true;
|
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response;
|
||||||
dynamic bangumiDetail = (loadingState.value as Success).response;
|
|
||||||
bangumiDetail.stat!['coins'] = bangumiDetail.stat!['coins'] + coin;
|
bangumiDetail.stat!['coins'] = bangumiDetail.stat!['coins'] + coin;
|
||||||
if (selectLike && hasLike.value.not) {
|
if (selectLike && hasLike.value.not) {
|
||||||
hasLike.value = true;
|
hasLike.value = true;
|
||||||
bangumiDetail.stat!['likes'] = bangumiDetail.stat!['likes'] + 1;
|
bangumiDetail.stat!['likes'] = bangumiDetail.stat!['likes'] + 1;
|
||||||
}
|
}
|
||||||
loadingState.value = LoadingState.success(bangumiDetail);
|
hasCoin.value = true;
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
}
|
}
|
||||||
@@ -236,60 +212,6 @@ class BangumiIntroController extends CommonController {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// showDialog(
|
|
||||||
// context: Get.context!,
|
|
||||||
// builder: (context) {
|
|
||||||
// return AlertDialog(
|
|
||||||
// title: const Text('选择投币个数'),
|
|
||||||
// contentPadding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
|
|
||||||
// content: StatefulBuilder(builder: (context, StateSetter setState) {
|
|
||||||
// return Column(
|
|
||||||
// mainAxisSize: MainAxisSize.min,
|
|
||||||
// children: [
|
|
||||||
// RadioListTile(
|
|
||||||
// value: 1,
|
|
||||||
// title: const Text('1枚'),
|
|
||||||
// groupValue: _tempThemeValue,
|
|
||||||
// onChanged: (value) {
|
|
||||||
// _tempThemeValue = value!;
|
|
||||||
// Get.appUpdate();
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// RadioListTile(
|
|
||||||
// value: 2,
|
|
||||||
// title: const Text('2枚'),
|
|
||||||
// groupValue: _tempThemeValue,
|
|
||||||
// onChanged: (value) {
|
|
||||||
// _tempThemeValue = value!;
|
|
||||||
// Get.appUpdate();
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }),
|
|
||||||
// actions: [
|
|
||||||
// TextButton(onPressed: () => Get.back(), child: const Text('取消')),
|
|
||||||
// TextButton(
|
|
||||||
// onPressed: () async {
|
|
||||||
// var res = await VideoHttp.coinVideo(
|
|
||||||
// bvid: bvid, multiply: _tempThemeValue);
|
|
||||||
// if (res['status']) {
|
|
||||||
// SmartDialog.showToast('投币成功');
|
|
||||||
// hasCoin.value = true;
|
|
||||||
// dynamic bangumiDetail =
|
|
||||||
// (loadingState.value as Success).response;
|
|
||||||
// bangumiDetail.stat!['coins'] =
|
|
||||||
// bangumiDetail.stat!['coins'] + _tempThemeValue;
|
|
||||||
// loadingState.value = LoadingState.success(bangumiDetail);
|
|
||||||
// } else {
|
|
||||||
// SmartDialog.showToast(res['msg']);
|
|
||||||
// }
|
|
||||||
// Get.back();
|
|
||||||
// },
|
|
||||||
// child: const Text('确定'))
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// (取消)收藏 bangumi
|
// (取消)收藏 bangumi
|
||||||
@@ -582,8 +504,11 @@ class BangumiIntroController extends CommonController {
|
|||||||
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
||||||
PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
|
PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
|
||||||
|
|
||||||
if ((loadingState.value as Success).response.episodes != null) {
|
if ((loadingState.value as Success<BangumiInfoModel>).response.episodes !=
|
||||||
episodes = (loadingState.value as Success).response.episodes!;
|
null) {
|
||||||
|
episodes = (loadingState.value as Success<BangumiInfoModel>)
|
||||||
|
.response
|
||||||
|
.episodes!;
|
||||||
} else {
|
} else {
|
||||||
if (playRepeat == PlayRepeat.autoPlayRelated) {
|
if (playRepeat == PlayRepeat.autoPlayRelated) {
|
||||||
return playRelated();
|
return playRelated();
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ class BangumiInfo extends StatefulWidget {
|
|||||||
State<BangumiInfo> createState() => _BangumiInfoState();
|
State<BangumiInfo> createState() => _BangumiInfoState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BangumiInfoState extends State<BangumiInfo>
|
class _BangumiInfoState extends State<BangumiInfo> {
|
||||||
with TickerProviderStateMixin {
|
|
||||||
late final BangumiIntroController bangumiIntroController;
|
late final BangumiIntroController bangumiIntroController;
|
||||||
late final VideoDetailController videoDetailCtr;
|
late final VideoDetailController videoDetailCtr;
|
||||||
late final BangumiInfoModel? bangumiItem;
|
late final BangumiInfoModel? bangumiItem;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import 'package:PiliPlus/http/bangumi.dart';
|
import 'package:PiliPlus/http/bangumi.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/bangumi/pgc_index/condition.dart';
|
import 'package:PiliPlus/models/bangumi/pgc_index/condition.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:get/get.dart' hide Condition;
|
import 'package:get/get.dart' hide Condition;
|
||||||
|
|
||||||
class PgcIndexController extends CommonController {
|
class PgcIndexController extends CommonListController {
|
||||||
PgcIndexController(this.indexType);
|
PgcIndexController(this.indexType);
|
||||||
int? indexType;
|
int? indexType;
|
||||||
Rx<LoadingState> conditionState = LoadingState.loading().obs;
|
Rx<LoadingState> conditionState = LoadingState.loading().obs;
|
||||||
@@ -51,20 +50,16 @@ class PgcIndexController extends CommonController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List? getDataList(response) {
|
||||||
|
return response['list'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
if (response.response['has_next'] == null ||
|
if (response.response['has_next'] == null ||
|
||||||
response.response['has_next'] == 0) {
|
response.response['has_next'] == 0) {
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
}
|
}
|
||||||
if (isEnd.not && (response.response['list'] as List?).isNullOrEmpty) {
|
return false;
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response['list'] ??= [];
|
|
||||||
response.response['list']!
|
|
||||||
.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response['list']);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,10 +207,10 @@ class _PgcIndexPageState extends State<PgcIndexPage>
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildList(LoadingState loadingState) {
|
Widget _buildList(LoadingState<List<dynamic>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => HttpError(errMsg: '加载中'),
|
Loading() => HttpError(errMsg: '加载中'),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverGrid(
|
? SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
mainAxisSpacing: StyleString.cardSpace,
|
mainAxisSpacing: StyleString.cardSpace,
|
||||||
@@ -221,13 +221,13 @@ class _PgcIndexPageState extends State<PgcIndexPage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_ctr.onLoadMore();
|
_ctr.onLoadMore();
|
||||||
}
|
}
|
||||||
return BangumiCardVPgcIndex(
|
return BangumiCardVPgcIndex(
|
||||||
bangumiItem: loadingState.response[index]);
|
bangumiItem: loadingState.response![index]);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(callback: _ctr.onReload),
|
: HttpError(callback: _ctr.onReload),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
|||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/bangumi/list.dart';
|
||||||
import 'package:PiliPlus/models/common/tab_type.dart';
|
import 'package:PiliPlus/models/common/tab_type.dart';
|
||||||
import 'package:PiliPlus/pages/bangumi/pgc_index/pgc_index_page.dart';
|
import 'package:PiliPlus/pages/bangumi/pgc_index/pgc_index_page.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||||
@@ -230,10 +231,10 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<BangumiListItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => const SliverToBoxAdapter(),
|
Loading() => const SliverToBoxAdapter(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverGrid(
|
? SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
// 行间距
|
// 行间距
|
||||||
@@ -247,13 +248,13 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
controller.onLoadMore();
|
controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return BangumiCardV(
|
return BangumiCardV(
|
||||||
bangumiItem: loadingState.response[index]);
|
bangumiItem: loadingState.response![index]);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(
|
: HttpError(
|
||||||
|
|||||||
61
lib/pages/blacklist/controller.dart
Normal file
61
lib/pages/blacklist/controller.dart
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||||
|
import 'package:PiliPlus/http/black.dart';
|
||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/http/video.dart';
|
||||||
|
import 'package:PiliPlus/models/user/black.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class BlackListController
|
||||||
|
extends CommonListController<BlackListDataModel, BlackListItem> {
|
||||||
|
int pageSize = 50;
|
||||||
|
RxInt total = 0.obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
queryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<BlackListItem>? getDataList(BlackListDataModel response) {
|
||||||
|
return response.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void checkIsEnd(int length) {
|
||||||
|
if (length >= total.value) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(
|
||||||
|
bool isRefresh, Success<BlackListDataModel> response) {
|
||||||
|
total.value = response.response.total ?? 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future onRemove(BuildContext context, int index, name, mid) async {
|
||||||
|
showConfirmDialog(
|
||||||
|
context: context,
|
||||||
|
title: '确定将 $name 移出黑名单?',
|
||||||
|
onConfirm: () async {
|
||||||
|
var result = await VideoHttp.relationMod(mid: mid, act: 6, reSrc: 11);
|
||||||
|
if (result['status']) {
|
||||||
|
List<BlackListItem> list = (loadingState.value as Success).response;
|
||||||
|
list.removeAt(index);
|
||||||
|
total.value -= 1;
|
||||||
|
loadingState.refresh();
|
||||||
|
SmartDialog.showToast('操作成功');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<BlackListDataModel>> customGetData() =>
|
||||||
|
BlackHttp.blackList(pn: currentPage, ps: pageSize);
|
||||||
|
}
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
|
||||||
import 'package:PiliPlus/models/user/black.dart';
|
import 'package:PiliPlus/models/user/black.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/blacklist/controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/http/black.dart';
|
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
@@ -50,36 +45,37 @@ class _BlackListPageState extends State<BlackListPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<BlackListItem>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? ListView.builder(
|
? ListView.builder(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _blackListController.scrollController,
|
controller: _blackListController.scrollController,
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_blackListController.onLoadMore();
|
_blackListController.onLoadMore();
|
||||||
}
|
}
|
||||||
|
final item = loadingState.response![index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed('/member?mid=${item.mid}');
|
||||||
'/member?mid=${loadingState.response[index].mid}');
|
|
||||||
},
|
},
|
||||||
leading: NetworkImgLayer(
|
leading: NetworkImgLayer(
|
||||||
width: 45,
|
width: 45,
|
||||||
height: 45,
|
height: 45,
|
||||||
type: 'avatar',
|
type: 'avatar',
|
||||||
src: loadingState.response[index].face,
|
src: item.face,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
loadingState.response[index].uname!,
|
item.uname!,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
Utils.dateFormat(loadingState.response[index].mtime),
|
Utils.dateFormat(item.mtime),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style:
|
style:
|
||||||
TextStyle(color: Theme.of(context).colorScheme.outline),
|
TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||||
@@ -87,10 +83,11 @@ class _BlackListPageState extends State<BlackListPage> {
|
|||||||
),
|
),
|
||||||
dense: true,
|
dense: true,
|
||||||
trailing: TextButton(
|
trailing: TextButton(
|
||||||
onPressed: () => _blackListController.removeBlack(
|
onPressed: () => _blackListController.onRemove(
|
||||||
context,
|
context,
|
||||||
loadingState.response[index].uname,
|
index,
|
||||||
loadingState.response[index].mid,
|
item.uname,
|
||||||
|
item.mid,
|
||||||
),
|
),
|
||||||
child: const Text('移除'),
|
child: const Text('移除'),
|
||||||
),
|
),
|
||||||
@@ -108,56 +105,3 @@ class _BlackListPageState extends State<BlackListPage> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlackListController extends CommonController {
|
|
||||||
int pageSize = 50;
|
|
||||||
RxInt total = 0.obs;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onInit() {
|
|
||||||
super.onInit();
|
|
||||||
queryData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool customHandleResponse(Success response) {
|
|
||||||
total.value = response.response.total;
|
|
||||||
if ((response.response.list as List?).isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response.list ??= <BlackListItem>[];
|
|
||||||
response.response.list!
|
|
||||||
.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
if (isEnd.not && response.response.list.length >= total.value) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response.list.isNotEmpty
|
|
||||||
? response.response.list
|
|
||||||
: <BlackListItem>[]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future removeBlack(context, name, mid) async {
|
|
||||||
showConfirmDialog(
|
|
||||||
context: context,
|
|
||||||
title: '确定将 $name 移出黑名单?',
|
|
||||||
onConfirm: () async {
|
|
||||||
var result = await VideoHttp.relationMod(mid: mid, act: 6, reSrc: 11);
|
|
||||||
if (result['status']) {
|
|
||||||
List list = (loadingState.value as Success).response;
|
|
||||||
list.removeWhere((e) => e.mid == mid);
|
|
||||||
total.value = total.value - 1;
|
|
||||||
loadingState.value =
|
|
||||||
LoadingState.success(list.isNotEmpty ? list : <BlackListItem>[]);
|
|
||||||
SmartDialog.showToast('操作成功');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<LoadingState> customGetData() =>
|
|
||||||
BlackHttp.blackList(pn: currentPage, ps: pageSize);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ abstract mixin class ScrollOrRefreshMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class CommonController extends GetxController
|
abstract class CommonController<R, T> extends GetxController
|
||||||
with ScrollOrRefreshMixin {
|
with ScrollOrRefreshMixin {
|
||||||
@override
|
@override
|
||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
@@ -35,13 +35,13 @@ abstract class CommonController extends GetxController
|
|||||||
late int currentPage = 1;
|
late int currentPage = 1;
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
late bool isEnd = false;
|
late bool isEnd = false;
|
||||||
Rx<LoadingState> loadingState = LoadingState.loading().obs;
|
Rx<LoadingState> get loadingState;
|
||||||
|
|
||||||
Future<LoadingState> customGetData();
|
Future<LoadingState<R>> customGetData();
|
||||||
|
|
||||||
void handleListResponse(List dataList) {}
|
void handleListResponse(List dataList) {}
|
||||||
|
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<R> response) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,27 +49,36 @@ abstract class CommonController extends GetxController
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<T>? getDataList(R response) {
|
||||||
|
return response as List<T>?;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkIsEnd(int length) {}
|
||||||
|
|
||||||
Future queryData([bool isRefresh = true]) async {
|
Future queryData([bool isRefresh = true]) async {
|
||||||
if (isLoading || (isRefresh.not && isEnd)) return;
|
if (isLoading || (isRefresh.not && isEnd)) return;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
LoadingState response = await customGetData();
|
LoadingState<R> response = await customGetData();
|
||||||
if (response is Success) {
|
if (response is Success<R>) {
|
||||||
if (!customHandleResponse(response)) {
|
if (!customHandleResponse(isRefresh, response)) {
|
||||||
List? dataList = response.response;
|
List<T>? dataList = getDataList(response.response);
|
||||||
if (dataList.isNullOrEmpty) {
|
if (dataList.isNullOrEmpty) {
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
loadingState.value = response;
|
loadingState.value = LoadingState<List<T>?>.success(dataList);
|
||||||
}
|
}
|
||||||
|
isLoading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleListResponse(dataList!);
|
handleListResponse(dataList!);
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
loadingState.value = LoadingState.success(dataList);
|
checkIsEnd(dataList.length);
|
||||||
|
loadingState.value = LoadingState<List<T>?>.success(dataList);
|
||||||
} else if (loadingState.value is Success) {
|
} else if (loadingState.value is Success) {
|
||||||
List currentList = (loadingState.value as Success).response ?? [];
|
List<T> list = (loadingState.value as Success).response;
|
||||||
currentList.addAll(dataList);
|
list.addAll(dataList);
|
||||||
loadingState.value = LoadingState.success(currentList);
|
checkIsEnd(list.length);
|
||||||
|
loadingState.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentPage++;
|
currentPage++;
|
||||||
|
|||||||
8
lib/pages/common/common_data_controller.dart
Normal file
8
lib/pages/common/common_data_controller.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_controller.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
abstract class CommonDataController<R, T> extends CommonController<R, T> {
|
||||||
|
@override
|
||||||
|
Rx<LoadingState<T>> loadingState = LoadingState<T>.loading().obs;
|
||||||
|
}
|
||||||
9
lib/pages/common/common_list_controller.dart
Normal file
9
lib/pages/common/common_list_controller.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_controller.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
abstract class CommonListController<R, T> extends CommonController<R, T> {
|
||||||
|
@override
|
||||||
|
Rx<LoadingState<List<T>?>> loadingState =
|
||||||
|
LoadingState<List<T>?>.loading().obs;
|
||||||
|
}
|
||||||
@@ -1,32 +1,43 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
|
|
||||||
abstract class MultiSelectController extends CommonController {
|
mixin class MultiSelectData {
|
||||||
|
bool? checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class MultiSelectController<R, T extends MultiSelectData>
|
||||||
|
extends CommonListController<R, T> {
|
||||||
late final RxBool enableMultiSelect = false.obs;
|
late final RxBool enableMultiSelect = false.obs;
|
||||||
late final RxInt checkedCount = 0.obs;
|
late final RxInt checkedCount = 0.obs;
|
||||||
|
late final allSelected = false.obs;
|
||||||
|
|
||||||
onSelect(int index) {
|
void onSelect(int index, [bool disableSelect = true]) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<T> list = (loadingState.value as Success).response;
|
||||||
list[index].checked = !(list[index]?.checked ?? false);
|
list[index].checked = !(list[index].checked ?? false);
|
||||||
checkedCount.value = list.where((item) => item.checked == true).length;
|
checkedCount.value = list.where((item) => item.checked == true).length;
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
|
if (disableSelect) {
|
||||||
if (checkedCount.value == 0) {
|
if (checkedCount.value == 0) {
|
||||||
enableMultiSelect.value = false;
|
enableMultiSelect.value = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
allSelected.value = checkedCount.value == list.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSelect([bool checked = false]) {
|
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||||
if (loadingState.value is Success) {
|
if (loadingState.value is Success) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<T>? list = (loadingState.value as Success).response;
|
||||||
if (list.isNotEmpty) {
|
if (list?.isNotEmpty == true) {
|
||||||
loadingState.value = LoadingState.success(
|
for (T item in list!) {
|
||||||
list.map((item) => item..checked = checked).toList());
|
item.checked = checked;
|
||||||
|
}
|
||||||
|
loadingState.refresh();
|
||||||
checkedCount.value = checked ? list.length : 0;
|
checkedCount.value = checked ? list.length : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (checked.not) {
|
if (disableSelect && !checked) {
|
||||||
enableMultiSelect.value = false;
|
enableMultiSelect.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import 'package:PiliPlus/http/loading_state.dart';
|
|||||||
import 'package:PiliPlus/http/reply.dart';
|
import 'package:PiliPlus/http/reply.dart';
|
||||||
import 'package:PiliPlus/models/common/reply_type.dart';
|
import 'package:PiliPlus/models/common/reply_type.dart';
|
||||||
import 'package:PiliPlus/models/video/reply/data.dart';
|
import 'package:PiliPlus/models/video/reply/data.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart';
|
import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart';
|
||||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
@@ -16,12 +16,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/models/common/reply_sort_type.dart';
|
import 'package:PiliPlus/models/common/reply_sort_type.dart';
|
||||||
import 'package:PiliPlus/models/video/reply/item.dart';
|
|
||||||
import 'package:PiliPlus/utils/feed_back.dart';
|
import 'package:PiliPlus/utils/feed_back.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
|
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
|
||||||
|
|
||||||
abstract class ReplyController extends CommonController {
|
abstract class ReplyController<R> extends CommonListController<R, ReplyInfo> {
|
||||||
String nextOffset = '';
|
String nextOffset = '';
|
||||||
RxInt count = (-1).obs;
|
RxInt count = (-1).obs;
|
||||||
|
|
||||||
@@ -31,6 +30,7 @@ abstract class ReplyController extends CommonController {
|
|||||||
|
|
||||||
late final bool isLogin = Accounts.main.isLogin;
|
late final bool isLogin = Accounts.main.isLogin;
|
||||||
|
|
||||||
|
dynamic upMid;
|
||||||
CursorReply? cursor;
|
CursorReply? cursor;
|
||||||
late Rx<Mode> mode = Mode.MAIN_LIST_HOT.obs;
|
late Rx<Mode> mode = Mode.MAIN_LIST_HOT.obs;
|
||||||
late bool hasUpTop = false;
|
late bool hasUpTop = false;
|
||||||
@@ -59,6 +59,29 @@ abstract class ReplyController extends CommonController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void checkIsEnd(int length) {
|
||||||
|
if (length >= count.value) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
|
MainListReply data = response.response;
|
||||||
|
cursor = data.cursor;
|
||||||
|
count.value = data.subjectControl.count.toInt();
|
||||||
|
if (isRefresh) {
|
||||||
|
upMid ??= data.subjectControl.upMid;
|
||||||
|
hasUpTop = data.hasUpTop();
|
||||||
|
if (data.hasUpTop()) {
|
||||||
|
data.replies.insert(0, data.upTop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEnd = data.cursor.isEnd;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future onRefresh() {
|
Future onRefresh() {
|
||||||
cursor = null;
|
cursor = null;
|
||||||
@@ -66,29 +89,6 @@ abstract class ReplyController extends CommonController {
|
|||||||
return super.onRefresh();
|
return super.onRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
bool customHandleResponse(Success response) {
|
|
||||||
MainListReply replies = response.response;
|
|
||||||
if (cursor == null) {
|
|
||||||
count.value = replies.subjectControl.count.toInt();
|
|
||||||
hasUpTop = replies.hasUpTop();
|
|
||||||
if (replies.hasUpTop()) {
|
|
||||||
replies.replies.insert(0, replies.upTop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor = replies.cursor;
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
replies.replies
|
|
||||||
.insertAll(0, (loadingState.value as Success).response.replies);
|
|
||||||
}
|
|
||||||
isEnd = replies.replies.isEmpty ||
|
|
||||||
replies.cursor.isEnd ||
|
|
||||||
replies.replies.length >= count.value;
|
|
||||||
loadingState.value = LoadingState.success(replies);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 排序搜索评论
|
// 排序搜索评论
|
||||||
queryBySort() {
|
queryBySort() {
|
||||||
EasyThrottle.throttle('queryBySort', const Duration(seconds: 1), () {
|
EasyThrottle.throttle('queryBySort', const Duration(seconds: 1), () {
|
||||||
@@ -168,16 +168,24 @@ abstract class ReplyController extends CommonController {
|
|||||||
if (res != null) {
|
if (res != null) {
|
||||||
savedReplies[key] = null;
|
savedReplies[key] = null;
|
||||||
ReplyInfo replyInfo = Utils.replyCast(res);
|
ReplyInfo replyInfo = Utils.replyCast(res);
|
||||||
MainListReply response = loadingState.value is Success
|
if (loadingState.value is Success) {
|
||||||
? (loadingState.value as Success).response
|
List<ReplyInfo>? list = (loadingState.value as Success).response;
|
||||||
: MainListReply();
|
if (list == null) {
|
||||||
if (oid != null) {
|
loadingState.value = LoadingState.success([replyInfo]);
|
||||||
response.replies.insert(hasUpTop ? 1 : 0, replyInfo);
|
|
||||||
} else {
|
} else {
|
||||||
response.replies[index].replies.add(replyInfo);
|
if (oid != null) {
|
||||||
|
list.insert(hasUpTop ? 1 : 0, replyInfo);
|
||||||
|
} else {
|
||||||
|
list[index].replies.add(replyInfo);
|
||||||
|
}
|
||||||
|
loadingState.refresh();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadingState.value = LoadingState.success([replyInfo]);
|
||||||
}
|
}
|
||||||
count.value += 1;
|
count.value += 1;
|
||||||
loadingState.value = LoadingState.success(response);
|
|
||||||
|
// check reply
|
||||||
if (enableCommAntifraud && context.mounted) {
|
if (enableCommAntifraud && context.mounted) {
|
||||||
checkReply(
|
checkReply(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -203,28 +211,19 @@ abstract class ReplyController extends CommonController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMDelete(rpid, frpid) {
|
void onRemove(int index, int? subIndex) {
|
||||||
MainListReply response = (loadingState.value as Success).response;
|
List<ReplyInfo> list = (loadingState.value as Success).response;
|
||||||
if (frpid == null) {
|
if (subIndex == null) {
|
||||||
response.replies.removeWhere((item) {
|
list.removeAt(index);
|
||||||
return item.id.toInt() == rpid;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
response.replies.map((item) {
|
list[index].replies.removeAt(subIndex);
|
||||||
if (item.id == frpid) {
|
|
||||||
return item..replies.removeWhere((reply) => reply.id.toInt() == rpid);
|
|
||||||
} else {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}).toList();
|
|
||||||
}
|
}
|
||||||
count.value -= 1;
|
count.value -= 1;
|
||||||
loadingState.value = LoadingState.success(response);
|
loadingState.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCheckReply(context, item) {
|
void onCheckReply(context, item) {
|
||||||
try {
|
try {
|
||||||
if (item is ReplyInfo) {
|
|
||||||
checkReply(
|
checkReply(
|
||||||
context: context,
|
context: context,
|
||||||
oid: item.oid.toInt(),
|
oid: item.oid.toInt(),
|
||||||
@@ -242,24 +241,6 @@ abstract class ReplyController extends CommonController {
|
|||||||
//
|
//
|
||||||
isManual: true,
|
isManual: true,
|
||||||
);
|
);
|
||||||
} else if (item is ReplyItemModel) {
|
|
||||||
checkReply(
|
|
||||||
context: context,
|
|
||||||
oid: item.oid,
|
|
||||||
rpid: item.root == 0 ? null : item.root,
|
|
||||||
replyType: item.type!,
|
|
||||||
replyId: item.rpid!,
|
|
||||||
message: item.content!.message!,
|
|
||||||
//
|
|
||||||
root: item.root,
|
|
||||||
parent: item.parent,
|
|
||||||
ctime: item.ctime,
|
|
||||||
pictures: item.content?.pictures,
|
|
||||||
mid: item.mid,
|
|
||||||
//
|
|
||||||
isManual: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
SmartDialog.showToast(e.toString());
|
SmartDialog.showToast(e.toString());
|
||||||
}
|
}
|
||||||
@@ -502,16 +483,14 @@ https://api.bilibili.com/x/v2/reply/reply?oid=$oid&pn=1&ps=20&root=${rpid ?? rep
|
|||||||
isUpTop: isUpTop,
|
isUpTop: isUpTop,
|
||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
final data = (loadingState.value as Success).response;
|
List<ReplyInfo> list = (loadingState.value as Success).response;
|
||||||
if (data is MainListReply) {
|
list[index].replyControl.isUpTop = !isUpTop;
|
||||||
data.replies[index].replyControl.isUpTop = !isUpTop;
|
|
||||||
if (!isUpTop && index != 0) {
|
if (!isUpTop && index != 0) {
|
||||||
data.replies[0].replyControl.isUpTop = false;
|
list[0].replyControl.isUpTop = false;
|
||||||
final item = data.replies.removeAt(index);
|
final item = list.removeAt(index);
|
||||||
data.replies.insert(0, item);
|
list.insert(0, item);
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data);
|
|
||||||
}
|
}
|
||||||
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('${isUpTop ? '取消' : ''}置顶成功');
|
SmartDialog.showToast('${isUpTop ? '取消' : ''}置顶成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import 'package:PiliPlus/http/html.dart';
|
|||||||
import 'package:PiliPlus/http/reply.dart';
|
import 'package:PiliPlus/http/reply.dart';
|
||||||
import 'package:fixnum/fixnum.dart' as $fixnum;
|
import 'package:fixnum/fixnum.dart' as $fixnum;
|
||||||
|
|
||||||
class DynamicDetailController extends ReplyController {
|
class DynamicDetailController extends ReplyController<MainListReply> {
|
||||||
DynamicDetailController(this.oid, this.type);
|
DynamicDetailController(this.oid, this.type);
|
||||||
int oid;
|
int oid;
|
||||||
int type;
|
int type;
|
||||||
@@ -47,7 +47,13 @@ class DynamicDetailController extends ReplyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => ReplyHttp.replyListGrpc(
|
List<ReplyInfo>? getDataList(MainListReply response) {
|
||||||
|
return response.replies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<MainListReply>> customGetData() =>
|
||||||
|
ReplyHttp.replyListGrpc(
|
||||||
type: type,
|
type: type,
|
||||||
oid: oid,
|
oid: oid,
|
||||||
cursor: CursorReq(
|
cursor: CursorReq(
|
||||||
|
|||||||
@@ -775,7 +775,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget replyList(LoadingState loadingState) {
|
Widget replyList(LoadingState<List<ReplyInfo>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverList(
|
Loading() => SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
@@ -785,11 +785,11 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
childCount: 8,
|
childCount: 8,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response.replies as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverList(
|
? SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.replies.length) {
|
if (index == loadingState.response!.length) {
|
||||||
_dynamicDetailController.onLoadMore();
|
_dynamicDetailController.onLoadMore();
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@@ -799,7 +799,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
child: Text(
|
child: Text(
|
||||||
_dynamicDetailController.isEnd.not
|
_dynamicDetailController.isEnd.not
|
||||||
? '加载中...'
|
? '加载中...'
|
||||||
: loadingState.response.replies.isEmpty
|
: loadingState.response!.isEmpty
|
||||||
? '还没有评论'
|
? '还没有评论'
|
||||||
: '没有更多了',
|
: '没有更多了',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -810,19 +810,20 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ReplyItemGrpc(
|
return ReplyItemGrpc(
|
||||||
replyItem: loadingState.response.replies[index],
|
replyItem: loadingState.response![index],
|
||||||
replyLevel: '1',
|
replyLevel: '1',
|
||||||
replyReply: (replyItem, id) =>
|
replyReply: (replyItem, id) =>
|
||||||
replyReply(context, replyItem, id),
|
replyReply(context, replyItem, id),
|
||||||
onReply: () {
|
onReply: () {
|
||||||
_dynamicDetailController.onReply(
|
_dynamicDetailController.onReply(
|
||||||
context,
|
context,
|
||||||
replyItem: loadingState.response.replies[index],
|
replyItem: loadingState.response![index],
|
||||||
index: index,
|
index: index,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onDelete: _dynamicDetailController.onMDelete,
|
onDelete: (subIndex) =>
|
||||||
upMid: loadingState.response.subjectControl.upMid,
|
_dynamicDetailController.onRemove(index, subIndex),
|
||||||
|
upMid: _dynamicDetailController.upMid,
|
||||||
callback: _getImageCallback,
|
callback: _getImageCallback,
|
||||||
onCheckReply: (item) =>
|
onCheckReply: (item) =>
|
||||||
_dynamicDetailController.onCheckReply(context, item),
|
_dynamicDetailController.onCheckReply(context, item),
|
||||||
@@ -837,7 +838,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.replies.length + 1,
|
childCount: loadingState.response!.length + 1,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(
|
: HttpError(
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/pages/main/controller.dart';
|
import 'package:PiliPlus/pages/main/controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../../../http/dynamics.dart';
|
import '../../../http/dynamics.dart';
|
||||||
|
|
||||||
class DynamicsTabController extends CommonController {
|
class DynamicsTabController
|
||||||
|
extends CommonListController<DynamicsDataModel, DynamicItemModel> {
|
||||||
DynamicsTabController({required this.dynamicsType});
|
DynamicsTabController({required this.dynamicsType});
|
||||||
final String dynamicsType;
|
final String dynamicsType;
|
||||||
String offset = '';
|
String offset = '';
|
||||||
@@ -32,22 +32,20 @@ class DynamicsTabController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<DynamicItemModel>? getDataList(DynamicsDataModel response) {
|
||||||
offset = response.response.offset;
|
return response.items;
|
||||||
if ((response.response.items as List?).isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response.items ??= <DynamicItemModel>[];
|
|
||||||
response.response.items!
|
|
||||||
.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response.items);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => DynamicsHttp.followDynamic(
|
bool customHandleResponse(
|
||||||
|
bool isRefresh, Success<DynamicsDataModel> response) {
|
||||||
|
offset = response.response.offset ?? '';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<DynamicsDataModel>> customGetData() =>
|
||||||
|
DynamicsHttp.followDynamic(
|
||||||
type: dynamicsType == "up" ? "all" : dynamicsType,
|
type: dynamicsType == "up" ? "all" : dynamicsType,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
mid: dynamicsType == "up" ? mid : -1,
|
mid: dynamicsType == "up" ? mid : -1,
|
||||||
@@ -56,9 +54,9 @@ class DynamicsTabController extends CommonController {
|
|||||||
Future onRemove(dynamic dynamicId) async {
|
Future onRemove(dynamic dynamicId) async {
|
||||||
var res = await MsgHttp.removeDynamic(dynamicId);
|
var res = await MsgHttp.removeDynamic(dynamicId);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<DynamicItemModel> list = (loadingState.value as Success).response;
|
||||||
list.removeWhere((item) => item.idStr == dynamicId);
|
list.removeWhere((item) => item.idStr == dynamicId);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||||
import 'package:PiliPlus/pages/main/controller.dart';
|
import 'package:PiliPlus/pages/main/controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
@@ -137,10 +138,10 @@ class _DynamicsTabPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<DynamicItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => skeleton(),
|
Loading() => skeleton(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||||
@@ -153,23 +154,23 @@ class _DynamicsTabPageState
|
|||||||
// mainAxisSpacing: StyleString.cardSpace / 2,
|
// mainAxisSpacing: StyleString.cardSpace / 2,
|
||||||
|
|
||||||
lastChildLayoutTypeBuilder: (index) {
|
lastChildLayoutTypeBuilder: (index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
controller.onLoadMore();
|
controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return index == loadingState.response.length
|
return index == loadingState.response!.length
|
||||||
? LastChildLayoutType.foot
|
? LastChildLayoutType.foot
|
||||||
: LastChildLayoutType.none;
|
: LastChildLayoutType.none;
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
if (dynamicsController.tabController.index == 4 &&
|
if (dynamicsController.tabController.index == 4 &&
|
||||||
dynamicsController.mid.value != -1) ...[
|
dynamicsController.mid.value != -1) ...[
|
||||||
for (var i in loadingState.response)
|
for (var i in loadingState.response!)
|
||||||
DynamicPanel(
|
DynamicPanel(
|
||||||
item: i,
|
item: i,
|
||||||
onRemove: controller.onRemove,
|
onRemove: controller.onRemove,
|
||||||
),
|
),
|
||||||
] else ...[
|
] else ...[
|
||||||
for (var i in loadingState.response)
|
for (var i in loadingState.response!)
|
||||||
if (!dynamicsController.tempBannedList
|
if (!dynamicsController.tempBannedList
|
||||||
.contains(i.modules?.moduleAuthor?.mid))
|
.contains(i.modules?.moduleAuthor?.mid))
|
||||||
DynamicPanel(
|
DynamicPanel(
|
||||||
@@ -187,23 +188,24 @@ class _DynamicsTabPageState
|
|||||||
sliver: SliverList(
|
sliver: SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index ==
|
||||||
|
loadingState.response!.length - 1) {
|
||||||
controller.onLoadMore();
|
controller.onLoadMore();
|
||||||
}
|
}
|
||||||
|
final item = loadingState.response![index];
|
||||||
if ((dynamicsController.tabController.index ==
|
if ((dynamicsController.tabController.index ==
|
||||||
4 &&
|
4 &&
|
||||||
dynamicsController.mid.value != -1) ||
|
dynamicsController.mid.value != -1) ||
|
||||||
!dynamicsController.tempBannedList.contains(
|
!dynamicsController.tempBannedList.contains(
|
||||||
loadingState.response[index].modules
|
item.modules?.moduleAuthor?.mid)) {
|
||||||
?.moduleAuthor?.mid)) {
|
|
||||||
return DynamicPanel(
|
return DynamicPanel(
|
||||||
item: loadingState.response[index],
|
item: item,
|
||||||
onRemove: controller.onRemove,
|
onRemove: controller.onRemove,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,293 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pb.dart' as dyn;
|
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
|
||||||
import 'package:PiliPlus/http/user.dart';
|
|
||||||
import 'package:PiliPlus/utils/feed_back.dart';
|
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
|
||||||
|
|
||||||
import '../../../http/constants.dart';
|
|
||||||
import '../controller.dart';
|
|
||||||
|
|
||||||
class AuthorPanelGrpc extends StatelessWidget {
|
|
||||||
final dyn.DynamicItem item;
|
|
||||||
final Function? addBannedList;
|
|
||||||
final String? source;
|
|
||||||
final Function? onRemove;
|
|
||||||
const AuthorPanelGrpc({
|
|
||||||
super.key,
|
|
||||||
required this.item,
|
|
||||||
this.addBannedList,
|
|
||||||
this.source,
|
|
||||||
this.onRemove,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
String heroTag = Utils.makeHeroTag(item.modules.first.moduleAuthor.mid);
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
// 番剧
|
|
||||||
// if (item.modules.first.moduleAuthor.type == 'AUTHOR_TYPE_PGC') {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
feedBack();
|
|
||||||
Get.toNamed(
|
|
||||||
'/member?mid=${item.modules.first.moduleAuthor.author.mid}',
|
|
||||||
arguments: {
|
|
||||||
'face': item.modules.first.moduleAuthor.author.face,
|
|
||||||
'heroTag': heroTag
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Hero(
|
|
||||||
tag: heroTag,
|
|
||||||
child: NetworkImgLayer(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
type: 'avatar',
|
|
||||||
src: item.modules.first.moduleAuthor.author.face,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
item.modules.first.moduleAuthor.author.name,
|
|
||||||
// semanticsLabel: "UP主:${item.modules.moduleAuthor.name}",
|
|
||||||
style: TextStyle(
|
|
||||||
color: item.modules.first.moduleAuthor.author.vip.status >
|
|
||||||
0 &&
|
|
||||||
item.modules.first.moduleAuthor.author.vip.type == 2
|
|
||||||
? context.vipColor
|
|
||||||
: Theme.of(context).colorScheme.onSurface,
|
|
||||||
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
// DefaultTextStyle.merge(
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: Theme.of(context).colorScheme.outline,
|
|
||||||
// fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
|
||||||
// ),
|
|
||||||
// child: Row(
|
|
||||||
// children: [
|
|
||||||
// Text(item.modules.first.moduleAuthor.pubTime),
|
|
||||||
// if (item.modules.first.moduleAuthor.pubTime != '' &&
|
|
||||||
// item.modules.first.moduleAuthor.pubAction != '')
|
|
||||||
// const Text(' '),
|
|
||||||
// Text(item.modules.first.moduleAuthor.pubAction),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
// if (source != 'detail' && item.modules.first?.moduleTag?.text != null)
|
|
||||||
// Container(
|
|
||||||
// padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: Theme.of(context).colorScheme.surface,
|
|
||||||
// borderRadius: const BorderRadius.all(Radius.circular(4)),
|
|
||||||
// border: Border.all(
|
|
||||||
// width: 1.25,
|
|
||||||
// color: Theme.of(context).colorScheme.primary,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// child: Text(
|
|
||||||
// item.modules.first.moduleTag.text,
|
|
||||||
// style: TextStyle(
|
|
||||||
// height: 1,
|
|
||||||
// fontSize: 12,
|
|
||||||
// color: Theme.of(context).colorScheme.primary,
|
|
||||||
// ),
|
|
||||||
// strutStyle: const StrutStyle(
|
|
||||||
// leading: 0,
|
|
||||||
// height: 1,
|
|
||||||
// fontSize: 12,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
SizedBox(
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
child: IconButton(
|
|
||||||
tooltip: '更多',
|
|
||||||
style: ButtonStyle(
|
|
||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
useSafeArea: true,
|
|
||||||
isScrollControlled: true,
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: min(640, min(Get.width, Get.height)),
|
|
||||||
),
|
|
||||||
builder: (context) {
|
|
||||||
return MorePanel(
|
|
||||||
item: item,
|
|
||||||
onRemove: onRemove,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.more_vert_outlined, size: 18),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MorePanel extends StatelessWidget {
|
|
||||||
final dynamic item;
|
|
||||||
final Function? onRemove;
|
|
||||||
const MorePanel({
|
|
||||||
super.key,
|
|
||||||
required this.item,
|
|
||||||
this.onRemove,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: Get.back,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(28),
|
|
||||||
topRight: Radius.circular(28),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 35,
|
|
||||||
padding: const EdgeInsets.only(bottom: 2),
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
width: 32,
|
|
||||||
height: 3,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(3))),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (item.type == 'DYNAMIC_TYPE_AV')
|
|
||||||
ListTile(
|
|
||||||
onTap: () async {
|
|
||||||
try {
|
|
||||||
String bvid = item.modules.moduleDynamic.major.archive.bvid;
|
|
||||||
var res = await UserHttp.toViewLater(bvid: bvid);
|
|
||||||
SmartDialog.showToast(res['msg']);
|
|
||||||
Get.back();
|
|
||||||
} catch (err) {
|
|
||||||
SmartDialog.showToast('出错了:${err.toString()}');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
// dense: true,
|
|
||||||
leading: const Icon(Icons.watch_later_outlined, size: 19),
|
|
||||||
title: Text(
|
|
||||||
'稍后再看',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title: Text(
|
|
||||||
'分享动态',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
leading: const Icon(Icons.share_outlined, size: 19),
|
|
||||||
onTap: () {
|
|
||||||
Get.back();
|
|
||||||
Utils.shareText(
|
|
||||||
'${HttpString.dynamicShareBaseUrl}/${item.idStr}');
|
|
||||||
},
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title: Text(
|
|
||||||
'临时屏蔽:${item.modules.moduleAuthor.name}',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
leading: const Icon(Icons.visibility_off_outlined, size: 19),
|
|
||||||
onTap: () {
|
|
||||||
Get.back();
|
|
||||||
DynamicsController dynamicsController =
|
|
||||||
Get.find<DynamicsController>();
|
|
||||||
dynamicsController.tempBannedList
|
|
||||||
.add(item.modules.moduleAuthor.mid);
|
|
||||||
SmartDialog.showToast(
|
|
||||||
'已临时屏蔽${item.modules.moduleAuthor.name}(${item.modules.moduleAuthor.mid}),重启恢复');
|
|
||||||
},
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
),
|
|
||||||
if (item.modules.moduleAuthor.mid == Accounts.main.mid)
|
|
||||||
ListTile(
|
|
||||||
onTap: () async {
|
|
||||||
Get.back();
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('确定删除该动态?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: Get.back,
|
|
||||||
child: Text(
|
|
||||||
'取消',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
onRemove?.call(item.idStr);
|
|
||||||
},
|
|
||||||
child: const Text('确定'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
leading: Icon(Icons.delete_outline,
|
|
||||||
color: Theme.of(context).colorScheme.error, size: 19),
|
|
||||||
title: Text('删除',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.titleSmall!
|
|
||||||
.copyWith(color: Theme.of(context).colorScheme.error)),
|
|
||||||
),
|
|
||||||
const Divider(thickness: 0.1, height: 1),
|
|
||||||
ListTile(
|
|
||||||
onTap: () => Get.back(),
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
dense: true,
|
|
||||||
title: Text(
|
|
||||||
'取消',
|
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// 内容
|
|
||||||
import 'package:PiliPlus/common/widgets/image_view.dart';
|
|
||||||
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pb.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'rich_node_panel.dart';
|
|
||||||
|
|
||||||
class ContentGrpc extends StatelessWidget {
|
|
||||||
final DynamicItem item;
|
|
||||||
final String? source;
|
|
||||||
|
|
||||||
const ContentGrpc({
|
|
||||||
super.key,
|
|
||||||
required this.item,
|
|
||||||
this.source,
|
|
||||||
});
|
|
||||||
|
|
||||||
InlineSpan picsNodes() {
|
|
||||||
return WidgetSpan(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) => imageView(
|
|
||||||
constraints.maxWidth,
|
|
||||||
item.modules.first.moduleDynamic.dynDraw.items
|
|
||||||
.map(
|
|
||||||
(item) => ImageModel(
|
|
||||||
width: item.width,
|
|
||||||
height: item.height,
|
|
||||||
url: item.src,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
TextStyle authorStyle =
|
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
|
||||||
InlineSpan? richNodes = richNode(item, context);
|
|
||||||
return Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 6),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (item.modules.first.moduleDynamic.hasDynTopicSet()) ...[
|
|
||||||
GestureDetector(
|
|
||||||
child: Text(
|
|
||||||
'#${item.modules.first.moduleDynamic.dynTopicSet.topics.first.topicName}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
if (richNodes != null)
|
|
||||||
IgnorePointer(
|
|
||||||
// 禁用SelectableRegion的触摸交互功能
|
|
||||||
ignoring: source == 'detail' ? false : true,
|
|
||||||
child: SelectableRegion(
|
|
||||||
magnifierConfiguration: const TextMagnifierConfiguration(),
|
|
||||||
focusNode: FocusNode(),
|
|
||||||
selectionControls: MaterialTextSelectionControls(),
|
|
||||||
child: Text.rich(
|
|
||||||
/// fix 默认20px高度
|
|
||||||
style: const TextStyle(height: 0),
|
|
||||||
richNodes,
|
|
||||||
maxLines: source == 'detail' ? null : 6,
|
|
||||||
overflow: source == 'detail' ? null : TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (item.modules.first.moduleDynamic.hasDynDraw())
|
|
||||||
Text.rich(
|
|
||||||
picsNodes(),
|
|
||||||
// semanticsLabel: '动态图片',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pb.dart';
|
|
||||||
import 'package:PiliPlus/pages/dynamics/widgets/author_panel_grpc.dart';
|
|
||||||
import 'package:PiliPlus/pages/dynamics/widgets/content_panel_grpc.dart';
|
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DynamicPanelGrpc extends StatelessWidget {
|
|
||||||
final DynamicItem item;
|
|
||||||
final String? source;
|
|
||||||
final Function? onRemove;
|
|
||||||
|
|
||||||
const DynamicPanelGrpc({
|
|
||||||
required this.item,
|
|
||||||
this.source,
|
|
||||||
this.onRemove,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: source == 'detail'
|
|
||||||
? const EdgeInsets.only(bottom: 12)
|
|
||||||
: EdgeInsets.zero,
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// border: Border(
|
|
||||||
// bottom: BorderSide(
|
|
||||||
// width: 8,
|
|
||||||
// color: Theme.of(context).dividerColor.withOpacity(0.05),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
child: Material(
|
|
||||||
elevation: 0,
|
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
color: Theme.of(context).cardColor.withOpacity(0.5),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: source == 'detail' && item.itemType == DynamicType.draw
|
|
||||||
? null
|
|
||||||
: () => Utils.pushDynDetail(item, 1),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 6),
|
|
||||||
child: AuthorPanelGrpc(
|
|
||||||
item: item,
|
|
||||||
source: source,
|
|
||||||
onRemove: onRemove,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ContentGrpc(item: item, source: source),
|
|
||||||
// forWard(item, context, _dynamicsController, source),
|
|
||||||
const SizedBox(height: 2),
|
|
||||||
// if (source == null) ActionPanel(item: item),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/video/reply/emote.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../../http/reply.dart';
|
import '../../http/reply.dart';
|
||||||
|
|
||||||
class EmotePanelController extends CommonController
|
class EmotePanelController
|
||||||
|
extends CommonListController<List<Packages>?, Packages>
|
||||||
with GetTickerProviderStateMixin {
|
with GetTickerProviderStateMixin {
|
||||||
TabController? tabController;
|
TabController? tabController;
|
||||||
|
|
||||||
@@ -16,15 +18,17 @@ class EmotePanelController extends CommonController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<List<Packages>?> response) {
|
||||||
|
if (response.response?.isNotEmpty == true) {
|
||||||
tabController =
|
tabController =
|
||||||
TabController(length: response.response.length, vsync: this);
|
TabController(length: response.response!.length, vsync: this);
|
||||||
|
}
|
||||||
loadingState.value = response;
|
loadingState.value = response;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<List<Packages>?>> customGetData() =>
|
||||||
ReplyHttp.getEmoteList(business: 'reply');
|
ReplyHttp.getEmoteList(business: 'reply');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -29,16 +29,16 @@ class _EmotePanelState extends State<EmotePanel>
|
|||||||
return Obx(() => _buildBody(_emotePanelController.loadingState.value));
|
return Obx(() => _buildBody(_emotePanelController.loadingState.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<Packages>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? Column(
|
? Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: tabBarView(
|
child: tabBarView(
|
||||||
controller: _emotePanelController.tabController,
|
controller: _emotePanelController.tabController,
|
||||||
children: (loadingState.response as List<Packages>).map(
|
children: loadingState.response!.map(
|
||||||
(e) {
|
(e) {
|
||||||
int size = e.emote!.first.meta!.size!;
|
int size = e.emote!.first.meta!.size!;
|
||||||
int type = e.type!;
|
int type = e.type!;
|
||||||
@@ -100,7 +100,7 @@ class _EmotePanelState extends State<EmotePanel>
|
|||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
dividerHeight: 0,
|
dividerHeight: 0,
|
||||||
isScrollable: true,
|
isScrollable: true,
|
||||||
tabs: (loadingState.response as List<Packages>)
|
tabs: loadingState.response!
|
||||||
.map(
|
.map(
|
||||||
(e) => Padding(
|
(e) => Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'package:PiliPlus/http/fan.dart';
|
import 'package:PiliPlus/http/fan.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/fans/result.dart';
|
import 'package:PiliPlus/models/fans/result.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
|
||||||
class FansController extends CommonController {
|
class FansController
|
||||||
|
extends CommonListController<FansDataModel, FansItemModel> {
|
||||||
int ps = 20;
|
int ps = 20;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
late int? mid;
|
late int? mid;
|
||||||
@@ -28,22 +28,12 @@ class FansController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<FansItemModel>? getDataList(FansDataModel response) {
|
||||||
if ((currentPage == 1 && response.response.total < ps) ||
|
return response.list;
|
||||||
(response.response.list as List?).isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response.list ??= <FansItemModel>[];
|
|
||||||
response.response.list!
|
|
||||||
.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response.list);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => FanHttp.fans(
|
Future<LoadingState<FansDataModel>> customGetData() => FanHttp.fans(
|
||||||
vmid: mid,
|
vmid: mid,
|
||||||
pn: currentPage,
|
pn: currentPage,
|
||||||
ps: ps,
|
ps: ps,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/fans/result.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -48,23 +49,27 @@ class _FansPageState extends State<FansPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<FansItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => HttpError(),
|
Loading() => HttpError(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverGrid(
|
? SliverPadding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
|
sliver: SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||||
mainAxisExtent: 56,
|
mainAxisExtent: 56,
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_fansController.onLoadMore();
|
_fansController.onLoadMore();
|
||||||
}
|
}
|
||||||
return fanItem(item: loadingState.response[index]);
|
return fanItem(item: loadingState.response![index]);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(
|
: HttpError(
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
class FavArticleController extends CommonController {
|
class FavArticleController extends CommonListController {
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -19,7 +19,7 @@ class FavArticleController extends CommonController {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List list = (loadingState.value as Success).response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('已取消收藏');
|
SmartDialog.showToast('已取消收藏');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class _FavArticlePageState extends State<FavArticlePage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<dynamic>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
@@ -55,7 +55,7 @@ class _FavArticlePageState extends State<FavArticlePage>
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: StyleString.safeSpace - 5,
|
top: StyleString.safeSpace - 5,
|
||||||
@@ -69,11 +69,11 @@ class _FavArticlePageState extends State<FavArticlePage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favArticleController.onLoadMore();
|
_favArticleController.onLoadMore();
|
||||||
}
|
}
|
||||||
return FavArticleItem(
|
return FavArticleItem(
|
||||||
item: loadingState.response[index],
|
item: loadingState.response![index],
|
||||||
onDelete: () {
|
onDelete: () {
|
||||||
showConfirmDialog(
|
showConfirmDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -81,13 +81,13 @@ class _FavArticlePageState extends State<FavArticlePage>
|
|||||||
onConfirm: () {
|
onConfirm: () {
|
||||||
_favArticleController.onRemove(
|
_favArticleController.onRemove(
|
||||||
index,
|
index,
|
||||||
loadingState.response[index]['opus_id'],
|
loadingState.response![index]['opus_id'],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:PiliPlus/common/widgets/http_error.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/member/article.dart';
|
||||||
import 'package:PiliPlus/pages/fav/note/controller.dart';
|
import 'package:PiliPlus/pages/fav/note/controller.dart';
|
||||||
import 'package:PiliPlus/pages/fav/note/widget/item.dart';
|
import 'package:PiliPlus/pages/fav/note/widget/item.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -132,7 +133,7 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<FavArticleModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
@@ -147,7 +148,7 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
@@ -159,18 +160,18 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favNoteController.onLoadMore();
|
_favNoteController.onLoadMore();
|
||||||
}
|
}
|
||||||
return FavNoteItem(
|
return FavNoteItem(
|
||||||
item: loadingState.response[index],
|
item: loadingState.response![index],
|
||||||
ctr: _favNoteController,
|
ctr: _favNoteController,
|
||||||
onSelect: () {
|
onSelect: () {
|
||||||
_favNoteController.onSelect(index);
|
_favNoteController.onSelect(index);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
|
import 'package:PiliPlus/models/member/article.dart';
|
||||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
|
|
||||||
class FavNoteController extends MultiSelectController {
|
class FavNoteController
|
||||||
|
extends MultiSelectController<List<FavArticleModel>?, FavArticleModel> {
|
||||||
FavNoteController(this.isPublish);
|
FavNoteController(this.isPublish);
|
||||||
|
|
||||||
final bool isPublish;
|
final bool isPublish;
|
||||||
|
|
||||||
late final allSelected = false.obs;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -18,48 +17,36 @@ class FavNoteController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
onSelect(int index) {
|
onSelect(int index, [bool disableSelect = true]) {
|
||||||
List list = (loadingState.value as Success).response;
|
super.onSelect(index, false);
|
||||||
list[index]['checked'] = !(list[index]['checked'] ?? false);
|
|
||||||
checkedCount.value = list.where((item) => item['checked'] == true).length;
|
|
||||||
loadingState.value = LoadingState.success(list);
|
|
||||||
allSelected.value = checkedCount.value == list.length;
|
|
||||||
if (checkedCount.value == 0) {
|
|
||||||
enableMultiSelect.value = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleSelect([bool checked = false]) {
|
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||||
allSelected.value = checked;
|
allSelected.value = checked;
|
||||||
if (loadingState.value is Success) {
|
super.handleSelect(checked, false);
|
||||||
List list = (loadingState.value as Success).response;
|
|
||||||
if (list.isNotEmpty) {
|
|
||||||
loadingState.value = LoadingState.success(
|
|
||||||
list.map((item) => item..['checked'] = checked).toList());
|
|
||||||
checkedCount.value = checked ? list.length : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() {
|
Future<LoadingState<List<FavArticleModel>?>> customGetData() {
|
||||||
return isPublish
|
return isPublish
|
||||||
? VideoHttp.userNoteList(page: currentPage)
|
? VideoHttp.userNoteList(page: currentPage)
|
||||||
: VideoHttp.noteList(page: currentPage);
|
: VideoHttp.noteList(page: currentPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRemove() async {
|
void onRemove() async {
|
||||||
List dataList = (loadingState.value as Success).response as List;
|
List<FavArticleModel> dataList = (loadingState.value as Success).response;
|
||||||
Set removeList = dataList.where((item) => item['checked'] == true).toSet();
|
Set<FavArticleModel> removeList =
|
||||||
|
dataList.where((item) => item.checked == true).toSet();
|
||||||
final res = await VideoHttp.delNote(
|
final res = await VideoHttp.delNote(
|
||||||
isPublish: isPublish,
|
isPublish: isPublish,
|
||||||
noteIds: removeList
|
noteIds: removeList
|
||||||
.map((item) => isPublish ? item['cvid'] : item['note_id'])
|
.map((item) => isPublish ? item.cvid : item.noteId)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List remainList = dataList.toSet().difference(removeList).toList();
|
List<FavArticleModel> remainList =
|
||||||
|
dataList.toSet().difference(removeList).toList();
|
||||||
loadingState.value = LoadingState.success(remainList);
|
loadingState.value = LoadingState.success(remainList);
|
||||||
enableMultiSelect.value = false;
|
enableMultiSelect.value = false;
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:PiliPlus/models/member/article.dart';
|
||||||
import 'package:PiliPlus/pages/fav/note/controller.dart';
|
import 'package:PiliPlus/pages/fav/note/controller.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -12,7 +13,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
required this.onSelect,
|
required this.onSelect,
|
||||||
});
|
});
|
||||||
|
|
||||||
final dynamic item;
|
final FavArticleModel item;
|
||||||
final FavNoteController ctr;
|
final FavNoteController ctr;
|
||||||
final VoidCallback onSelect;
|
final VoidCallback onSelect;
|
||||||
|
|
||||||
@@ -26,10 +27,12 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
onSelect();
|
onSelect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (item.webUrl?.isNotEmpty == true) {
|
||||||
Utils.handleWebview(
|
Utils.handleWebview(
|
||||||
item['web_url'],
|
item.webUrl!,
|
||||||
inApp: true,
|
inApp: true,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
if (!ctr.enableMultiSelect.value) {
|
if (!ctr.enableMultiSelect.value) {
|
||||||
@@ -53,7 +56,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
item['title'],
|
item.title ?? '',
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -64,14 +67,14 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
item['summary'],
|
item.summary ?? '',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
item['message'],
|
item.message ?? '',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
@@ -80,7 +83,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (item['arc']?['pic'] != null) ...[
|
if (item.pic?.isNotEmpty == true) ...[
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
AspectRatio(
|
AspectRatio(
|
||||||
aspectRatio: StyleString.aspectRatio,
|
aspectRatio: StyleString.aspectRatio,
|
||||||
@@ -91,7 +94,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
NetworkImgLayer(
|
NetworkImgLayer(
|
||||||
src: item['arc']?['pic'],
|
src: item.pic,
|
||||||
width: boxConstraints.maxWidth,
|
width: boxConstraints.maxWidth,
|
||||||
height: boxConstraints.maxHeight,
|
height: boxConstraints.maxHeight,
|
||||||
),
|
),
|
||||||
@@ -100,7 +103,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, constraints) =>
|
builder: (context, constraints) =>
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: item['checked'] == true ? 1 : 0,
|
opacity: item.checked == true ? 1 : 0,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@@ -115,7 +118,7 @@ class FavNoteItem extends StatelessWidget {
|
|||||||
width: 34,
|
width: 34,
|
||||||
height: 34,
|
height: 34,
|
||||||
child: AnimatedScale(
|
child: AnimatedScale(
|
||||||
scale: item['checked'] == true ? 1 : 0,
|
scale: item.checked == true ? 1 : 0,
|
||||||
duration:
|
duration:
|
||||||
const Duration(milliseconds: 250),
|
const Duration(milliseconds: 250),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:PiliPlus/common/widgets/http_error.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/bangumi/list.dart';
|
||||||
import 'package:PiliPlus/pages/fav/pgc/controller.dart';
|
import 'package:PiliPlus/pages/fav/pgc/controller.dart';
|
||||||
import 'package:PiliPlus/pages/fav/pgc/widget/item.dart';
|
import 'package:PiliPlus/pages/fav/pgc/widget/item.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -126,7 +127,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
if (_favPgcController.checkedCount.value !=
|
if (_favPgcController.checkedCount.value !=
|
||||||
0) {
|
0) {
|
||||||
_favPgcController
|
_favPgcController
|
||||||
.onUpdate(item['followStatus']);
|
.onUpdateList(item['followStatus']);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -156,7 +157,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<BangumiListItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
@@ -171,7 +172,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
@@ -183,11 +184,12 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favPgcController.onLoadMore();
|
_favPgcController.onLoadMore();
|
||||||
}
|
}
|
||||||
|
final item = loadingState.response![index];
|
||||||
return FavPgcItem(
|
return FavPgcItem(
|
||||||
item: loadingState.response[index],
|
item: item,
|
||||||
ctr: _favPgcController,
|
ctr: _favPgcController,
|
||||||
onSelect: () {
|
onSelect: () {
|
||||||
_favPgcController.onSelect(index);
|
_favPgcController.onSelect(index);
|
||||||
@@ -201,13 +203,13 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
if (followStatus == -1) {
|
if (followStatus == -1) {
|
||||||
_favPgcController.bangumiDel(
|
_favPgcController.bangumiDel(
|
||||||
index,
|
index,
|
||||||
loadingState.response[index].seasonId,
|
item.seasonId,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_favPgcController.bangumiUpdate(
|
_favPgcController.onUpdate(
|
||||||
index,
|
index,
|
||||||
followStatus,
|
followStatus,
|
||||||
loadingState.response[index].seasonId,
|
item.seasonId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -215,7 +217,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,14 +8,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class FavPgcController extends MultiSelectController {
|
class FavPgcController
|
||||||
|
extends MultiSelectController<BangumiListDataModel, BangumiListItemModel> {
|
||||||
final int type;
|
final int type;
|
||||||
final int followStatus;
|
final int followStatus;
|
||||||
|
|
||||||
FavPgcController(this.type, this.followStatus);
|
FavPgcController(this.type, this.followStatus);
|
||||||
|
|
||||||
late final allSelected = false.obs;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -23,34 +22,24 @@ class FavPgcController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
onSelect(int index) {
|
onSelect(int index, [bool disableSelect = true]) {
|
||||||
List<BangumiListItemModel> list = (loadingState.value as Success).response;
|
super.onSelect(index, false);
|
||||||
list[index].checked = !(list[index].checked ?? false);
|
|
||||||
checkedCount.value = list.where((item) => item.checked == true).length;
|
|
||||||
loadingState.value = LoadingState.success(list);
|
|
||||||
allSelected.value = checkedCount.value == list.length;
|
|
||||||
if (checkedCount.value == 0) {
|
|
||||||
enableMultiSelect.value = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleSelect([bool checked = false]) {
|
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||||
allSelected.value = checked;
|
allSelected.value = checked;
|
||||||
if (loadingState.value is Success) {
|
super.handleSelect(checked, false);
|
||||||
List<BangumiListItemModel> list =
|
|
||||||
(loadingState.value as Success).response;
|
|
||||||
if (list.isNotEmpty) {
|
|
||||||
loadingState.value = LoadingState.success(list
|
|
||||||
.map<BangumiListItemModel>((item) => item..checked = checked)
|
|
||||||
.toList());
|
|
||||||
checkedCount.value = checked ? list.length : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => BangumiHttp.bangumiFollowList(
|
List<BangumiListItemModel>? getDataList(BangumiListDataModel response) {
|
||||||
|
return response.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<BangumiListDataModel>> customGetData() =>
|
||||||
|
BangumiHttp.bangumiFollowList(
|
||||||
mid: Accounts.main.mid,
|
mid: Accounts.main.mid,
|
||||||
type: type,
|
type: type,
|
||||||
followStatus: followStatus,
|
followStatus: followStatus,
|
||||||
@@ -71,12 +60,12 @@ class FavPgcController extends MultiSelectController {
|
|||||||
List<BangumiListItemModel> list =
|
List<BangumiListItemModel> list =
|
||||||
(loadingState.value as Success).response;
|
(loadingState.value as Success).response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
}
|
}
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future onUpdate(followStatus) async {
|
Future onUpdateList(followStatus) async {
|
||||||
List<BangumiListItemModel> dataList =
|
List<BangumiListItemModel> dataList =
|
||||||
(loadingState.value as Success).response as List<BangumiListItemModel>;
|
(loadingState.value as Success).response as List<BangumiListItemModel>;
|
||||||
Set<BangumiListItemModel> updateList =
|
Set<BangumiListItemModel> updateList =
|
||||||
@@ -96,7 +85,7 @@ class FavPgcController extends MultiSelectController {
|
|||||||
List<BangumiListItemModel> list =
|
List<BangumiListItemModel> list =
|
||||||
(ctr.loadingState.value as Success).response;
|
(ctr.loadingState.value as Success).response;
|
||||||
list.insertAll(0, updateList.map((item) => item..checked = null));
|
list.insertAll(0, updateList.map((item) => item..checked = null));
|
||||||
ctr.loadingState.value = LoadingState.success(list);
|
ctr.loadingState.refresh();
|
||||||
ctr.allSelected.value = false;
|
ctr.allSelected.value = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -106,7 +95,7 @@ class FavPgcController extends MultiSelectController {
|
|||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future bangumiUpdate(index, followStatus, seasonId) async {
|
Future onUpdate(index, followStatus, seasonId) async {
|
||||||
var result = await VideoHttp.bangumiUpdate(
|
var result = await VideoHttp.bangumiUpdate(
|
||||||
seasonId: [seasonId],
|
seasonId: [seasonId],
|
||||||
status: followStatus,
|
status: followStatus,
|
||||||
@@ -115,14 +104,14 @@ class FavPgcController extends MultiSelectController {
|
|||||||
List<BangumiListItemModel> list =
|
List<BangumiListItemModel> list =
|
||||||
(loadingState.value as Success).response;
|
(loadingState.value as Success).response;
|
||||||
final item = list.removeAt(index);
|
final item = list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
try {
|
try {
|
||||||
final ctr = Get.find<FavPgcController>(tag: '$type$followStatus');
|
final ctr = Get.find<FavPgcController>(tag: '$type$followStatus');
|
||||||
if (ctr.loadingState.value is Success) {
|
if (ctr.loadingState.value is Success) {
|
||||||
List<BangumiListItemModel> list =
|
List<BangumiListItemModel> list =
|
||||||
(ctr.loadingState.value as Success).response;
|
(ctr.loadingState.value as Success).response;
|
||||||
list.insert(0, item);
|
list.insert(0, item);
|
||||||
ctr.loadingState.value = LoadingState.success(list);
|
ctr.loadingState.refresh();
|
||||||
ctr.allSelected.value = false;
|
ctr.allSelected.value = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/user/fav_folder.dart';
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
|
||||||
class FavController extends CommonController {
|
class FavController
|
||||||
|
extends CommonListController<FavFolderData, FavFolderItemData> {
|
||||||
late final dynamic mid = Accounts.main.mid;
|
late final dynamic mid = Accounts.main.mid;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -24,22 +24,20 @@ class FavController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<FavFolderItemData>? getDataList(FavFolderData response) {
|
||||||
if (response.response.hasMore == false ||
|
return response.list;
|
||||||
(response.response.list as List?).isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response.list ??= <FavFolderItemData>[];
|
|
||||||
response.response.list!
|
|
||||||
.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response.list);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => UserHttp.userfavFolder(
|
bool customHandleResponse(bool isRefresh, Success<FavFolderData> response) {
|
||||||
|
if (response.response.hasMore == false) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<FavFolderData>> customGetData() => UserHttp.userfavFolder(
|
||||||
pn: currentPage,
|
pn: currentPage,
|
||||||
ps: 10,
|
ps: 10,
|
||||||
mid: mid,
|
mid: mid,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -44,7 +45,7 @@ class _FavVideoPageState extends State<FavVideoPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<FavFolderItemData>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
@@ -59,7 +60,7 @@ class _FavVideoPageState extends State<FavVideoPage>
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: StyleString.safeSpace - 5,
|
top: StyleString.safeSpace - 5,
|
||||||
@@ -72,33 +73,31 @@ class _FavVideoPageState extends State<FavVideoPage>
|
|||||||
childAspectRatio: StyleString.aspectRatio * 2.2,
|
childAspectRatio: StyleString.aspectRatio * 2.2,
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favController.onLoadMore();
|
_favController.onLoadMore();
|
||||||
}
|
}
|
||||||
String heroTag =
|
final item = loadingState.response![index];
|
||||||
Utils.makeHeroTag(loadingState.response[index].fid);
|
String heroTag = Utils.makeHeroTag(item.fid);
|
||||||
return FavItem(
|
return FavItem(
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
favFolderItem: loadingState.response[index],
|
favFolderItem: item,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
dynamic res = await Get.toNamed(
|
dynamic res = await Get.toNamed(
|
||||||
'/favDetail',
|
'/favDetail',
|
||||||
arguments: loadingState.response[index],
|
arguments: item,
|
||||||
parameters: {
|
parameters: {
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'mediaId':
|
'mediaId': item.id.toString(),
|
||||||
loadingState.response[index].id.toString(),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
List list =
|
List<FavFolderItemData> list =
|
||||||
(_favController.loadingState.value as Success)
|
(_favController.loadingState.value as Success)
|
||||||
.response;
|
.response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
_favController.loadingState.value =
|
_favController.loadingState.refresh();
|
||||||
LoadingState.success(list);
|
|
||||||
} else {
|
} else {
|
||||||
Future.delayed(const Duration(milliseconds: 255), () {
|
Future.delayed(const Duration(milliseconds: 255), () {
|
||||||
_favController.onRefresh();
|
_favController.onRefresh();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
import 'package:PiliPlus/pages/fav/article/view.dart';
|
import 'package:PiliPlus/pages/fav/article/view.dart';
|
||||||
import 'package:PiliPlus/pages/fav/note/view.dart';
|
import 'package:PiliPlus/pages/fav/note/view.dart';
|
||||||
import 'package:PiliPlus/pages/fav/pgc/view.dart';
|
import 'package:PiliPlus/pages/fav/pgc/view.dart';
|
||||||
@@ -54,13 +55,13 @@ class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
|
|||||||
Get.toNamed('/createFav')?.then(
|
Get.toNamed('/createFav')?.then(
|
||||||
(data) {
|
(data) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
List list = _favController.loadingState.value is Success
|
List<FavFolderItemData> list =
|
||||||
|
_favController.loadingState.value is Success
|
||||||
? (_favController.loadingState.value as Success)
|
? (_favController.loadingState.value as Success)
|
||||||
.response
|
.response
|
||||||
: [];
|
: <FavFolderItemData>[];
|
||||||
list.insert(list.isNotEmpty ? 1 : 0, data);
|
list.insert(list.isNotEmpty ? 1 : 0, data);
|
||||||
_favController.loadingState.value =
|
_favController.loadingState.refresh();
|
||||||
LoadingState.success(list);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -81,6 +82,7 @@ class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
|
|||||||
'title': item.title,
|
'title': item.title,
|
||||||
'count': item.mediaCount,
|
'count': item.mediaCount,
|
||||||
'searchType': SearchType.fav,
|
'searchType': SearchType.fav,
|
||||||
|
'isOwner': true,
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:PiliPlus/http/user.dart';
|
|||||||
import 'package:PiliPlus/models/user/fav_detail.dart';
|
import 'package:PiliPlus/models/user/fav_detail.dart';
|
||||||
import 'package:PiliPlus/models/user/fav_folder.dart';
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -11,7 +10,8 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
|
|
||||||
class FavDetailController extends MultiSelectController {
|
class FavDetailController
|
||||||
|
extends MultiSelectController<FavDetailData, FavDetailItemData> {
|
||||||
Rx<FavFolderItemData> item = FavFolderItemData().obs;
|
Rx<FavFolderItemData> item = FavFolderItemData().obs;
|
||||||
int? mediaId;
|
int? mediaId;
|
||||||
late String heroTag;
|
late String heroTag;
|
||||||
@@ -35,40 +35,39 @@ class FavDetailController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<FavDetailItemData>? getDataList(FavDetailData response) {
|
||||||
|
return response.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void checkIsEnd(int length) {
|
||||||
|
if (item.value.mediaCount != null && length >= item.value.mediaCount!) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success<FavDetailData> response) {
|
||||||
FavDetailData data = response.response;
|
FavDetailData data = response.response;
|
||||||
if (currentPage == 1) {
|
if (isRefresh) {
|
||||||
item.value = data.info ?? FavFolderItemData();
|
item.value = data.info ?? FavFolderItemData();
|
||||||
isOwner.value = data.info?.mid == mid;
|
isOwner.value = data.info?.mid == mid;
|
||||||
}
|
}
|
||||||
if (data.list.isNullOrEmpty) {
|
return false;
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
data.list ??= <FavDetailItemData>[];
|
|
||||||
data.list!.insertAll(
|
|
||||||
0,
|
|
||||||
(loadingState.value as Success).response,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isEnd.not && (data.list?.length ?? 0) >= (data.info?.mediaCount ?? 0)) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.list);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancelFav(int id, int type) async {
|
onCancelFav(int index, int id, int type) async {
|
||||||
var result = await VideoHttp.delFav(
|
var result = await VideoHttp.delFav(
|
||||||
ids: ['$id:$type'],
|
ids: ['$id:$type'],
|
||||||
delIds: mediaId.toString(),
|
delIds: mediaId.toString(),
|
||||||
);
|
);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
List dataList = (loadingState.value as Success).response;
|
List<FavDetailItemData> dataList =
|
||||||
dataList.removeWhere((item) => item.id == id);
|
(loadingState.value as Success).response;
|
||||||
item.value.mediaCount = item.value.mediaCount! - 1;
|
item.value.mediaCount = item.value.mediaCount! - 1;
|
||||||
item.refresh();
|
item.refresh();
|
||||||
loadingState.value = LoadingState.success(dataList);
|
dataList.removeAt(index);
|
||||||
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('取消收藏');
|
SmartDialog.showToast('取消收藏');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
@@ -76,7 +75,8 @@ class FavDetailController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => UserHttp.userFavFolderDetail(
|
Future<LoadingState<FavDetailData>> customGetData() =>
|
||||||
|
UserHttp.userFavFolderDetail(
|
||||||
pn: currentPage,
|
pn: currentPage,
|
||||||
ps: 20,
|
ps: 20,
|
||||||
mediaId: mediaId!,
|
mediaId: mediaId!,
|
||||||
@@ -110,8 +110,9 @@ class FavDetailController extends MultiSelectController {
|
|||||||
delIds: mediaId.toString(),
|
delIds: mediaId.toString(),
|
||||||
);
|
);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
List dataList = (loadingState.value as Success).response;
|
List<FavDetailItemData> dataList =
|
||||||
List remainList =
|
(loadingState.value as Success).response;
|
||||||
|
List<FavDetailItemData> remainList =
|
||||||
dataList.toSet().difference(list.toSet()).toList();
|
dataList.toSet().difference(list.toSet()).toList();
|
||||||
item.value.mediaCount = item.value.mediaCount! - list.length;
|
item.value.mediaCount = item.value.mediaCount! - list.length;
|
||||||
item.refresh();
|
item.refresh();
|
||||||
@@ -137,8 +138,7 @@ class FavDetailController extends MultiSelectController {
|
|||||||
|
|
||||||
void toViewPlayAll() {
|
void toViewPlayAll() {
|
||||||
if (loadingState.value is Success) {
|
if (loadingState.value is Success) {
|
||||||
List<FavDetailItemData> list = List<FavDetailItemData>.from(
|
List<FavDetailItemData> list = (loadingState.value as Success).response;
|
||||||
(loadingState.value as Success).response);
|
|
||||||
for (FavDetailItemData element in list) {
|
for (FavDetailItemData element in list) {
|
||||||
if (element.cid == null) {
|
if (element.cid == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class _FavSortPageState extends State<FavSortPage> {
|
|||||||
FavDetailController get _favDetailController => widget.favDetailController;
|
FavDetailController get _favDetailController => widget.favDetailController;
|
||||||
|
|
||||||
final GlobalKey _key = GlobalKey();
|
final GlobalKey _key = GlobalKey();
|
||||||
late List<FavDetailItemData> list = List<FavDetailItemData>.from(
|
late List<FavDetailItemData> sortList = List<FavDetailItemData>.from(
|
||||||
(_favDetailController.loadingState.value as Success).response);
|
(_favDetailController.loadingState.value as Success).response);
|
||||||
List<String> sort = <String>[];
|
List<String> sort = <String>[];
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class _FavSortPageState extends State<FavSortPage> {
|
|||||||
if (_favDetailController.loadingState.value is Success) {
|
if (_favDetailController.loadingState.value is Success) {
|
||||||
List<FavDetailItemData> list =
|
List<FavDetailItemData> list =
|
||||||
(_favDetailController.loadingState.value as Success).response;
|
(_favDetailController.loadingState.value as Success).response;
|
||||||
this.list.addAll(list.sublist(this.list.length));
|
this.sortList.addAll(list.sublist(this.sortList.length));
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ class _FavSortPageState extends State<FavSortPage> {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast('排序完成');
|
SmartDialog.showToast('排序完成');
|
||||||
_favDetailController.loadingState.value =
|
_favDetailController.loadingState.value =
|
||||||
LoadingState.success(list);
|
LoadingState.success(sortList);
|
||||||
Get.back();
|
Get.back();
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
@@ -103,14 +103,14 @@ class _FavSortPageState extends State<FavSortPage> {
|
|||||||
newIndex -= 1;
|
newIndex -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
final oldItem = list[oldIndex];
|
final oldItem = sortList[oldIndex];
|
||||||
final newItem =
|
final newItem =
|
||||||
list.getOrNull(oldIndex > newIndex ? newIndex - 1 : newIndex);
|
sortList.getOrNull(oldIndex > newIndex ? newIndex - 1 : newIndex);
|
||||||
sort.add(
|
sort.add(
|
||||||
'${newItem == null ? '0:0' : '${newItem.id}:${newItem.type}'}:${oldItem.id}:${oldItem.type}');
|
'${newItem == null ? '0:0' : '${newItem.id}:${newItem.type}'}:${oldItem.id}:${oldItem.type}');
|
||||||
|
|
||||||
final tabsItem = list.removeAt(oldIndex);
|
final tabsItem = sortList.removeAt(oldIndex);
|
||||||
list.insert(newIndex, tabsItem);
|
sortList.insert(newIndex, tabsItem);
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ class _FavSortPageState extends State<FavSortPage> {
|
|||||||
footer: SizedBox(
|
footer: SizedBox(
|
||||||
height: MediaQuery.of(context).padding.bottom + 80,
|
height: MediaQuery.of(context).padding.bottom + 80,
|
||||||
),
|
),
|
||||||
children: list
|
children: sortList
|
||||||
.map(
|
.map(
|
||||||
(item) => Stack(
|
(item) => Stack(
|
||||||
key: Key(item.id.toString()),
|
key: Key(item.id.toString()),
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
visualDensity:
|
visualDensity:
|
||||||
VisualDensity(horizontal: -2, vertical: -2),
|
VisualDensity(horizontal: -2, vertical: -2),
|
||||||
),
|
),
|
||||||
onPressed: () => Utils.onCopyOrMove(
|
onPressed: () =>
|
||||||
|
Utils.onCopyOrMove<FavDetailItemData>(
|
||||||
context: context,
|
context: context,
|
||||||
isCopy: true,
|
isCopy: true,
|
||||||
ctr: _favDetailController,
|
ctr: _favDetailController,
|
||||||
@@ -155,7 +156,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
visualDensity:
|
visualDensity:
|
||||||
VisualDensity(horizontal: -2, vertical: -2),
|
VisualDensity(horizontal: -2, vertical: -2),
|
||||||
),
|
),
|
||||||
onPressed: () => Utils.onCopyOrMove(
|
onPressed: () =>
|
||||||
|
Utils.onCopyOrMove<FavDetailItemData>(
|
||||||
context: context,
|
context: context,
|
||||||
isCopy: false,
|
isCopy: false,
|
||||||
ctr: _favDetailController,
|
ctr: _favDetailController,
|
||||||
@@ -188,15 +190,18 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
: [
|
: [
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: '搜索',
|
tooltip: '搜索',
|
||||||
onPressed: () =>
|
onPressed: () => Get.toNamed(
|
||||||
Get.toNamed('/favSearch', arguments: {
|
'/favSearch',
|
||||||
|
arguments: {
|
||||||
'type': 0,
|
'type': 0,
|
||||||
'mediaId': int.parse(mediaId),
|
'mediaId': int.parse(mediaId),
|
||||||
'title': _favDetailController.item.value.title,
|
'title': _favDetailController.item.value.title,
|
||||||
'count':
|
'count':
|
||||||
_favDetailController.item.value.mediaCount,
|
_favDetailController.item.value.mediaCount,
|
||||||
'searchType': SearchType.fav,
|
'searchType': SearchType.fav,
|
||||||
}),
|
'isOwner': _favDetailController.isOwner.value,
|
||||||
|
},
|
||||||
|
),
|
||||||
icon: const Icon(Icons.search_outlined),
|
icon: const Icon(Icons.search_outlined),
|
||||||
),
|
),
|
||||||
// IconButton(
|
// IconButton(
|
||||||
@@ -416,7 +421,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<FavDetailItemData>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
@@ -431,7 +436,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.of(context).padding.bottom + 85,
|
bottom: MediaQuery.of(context).padding.bottom + 85,
|
||||||
@@ -444,7 +449,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length) {
|
if (index == loadingState.response!.length) {
|
||||||
_favDetailController.onLoadMore();
|
_favDetailController.onLoadMore();
|
||||||
return Container(
|
return Container(
|
||||||
height: 60,
|
height: 60,
|
||||||
@@ -458,25 +463,26 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
FavDetailItemData element = loadingState.response[index];
|
FavDetailItemData item = loadingState.response![index];
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: FavVideoCardH(
|
child: FavVideoCardH(
|
||||||
videoItem: element,
|
videoItem: item,
|
||||||
callFn: () => _favDetailController.onCancelFav(
|
callFn: () => _favDetailController.onCancelFav(
|
||||||
element.id!,
|
index,
|
||||||
element.type!,
|
item.id!,
|
||||||
|
item.type!,
|
||||||
),
|
),
|
||||||
onViewFav: () {
|
onViewFav: () {
|
||||||
Utils.toViewPage(
|
Utils.toViewPage(
|
||||||
'bvid=${element.bvid}&cid=${element.cid}',
|
'bvid=${item.bvid}&cid=${item.cid}',
|
||||||
arguments: {
|
arguments: {
|
||||||
'videoItem': element,
|
'videoItem': item,
|
||||||
'heroTag': Utils.makeHeroTag(element.bvid),
|
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||||
'sourceType': 'fav',
|
'sourceType': 'fav',
|
||||||
'mediaId': _favDetailController.item.value.id,
|
'mediaId': _favDetailController.item.value.id,
|
||||||
'oid': element.id,
|
'oid': item.id,
|
||||||
'favTitle':
|
'favTitle':
|
||||||
_favDetailController.item.value.title,
|
_favDetailController.item.value.title,
|
||||||
'count': _favDetailController
|
'count': _favDetailController
|
||||||
@@ -513,10 +519,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, constraints) =>
|
builder: (context, constraints) =>
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity:
|
opacity: item.checked == true ? 1 : 0,
|
||||||
loadingState.response[index].checked == true
|
|
||||||
? 1
|
|
||||||
: 0,
|
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@@ -531,11 +534,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
width: 34,
|
width: 34,
|
||||||
height: 34,
|
height: 34,
|
||||||
child: AnimatedScale(
|
child: AnimatedScale(
|
||||||
scale: loadingState
|
scale: item.checked == true ? 1 : 0,
|
||||||
.response[index].checked ==
|
|
||||||
true
|
|
||||||
? 1
|
|
||||||
: 0,
|
|
||||||
duration:
|
duration:
|
||||||
const Duration(milliseconds: 250),
|
const Duration(milliseconds: 250),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
@@ -571,7 +570,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length + 1,
|
childCount: loadingState.response!.length + 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
@@ -9,7 +9,7 @@ import 'package:PiliPlus/http/user.dart';
|
|||||||
|
|
||||||
import '../../http/video.dart';
|
import '../../http/video.dart';
|
||||||
|
|
||||||
class FavSearchController extends CommonController {
|
class FavSearchController extends CommonListController {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
final searchFocusNode = FocusNode();
|
final searchFocusNode = FocusNode();
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ class FavSearchController extends CommonController {
|
|||||||
int? mediaId;
|
int? mediaId;
|
||||||
int? mid;
|
int? mid;
|
||||||
late SearchType searchType;
|
late SearchType searchType;
|
||||||
|
final bool? isOwner = Get.arguments['isOwner'];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@@ -45,23 +46,19 @@ class FavSearchController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List? getDataList(response) {
|
||||||
late List currentList = loadingState.value is Success
|
return response.list;
|
||||||
? (loadingState.value as Success).response
|
}
|
||||||
: [];
|
|
||||||
List? dataList = currentPage == 1
|
@override
|
||||||
? response.response.list
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
: response.response.list != null
|
|
||||||
? currentList + response.response.list
|
|
||||||
: currentList;
|
|
||||||
isEnd = searchType == SearchType.fav
|
isEnd = searchType == SearchType.fav
|
||||||
? response.response.hasMore == false
|
? response.response.hasMore == false
|
||||||
: response.response.list == null || response.response.list.isEmpty;
|
: response.response.list == null || response.response.list.isEmpty;
|
||||||
loadingState.value = LoadingState.success(dataList);
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancelFav(int id, int type) async {
|
onCancelFav(int index, int id, int type) async {
|
||||||
var result = await VideoHttp.favVideo(
|
var result = await VideoHttp.favVideo(
|
||||||
aid: id,
|
aid: id,
|
||||||
addIds: '',
|
addIds: '',
|
||||||
@@ -70,8 +67,8 @@ class FavSearchController extends CommonController {
|
|||||||
);
|
);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
List dataList = (loadingState.value as Success).response;
|
List dataList = (loadingState.value as Success).response;
|
||||||
dataList.removeWhere((item) => item.id == id);
|
dataList.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(dataList);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('取消收藏');
|
SmartDialog.showToast('取消收藏');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +101,7 @@ class FavSearchController extends CommonController {
|
|||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future delHistory(kid, business) async {
|
Future onDelHistory(index, kid, business) async {
|
||||||
String resKid = 'archive_$kid';
|
String resKid = 'archive_$kid';
|
||||||
if (business == 'live') {
|
if (business == 'live') {
|
||||||
resKid = 'live_$kid';
|
resKid = 'live_$kid';
|
||||||
@@ -115,8 +112,8 @@ class FavSearchController extends CommonController {
|
|||||||
var res = await UserHttp.delHistory([resKid]);
|
var res = await UserHttp.delHistory([resKid]);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List historyList = (loadingState.value as Success).response;
|
List historyList = (loadingState.value as Success).response;
|
||||||
historyList.removeWhere((e) => e.kid == kid);
|
historyList.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(historyList);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,12 +61,12 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<dynamic>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => errorWidget(),
|
Loading() => errorWidget(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? switch (_favSearchCtr.searchType) {
|
? switch (_favSearchCtr.searchType) {
|
||||||
SearchType.fav => CustomScrollView(
|
SearchType.fav || SearchType.history => CustomScrollView(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _favSearchCtr.scrollController,
|
controller: _favSearchCtr.scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
@@ -82,30 +82,34 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favSearchCtr.onLoadMore();
|
_favSearchCtr.onLoadMore();
|
||||||
}
|
}
|
||||||
final element = loadingState.response[index];
|
final item = loadingState.response![index];
|
||||||
return FavVideoCardH(
|
return _favSearchCtr.searchType == SearchType.fav
|
||||||
videoItem: element,
|
? FavVideoCardH(
|
||||||
|
videoItem: item,
|
||||||
|
isOwner: _favSearchCtr.isOwner ?? false,
|
||||||
searchType: _favSearchCtr.type,
|
searchType: _favSearchCtr.type,
|
||||||
callFn: _favSearchCtr.type != 1
|
callFn: _favSearchCtr.type != 1
|
||||||
? () {
|
? () {
|
||||||
_favSearchCtr.onCancelFav(
|
_favSearchCtr.onCancelFav(
|
||||||
element.id!,
|
index,
|
||||||
element.type,
|
item.id!,
|
||||||
|
item.type,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
onViewFav: () {
|
onViewFav: () {
|
||||||
Utils.toViewPage(
|
Utils.toViewPage(
|
||||||
'bvid=${element.bvid}&cid=${element.cid}',
|
'bvid=${item.bvid}&cid=${item.cid}',
|
||||||
arguments: {
|
arguments: {
|
||||||
'videoItem': element,
|
'videoItem': item,
|
||||||
'heroTag': Utils.makeHeroTag(element.bvid),
|
'heroTag':
|
||||||
|
Utils.makeHeroTag(item.bvid),
|
||||||
'sourceType': 'fav',
|
'sourceType': 'fav',
|
||||||
'mediaId': Get.arguments['mediaId'],
|
'mediaId': Get.arguments['mediaId'],
|
||||||
'oid': element.id,
|
'oid': item.id,
|
||||||
'favTitle': Get.arguments['title'],
|
'favTitle': Get.arguments['title'],
|
||||||
'count': Get.arguments['count'],
|
'count': Get.arguments['count'],
|
||||||
'desc': true,
|
'desc': true,
|
||||||
@@ -113,9 +117,18 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: HistoryItem(
|
||||||
|
videoItem: item,
|
||||||
|
ctr: _favSearchCtr,
|
||||||
|
onChoose: null,
|
||||||
|
onDelete: (kid, business) {
|
||||||
|
_favSearchCtr.onDelHistory(
|
||||||
|
index, kid, business);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -126,47 +139,16 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||||
),
|
),
|
||||||
controller: _favSearchCtr.scrollController,
|
controller: _favSearchCtr.scrollController,
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
itemBuilder: ((context, index) {
|
itemBuilder: ((context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_favSearchCtr.onLoadMore();
|
_favSearchCtr.onLoadMore();
|
||||||
}
|
}
|
||||||
return FollowItem(
|
return FollowItem(
|
||||||
item: loadingState.response[index],
|
item: loadingState.response![index],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
SearchType.history => CustomScrollView(
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
controller: _favSearchCtr.scrollController,
|
|
||||||
slivers: [
|
|
||||||
SliverPadding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
|
||||||
),
|
|
||||||
sliver: SliverGrid(
|
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
|
||||||
mainAxisSpacing: 2,
|
|
||||||
maxCrossAxisExtent: Grid.mediumCardWidth * 2,
|
|
||||||
childAspectRatio: StyleString.aspectRatio * 2.2,
|
|
||||||
),
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(context, index) {
|
|
||||||
if (index == loadingState.response.length - 1) {
|
|
||||||
_favSearchCtr.onLoadMore();
|
|
||||||
}
|
|
||||||
return HistoryItem(
|
|
||||||
videoItem: loadingState.response[index],
|
|
||||||
ctr: _favSearchCtr,
|
|
||||||
onChoose: null,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
childCount: loadingState.response.length,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
: errorWidget(
|
: errorWidget(
|
||||||
callback: _favSearchCtr.onReload,
|
callback: _favSearchCtr.onReload,
|
||||||
|
|||||||
@@ -37,12 +37,16 @@ class _FollowPageState extends State<FollowPage> {
|
|||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => Get.toNamed('/favSearch', arguments: {
|
onPressed: () => Get.toNamed(
|
||||||
|
'/favSearch',
|
||||||
|
arguments: {
|
||||||
'mid': int.parse(mid),
|
'mid': int.parse(mid),
|
||||||
'searchType': SearchType.follow,
|
'searchType': SearchType.follow,
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
icon: const Icon(Icons.search_outlined),
|
icon: const Icon(Icons.search_outlined),
|
||||||
tooltip: '搜索'),
|
tooltip: '搜索',
|
||||||
|
),
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
icon: const Icon(Icons.more_vert),
|
icon: const Icon(Icons.more_vert),
|
||||||
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
|
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import 'package:PiliPlus/http/user.dart';
|
|||||||
import 'package:PiliPlus/models/user/history.dart';
|
import 'package:PiliPlus/models/user/history.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
|
||||||
class HistoryController extends MultiSelectController
|
class HistoryController extends MultiSelectController<HistoryData, HisListItem>
|
||||||
with GetTickerProviderStateMixin {
|
with GetTickerProviderStateMixin {
|
||||||
HistoryController(this.type);
|
HistoryController(this.type);
|
||||||
|
|
||||||
@@ -37,25 +37,27 @@ class HistoryController extends MultiSelectController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
onSelect(int index) {
|
onSelect(int index, [bool disableSelect = true]) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<HisListItem> list = (loadingState.value as Success).response;
|
||||||
list[index].checked = !(list[index]?.checked ?? false);
|
list[index].checked = !(list[index].checked ?? false);
|
||||||
baseCtr.checkedCount.value =
|
baseCtr.checkedCount.value =
|
||||||
list.where((item) => item.checked == true).length;
|
list.where((item) => item.checked == true).length;
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
if (baseCtr.checkedCount.value == 0) {
|
if (baseCtr.checkedCount.value == 0) {
|
||||||
baseCtr.enableMultiSelect.value = false;
|
baseCtr.enableMultiSelect.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleSelect([bool checked = false]) {
|
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||||
if (loadingState.value is Success) {
|
if (loadingState.value is Success) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<HisListItem>? list = (loadingState.value as Success).response;
|
||||||
if (list.isNotEmpty) {
|
if (list?.isNotEmpty == true) {
|
||||||
loadingState.value = LoadingState.success(
|
for (HisListItem item in list!) {
|
||||||
list.map((item) => item..checked = checked).toList());
|
item.checked = checked;
|
||||||
|
}
|
||||||
baseCtr.checkedCount.value = checked ? list.length : 0;
|
baseCtr.checkedCount.value = checked ? list.length : 0;
|
||||||
|
loadingState.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (checked.not) {
|
if (checked.not) {
|
||||||
@@ -64,26 +66,28 @@ class HistoryController extends MultiSelectController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<HisListItem>? getDataList(HistoryData response) {
|
||||||
|
return response.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success<HistoryData> response) {
|
||||||
HistoryData data = response.response;
|
HistoryData data = response.response;
|
||||||
isEnd = data.list.isNullOrEmpty;
|
isEnd = data.list.isNullOrEmpty;
|
||||||
max = data.list?.lastOrNull?.history.oid;
|
max = data.list?.lastOrNull?.history.oid;
|
||||||
viewAt = data.list?.lastOrNull?.viewAt;
|
viewAt = data.list?.lastOrNull?.viewAt;
|
||||||
if (currentPage == 1) {
|
|
||||||
if (type == null && tabs.isEmpty && data.tab?.isNotEmpty == true) {
|
if (isRefresh && type == null) {
|
||||||
|
if (tabs.isEmpty && data.tab?.isNotEmpty == true) {
|
||||||
tabs.value = data.tab!;
|
tabs.value = data.tab!;
|
||||||
tabController =
|
tabController = TabController(
|
||||||
TabController(length: data.tab!.length + 1, vsync: this);
|
length: data.tab!.length + 1,
|
||||||
}
|
vsync: this,
|
||||||
} else if (loadingState.value is Success) {
|
|
||||||
data.list ??= <HisListItem>[];
|
|
||||||
data.list!.insertAll(
|
|
||||||
0,
|
|
||||||
List<HisListItem>.from((loadingState.value as Success).response),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
loadingState.value = LoadingState.success(data.list);
|
}
|
||||||
return true;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 观看历史暂停状态
|
// 观看历史暂停状态
|
||||||
@@ -125,7 +129,8 @@ class HistoryController extends MultiSelectController
|
|||||||
}).toList();
|
}).toList();
|
||||||
dynamic response = await UserHttp.delHistory(kidList);
|
dynamic response = await UserHttp.delHistory(kidList);
|
||||||
if (response['status']) {
|
if (response['status']) {
|
||||||
List remainList = ((loadingState.value as Success).response as List)
|
List<HisListItem> remainList =
|
||||||
|
((loadingState.value as Success).response as List<HisListItem>)
|
||||||
.toSet()
|
.toSet()
|
||||||
.difference(result.toSet())
|
.difference(result.toSet())
|
||||||
.toList();
|
.toList();
|
||||||
@@ -179,7 +184,7 @@ class HistoryController extends MultiSelectController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<HistoryData>> customGetData() =>
|
||||||
UserHttp.historyList(type: type ?? 'all', max: max, viewAt: viewAt);
|
UserHttp.historyList(type: type ?? 'all', max: max, viewAt: viewAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/widgets/http_error.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/user/history.dart';
|
||||||
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
||||||
import 'package:PiliPlus/pages/history/base_controller.dart';
|
import 'package:PiliPlus/pages/history/base_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
@@ -261,7 +262,7 @@ class _HistoryPageState extends State<HistoryPage>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<HisListItem>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
@@ -276,7 +277,7 @@ class _HistoryPageState extends State<HistoryPage>
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: StyleString.safeSpace - 5,
|
top: StyleString.safeSpace - 5,
|
||||||
@@ -290,18 +291,18 @@ class _HistoryPageState extends State<HistoryPage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_historyController.onLoadMore();
|
_historyController.onLoadMore();
|
||||||
}
|
}
|
||||||
return HistoryItem(
|
return HistoryItem(
|
||||||
videoItem: loadingState.response[index],
|
videoItem: loadingState.response![index],
|
||||||
ctr: _historyController.baseCtr,
|
ctr: _historyController.baseCtr,
|
||||||
onChoose: () => _historyController.onSelect(index),
|
onChoose: () => _historyController.onSelect(index),
|
||||||
onDelete: (kid, business) =>
|
onDelete: (kid, business) =>
|
||||||
_historyController.delHistory(kid, business),
|
_historyController.delHistory(kid, business),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ class HistoryItem extends StatelessWidget {
|
|||||||
final HisListItem videoItem;
|
final HisListItem videoItem;
|
||||||
final dynamic ctr;
|
final dynamic ctr;
|
||||||
final Function? onChoose;
|
final Function? onChoose;
|
||||||
final Function? onDelete;
|
final Function(dynamic kid, dynamic business) onDelete;
|
||||||
|
|
||||||
const HistoryItem({
|
const HistoryItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.videoItem,
|
required this.videoItem,
|
||||||
this.ctr,
|
this.ctr,
|
||||||
this.onChoose,
|
this.onChoose,
|
||||||
this.onDelete,
|
required this.onDelete,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -380,10 +380,8 @@ class HistoryItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
onTap: () => onDelete != null
|
onTap: () =>
|
||||||
? onDelete!(videoItem.kid, videoItem.history.business)
|
onDelete(videoItem.kid, videoItem.history.business),
|
||||||
: ctr.delHistory(
|
|
||||||
videoItem.kid, videoItem.history.business),
|
|
||||||
height: 35,
|
height: 35,
|
||||||
child: const Row(
|
child: const Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class HomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage>
|
class _HomePageState extends State<HomePage>
|
||||||
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
|
with AutomaticKeepAliveClientMixin {
|
||||||
final HomeController _homeController = Get.put(HomeController());
|
final HomeController _homeController = Get.put(HomeController());
|
||||||
final MainController _mainController = Get.put(MainController());
|
final MainController _mainController = Get.put(MainController());
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
|
import 'package:PiliPlus/models/model_hot_video_item.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class HotController extends CommonController {
|
class HotController
|
||||||
|
extends CommonListController<List<HotVideoItemModel>, HotVideoItemModel> {
|
||||||
// int idx = 0;
|
// int idx = 0;
|
||||||
|
|
||||||
late RxBool showHotRcmd = GStorage.showHotRcmd.obs;
|
late RxBool showHotRcmd = GStorage.showHotRcmd.obs;
|
||||||
@@ -22,7 +24,8 @@ class HotController extends CommonController {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => VideoHttp.hotVideoList(
|
Future<LoadingState<List<HotVideoItemModel>>> customGetData() =>
|
||||||
|
VideoHttp.hotVideoList(
|
||||||
pn: currentPage,
|
pn: currentPage,
|
||||||
ps: 20,
|
ps: 20,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/video_card_h.dart';
|
import 'package:PiliPlus/common/widgets/video_card_h.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/common/tab_type.dart';
|
import 'package:PiliPlus/models/common/tab_type.dart';
|
||||||
|
import 'package:PiliPlus/models/model_hot_video_item.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||||
import 'package:PiliPlus/pages/rank/view.dart';
|
import 'package:PiliPlus/pages/rank/view.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -160,10 +161,10 @@ class _HotPageState extends CommonPageState<HotPage, HotController>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<HotVideoItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => _buildSkeleton(),
|
Loading() => _buildSkeleton(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverGrid(
|
? SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
mainAxisSpacing: 2,
|
mainAxisSpacing: 2,
|
||||||
@@ -172,15 +173,15 @@ class _HotPageState extends CommonPageState<HotPage, HotController>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
controller.onLoadMore();
|
controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return VideoCardH(
|
return VideoCardH(
|
||||||
videoItem: loadingState.response[index],
|
videoItem: loadingState.response![index],
|
||||||
showPubdate: true,
|
showPubdate: true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(
|
: HttpError(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'package:PiliPlus/http/html.dart';
|
|||||||
import 'package:PiliPlus/http/reply.dart';
|
import 'package:PiliPlus/http/reply.dart';
|
||||||
import 'package:fixnum/fixnum.dart' as $fixnum;
|
import 'package:fixnum/fixnum.dart' as $fixnum;
|
||||||
|
|
||||||
class HtmlRenderController extends ReplyController {
|
class HtmlRenderController extends ReplyController<MainListReply> {
|
||||||
late String id;
|
late String id;
|
||||||
late String dynamicType;
|
late String dynamicType;
|
||||||
late int type;
|
late int type;
|
||||||
@@ -91,7 +91,12 @@ class HtmlRenderController extends ReplyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() {
|
List<ReplyInfo>? getDataList(MainListReply response) {
|
||||||
|
return response.replies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<MainListReply>> customGetData() {
|
||||||
return ReplyHttp.replyListGrpc(
|
return ReplyHttp.replyListGrpc(
|
||||||
type: type,
|
type: type,
|
||||||
oid: oid.value,
|
oid: oid.value,
|
||||||
|
|||||||
@@ -763,7 +763,7 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget replyList(LoadingState loadingState) {
|
Widget replyList(LoadingState<List<ReplyInfo>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverList.builder(
|
Loading() => SliverList.builder(
|
||||||
itemCount: 5,
|
itemCount: 5,
|
||||||
@@ -771,11 +771,11 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
|
|||||||
return const VideoReplySkeleton();
|
return const VideoReplySkeleton();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response.replies as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverList.builder(
|
? SliverList.builder(
|
||||||
itemCount: loadingState.response.replies.length + 1,
|
itemCount: loadingState.response!.length + 1,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == loadingState.response.replies.length) {
|
if (index == loadingState.response!.length) {
|
||||||
_htmlRenderCtr.onLoadMore();
|
_htmlRenderCtr.onLoadMore();
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@@ -785,7 +785,7 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
|
|||||||
child: Text(
|
child: Text(
|
||||||
_htmlRenderCtr.isEnd.not
|
_htmlRenderCtr.isEnd.not
|
||||||
? '加载中...'
|
? '加载中...'
|
||||||
: loadingState.response.replies.isEmpty
|
: loadingState.response!.isEmpty
|
||||||
? '还没有评论'
|
? '还没有评论'
|
||||||
: '没有更多了',
|
: '没有更多了',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -796,19 +796,20 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ReplyItemGrpc(
|
return ReplyItemGrpc(
|
||||||
replyItem: loadingState.response.replies[index],
|
replyItem: loadingState.response![index],
|
||||||
replyLevel: '1',
|
replyLevel: '1',
|
||||||
replyReply: (replyItem, id) =>
|
replyReply: (replyItem, id) =>
|
||||||
replyReply(context, replyItem, id),
|
replyReply(context, replyItem, id),
|
||||||
onReply: () {
|
onReply: () {
|
||||||
_htmlRenderCtr.onReply(
|
_htmlRenderCtr.onReply(
|
||||||
context,
|
context,
|
||||||
replyItem: loadingState.response.replies[index],
|
replyItem: loadingState.response![index],
|
||||||
index: index,
|
index: index,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onDelete: _htmlRenderCtr.onMDelete,
|
onDelete: (subIndex) =>
|
||||||
upMid: loadingState.response.subjectControl.upMid,
|
_htmlRenderCtr.onRemove(index, subIndex),
|
||||||
|
upMid: _htmlRenderCtr.upMid,
|
||||||
callback: _getImageCallback,
|
callback: _getImageCallback,
|
||||||
onCheckReply: (item) =>
|
onCheckReply: (item) =>
|
||||||
_htmlRenderCtr.onCheckReply(context, item),
|
_htmlRenderCtr.onCheckReply(context, item),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
|
|
||||||
class LaterController extends MultiSelectController {
|
class LaterController extends MultiSelectController<Map, HotVideoItemModel> {
|
||||||
RxInt count = (-1).obs;
|
RxInt count = (-1).obs;
|
||||||
|
|
||||||
dynamic mid;
|
dynamic mid;
|
||||||
@@ -22,25 +22,24 @@ class LaterController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<HotVideoItemModel>? getDataList(response) {
|
||||||
count.value = response.response['count'];
|
return response['list'];
|
||||||
if (response.response['list'].isEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
response.response['list'].insertAll(
|
|
||||||
0,
|
|
||||||
List<HotVideoItemModel>.from((loadingState.value as Success).response),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (response.response['list'].length >= count.value) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(response.response['list']);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future toViewDel(BuildContext context, {int? aid}) async {
|
@override
|
||||||
|
void checkIsEnd(int length) {
|
||||||
|
if (length >= count.value) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
|
count.value = response.response['count'];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future toViewDel(BuildContext context, {index, aid}) async {
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -50,7 +49,7 @@ class LaterController extends MultiSelectController {
|
|||||||
aid != null ? '即将移除该视频,确定是否移除' : '即将删除所有已观看视频,此操作不可恢复。确定是否删除?'),
|
aid != null ? '即将移除该视频,确定是否移除' : '即将删除所有已观看视频,此操作不可恢复。确定是否删除?'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Get.back(),
|
onPressed: Get.back,
|
||||||
child: Text(
|
child: Text(
|
||||||
'取消',
|
'取消',
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||||
@@ -62,10 +61,11 @@ class LaterController extends MultiSelectController {
|
|||||||
await UserHttp.toViewDel(aids: aid != null ? [aid] : null);
|
await UserHttp.toViewDel(aids: aid != null ? [aid] : null);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
if (aid != null) {
|
if (aid != null) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<HotVideoItemModel> list =
|
||||||
list.removeWhere((e) => e.aid == aid);
|
(loadingState.value as Success).response;
|
||||||
|
list.removeAt(index);
|
||||||
count.value -= 1;
|
count.value -= 1;
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
} else {
|
} else {
|
||||||
onReload();
|
onReload();
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ class LaterController extends MultiSelectController {
|
|||||||
onConfirm: () async {
|
onConfirm: () async {
|
||||||
var res = await UserHttp.toViewClear();
|
var res = await UserHttp.toViewClear();
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
loadingState.value = LoadingState.success([]);
|
loadingState.value = LoadingState.success(null);
|
||||||
}
|
}
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
},
|
},
|
||||||
@@ -98,7 +98,7 @@ class LaterController extends MultiSelectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => UserHttp.seeYouLater();
|
Future<LoadingState<Map>> customGetData() => UserHttp.seeYouLater();
|
||||||
|
|
||||||
onDelChecked(BuildContext context) {
|
onDelChecked(BuildContext context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
@@ -137,7 +137,8 @@ class LaterController extends MultiSelectController {
|
|||||||
List aids = result.map((item) => item.aid).toList();
|
List aids = result.map((item) => item.aid).toList();
|
||||||
dynamic res = await UserHttp.toViewDel(aids: aids);
|
dynamic res = await UserHttp.toViewDel(aids: aids);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
Set remainList = ((loadingState.value as Success).response as List)
|
Set<HotVideoItemModel> remainList =
|
||||||
|
((loadingState.value as Success).response as List<HotVideoItemModel>)
|
||||||
.toSet()
|
.toSet()
|
||||||
.difference(result.toSet());
|
.difference(result.toSet());
|
||||||
count.value -= aids.length;
|
count.value -= aids.length;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/model_hot_video_item.dart';
|
||||||
import 'package:PiliPlus/pages/history/view.dart' show AppBarWidget;
|
import 'package:PiliPlus/pages/history/view.dart' show AppBarWidget;
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
@@ -93,7 +94,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
visualDensity: VisualDensity(horizontal: -2, vertical: -2),
|
visualDensity: VisualDensity(horizontal: -2, vertical: -2),
|
||||||
),
|
),
|
||||||
onPressed: () => Utils.onCopyOrMove(
|
onPressed: () => Utils.onCopyOrMove<HotVideoItemModel>(
|
||||||
context: context,
|
context: context,
|
||||||
isCopy: true,
|
isCopy: true,
|
||||||
ctr: _laterController,
|
ctr: _laterController,
|
||||||
@@ -110,7 +111,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
visualDensity: VisualDensity(horizontal: -2, vertical: -2),
|
visualDensity: VisualDensity(horizontal: -2, vertical: -2),
|
||||||
),
|
),
|
||||||
onPressed: () => Utils.onCopyOrMove(
|
onPressed: () => Utils.onCopyOrMove<HotVideoItemModel>(
|
||||||
context: context,
|
context: context,
|
||||||
isCopy: false,
|
isCopy: false,
|
||||||
ctr: _laterController,
|
ctr: _laterController,
|
||||||
@@ -171,7 +172,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<HotVideoItemModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverGrid(
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
@@ -186,7 +187,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
childCount: 10,
|
childCount: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverGrid(
|
? SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
mainAxisSpacing: 2,
|
mainAxisSpacing: 2,
|
||||||
@@ -195,7 +196,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
var videoItem = loadingState.response[index];
|
var videoItem = loadingState.response![index];
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
VideoCardH(
|
VideoCardH(
|
||||||
@@ -209,7 +210,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
'oid': videoItem.aid,
|
'oid': videoItem.aid,
|
||||||
'heroTag': Utils.makeHeroTag(videoItem.bvid),
|
'heroTag': Utils.makeHeroTag(videoItem.bvid),
|
||||||
'sourceType': 'watchLater',
|
'sourceType': 'watchLater',
|
||||||
'count': loadingState.response.length,
|
'count': loadingState.response!.length,
|
||||||
'favTitle': '稍后再看',
|
'favTitle': '稍后再看',
|
||||||
'mediaId': _laterController.mid,
|
'mediaId': _laterController.mid,
|
||||||
'desc': false,
|
'desc': false,
|
||||||
@@ -293,6 +294,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
_laterController.toViewDel(
|
_laterController.toViewDel(
|
||||||
context,
|
context,
|
||||||
|
index: index,
|
||||||
aid: videoItem.aid,
|
aid: videoItem.aid,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -305,7 +307,7 @@ class _LaterPageState extends State<LaterPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: HttpError(
|
: HttpError(
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/live.dart';
|
import 'package:PiliPlus/http/live.dart';
|
||||||
import 'package:PiliPlus/models/live/follow.dart';
|
import 'package:PiliPlus/models/live/follow.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/live/item.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||||
|
|
||||||
class LiveController extends CommonController {
|
class LiveController
|
||||||
|
extends CommonListController<List<LiveItemModel>?, LiveItemModel> {
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -17,7 +19,8 @@ class LiveController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => LiveHttp.liveList(pn: currentPage);
|
Future<LoadingState<List<LiveItemModel>?>> customGetData() =>
|
||||||
|
LiveHttp.liveList(pn: currentPage);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future onRefresh() {
|
Future onRefresh() {
|
||||||
@@ -41,20 +44,34 @@ class LiveController extends CommonController {
|
|||||||
}
|
}
|
||||||
dynamic res = await LiveHttp.liveFollowing(pn: followPage, ps: 20);
|
dynamic res = await LiveHttp.liveFollowing(pn: followPage, ps: 20);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
followPage++;
|
LiveFollowingModel data = res['data'];
|
||||||
liveCount.value = res['data'].liveCount;
|
liveCount.value = data.liveCount ?? 0;
|
||||||
List list = res['data']
|
List<LiveFollowingItemModel>? dataList = data.list
|
||||||
.list
|
?.where((LiveFollowingItemModel item) =>
|
||||||
.where((LiveFollowingItemModel item) =>
|
|
||||||
item.liveStatus == 1 && item.recordLiveTime == 0)
|
item.liveStatus == 1 && item.recordLiveTime == 0)
|
||||||
.toList();
|
.toList();
|
||||||
if (isRefresh.not && followListState.value is Success) {
|
if (dataList.isNullOrEmpty) {
|
||||||
list.insertAll(0, (followListState.value as Success).response);
|
followEnd = true;
|
||||||
|
if (isRefresh) {
|
||||||
|
followListState.value = LoadingState.success(dataList);
|
||||||
}
|
}
|
||||||
followEnd = list.length >= liveCount.value ||
|
return;
|
||||||
list.isEmpty ||
|
}
|
||||||
(res['data'].list as List?).isNullOrEmpty;
|
if (isRefresh) {
|
||||||
followListState.value = LoadingState.success(list);
|
if (dataList!.length >= liveCount.value) {
|
||||||
|
followEnd = true;
|
||||||
|
}
|
||||||
|
followListState.value = LoadingState.success(dataList);
|
||||||
|
} else if (loadingState.value is Success) {
|
||||||
|
List<LiveFollowingItemModel> list =
|
||||||
|
(loadingState.value as Success).response;
|
||||||
|
list.addAll(dataList!);
|
||||||
|
if (list.length >= liveCount.value) {
|
||||||
|
followEnd = true;
|
||||||
|
}
|
||||||
|
loadingState.refresh();
|
||||||
|
}
|
||||||
|
followPage++;
|
||||||
} else {
|
} else {
|
||||||
followListState.value = LoadingState.error(res['msg']);
|
followListState.value = LoadingState.error(res['msg']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart';
|
import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/live/item.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||||
import 'package:PiliPlus/pages/live/controller.dart';
|
import 'package:PiliPlus/pages/live/controller.dart';
|
||||||
import 'package:PiliPlus/pages/live/widgets/live_item.dart';
|
import 'package:PiliPlus/pages/live/widgets/live_item.dart';
|
||||||
@@ -66,17 +67,7 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
|||||||
top: StyleString.cardSpace,
|
top: StyleString.cardSpace,
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||||
),
|
),
|
||||||
sliver: Obx(
|
sliver: Obx(() => _buildBody(controller.loadingState.value)),
|
||||||
() => controller.loadingState.value is Loading ||
|
|
||||||
controller.loadingState.value is Success
|
|
||||||
? contentGrid(controller.loadingState.value)
|
|
||||||
: HttpError(
|
|
||||||
errMsg: controller.loadingState.value is Error
|
|
||||||
? (controller.loadingState.value as Error).errMsg
|
|
||||||
: '没有相关数据',
|
|
||||||
callback: controller.onReload,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -84,33 +75,49 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget contentGrid(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<LiveItemModel>?> loadingState) {
|
||||||
return SliverGrid(
|
return switch (loadingState) {
|
||||||
|
Loading() => SliverGrid(
|
||||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
// 行间距
|
|
||||||
mainAxisSpacing: StyleString.cardSpace,
|
mainAxisSpacing: StyleString.cardSpace,
|
||||||
// 列间距
|
|
||||||
crossAxisSpacing: StyleString.cardSpace,
|
crossAxisSpacing: StyleString.cardSpace,
|
||||||
// 最大宽度
|
|
||||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||||
childAspectRatio: StyleString.aspectRatio,
|
childAspectRatio: StyleString.aspectRatio,
|
||||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(context, index) {
|
||||||
if (loadingState is Success &&
|
return const VideoCardVSkeleton();
|
||||||
index == loadingState.response.length - 1) {
|
},
|
||||||
|
childCount: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
|
? 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();
|
controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return loadingState is Success
|
return LiveCardV(liveItem: loadingState.response![index]);
|
||||||
? LiveCardV(
|
|
||||||
liveItem: loadingState.response[index],
|
|
||||||
)
|
|
||||||
: const VideoCardVSkeleton();
|
|
||||||
},
|
},
|
||||||
childCount: loadingState is Success ? loadingState.response.length : 10,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
);
|
)
|
||||||
|
: scrollErrorWidget(callback: controller.onReload),
|
||||||
|
Error() => HttpError(
|
||||||
|
errMsg: loadingState.errMsg,
|
||||||
|
callback: controller.onReload,
|
||||||
|
),
|
||||||
|
_ => throw UnimplementedError(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFollowList() {
|
Widget _buildFollowList() {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
|
||||||
class MediaController extends CommonController {
|
class MediaController
|
||||||
|
extends CommonDataController<FavFolderData, FavFolderData> {
|
||||||
List list = [
|
List list = [
|
||||||
// {
|
// {
|
||||||
// 'icon': Icons.file_download_outlined,
|
// 'icon': Icons.file_download_outlined,
|
||||||
@@ -52,14 +54,14 @@ class MediaController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<FavFolderData> response) {
|
||||||
count.value = response.response.count;
|
count.value = response.response.count ?? -1;
|
||||||
loadingState.value = response;
|
loadingState.value = response;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() {
|
Future<LoadingState<FavFolderData>> customGetData() {
|
||||||
mid ??= Accounts.main.mid;
|
mid ??= Accounts.main.mid;
|
||||||
return UserHttp.userfavFolder(
|
return UserHttp.userfavFolder(
|
||||||
pn: 1,
|
pn: 1,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/space_article/item.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart';
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/widget/item.dart';
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/widget/item.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -38,10 +39,10 @@ class _MemberArticleState extends State<MemberArticle>
|
|||||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
return Obx(() => _buildBody(_controller.loadingState.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildBody(LoadingState loadingState) {
|
_buildBody(LoadingState<List<Item>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? refreshIndicator(
|
? refreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _controller.onRefresh();
|
await _controller.onRefresh();
|
||||||
@@ -56,14 +57,14 @@ class _MemberArticleState extends State<MemberArticle>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_controller.onLoadMore();
|
_controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return MemberArticleItem(
|
return MemberArticleItem(
|
||||||
item: loadingState.response[index],
|
item: loadingState.response![index],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import 'package:PiliPlus/http/loading_state.dart';
|
|||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/models/space_article/item.dart';
|
import 'package:PiliPlus/models/space_article/item.dart';
|
||||||
import 'package:PiliPlus/models/space_article/data.dart';
|
import 'package:PiliPlus/models/space_article/data.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
|
|
||||||
class MemberArticleCtr extends CommonController {
|
class MemberArticleCtr extends CommonListController<Data, Item> {
|
||||||
MemberArticleCtr({
|
MemberArticleCtr({
|
||||||
required this.mid,
|
required this.mid,
|
||||||
});
|
});
|
||||||
@@ -21,24 +20,24 @@ class MemberArticleCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<Item>? getDataList(Data response) {
|
||||||
Data data = response.response;
|
return response.item;
|
||||||
if (data.item.isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
count = data.count ?? -1;
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
data.item ??= <Item>[];
|
|
||||||
data.item!.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
if ((data.item?.length ?? -1) >= count) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.item);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
void checkIsEnd(int length) {
|
||||||
|
if (length >= count) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success<Data> response) {
|
||||||
|
count = response.response.count ?? -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<Data>> customGetData() =>
|
||||||
MemberHttp.spaceArticle(mid: mid, page: currentPage);
|
MemberHttp.spaceArticle(mid: mid, page: currentPage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/space_archive/item.dart';
|
||||||
import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_member_home.dart';
|
import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_member_home.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart';
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -41,10 +42,10 @@ class _MemberBangumiState extends State<MemberBangumi>
|
|||||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
return Obx(() => _buildBody(_controller.loadingState.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildBody(LoadingState loadingState) {
|
_buildBody(LoadingState<List<Item>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? refreshIndicator(
|
? refreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _controller.onRefresh();
|
await _controller.onRefresh();
|
||||||
@@ -70,14 +71,14 @@ class _MemberBangumiState extends State<MemberBangumi>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_controller.onLoadMore();
|
_controller.onLoadMore();
|
||||||
}
|
}
|
||||||
return BangumiCardVMemberHome(
|
return BangumiCardVMemberHome(
|
||||||
bangumiItem: loadingState.response[index],
|
bangumiItem: loadingState.response![index],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,15 +2,14 @@ import 'package:PiliPlus/http/loading_state.dart';
|
|||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/models/space_archive/data.dart';
|
import 'package:PiliPlus/models/space_archive/data.dart';
|
||||||
import 'package:PiliPlus/models/space_archive/item.dart';
|
import 'package:PiliPlus/models/space_archive/item.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
||||||
show ContributeType;
|
show ContributeType;
|
||||||
import 'package:PiliPlus/pages/member/new/controller.dart';
|
import 'package:PiliPlus/pages/member/new/controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/models/space/data.dart' as space;
|
import 'package:PiliPlus/models/space/data.dart' as space;
|
||||||
|
|
||||||
class MemberBangumiCtr extends CommonController {
|
class MemberBangumiCtr extends CommonListController<Data, Item> {
|
||||||
MemberBangumiCtr({
|
MemberBangumiCtr({
|
||||||
required this.mid,
|
required this.mid,
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
@@ -37,24 +36,19 @@ class MemberBangumiCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<Item>? getDataList(Data response) {
|
||||||
Data data = response.response;
|
return response.item;
|
||||||
if (data.item.isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
data.item ??= <Item>[];
|
|
||||||
data.item!.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
if (isEnd.not && count != null && data.item!.length >= count!) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.item);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => MemberHttp.spaceArchive(
|
void checkIsEnd(int length) {
|
||||||
|
if (count != null && length >= count!) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<Data>> customGetData() => MemberHttp.spaceArchive(
|
||||||
type: ContributeType.bangumi,
|
type: ContributeType.bangumi,
|
||||||
mid: mid,
|
mid: mid,
|
||||||
pn: currentPage,
|
pn: currentPage,
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import 'package:PiliPlus/http/loading_state.dart';
|
|||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/models/space_fav/datum.dart';
|
import 'package:PiliPlus/models/space_fav/datum.dart';
|
||||||
import 'package:PiliPlus/models/space_fav/list.dart';
|
import 'package:PiliPlus/models/space_fav/list.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class MemberFavoriteCtr extends CommonController {
|
class MemberFavoriteCtr extends CommonDataController {
|
||||||
MemberFavoriteCtr({
|
MemberFavoriteCtr({
|
||||||
required this.mid,
|
required this.mid,
|
||||||
});
|
});
|
||||||
@@ -39,7 +39,7 @@ class MemberFavoriteCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
try {
|
try {
|
||||||
List<Datum> res = response.response;
|
List<Datum> res = response.response;
|
||||||
first.value = res.first;
|
first.value = res.first;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
|
|
||||||
class SeasonSeriesController extends CommonController {
|
class SeasonSeriesController extends CommonListController {
|
||||||
SeasonSeriesController(this.mid);
|
SeasonSeriesController(this.mid);
|
||||||
final int mid;
|
final int mid;
|
||||||
|
int? count;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@@ -13,16 +14,22 @@ class SeasonSeriesController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List? getDataList(response) {
|
||||||
Map data = response.response;
|
return ((response['seasons_list'] as List?) ?? []) +
|
||||||
List list = ((data['seasons_list'] as List?) ?? []) +
|
((response['series_list'] as List?) ?? []);
|
||||||
((data['series_list'] as List?) ?? []);
|
|
||||||
if (currentPage != 0 && loadingState.value is Success) {
|
|
||||||
list.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
}
|
||||||
isEnd = list.length >= ((data['page']['total'] as int?) ?? 0);
|
|
||||||
loadingState.value = LoadingState.success(list);
|
@override
|
||||||
return true;
|
void checkIsEnd(int length) {
|
||||||
|
if (count != null && length >= count!) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success response) {
|
||||||
|
count = response.response['page']?['total'];
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ class _SeasonSeriesPageState extends State<SeasonSeriesPage>
|
|||||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
return Obx(() => _buildBody(_controller.loadingState.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<dynamic>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? CustomScrollView(
|
? CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
@@ -58,13 +58,13 @@ class _SeasonSeriesPageState extends State<SeasonSeriesPage>
|
|||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_controller.onLoadMore();
|
_controller.onLoadMore();
|
||||||
}
|
}
|
||||||
|
dynamic item = loadingState.response![index];
|
||||||
return SeasonSeriesCard(
|
return SeasonSeriesCard(
|
||||||
item: loadingState.response[index],
|
item: item,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
dynamic item = loadingState.response[index];
|
|
||||||
bool isSeason = item['meta']['season_id'] != null;
|
bool isSeason = item['meta']['season_id'] != null;
|
||||||
dynamic id = isSeason
|
dynamic id = isSeason
|
||||||
? item['meta']['season_id']
|
? item['meta']['season_id']
|
||||||
@@ -89,7 +89,7 @@ class _SeasonSeriesPageState extends State<SeasonSeriesPage>
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ class _MemberVideoState extends State<MemberVideo>
|
|||||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
return Obx(() => _buildBody(_controller.loadingState.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildBody(LoadingState loadingState) {
|
_buildBody(LoadingState<List<Item>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? Stack(
|
? Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
@@ -186,17 +186,17 @@ class _MemberVideoState extends State<MemberVideo>
|
|||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (widget.type != ContributeType.season &&
|
if (widget.type != ContributeType.season &&
|
||||||
index == loadingState.response.length - 1) {
|
index == loadingState.response!.length - 1) {
|
||||||
_controller.onLoadMore();
|
_controller.onLoadMore();
|
||||||
}
|
}
|
||||||
final Item item = loadingState.response[index];
|
final Item item = loadingState.response![index];
|
||||||
return VideoCardHMemberVideo(
|
return VideoCardHMemberVideo(
|
||||||
key: ValueKey('${item.param}'),
|
key: ValueKey('${item.param}'),
|
||||||
videoItem: item,
|
videoItem: item,
|
||||||
fromViewAid: _controller.fromViewAid,
|
fromViewAid: _controller.fromViewAid,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:PiliPlus/http/search.dart';
|
|||||||
import 'package:PiliPlus/models/space_archive/data.dart';
|
import 'package:PiliPlus/models/space_archive/data.dart';
|
||||||
import 'package:PiliPlus/models/space_archive/episodic_button.dart';
|
import 'package:PiliPlus/models/space_archive/episodic_button.dart';
|
||||||
import 'package:PiliPlus/models/space_archive/item.dart';
|
import 'package:PiliPlus/models/space_archive/item.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
|
||||||
show ContributeType;
|
show ContributeType;
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
@@ -13,7 +13,7 @@ import 'package:PiliPlus/utils/utils.dart';
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class MemberVideoCtr extends CommonController {
|
class MemberVideoCtr extends CommonListController<Data, Item> {
|
||||||
MemberVideoCtr({
|
MemberVideoCtr({
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.mid,
|
required this.mid,
|
||||||
@@ -70,7 +70,7 @@ class MemberVideoCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<Data> response) {
|
||||||
Data data = response.response;
|
Data data = response.response;
|
||||||
episodicButton.value = data.episodicButton ?? EpisodicButton();
|
episodicButton.value = data.episodicButton ?? EpisodicButton();
|
||||||
episodicButton.refresh();
|
episodicButton.refresh();
|
||||||
@@ -105,7 +105,7 @@ class MemberVideoCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => MemberHttp.spaceArchive(
|
Future<LoadingState<Data>> customGetData() => MemberHttp.spaceArchive(
|
||||||
type: type,
|
type: type,
|
||||||
mid: mid,
|
mid: mid,
|
||||||
aid: type == ContributeType.video
|
aid: type == ContributeType.video
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'dart:math';
|
|||||||
|
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/space/tab2.dart';
|
import 'package:PiliPlus/models/space/tab2.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:PiliPlus/pages/member/new/controller.dart';
|
import 'package:PiliPlus/pages/member/new/controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -10,7 +10,7 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
import '../../../../../models/space/item.dart';
|
import '../../../../../models/space/item.dart';
|
||||||
|
|
||||||
class MemberContributeCtr extends CommonController
|
class MemberContributeCtr extends CommonDataController
|
||||||
with GetTickerProviderStateMixin {
|
with GetTickerProviderStateMixin {
|
||||||
MemberContributeCtr({
|
MemberContributeCtr({
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
|
||||||
import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel_grpc.dart';
|
|
||||||
import 'package:PiliPlus/pages/member/new/content/member_dynamic/member_dynamic_ctr.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
|
|
||||||
@Deprecated('Use MemberDynamicsPage instead')
|
|
||||||
class MemberDynamic extends StatefulWidget {
|
|
||||||
const MemberDynamic({
|
|
||||||
super.key,
|
|
||||||
required this.mid,
|
|
||||||
});
|
|
||||||
|
|
||||||
final int mid;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MemberDynamic> createState() => _MemberDynamicState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MemberDynamicState extends State<MemberDynamic>
|
|
||||||
with AutomaticKeepAliveClientMixin {
|
|
||||||
@override
|
|
||||||
bool get wantKeepAlive => true;
|
|
||||||
|
|
||||||
late final _controller = Get.put(MemberDynamicCtr(mid: widget.mid));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
super.build(context);
|
|
||||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
|
||||||
}
|
|
||||||
|
|
||||||
_buildBody(LoadingState loadingState) {
|
|
||||||
return switch (loadingState) {
|
|
||||||
Loading() => loadingWidget,
|
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
|
||||||
? refreshIndicator(
|
|
||||||
onRefresh: () async {
|
|
||||||
await _controller.onRefresh();
|
|
||||||
},
|
|
||||||
child: ListView.separated(
|
|
||||||
itemCount: loadingState.response.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
if (index == loadingState.response.length - 1) {
|
|
||||||
_controller.onLoadMore();
|
|
||||||
}
|
|
||||||
return DynamicPanelGrpc(
|
|
||||||
item: loadingState.response[index],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (context, index) =>
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: scrollErrorWidget(
|
|
||||||
callback: _controller.onReload,
|
|
||||||
),
|
|
||||||
Error() => scrollErrorWidget(
|
|
||||||
errMsg: loadingState.errMsg,
|
|
||||||
callback: _controller.onReload,
|
|
||||||
),
|
|
||||||
LoadingState() => throw UnimplementedError(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pb.dart';
|
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
|
||||||
import 'package:PiliPlus/http/member.dart';
|
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
|
|
||||||
class MemberDynamicCtr extends CommonController {
|
|
||||||
MemberDynamicCtr({
|
|
||||||
required this.mid,
|
|
||||||
});
|
|
||||||
int mid;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool customHandleResponse(Success response) {
|
|
||||||
DynSpaceRsp res = response.response;
|
|
||||||
isEnd = !res.hasMore;
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
res.list.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(res.list);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<LoadingState> customGetData() => MemberHttp.spaceDynamic(
|
|
||||||
mid: mid,
|
|
||||||
page: currentPage,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ import 'package:PiliPlus/http/video.dart';
|
|||||||
import 'package:PiliPlus/models/space/data.dart';
|
import 'package:PiliPlus/models/space/data.dart';
|
||||||
import 'package:PiliPlus/models/space/item.dart';
|
import 'package:PiliPlus/models/space/item.dart';
|
||||||
import 'package:PiliPlus/models/space/tab2.dart';
|
import 'package:PiliPlus/models/space/tab2.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -20,7 +20,7 @@ extension MemberTabTypeExt on MemberTabType {
|
|||||||
String get title => ['默认', '首页', '动态', '投稿', '收藏', '番剧'][index];
|
String get title => ['默认', '首页', '动态', '投稿', '收藏', '番剧'][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemberControllerNew extends CommonController
|
class MemberControllerNew extends CommonDataController<Data, dynamic>
|
||||||
with GetTickerProviderStateMixin {
|
with GetTickerProviderStateMixin {
|
||||||
MemberControllerNew({required this.mid});
|
MemberControllerNew({required this.mid});
|
||||||
int mid;
|
int mid;
|
||||||
@@ -58,7 +58,7 @@ class MemberControllerNew extends CommonController
|
|||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<Data> response) {
|
||||||
Data data = response.response;
|
Data data = response.response;
|
||||||
username = data.card?.name ?? '';
|
username = data.card?.name ?? '';
|
||||||
isFollow.value = data.card?.relation?.isFollow == 1;
|
isFollow.value = data.card?.relation?.isFollow == 1;
|
||||||
@@ -138,7 +138,7 @@ class MemberControllerNew extends CommonController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => MemberHttp.space(
|
Future<LoadingState<Data>> customGetData() => MemberHttp.space(
|
||||||
mid: mid,
|
mid: mid,
|
||||||
fromViewAid: fromViewAid,
|
fromViewAid: fromViewAid,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ class MemberPageNew extends StatefulWidget {
|
|||||||
State<MemberPageNew> createState() => _MemberPageNewState();
|
State<MemberPageNew> createState() => _MemberPageNewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MemberPageNewState extends State<MemberPageNew>
|
class _MemberPageNewState extends State<MemberPageNew> {
|
||||||
with TickerProviderStateMixin {
|
|
||||||
late final int _mid;
|
late final int _mid;
|
||||||
late final String _heroTag;
|
late final String _heroTag;
|
||||||
late final MemberControllerNew _userController;
|
late final MemberControllerNew _userController;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
|
|
||||||
class MemberCoinController extends CommonController {
|
class MemberCoinController extends CommonListController<
|
||||||
|
List<MemberCoinsDataModel>?, MemberCoinsDataModel> {
|
||||||
final dynamic mid;
|
final dynamic mid;
|
||||||
MemberCoinController({this.mid});
|
MemberCoinController({this.mid});
|
||||||
|
|
||||||
@@ -13,6 +15,6 @@ class MemberCoinController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<List<MemberCoinsDataModel>?>> customGetData() =>
|
||||||
MemberHttp.getRecentCoinVideo(mid: mid);
|
MemberHttp.getRecentCoinVideo(mid: mid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
import 'package:PiliPlus/pages/member_coin/controller.dart';
|
import 'package:PiliPlus/pages/member_coin/controller.dart';
|
||||||
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
|
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -41,10 +42,10 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? GridView.builder(
|
? GridView.builder(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: StyleString.safeSpace - 5,
|
top: StyleString.safeSpace - 5,
|
||||||
@@ -59,9 +60,9 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
|
|||||||
childAspectRatio: StyleString.aspectRatio,
|
childAspectRatio: StyleString.aspectRatio,
|
||||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
|
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
|
||||||
),
|
),
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return MemberCoinsItem(coinItem: loadingState.response[index]);
|
return MemberCoinsItem(coinItem: loadingState.response![index]);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: scrollErrorWidget(callback: _ctr.onReload),
|
: scrollErrorWidget(callback: _ctr.onReload),
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
class MemberDynamicsController extends CommonController {
|
class MemberDynamicsController
|
||||||
|
extends CommonListController<DynamicsDataModel, DynamicItemModel> {
|
||||||
MemberDynamicsController(this.mid);
|
MemberDynamicsController(this.mid);
|
||||||
int mid;
|
int mid;
|
||||||
String offset = '';
|
String offset = '';
|
||||||
@@ -32,22 +33,24 @@ class MemberDynamicsController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<DynamicItemModel>? getDataList(DynamicsDataModel response) {
|
||||||
DynamicsDataModel data = response.response;
|
return response.items;
|
||||||
offset = data.offset?.isNotEmpty == true ? data.offset! : '-1';
|
|
||||||
if (data.hasMore == false || data.items.isNullOrEmpty) {
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
|
||||||
data.items ??= <DynamicItemModel>[];
|
|
||||||
data.items?.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.items);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() => MemberHttp.memberDynamic(
|
bool customHandleResponse(
|
||||||
|
bool isRefresh, Success<DynamicsDataModel> response) {
|
||||||
|
DynamicsDataModel data = response.response;
|
||||||
|
offset = data.offset?.isNotEmpty == true ? data.offset! : '-1';
|
||||||
|
if (data.hasMore == false) {
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<DynamicsDataModel>> customGetData() =>
|
||||||
|
MemberHttp.memberDynamic(
|
||||||
offset: offset,
|
offset: offset,
|
||||||
mid: mid,
|
mid: mid,
|
||||||
);
|
);
|
||||||
@@ -55,9 +58,9 @@ class MemberDynamicsController extends CommonController {
|
|||||||
Future onRemove(dynamicId) async {
|
Future onRemove(dynamicId) async {
|
||||||
var res = await MsgHttp.removeDynamic(dynamicId);
|
var res = await MsgHttp.removeDynamic(dynamicId);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<DynamicItemModel> list = (loadingState.value as Success).response;
|
||||||
list.removeWhere((item) => item.idStr == dynamicId);
|
list.removeWhere((item) => item.idStr == dynamicId);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import 'package:PiliPlus/common/skeleton/dynamic_card.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/pages/member_dynamics/index.dart';
|
import 'package:PiliPlus/pages/member_dynamics/index.dart';
|
||||||
@@ -56,26 +58,57 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage>
|
|||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _memberDynamicController.onRefresh();
|
await _memberDynamicController.onRefresh();
|
||||||
},
|
},
|
||||||
child: Obx(
|
child: CustomScrollView(
|
||||||
() => _memberDynamicController.loadingState.value is Loading
|
|
||||||
? Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
)
|
|
||||||
: CustomScrollView(
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
slivers: [
|
slivers: [
|
||||||
_buildContent(_memberDynamicController.loadingState.value),
|
Obx(
|
||||||
|
() => _buildContent(_memberDynamicController.loadingState.value),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_buildContent(LoadingState loadingState) {
|
Widget skeleton() {
|
||||||
return switch (loadingState) {
|
if (!dynamicsWaterfallFlow) {
|
||||||
Loading() => HttpError(
|
return SliverCrossAxisGroup(
|
||||||
callback: _memberDynamicController.onReload,
|
slivers: [
|
||||||
|
const SliverFillRemaining(),
|
||||||
|
SliverConstrainedCrossAxis(
|
||||||
|
maxExtent: Grid.smallCardWidth * 2,
|
||||||
|
sliver: SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return const DynamicCardSkeleton();
|
||||||
|
},
|
||||||
|
childCount: 10,
|
||||||
),
|
),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
),
|
||||||
|
),
|
||||||
|
const SliverFillRemaining()
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return SliverGrid(
|
||||||
|
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||||
|
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||||
|
mainAxisSpacing: StyleString.cardSpace / 2,
|
||||||
|
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||||
|
childAspectRatio: StyleString.aspectRatio,
|
||||||
|
mainAxisExtent: 50,
|
||||||
|
),
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return const DynamicCardSkeleton();
|
||||||
|
},
|
||||||
|
childCount: 10,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildContent(LoadingState<List<DynamicItemModel>?> loadingState) {
|
||||||
|
return switch (loadingState) {
|
||||||
|
Loading() => skeleton(),
|
||||||
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? SliverPadding(
|
? SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||||
@@ -83,24 +116,12 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage>
|
|||||||
sliver: dynamicsWaterfallFlow
|
sliver: dynamicsWaterfallFlow
|
||||||
? SliverWaterfallFlow.extent(
|
? SliverWaterfallFlow.extent(
|
||||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||||
//cacheExtent: 0.0,
|
|
||||||
crossAxisSpacing: StyleString.safeSpace,
|
crossAxisSpacing: StyleString.safeSpace,
|
||||||
// mainAxisSpacing: StyleString.safeSpace,
|
|
||||||
|
|
||||||
/// follow max child trailing layout offset and layout with full cross axis extend
|
|
||||||
/// last child as loadmore item/no more item in [GridView] and [WaterfallFlow]
|
|
||||||
/// with full cross axis extend
|
|
||||||
// LastChildLayoutType.fullCrossAxisExtend,
|
|
||||||
|
|
||||||
/// as foot at trailing and layout with full cross axis extend
|
|
||||||
/// show no more item at trailing when children are not full of viewport
|
|
||||||
/// if children is full of viewport, it's the same as fullCrossAxisExtend
|
|
||||||
// LastChildLayoutType.foot,
|
|
||||||
lastChildLayoutTypeBuilder: (index) {
|
lastChildLayoutTypeBuilder: (index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_memberDynamicController.onLoadMore();
|
_memberDynamicController.onLoadMore();
|
||||||
}
|
}
|
||||||
return index == loadingState.response.length
|
return index == loadingState.response!.length
|
||||||
? LastChildLayoutType.foot
|
? LastChildLayoutType.foot
|
||||||
: LastChildLayoutType.none;
|
: LastChildLayoutType.none;
|
||||||
},
|
},
|
||||||
@@ -121,15 +142,16 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage>
|
|||||||
sliver: SliverList(
|
sliver: SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index ==
|
||||||
|
loadingState.response!.length - 1) {
|
||||||
_memberDynamicController.onLoadMore();
|
_memberDynamicController.onLoadMore();
|
||||||
}
|
}
|
||||||
return DynamicPanel(
|
return DynamicPanel(
|
||||||
item: loadingState.response[index],
|
item: loadingState.response![index],
|
||||||
onRemove: _memberDynamicController.onRemove,
|
onRemove: _memberDynamicController.onRemove,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: loadingState.response.length,
|
childCount: loadingState.response!.length,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
|
|
||||||
class MemberLikeController extends CommonController {
|
class MemberLikeController extends CommonListController<
|
||||||
|
List<MemberCoinsDataModel>?, MemberCoinsDataModel> {
|
||||||
final dynamic mid;
|
final dynamic mid;
|
||||||
MemberLikeController({this.mid});
|
MemberLikeController({this.mid});
|
||||||
|
|
||||||
@@ -13,6 +15,6 @@ class MemberLikeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<List<MemberCoinsDataModel>?>> customGetData() =>
|
||||||
MemberHttp.getRecentLikeVideo(mid: mid);
|
MemberHttp.getRecentLikeVideo(mid: mid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
|
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
|
||||||
import 'package:PiliPlus/pages/member_like/controller.dart';
|
import 'package:PiliPlus/pages/member_like/controller.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -41,10 +42,10 @@ class _MemberLikePageState extends State<MemberLikePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? GridView.builder(
|
? GridView.builder(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: StyleString.safeSpace - 5,
|
top: StyleString.safeSpace - 5,
|
||||||
@@ -59,9 +60,9 @@ class _MemberLikePageState extends State<MemberLikePage> {
|
|||||||
childAspectRatio: StyleString.aspectRatio,
|
childAspectRatio: StyleString.aspectRatio,
|
||||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
|
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
|
||||||
),
|
),
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return MemberCoinsItem(coinItem: loadingState.response[index]);
|
return MemberCoinsItem(coinItem: loadingState.response![index]);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: scrollErrorWidget(callback: _ctr.onReload),
|
: scrollErrorWidget(callback: _ctr.onReload),
|
||||||
|
|||||||
@@ -91,22 +91,31 @@ class MemberSearchController extends GetxController
|
|||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
DynamicsDataModel data = res['data'];
|
DynamicsDataModel data = res['data'];
|
||||||
if (data.hasMore == false || data.items.isNullOrEmpty) {
|
List<DynamicItemModel>? items = data.items;
|
||||||
isEndDynamic = true;
|
|
||||||
}
|
|
||||||
if (isRefresh) {
|
|
||||||
dynamicCount.value = data.total ?? 0;
|
dynamicCount.value = data.total ?? 0;
|
||||||
}
|
|
||||||
offset = data.offset ?? '';
|
offset = data.offset ?? '';
|
||||||
if (isRefresh.not && dynamicState.value is Success) {
|
|
||||||
data.items ??= <DynamicItemModel>[];
|
if (data.hasMore == false || items.isNullOrEmpty) {
|
||||||
data.items!.insertAll(0, (dynamicState.value as Success).response);
|
|
||||||
}
|
|
||||||
if (!isEndDynamic && (data.items?.length ?? 0) >= dynamicCount.value) {
|
|
||||||
isEndDynamic = true;
|
isEndDynamic = true;
|
||||||
|
dynamicState.value = LoadingState.success(items);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRefresh) {
|
||||||
|
if (items!.length >= dynamicCount.value) {
|
||||||
|
isEndDynamic = true;
|
||||||
|
}
|
||||||
|
dynamicState.value = LoadingState.success(items);
|
||||||
|
} else if (dynamicState.value is Success) {
|
||||||
|
List<DynamicItemModel> currentList =
|
||||||
|
(dynamicState.value as Success).response;
|
||||||
|
currentList.addAll(items!);
|
||||||
|
if (currentList.length >= dynamicCount.value) {
|
||||||
|
isEndDynamic = true;
|
||||||
|
}
|
||||||
|
dynamicState.refresh();
|
||||||
}
|
}
|
||||||
dynamicPn++;
|
dynamicPn++;
|
||||||
dynamicState.value = LoadingState.success(data.items);
|
|
||||||
} else if (isRefresh) {
|
} else if (isRefresh) {
|
||||||
dynamicState.value = LoadingState.error(res['msg']);
|
dynamicState.value = LoadingState.error(res['msg']);
|
||||||
}
|
}
|
||||||
@@ -124,24 +133,30 @@ class MemberSearchController extends GetxController
|
|||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
MemberArchiveDataModel data = res['data'];
|
MemberArchiveDataModel data = res['data'];
|
||||||
if (isRefresh) {
|
List<VListItemModel>? vlist = data.list?.vlist;
|
||||||
archiveCount.value = data.page?['count'] ?? 0;
|
archiveCount.value = data.page?['count'] ?? 0;
|
||||||
|
|
||||||
|
if (vlist.isNullOrEmpty) {
|
||||||
|
isEndArchive = true;
|
||||||
|
archiveState.value = LoadingState.success(vlist);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (data.list == null || data.list!.vlist.isNullOrEmpty) {
|
|
||||||
|
if (isRefresh) {
|
||||||
|
if (vlist!.length >= archiveCount.value) {
|
||||||
isEndArchive = true;
|
isEndArchive = true;
|
||||||
}
|
}
|
||||||
if (isRefresh.not && archiveState.value is Success) {
|
archiveState.value = LoadingState.success(vlist);
|
||||||
data.list ??= ArchiveListModel();
|
} else if (dynamicState.value is Success) {
|
||||||
data.list!.vlist ??= <VListItemModel>[];
|
List<VListItemModel> currentList =
|
||||||
data.list!.vlist!
|
(dynamicState.value as Success).response;
|
||||||
.insertAll(0, (archiveState.value as Success).response);
|
currentList.addAll(vlist!);
|
||||||
|
if (currentList.length >= archiveCount.value) {
|
||||||
|
isEndDynamic = true;
|
||||||
}
|
}
|
||||||
if (!isEndArchive &&
|
archiveState.refresh();
|
||||||
(data.list?.vlist?.length ?? 0) >= archiveCount.value) {
|
|
||||||
isEndArchive = true;
|
|
||||||
}
|
}
|
||||||
archivePn++;
|
archivePn++;
|
||||||
archiveState.value = LoadingState.success(data.list?.vlist);
|
|
||||||
} else if (isRefresh) {
|
} else if (isRefresh) {
|
||||||
archiveState.value = LoadingState.error(res['msg']);
|
archiveState.value = LoadingState.error(res['msg']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
import 'package:PiliPlus/models/msg/msgfeed_at_me.dart';
|
import 'package:PiliPlus/models/msg/msgfeed_at_me.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
class AtMeController extends CommonController {
|
class AtMeController extends CommonListController<MsgFeedAtMe, AtMeItems> {
|
||||||
int cursor = -1;
|
int cursor = -1;
|
||||||
int cursorTime = -1;
|
int cursorTime = -1;
|
||||||
|
|
||||||
@@ -16,19 +15,19 @@ class AtMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<AtMeItems>? getDataList(MsgFeedAtMe response) {
|
||||||
|
return response.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success<MsgFeedAtMe> response) {
|
||||||
MsgFeedAtMe data = response.response;
|
MsgFeedAtMe data = response.response;
|
||||||
if (data.cursor?.isEnd == true || data.items.isNullOrEmpty) {
|
if (data.cursor?.isEnd == true) {
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
}
|
}
|
||||||
cursor = data.cursor?.id ?? -1;
|
cursor = data.cursor?.id ?? -1;
|
||||||
cursorTime = data.cursor?.time ?? -1;
|
cursorTime = data.cursor?.time ?? -1;
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
return false;
|
||||||
data.items ??= <AtMeItems>[];
|
|
||||||
data.items!.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.items);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -39,16 +38,16 @@ class AtMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<MsgFeedAtMe>> customGetData() =>
|
||||||
MsgHttp.msgFeedAtMe(cursor: cursor, cursorTime: cursorTime);
|
MsgHttp.msgFeedAtMe(cursor: cursor, cursorTime: cursorTime);
|
||||||
|
|
||||||
Future onRemove(dynamic id, int index) async {
|
Future onRemove(dynamic id, int index) async {
|
||||||
try {
|
try {
|
||||||
var res = await MsgHttp.delMsgfeed(2, id);
|
var res = await MsgHttp.delMsgfeed(2, id);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<AtMeItems> list = (loadingState.value as Success).response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/msg/msgfeed_at_me.dart';
|
||||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -35,20 +36,20 @@ class _AtMePageState extends State<AtMePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<AtMeItems>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? ListView.separated(
|
? ListView.separated(
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
itemBuilder: (context, int index) {
|
itemBuilder: (context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_atMeController.onLoadMore();
|
_atMeController.onLoadMore();
|
||||||
}
|
}
|
||||||
final item = loadingState.response[index];
|
final item = loadingState.response![index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
String? nativeUri = item.item?.nativeUri;
|
String? nativeUri = item.item?.nativeUri;
|
||||||
@@ -103,10 +104,9 @@ class _AtMePageState extends State<AtMePage> {
|
|||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if ((item.item?.sourceContent as String?)?.isNotEmpty ==
|
if (item.item?.sourceContent?.isNotEmpty == true) ...[
|
||||||
true) ...[
|
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(item.item?.sourceContent,
|
Text(item.item!.sourceContent!,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/models/msg/msgfeed_like_me.dart';
|
import 'package:PiliPlus/models/msg/msgfeed_like_me.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
class LikeMeController extends CommonController {
|
class LikeMeController extends CommonDataController<MsgFeedLikeMe, dynamic> {
|
||||||
int cursor = -1;
|
int cursor = -1;
|
||||||
int cursorTime = -1;
|
int cursorTime = -1;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class LikeMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(bool isRefresh, Success<MsgFeedLikeMe> response) {
|
||||||
MsgFeedLikeMe data = response.response;
|
MsgFeedLikeMe data = response.response;
|
||||||
if (data.total?.cursor?.isEnd == true ||
|
if (data.total?.cursor?.isEnd == true ||
|
||||||
data.total?.items.isNullOrEmpty == true) {
|
data.total?.items.isNullOrEmpty == true) {
|
||||||
@@ -46,7 +46,7 @@ class LikeMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<MsgFeedLikeMe>> customGetData() =>
|
||||||
MsgHttp.msgFeedLikeMe(cursor: cursor, cursorTime: cursorTime);
|
MsgHttp.msgFeedLikeMe(cursor: cursor, cursorTime: cursorTime);
|
||||||
|
|
||||||
Future onRemove(dynamic id, int index, bool isLatest) async {
|
Future onRemove(dynamic id, int index, bool isLatest) async {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
import 'package:PiliPlus/models/msg/msgfeed_reply_me.dart';
|
import 'package:PiliPlus/models/msg/msgfeed_reply_me.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
class ReplyMeController extends CommonController {
|
class ReplyMeController
|
||||||
|
extends CommonListController<MsgFeedReplyMe, ReplyMeItems> {
|
||||||
int cursor = -1;
|
int cursor = -1;
|
||||||
int cursorTime = -1;
|
int cursorTime = -1;
|
||||||
|
|
||||||
@@ -16,19 +16,19 @@ class ReplyMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool customHandleResponse(Success response) {
|
List<ReplyMeItems>? getDataList(MsgFeedReplyMe response) {
|
||||||
MsgFeedReplyMe data = response.response;
|
return response.items;
|
||||||
if (data.cursor?.isEnd == true || data.items.isNullOrEmpty) {
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(bool isRefresh, Success<MsgFeedReplyMe> response) {
|
||||||
|
final data = response.response;
|
||||||
|
if (data.cursor?.isEnd == true) {
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
}
|
}
|
||||||
cursor = data.cursor?.id ?? -1;
|
cursor = data.cursor?.id ?? -1;
|
||||||
cursorTime = data.cursor?.time ?? -1;
|
cursorTime = data.cursor?.time ?? -1;
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
return false;
|
||||||
data.items ??= <ReplyMeItems>[];
|
|
||||||
data.items!.insertAll(0, (loadingState.value as Success).response);
|
|
||||||
}
|
|
||||||
loadingState.value = LoadingState.success(data.items);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -39,16 +39,16 @@ class ReplyMeController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<MsgFeedReplyMe>> customGetData() =>
|
||||||
MsgHttp.msgFeedReplyMe(cursor: cursor, cursorTime: cursorTime);
|
MsgHttp.msgFeedReplyMe(cursor: cursor, cursorTime: cursorTime);
|
||||||
|
|
||||||
Future onRemove(dynamic id, int index) async {
|
Future onRemove(dynamic id, int index) async {
|
||||||
try {
|
try {
|
||||||
var res = await MsgHttp.delMsgfeed(1, id);
|
var res = await MsgHttp.delMsgfeed(1, id);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<ReplyMeItems> list = (loadingState.value as Success).response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
|
|||||||
@@ -34,21 +34,21 @@ class _ReplyMePageState extends State<ReplyMePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<ReplyMeItems>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? ListView.separated(
|
? ListView.separated(
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
itemBuilder: (context, int index) {
|
itemBuilder: (context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_replyMeController.onLoadMore();
|
_replyMeController.onLoadMore();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplyMeItems item = loadingState.response[index];
|
ReplyMeItems item = loadingState.response![index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
String? nativeUri = item.item?.nativeUri;
|
String? nativeUri = item.item?.nativeUri;
|
||||||
@@ -121,12 +121,8 @@ class _ReplyMePageState extends State<ReplyMePage> {
|
|||||||
Text(item.item?.sourceContent ?? "",
|
Text(item.item?.sourceContent ?? "",
|
||||||
style: Theme.of(context).textTheme.bodyMedium),
|
style: Theme.of(context).textTheme.bodyMedium),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
if (loadingState
|
if (item.item?.targetReplyContent != null &&
|
||||||
.response[index].item?.targetReplyContent !=
|
item.item?.targetReplyContent != "")
|
||||||
null &&
|
|
||||||
loadingState
|
|
||||||
.response[index].item?.targetReplyContent !=
|
|
||||||
"")
|
|
||||||
Text("| ${item.item?.targetReplyContent}",
|
Text("| ${item.item?.targetReplyContent}",
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
import 'package:PiliPlus/models/msg/msgfeed_sys_msg.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
import 'package:PiliPlus/http/msg.dart';
|
||||||
|
|
||||||
class SysMsgController extends CommonController {
|
class SysMsgController
|
||||||
|
extends CommonListController<List<SystemNotifyList>?, SystemNotifyList> {
|
||||||
final pageSize = 20;
|
final pageSize = 20;
|
||||||
int cursor = -1;
|
int cursor = -1;
|
||||||
|
|
||||||
@@ -41,9 +43,9 @@ class SysMsgController extends CommonController {
|
|||||||
try {
|
try {
|
||||||
var res = await MsgHttp.delSysMsg(id);
|
var res = await MsgHttp.delSysMsg(id);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
List list = (loadingState.value as Success).response;
|
List<SystemNotifyList> list = (loadingState.value as Success).response;
|
||||||
list.removeAt(index);
|
list.removeAt(index);
|
||||||
loadingState.value = LoadingState.success(list);
|
loadingState.refresh();
|
||||||
SmartDialog.showToast('删除成功');
|
SmartDialog.showToast('删除成功');
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
@@ -52,6 +54,6 @@ class SysMsgController extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LoadingState> customGetData() =>
|
Future<LoadingState<List<SystemNotifyList>?>> customGetData() =>
|
||||||
MsgHttp.msgFeedNotify(cursor: cursor, pageSize: pageSize);
|
MsgHttp.msgFeedNotify(cursor: cursor, pageSize: pageSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/dialog.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/msg/msgfeed_sys_msg.dart';
|
||||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||||
import 'package:PiliPlus/utils/id_utils.dart';
|
import 'package:PiliPlus/utils/id_utils.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
@@ -39,21 +40,21 @@ class _SysMsgPageState extends State<SysMsgPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState loadingState) {
|
Widget _buildBody(LoadingState<List<SystemNotifyList>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => loadingWidget,
|
Loading() => loadingWidget,
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
? ListView.separated(
|
? ListView.separated(
|
||||||
itemCount: loadingState.response.length,
|
itemCount: loadingState.response!.length,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||||
itemBuilder: (context, int index) {
|
itemBuilder: (context, int index) {
|
||||||
if (index == loadingState.response.length - 1) {
|
if (index == loadingState.response!.length - 1) {
|
||||||
_sysMsgController.onLoadMore();
|
_sysMsgController.onLoadMore();
|
||||||
}
|
}
|
||||||
|
|
||||||
final item = loadingState.response[index];
|
final item = loadingState.response![index];
|
||||||
String? content = item.content;
|
String? content = item.content;
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class RankPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RankPageState extends State<RankPage>
|
class _RankPageState extends State<RankPage>
|
||||||
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
|
with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
|
||||||
final RankController _rankController = Get.put(RankController());
|
final RankController _rankController = Get.put(RankController());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user