Merge branch 'main' into design
This commit is contained in:
@ -430,7 +430,7 @@ class EpisodeGridItem extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isCurrentIndex
|
color: isCurrentIndex
|
||||||
? colorScheme.primaryContainer.withOpacity(0.6)
|
? colorScheme.primaryContainer.withOpacity(0.6)
|
||||||
: colorScheme.secondaryContainer.withOpacity(0.4),
|
: colorScheme.onInverseSurface.withOpacity(0.6),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isCurrentIndex
|
color: isCurrentIndex
|
||||||
|
|||||||
@ -175,7 +175,7 @@ class Api {
|
|||||||
static const String delHistory = '/x/v2/history/delete';
|
static const String delHistory = '/x/v2/history/delete';
|
||||||
|
|
||||||
// 搜索历史记录
|
// 搜索历史记录
|
||||||
static const String searchHistory = '/x/web-goblin/history/search';
|
static const String searchHistory = '/x/web-interface/history/search';
|
||||||
|
|
||||||
// 热搜
|
// 热搜
|
||||||
static const String hotSearchList =
|
static const String hotSearchList =
|
||||||
@ -301,10 +301,6 @@ class Api {
|
|||||||
static const String bangumiList =
|
static const String bangumiList =
|
||||||
'/pgc/season/index/result?st=1&order=3&season_version=-1&spoken_language_type=-1&area=-1&is_finish=-1©right=-1&season_status=-1&season_month=-1&year=-1&style_id=-1&sort=0&season_type=1&pagesize=20&type=1';
|
'/pgc/season/index/result?st=1&order=3&season_version=-1&spoken_language_type=-1&area=-1&is_finish=-1©right=-1&season_status=-1&season_month=-1&year=-1&style_id=-1&sort=0&season_type=1&pagesize=20&type=1';
|
||||||
|
|
||||||
// 我的订阅
|
|
||||||
static const String bangumiFollow =
|
|
||||||
'/x/space/bangumi/follow/list?type=1&follow_status=0&pn=1&ps=15&ts=1691544359969';
|
|
||||||
|
|
||||||
// 黑名单
|
// 黑名单
|
||||||
static const String blackLst = '/x/relation/blacks';
|
static const String blackLst = '/x/relation/blacks';
|
||||||
|
|
||||||
@ -604,4 +600,10 @@ class Api {
|
|||||||
|
|
||||||
/// 图片上传
|
/// 图片上传
|
||||||
static const String uploadImage = '/x/dynamic/feed/draw/upload_bfs';
|
static const String uploadImage = '/x/dynamic/feed/draw/upload_bfs';
|
||||||
|
|
||||||
|
/// 更新追番状态
|
||||||
|
static const String updateBangumiStatus = '/pgc/web/follow/status/update';
|
||||||
|
|
||||||
|
/// 番剧点赞投币收藏状态
|
||||||
|
static const String bangumiActionStatus = '/pgc/season/episode/community';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import '../models/bangumi/list.dart';
|
import '../models/bangumi/list.dart';
|
||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
import 'package:html/parser.dart' as html_parser;
|
||||||
|
import 'package:html/dom.dart' as html_dom;
|
||||||
|
|
||||||
class BangumiHttp {
|
class BangumiHttp {
|
||||||
static Future bangumiList({int? page}) async {
|
static Future bangumiList({int? page}) async {
|
||||||
@ -18,8 +21,19 @@ class BangumiHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future bangumiFollow({int? mid}) async {
|
static Future getRecentBangumi({
|
||||||
var res = await Request().get(Api.bangumiFollow, data: {'vmid': mid});
|
int? mid,
|
||||||
|
int type = 1,
|
||||||
|
int pn = 1,
|
||||||
|
int ps = 20,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().get(Api.getRecentBangumiApi, data: {
|
||||||
|
'vmid': mid,
|
||||||
|
'type': type,
|
||||||
|
'follow_status': 0,
|
||||||
|
'pn': pn,
|
||||||
|
'ps': ps,
|
||||||
|
});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {
|
return {
|
||||||
'status': true,
|
'status': true,
|
||||||
@ -33,4 +47,62 @@ class BangumiHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取追番状态
|
||||||
|
static Future bangumiStatus({required int seasonId}) async {
|
||||||
|
var res = await Request()
|
||||||
|
.get('https://www.bilibili.com/bangumi/play/ss$seasonId');
|
||||||
|
html_dom.Document document = html_parser.parse(res.data);
|
||||||
|
// 查找 id 为 __NEXT_DATA__ 的 script 元素
|
||||||
|
html_dom.Element? scriptElement =
|
||||||
|
document.querySelector('script#\\__NEXT_DATA__');
|
||||||
|
if (scriptElement != null) {
|
||||||
|
// 提取 script 元素的内容
|
||||||
|
String scriptContent = scriptElement.text;
|
||||||
|
final dynamic scriptContentJson = jsonDecode(scriptContent);
|
||||||
|
Map followState = scriptContentJson['props']['pageProps']['followState'];
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': {
|
||||||
|
'isFollowed': followState['isFollowed'],
|
||||||
|
'followStatus': followState['followStatus']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
print('Script element with id "__NEXT_DATA__" not found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新追番状态
|
||||||
|
static Future updateBangumiStatus({
|
||||||
|
required int seasonId,
|
||||||
|
required int status,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().post(Api.updateBangumiStatus, data: {
|
||||||
|
'season_id': seasonId,
|
||||||
|
'status': status,
|
||||||
|
});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true, 'data': res.data['data']};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取番剧点赞投币收藏状态
|
||||||
|
static Future bangumiActionStatus({required int epId}) async {
|
||||||
|
var res = await Request().get(
|
||||||
|
Api.bangumiActionStatus,
|
||||||
|
data: {'ep_id': epId},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true, 'data': res.data['data']};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pilipala/models/msg/like.dart';
|
import 'package:pilipala/models/msg/like.dart';
|
||||||
import 'package:pilipala/models/msg/reply.dart';
|
import 'package:pilipala/models/msg/reply.dart';
|
||||||
import 'package:pilipala/models/msg/system.dart';
|
import 'package:pilipala/models/msg/system.dart';
|
||||||
@ -63,7 +64,7 @@ class MsgHttp {
|
|||||||
.toList(),
|
.toList(),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print('err🔟: $err');
|
debugPrint('err: $err');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -47,6 +47,7 @@ class BangumiListItemModel {
|
|||||||
this.title,
|
this.title,
|
||||||
this.titleIcon,
|
this.titleIcon,
|
||||||
this.progress,
|
this.progress,
|
||||||
|
this.progressIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
String? badge;
|
String? badge;
|
||||||
@ -66,8 +67,8 @@ class BangumiListItemModel {
|
|||||||
String? subTitle;
|
String? subTitle;
|
||||||
String? title;
|
String? title;
|
||||||
String? titleIcon;
|
String? titleIcon;
|
||||||
|
|
||||||
String? progress;
|
String? progress;
|
||||||
|
int? progressIndex;
|
||||||
|
|
||||||
BangumiListItemModel.fromJson(Map<String, dynamic> json) {
|
BangumiListItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
badge = json['badge'] == '' ? null : json['badge'];
|
badge = json['badge'] == '' ? null : json['badge'];
|
||||||
@ -87,7 +88,9 @@ class BangumiListItemModel {
|
|||||||
subTitle = json['sub_title'];
|
subTitle = json['sub_title'];
|
||||||
title = json['title'];
|
title = json['title'];
|
||||||
titleIcon = json['title_icon'];
|
titleIcon = json['title_icon'];
|
||||||
|
|
||||||
progress = json['progress'];
|
progress = json['progress'];
|
||||||
|
progressIndex = int.parse(
|
||||||
|
RegExp(r'第(\d+)话').firstMatch(json['progress'] ?? '第1话')?.group(1) ??
|
||||||
|
'0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class Total {
|
|||||||
List<MessageLikeItem>? items;
|
List<MessageLikeItem>? items;
|
||||||
|
|
||||||
factory Total.fromJson(Map<String, dynamic> json) => Total(
|
factory Total.fromJson(Map<String, dynamic> json) => Total(
|
||||||
cursor: Cursor.fromJson(json['cursor']),
|
cursor: json['cursor'] != null ? Cursor.fromJson(json['cursor']) : null,
|
||||||
items: json["items"] == null
|
items: json["items"] == null
|
||||||
? []
|
? []
|
||||||
: json["items"].map<MessageLikeItem>((e) {
|
: json["items"].map<MessageLikeItem>((e) {
|
||||||
|
|||||||
@ -13,8 +13,9 @@ class SessionDataModel {
|
|||||||
|
|
||||||
SessionDataModel.fromJson(Map<String, dynamic> json) {
|
SessionDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
sessionList = json['session_list']
|
sessionList = json['session_list']
|
||||||
?.map<SessionList>((e) => SessionList.fromJson(e))
|
?.map<SessionList>((e) => SessionList.fromJson(e))
|
||||||
.toList();
|
.toList() ??
|
||||||
|
[];
|
||||||
hasMore = json['has_more'];
|
hasMore = json['has_more'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class ReplyCursor {
|
|||||||
isEnd = json['is_end'];
|
isEnd = json['is_end'];
|
||||||
mode = json['mode'];
|
mode = json['mode'];
|
||||||
modeText = json['mode_text'];
|
modeText = json['mode_text'];
|
||||||
allCount = json['all_count'];
|
allCount = json['all_count'] ?? 0;
|
||||||
supportMode = json['support_mode'].cast<int>();
|
supportMode = json['support_mode'].cast<int>();
|
||||||
name = json['name'];
|
name = json['name'];
|
||||||
paginationReply = json['pagination_reply'] != null
|
paginationReply = json['pagination_reply'] != null
|
||||||
|
|||||||
@ -11,6 +11,7 @@ class ReplyItemModel {
|
|||||||
this.parent,
|
this.parent,
|
||||||
this.dialog,
|
this.dialog,
|
||||||
this.count,
|
this.count,
|
||||||
|
this.rcount,
|
||||||
this.floor,
|
this.floor,
|
||||||
this.state,
|
this.state,
|
||||||
this.fansgrade,
|
this.fansgrade,
|
||||||
@ -41,6 +42,7 @@ class ReplyItemModel {
|
|||||||
int? parent;
|
int? parent;
|
||||||
int? dialog;
|
int? dialog;
|
||||||
int? count;
|
int? count;
|
||||||
|
int? rcount;
|
||||||
int? floor;
|
int? floor;
|
||||||
int? state;
|
int? state;
|
||||||
int? fansgrade;
|
int? fansgrade;
|
||||||
@ -72,6 +74,7 @@ class ReplyItemModel {
|
|||||||
parent = json['parent'];
|
parent = json['parent'];
|
||||||
dialog = json['dialog'];
|
dialog = json['dialog'];
|
||||||
count = json['count'];
|
count = json['count'];
|
||||||
|
rcount = json['rcount'] ?? 0;
|
||||||
floor = json['floor'];
|
floor = json['floor'];
|
||||||
state = json['state'];
|
state = json['state'];
|
||||||
fansgrade = json['fansgrade'];
|
fansgrade = json['fansgrade'];
|
||||||
|
|||||||
@ -9,6 +9,7 @@ class BangumiController extends GetxController {
|
|||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
RxList<BangumiListItemModel> bangumiList = <BangumiListItemModel>[].obs;
|
RxList<BangumiListItemModel> bangumiList = <BangumiListItemModel>[].obs;
|
||||||
RxList<BangumiListItemModel> bangumiFollowList = <BangumiListItemModel>[].obs;
|
RxList<BangumiListItemModel> bangumiFollowList = <BangumiListItemModel>[].obs;
|
||||||
|
RxInt total = 0.obs;
|
||||||
int _currentPage = 1;
|
int _currentPage = 1;
|
||||||
bool isLoadingMore = true;
|
bool isLoadingMore = true;
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
@ -54,9 +55,10 @@ class BangumiController extends GetxController {
|
|||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var result = await BangumiHttp.bangumiFollow(mid: userInfo.mid);
|
var result = await BangumiHttp.getRecentBangumi(mid: userInfo.mid);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
bangumiFollowList.value = result['data'].list;
|
bangumiFollowList.value = result['data'].list;
|
||||||
|
total.value = result['data'].total;
|
||||||
} else {}
|
} else {}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ 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:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/http/bangumi.dart';
|
||||||
import 'package:pilipala/http/constants.dart';
|
import 'package:pilipala/http/constants.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
@ -52,28 +53,34 @@ class BangumiIntroController extends GetxController {
|
|||||||
Rx<FavFolderData> favFolderData = FavFolderData().obs;
|
Rx<FavFolderData> favFolderData = FavFolderData().obs;
|
||||||
List addMediaIdsNew = [];
|
List addMediaIdsNew = [];
|
||||||
List delMediaIdsNew = [];
|
List delMediaIdsNew = [];
|
||||||
// 关注状态 默认未关注
|
// 追番状态 1想看 2在看 3已看
|
||||||
RxMap followStatus = {}.obs;
|
RxBool isFollowed = false.obs;
|
||||||
|
RxInt followStatus = 1.obs;
|
||||||
int _tempThemeValue = -1;
|
int _tempThemeValue = -1;
|
||||||
var userInfo;
|
var userInfo;
|
||||||
PersistentBottomSheetController? bottomSheetController;
|
PersistentBottomSheetController? bottomSheetController;
|
||||||
|
List<Map<String, dynamic>> followStatusList = [
|
||||||
|
{'title': '标记为 「想看」', 'status': 1},
|
||||||
|
{'title': '标记为 「在看」', 'status': 2},
|
||||||
|
{'title': '标记为 「已看」', 'status': 3},
|
||||||
|
{'title': '取消追番', 'status': -1},
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
userInfo = userInfoCache.get('userInfoCache');
|
userInfo = userInfoCache.get('userInfoCache');
|
||||||
userLogin = userInfo != null;
|
userLogin = userInfo != null;
|
||||||
|
if (userLogin && seasonId != null) {
|
||||||
|
bangumiStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取番剧简介&选集
|
// 获取番剧简介&选集
|
||||||
Future queryBangumiIntro() async {
|
Future queryBangumiIntro() async {
|
||||||
if (userLogin) {
|
if (userLogin) {
|
||||||
// 获取点赞状态
|
// 获取点赞投币收藏状态
|
||||||
queryHasLikeVideo();
|
bangumiActionStatus();
|
||||||
// 获取投币状态
|
|
||||||
queryHasCoinVideo();
|
|
||||||
// 获取收藏状态
|
|
||||||
queryHasFavVideo();
|
|
||||||
}
|
}
|
||||||
var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
|
var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
@ -83,26 +90,15 @@ class BangumiIntroController extends GetxController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取点赞状态
|
// 获取番剧点赞投币收藏状态
|
||||||
Future queryHasLikeVideo() async {
|
Future bangumiActionStatus() async {
|
||||||
var result = await VideoHttp.hasLikeVideo(bvid: bvid);
|
var result = await BangumiHttp.bangumiActionStatus(epId: epId!);
|
||||||
// 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']) {
|
if (result['status']) {
|
||||||
hasFav.value = result["data"]['favoured'];
|
hasLike.value = result['data']['like'] == 1;
|
||||||
|
hasCoin.value = result['data']['coin_number'] != 0;
|
||||||
|
hasFav.value = result['data']['favorite'] == 1;
|
||||||
} else {
|
} else {
|
||||||
hasFav.value = false;
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +106,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
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 ? '点赞成功 👍' : '取消赞');
|
SmartDialog.showToast(!hasLike.value ? '点赞成功' : '取消赞');
|
||||||
hasLike.value = !hasLike.value;
|
hasLike.value = !hasLike.value;
|
||||||
bangumiDetail.value.stat!['likes'] =
|
bangumiDetail.value.stat!['likes'] =
|
||||||
bangumiDetail.value.stat!['likes'] + (!hasLike.value ? 1 : -1);
|
bangumiDetail.value.stat!['likes'] + (!hasLike.value ? 1 : -1);
|
||||||
@ -147,7 +143,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
var res = await VideoHttp.coinVideo(
|
var res = await VideoHttp.coinVideo(
|
||||||
bvid: bvid, multiply: _tempThemeValue);
|
bvid: bvid, multiply: _tempThemeValue);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast('投币成功 👏');
|
SmartDialog.showToast('投币成功');
|
||||||
hasCoin.value = true;
|
hasCoin.value = true;
|
||||||
bangumiDetail.value.stat!['coins'] =
|
bangumiDetail.value.stat!['coins'] =
|
||||||
bangumiDetail.value.stat!['coins'] +
|
bangumiDetail.value.stat!['coins'] +
|
||||||
@ -185,9 +181,11 @@ class BangumiIntroController extends GetxController {
|
|||||||
addMediaIdsNew = [];
|
addMediaIdsNew = [];
|
||||||
delMediaIdsNew = [];
|
delMediaIdsNew = [];
|
||||||
// 重新获取收藏状态
|
// 重新获取收藏状态
|
||||||
queryHasFavVideo();
|
bangumiActionStatus();
|
||||||
SmartDialog.showToast('✅ 操作成功');
|
SmartDialog.showToast('操作成功');
|
||||||
Get.back();
|
Get.back();
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,15 +237,22 @@ class BangumiIntroController extends GetxController {
|
|||||||
|
|
||||||
// 追番
|
// 追番
|
||||||
Future bangumiAdd() async {
|
Future bangumiAdd() async {
|
||||||
var result =
|
var result = await VideoHttp.bangumiAdd(
|
||||||
await VideoHttp.bangumiAdd(seasonId: bangumiDetail.value.seasonId);
|
seasonId: seasonId ?? bangumiDetail.value.seasonId);
|
||||||
|
if (result['status']) {
|
||||||
|
followStatus.value = 2;
|
||||||
|
isFollowed.value = true;
|
||||||
|
}
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消追番
|
// 取消追番
|
||||||
Future bangumiDel() async {
|
Future bangumiDel() async {
|
||||||
var result =
|
var result = await VideoHttp.bangumiDel(
|
||||||
await VideoHttp.bangumiDel(seasonId: bangumiDetail.value.seasonId);
|
seasonId: seasonId ?? bangumiDetail.value.seasonId);
|
||||||
|
if (result['status']) {
|
||||||
|
isFollowed.value = false;
|
||||||
|
}
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,4 +320,35 @@ class BangumiIntroController extends GetxController {
|
|||||||
hiddenEpisodeBottomSheet() {
|
hiddenEpisodeBottomSheet() {
|
||||||
bottomSheetController?.close();
|
bottomSheetController?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取追番状态
|
||||||
|
Future bangumiStatus() async {
|
||||||
|
var result = await BangumiHttp.bangumiStatus(seasonId: seasonId!);
|
||||||
|
if (result['status']) {
|
||||||
|
followStatus.value = result['data']['followStatus'];
|
||||||
|
isFollowed.value = result['data']['isFollowed'];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新追番状态
|
||||||
|
Future updateBangumiStatus(int status) async {
|
||||||
|
Get.back();
|
||||||
|
if (status == -1) {
|
||||||
|
bangumiDel();
|
||||||
|
} else {
|
||||||
|
var result = await BangumiHttp.bangumiStatus(seasonId: seasonId!);
|
||||||
|
if (result['status']) {
|
||||||
|
followStatus.value = status;
|
||||||
|
final title = followStatusList.firstWhere(
|
||||||
|
(e) => e['status'] == status,
|
||||||
|
orElse: () => {'title': '未知状态'},
|
||||||
|
)['title'];
|
||||||
|
SmartDialog.showToast('追番状态$title');
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(result['msg']);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -239,104 +239,65 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => showIntroDetail(),
|
onTap: () => showIntroDetail(),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 115 / 0.75,
|
height: 115 / 0.75,
|
||||||
child: Column(
|
child: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
padding: const EdgeInsets.fromLTRB(6, 4, 6, 6),
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Row(
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Row(
|
||||||
child: Text(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
widget.bangumiDetail!.title!,
|
children: [
|
||||||
style: const TextStyle(
|
Expanded(
|
||||||
fontSize: 16,
|
child: Text(
|
||||||
fontWeight: FontWeight.w500,
|
widget.bangumiDetail!.title!,
|
||||||
),
|
style: const TextStyle(
|
||||||
maxLines: 1,
|
fontSize: 18,
|
||||||
overflow: TextOverflow.ellipsis,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
maxLines: 2,
|
||||||
const SizedBox(width: 20),
|
overflow: TextOverflow.ellipsis,
|
||||||
SizedBox(
|
|
||||||
width: 34,
|
|
||||||
height: 34,
|
|
||||||
child: IconButton(
|
|
||||||
style: ButtonStyle(
|
|
||||||
padding: MaterialStateProperty.all(
|
|
||||||
EdgeInsets.zero),
|
|
||||||
backgroundColor:
|
|
||||||
MaterialStateProperty.resolveWith(
|
|
||||||
(Set<MaterialState> states) {
|
|
||||||
return t.colorScheme.primaryContainer
|
|
||||||
.withOpacity(0.7);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
onPressed: () =>
|
|
||||||
bangumiIntroController.bangumiAdd(),
|
|
||||||
icon: Icon(
|
|
||||||
Icons.favorite_border_rounded,
|
|
||||||
color: t.colorScheme.primary,
|
|
||||||
size: 22,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 20),
|
||||||
],
|
Obx(
|
||||||
),
|
() => BangumiStatusWidget(
|
||||||
Row(
|
ctr: bangumiIntroController,
|
||||||
children: [
|
isFollowed:
|
||||||
StatView(
|
bangumiIntroController.isFollowed.value,
|
||||||
view: widget.bangumiDetail!.stat!['views'],
|
),
|
||||||
size: 'medium',
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
StatDanMu(
|
|
||||||
danmu: widget.bangumiDetail!.stat!['danmakus'],
|
|
||||||
size: 'medium',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 6),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
(widget.bangumiDetail!.areas!.isNotEmpty
|
|
||||||
? widget.bangumiDetail!.areas!.first['name']
|
|
||||||
: ''),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: t.colorScheme.outline,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
const SizedBox(width: 6),
|
|
||||||
Text(
|
|
||||||
widget.bangumiDetail!.publish!['pub_time_show'],
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: t.colorScheme.outline,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
widget.bangumiDetail!.newEp!['desc'],
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: t.colorScheme.outline,
|
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 4),
|
||||||
const Spacer(),
|
Row(
|
||||||
Text(
|
children: [
|
||||||
'简介:${widget.bangumiDetail!.evaluate!}',
|
StatView(
|
||||||
maxLines: 3,
|
view: widget.bangumiDetail!.stat!['views'],
|
||||||
overflow: TextOverflow.ellipsis,
|
size: 'medium',
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 13,
|
const SizedBox(width: 6),
|
||||||
color: t.colorScheme.outline,
|
StatDanMu(
|
||||||
|
danmu: widget.bangumiDetail!.stat!['danmakus'],
|
||||||
|
size: 'medium',
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 10),
|
||||||
],
|
Text(
|
||||||
|
'简介:${widget.bangumiDetail!.evaluate!}',
|
||||||
|
maxLines: 3,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: t.colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -426,3 +387,97 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 追番状态
|
||||||
|
class BangumiStatusWidget extends StatelessWidget {
|
||||||
|
final BangumiIntroController ctr;
|
||||||
|
final bool isFollowed;
|
||||||
|
|
||||||
|
const BangumiStatusWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.ctr,
|
||||||
|
required this.isFollowed,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ColorScheme colorScheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
void updateFollowStatus() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
useRootNavigator: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return morePanel(context, ctr);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Obx(
|
||||||
|
() => SizedBox(
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
|
backgroundColor:
|
||||||
|
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||||
|
return ctr.isFollowed.value
|
||||||
|
? colorScheme.primaryContainer.withOpacity(0.7)
|
||||||
|
: colorScheme.outlineVariant.withOpacity(0.7);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onPressed:
|
||||||
|
isFollowed ? () => updateFollowStatus() : () => ctr.bangumiAdd(),
|
||||||
|
icon: Icon(
|
||||||
|
ctr.isFollowed.value
|
||||||
|
? Icons.favorite
|
||||||
|
: Icons.favorite_border_rounded,
|
||||||
|
color: ctr.isFollowed.value
|
||||||
|
? colorScheme.primary
|
||||||
|
: colorScheme.outline,
|
||||||
|
size: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget morePanel(BuildContext context, BangumiIntroController ctr) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () => Get.back(),
|
||||||
|
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))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...ctr.followStatusList
|
||||||
|
.map(
|
||||||
|
(e) => ListTile(
|
||||||
|
onTap: () => ctr.updateBangumiStatus(e['status']),
|
||||||
|
selected: ctr.followStatus == e['status'],
|
||||||
|
title: Text(e['title']),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -76,9 +76,14 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Obx(
|
||||||
'最近追番',
|
() => 0 != _bangumidController.total.value
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
? Text(
|
||||||
|
'我的追番(${_bangumidController.total.value})',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.titleMedium,
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|||||||
@ -175,59 +175,60 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
return Container(
|
return Container(
|
||||||
width: 150,
|
width: 150,
|
||||||
margin: const EdgeInsets.only(right: 10),
|
margin: const EdgeInsets.only(right: 10),
|
||||||
child: Material(
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(8),
|
||||||
clipBehavior: Clip.hardEdge,
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => changeFucCall(page, i),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Padding(
|
onTap: () => changeFucCall(page, i),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: Padding(
|
||||||
vertical: 8,
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10,
|
vertical: 8,
|
||||||
),
|
horizontal: 10,
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: <Widget>[
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Row(
|
children: <Widget>[
|
||||||
children: [
|
Row(
|
||||||
if (isSelected) ...<Widget>[
|
children: [
|
||||||
Image.asset('assets/images/live.png',
|
if (isSelected) ...<Widget>[
|
||||||
color: primary, height: 12),
|
Image.asset('assets/images/live.png',
|
||||||
const SizedBox(width: 6)
|
color: primary, height: 12),
|
||||||
],
|
const SizedBox(width: 6)
|
||||||
|
],
|
||||||
|
Text(
|
||||||
|
'第${i + 1}话',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: isSelected ? primary : onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 2),
|
||||||
|
if (page.badge != null) ...[
|
||||||
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
'第${i + 1}话',
|
page.badge!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 12,
|
||||||
color: isSelected ? primary : onSurface,
|
color: primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 2),
|
]
|
||||||
if (page.badge != null) ...[
|
],
|
||||||
const Spacer(),
|
),
|
||||||
Text(
|
const SizedBox(height: 3),
|
||||||
page.badge!,
|
Text(
|
||||||
style: TextStyle(
|
page.longTitle!,
|
||||||
fontSize: 12,
|
maxLines: 1,
|
||||||
color: primary,
|
style: TextStyle(
|
||||||
),
|
fontSize: 13,
|
||||||
),
|
color: isSelected ? primary : onSurface,
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 3),
|
overflow: TextOverflow.ellipsis,
|
||||||
Text(
|
)
|
||||||
page.longTitle!,
|
],
|
||||||
maxLines: 1,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: isSelected ? primary : onSurface,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -25,6 +25,7 @@ class BangumiCardV extends StatelessWidget {
|
|||||||
RoutePush.bangumiPush(
|
RoutePush.bangumiPush(
|
||||||
bangumiItem.seasonId,
|
bangumiItem.seasonId,
|
||||||
null,
|
null,
|
||||||
|
progressIndex: bangumiItem.progressIndex,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -48,8 +48,17 @@ class DynamicDetailController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future queryReplyList({reqType = 'init'}) async {
|
Future queryReplyList({reqType = 'init'}) async {
|
||||||
|
if (isLoadingMore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isLoadingMore = true;
|
||||||
if (reqType == 'init') {
|
if (reqType == 'init') {
|
||||||
nextOffset = "";
|
nextOffset = '';
|
||||||
|
noMore.value = '';
|
||||||
|
}
|
||||||
|
if (noMore.value == '没有更多了') {
|
||||||
|
isLoadingMore = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
var res = await ReplyHttp.replyList(
|
var res = await ReplyHttp.replyList(
|
||||||
oid: oid!,
|
oid: oid!,
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
late DynamicDetailController _dynamicDetailController;
|
late DynamicDetailController _dynamicDetailController;
|
||||||
late AnimationController fabAnimationCtr;
|
late AnimationController fabAnimationCtr;
|
||||||
Future? _futureBuilderFuture;
|
late Future _futureBuilderFuture;
|
||||||
late StreamController<bool> titleStreamC =
|
late StreamController<bool> titleStreamC =
|
||||||
StreamController<bool>.broadcast(); // appBar title
|
StreamController<bool>.broadcast(); // appBar title
|
||||||
late ScrollController scrollController;
|
late ScrollController scrollController;
|
||||||
@ -278,8 +278,8 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
Map data = snapshot.data as Map;
|
Map? data = snapshot.data;
|
||||||
if (snapshot.data['status']) {
|
if (data != null && snapshot.data['status']) {
|
||||||
RxList<ReplyItemModel> replyList =
|
RxList<ReplyItemModel> replyList =
|
||||||
_dynamicDetailController.replyList;
|
_dynamicDetailController.replyList;
|
||||||
// 请求成功
|
// 请求成功
|
||||||
@ -345,8 +345,11 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
return HttpError(
|
return HttpError(
|
||||||
errMsg: data['msg'],
|
errMsg: data?['msg'] ?? '请求异常',
|
||||||
fn: () => setState(() {}),
|
fn: () => setState(() {
|
||||||
|
_futureBuilderFuture =
|
||||||
|
_dynamicDetailController.queryReplyList();
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -395,14 +395,17 @@ class SearchBar extends StatelessWidget {
|
|||||||
color: colorScheme.onSecondaryContainer,
|
color: colorScheme.onSecondaryContainer,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Obx(
|
Expanded(
|
||||||
() => Text(
|
child: Obx(
|
||||||
ctr!.defaultSearch.value,
|
() => Text(
|
||||||
maxLines: 1,
|
ctr!.defaultSearch.value,
|
||||||
overflow: TextOverflow.ellipsis,
|
maxLines: 1,
|
||||||
style: TextStyle(color: colorScheme.outline),
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(color: colorScheme.outline),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class MemberArticleController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future getMemberArticle(type) async {
|
Future getMemberArticle(type) async {
|
||||||
if (isLoading.value) {
|
if (isLoading.value || !hasMore) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
|
|||||||
@ -113,12 +113,14 @@ class _MemberArticlePageState extends State<MemberArticlePage> {
|
|||||||
'articleType': 'opus',
|
'articleType': 'opus',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
leading: NetworkImgLayer(
|
leading: item?.cover != null
|
||||||
width: 50,
|
? NetworkImgLayer(
|
||||||
height: 50,
|
width: 50,
|
||||||
type: 'emote',
|
height: 50,
|
||||||
src: item.cover['url'],
|
type: 'emote',
|
||||||
),
|
src: item?.cover?['url'] ?? '',
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
title: Text(
|
title: Text(
|
||||||
item.content,
|
item.content,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/common/widgets/no_data.dart';
|
||||||
import 'package:pilipala/models/msg/like.dart';
|
import 'package:pilipala/models/msg/like.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
import '../utils/index.dart';
|
import '../utils/index.dart';
|
||||||
@ -57,34 +58,34 @@ class _MessageLikePageState extends State<MessageLikePage> {
|
|||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.data == null) {
|
Map? data = snapshot.data;
|
||||||
return const SizedBox();
|
if (data != null && data['status']) {
|
||||||
}
|
|
||||||
if (snapshot.data['status']) {
|
|
||||||
final likeItems = _messageLikeCtr.likeItems;
|
final likeItems = _messageLikeCtr.likeItems;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => ListView.separated(
|
() => likeItems.isEmpty
|
||||||
controller: scrollController,
|
? const CustomScrollView(slivers: [NoData()])
|
||||||
itemBuilder: (context, index) => LikeItem(
|
: ListView.separated(
|
||||||
item: likeItems[index],
|
controller: scrollController,
|
||||||
index: index,
|
itemBuilder: (context, index) => LikeItem(
|
||||||
messageLikeCtr: _messageLikeCtr,
|
item: likeItems[index],
|
||||||
),
|
index: index,
|
||||||
itemCount: likeItems.length,
|
messageLikeCtr: _messageLikeCtr,
|
||||||
separatorBuilder: (BuildContext context, int index) {
|
),
|
||||||
return Divider(
|
itemCount: likeItems.length,
|
||||||
indent: 66,
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
endIndent: 14,
|
return Divider(
|
||||||
height: 1,
|
indent: 66,
|
||||||
color: Colors.grey.withOpacity(0.1),
|
endIndent: 14,
|
||||||
);
|
height: 1,
|
||||||
},
|
color: Colors.grey.withOpacity(0.1),
|
||||||
),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
return HttpError(
|
return HttpError(
|
||||||
errMsg: snapshot.data['msg'],
|
errMsg: data?['msg'] ?? '请求异常',
|
||||||
fn: () {
|
fn: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_futureBuilderFuture = _messageLikeCtr.queryMessageLike();
|
_futureBuilderFuture = _messageLikeCtr.queryMessageLike();
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/common/widgets/no_data.dart';
|
||||||
import 'package:pilipala/models/msg/reply.dart';
|
import 'package:pilipala/models/msg/reply.dart';
|
||||||
import 'package:pilipala/pages/message/utils/index.dart';
|
import 'package:pilipala/pages/message/utils/index.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
@ -58,31 +59,31 @@ class _MessageReplyPageState extends State<MessageReplyPage> {
|
|||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.data == null) {
|
Map? data = snapshot.data;
|
||||||
return const SizedBox();
|
if (data != null && data['status']) {
|
||||||
}
|
|
||||||
if (snapshot.data['status']) {
|
|
||||||
final replyItems = _messageReplyCtr.replyItems;
|
final replyItems = _messageReplyCtr.replyItems;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => ListView.separated(
|
() => replyItems.isEmpty
|
||||||
controller: scrollController,
|
? const CustomScrollView(slivers: [NoData()])
|
||||||
itemBuilder: (context, index) =>
|
: ListView.separated(
|
||||||
ReplyItem(item: replyItems[index]),
|
controller: scrollController,
|
||||||
itemCount: replyItems.length,
|
itemBuilder: (context, index) =>
|
||||||
separatorBuilder: (BuildContext context, int index) {
|
ReplyItem(item: replyItems[index]),
|
||||||
return Divider(
|
itemCount: replyItems.length,
|
||||||
indent: 66,
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
endIndent: 14,
|
return Divider(
|
||||||
height: 1,
|
indent: 66,
|
||||||
color: Colors.grey.withOpacity(0.1),
|
endIndent: 14,
|
||||||
);
|
height: 1,
|
||||||
},
|
color: Colors.grey.withOpacity(0.1),
|
||||||
),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
return HttpError(
|
return HttpError(
|
||||||
errMsg: snapshot.data['msg'],
|
errMsg: data?['msg'] ?? '请求异常',
|
||||||
fn: () {
|
fn: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_futureBuilderFuture =
|
_futureBuilderFuture =
|
||||||
|
|||||||
@ -75,60 +75,58 @@ class _MinePageState extends State<MinePage>
|
|||||||
parent: BouncingScrollPhysics()),
|
parent: BouncingScrollPhysics()),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 110),
|
padding: const EdgeInsets.only(bottom: 110),
|
||||||
child: Expanded(
|
child: Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
Obx(() => _buildProfileSection(context, ctr.userInfo.value)),
|
||||||
Obx(() => _buildProfileSection(context, ctr.userInfo.value)),
|
const SizedBox(height: 10),
|
||||||
const SizedBox(height: 10),
|
FutureBuilder(
|
||||||
FutureBuilder(
|
future: _futureBuilderFuture,
|
||||||
future: _futureBuilderFuture,
|
builder: (context, snapshot) {
|
||||||
builder: (context, snapshot) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.data == null) {
|
||||||
if (snapshot.data == null) {
|
return const SizedBox();
|
||||||
return const SizedBox();
|
}
|
||||||
}
|
if (snapshot.data['status']) {
|
||||||
if (snapshot.data['status']) {
|
return Obx(
|
||||||
return Obx(
|
() => _buildStatsSection(
|
||||||
() => _buildStatsSection(
|
|
||||||
context,
|
|
||||||
ctr.userStat.value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return _buildStatsSection(
|
|
||||||
context,
|
context,
|
||||||
ctr.userStat.value,
|
ctr.userStat.value,
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
} else {
|
} else {
|
||||||
return _buildStatsSection(
|
return _buildStatsSection(
|
||||||
context,
|
context,
|
||||||
ctr.userStat.value,
|
ctr.userStat.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
),
|
return _buildStatsSection(
|
||||||
_buildMenuSection(context),
|
context,
|
||||||
Obx(
|
ctr.userStat.value,
|
||||||
() => Visibility(
|
);
|
||||||
visible: ctr.userLogin.value,
|
}
|
||||||
child: Divider(
|
},
|
||||||
height: 25,
|
),
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
_buildMenuSection(context),
|
||||||
),
|
Obx(
|
||||||
|
() => Visibility(
|
||||||
|
visible: ctr.userLogin.value,
|
||||||
|
child: Divider(
|
||||||
|
height: 25,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
),
|
||||||
() => ctr.userLogin.value
|
Obx(
|
||||||
? _buildFavoritesSection(context)
|
() => ctr.userLogin.value
|
||||||
: const SizedBox(),
|
? _buildFavoritesSection(context)
|
||||||
),
|
: const SizedBox(),
|
||||||
SizedBox(
|
),
|
||||||
height: MediaQuery.of(context).padding.bottom +
|
SizedBox(
|
||||||
kBottomNavigationBarHeight,
|
height: MediaQuery.of(context).padding.bottom +
|
||||||
)
|
kBottomNavigationBarHeight,
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -80,16 +80,21 @@ class _SubDetailPageState extends State<SubDetailPage> {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
SizedBox(
|
||||||
_subDetailController.item.title!,
|
width: Get.size.width - 100,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
child: Text(
|
||||||
|
_subDetailController.item.title!,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'共${_subDetailController.item.mediaCount!}条视频',
|
'共${_subDetailController.item.mediaCount!}条视频',
|
||||||
style: Theme.of(context).textTheme.labelMedium,
|
style: Theme.of(context).textTheme.labelMedium,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -59,9 +59,7 @@ class ReplyItem extends StatelessWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
feedBack();
|
feedBack();
|
||||||
if (replyReply != null) {
|
replyReply?.call(replyItem, null, replyItem!.rcount! > 0);
|
||||||
replyReply!(replyItem, null, replyItem!.replies!.isNotEmpty);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
if (replySave) {
|
if (replySave) {
|
||||||
@ -267,9 +265,7 @@ class ReplyItem extends StatelessWidget {
|
|||||||
// 操作区域
|
// 操作区域
|
||||||
bottonAction(context, replyItem!.replyControl, replySave),
|
bottonAction(context, replyItem!.replyControl, replySave),
|
||||||
// 一楼的评论
|
// 一楼的评论
|
||||||
if ((replyItem!.replyControl!.isShow! ||
|
if ((replyItem!.rcount! > 0) && showReplyRow!) ...[
|
||||||
replyItem!.replies!.isNotEmpty) &&
|
|
||||||
showReplyRow!) ...[
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 5, bottom: 12),
|
padding: const EdgeInsets.only(top: 5, bottom: 12),
|
||||||
child: ReplyItemRow(
|
child: ReplyItemRow(
|
||||||
@ -416,8 +412,7 @@ class ReplyItemRow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bool isShow = replyControl!.isShow!;
|
final int extraRow = replyItem!.rcount! > 0 ? 1 : 0;
|
||||||
final int extraRow = replyControl != null && isShow ? 1 : 0;
|
|
||||||
ColorScheme colorScheme = Theme.of(context).colorScheme;
|
ColorScheme colorScheme = Theme.of(context).colorScheme;
|
||||||
TextTheme textTheme = Theme.of(context).textTheme;
|
TextTheme textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,9 @@ class WhisperController extends GetxController {
|
|||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
var res = await MsgHttp.sessionList(
|
var res = await MsgHttp.sessionList(
|
||||||
endTs: type == 'onLoad' ? sessionList.last.sessionTs : null);
|
endTs: type == 'onLoad' ? sessionList.last.sessionTs : null);
|
||||||
if (res['data'].sessionList != null && res['data'].sessionList.isNotEmpty) {
|
if (res['status'] &&
|
||||||
|
res['data'].sessionList != null &&
|
||||||
|
res['data'].sessionList.isNotEmpty) {
|
||||||
await queryAccountList(res['data'].sessionList);
|
await queryAccountList(res['data'].sessionList);
|
||||||
// 将 accountList 转换为 Map 结构
|
// 将 accountList 转换为 Map 结构
|
||||||
Map<int, dynamic> accountMap = {};
|
Map<int, dynamic> accountMap = {};
|
||||||
@ -67,8 +69,6 @@ class WhisperController extends GetxController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (res['status'] && res['data'].sessionList != null) {
|
|
||||||
if (type == 'onLoad') {
|
if (type == 'onLoad') {
|
||||||
sessionList.addAll(res['data'].sessionList);
|
sessionList.addAll(res['data'].sessionList);
|
||||||
} else {
|
} else {
|
||||||
@ -81,10 +81,33 @@ class WhisperController extends GetxController {
|
|||||||
|
|
||||||
Future queryAccountList(sessionList) async {
|
Future queryAccountList(sessionList) async {
|
||||||
List midsList = sessionList.map((e) => e.talkerId!).toList();
|
List midsList = sessionList.map((e) => e.talkerId!).toList();
|
||||||
|
var index = midsList.indexOf(0);
|
||||||
|
AccountListModel? accountInfo;
|
||||||
|
if (index != -1) {
|
||||||
|
accountInfo = AccountListModel(
|
||||||
|
mid: 0,
|
||||||
|
name: '客服消息',
|
||||||
|
face:
|
||||||
|
'https://i0.hdslb.com/bfs/activity-plat/static/20230809/f87fc7ea98282a4dd48ec7743044b0bf/OWdoP9ZXAX.png',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (midsList.length == 1 && index != -1) {
|
||||||
|
accountList.add(accountInfo!);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var res = await MsgHttp.accountList(midsList.join(','));
|
var res = await MsgHttp.accountList(midsList.join(','));
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
accountList.value = res['data'];
|
accountList.value = res['data'];
|
||||||
|
if (accountInfo != null) {
|
||||||
|
if (accountList.isNotEmpty) {
|
||||||
|
accountList.insert(index, accountInfo);
|
||||||
|
} else {
|
||||||
|
accountList.add(accountInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,9 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
import 'package:pilipala/common/skeleton/skeleton.dart';
|
import 'package:pilipala/common/skeleton/skeleton.dart';
|
||||||
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/common/widgets/no_data.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
@ -126,7 +128,7 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
RxList sessionList = _whisperController.sessionList;
|
RxList sessionList = _whisperController.sessionList;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => sessionList.isEmpty
|
() => sessionList.isEmpty
|
||||||
? const SizedBox()
|
? const CustomScrollView(slivers: [NoData()])
|
||||||
: ListView.separated(
|
: ListView.separated(
|
||||||
itemCount: sessionList.length,
|
itemCount: sessionList.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
@ -150,8 +152,15 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
return Center(
|
return HttpError(
|
||||||
child: Text(data?['msg'] ?? '请求异常'),
|
errMsg: data?['msg'] ?? '请求异常',
|
||||||
|
fn: () {
|
||||||
|
setState(() {
|
||||||
|
_futureBuilderFuture =
|
||||||
|
_whisperController.querySessionList('init');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isInSliver: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -227,8 +236,8 @@ class SessionItem extends StatelessWidget {
|
|||||||
'/whisperDetail',
|
'/whisperDetail',
|
||||||
parameters: {
|
parameters: {
|
||||||
'talkerId': sessionItem.talkerId.toString(),
|
'talkerId': sessionItem.talkerId.toString(),
|
||||||
'name': sessionItem.accountInfo.name,
|
'name': sessionItem.accountInfo?.name ?? '',
|
||||||
'face': sessionItem.accountInfo.face ?? '',
|
'face': sessionItem.accountInfo?.face ?? '',
|
||||||
'mid': (sessionItem.accountInfo?.mid ?? 0).toString(),
|
'mid': (sessionItem.accountInfo?.mid ?? 0).toString(),
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
},
|
},
|
||||||
@ -244,11 +253,11 @@ class SessionItem extends StatelessWidget {
|
|||||||
width: 45,
|
width: 45,
|
||||||
height: 45,
|
height: 45,
|
||||||
type: 'avatar',
|
type: 'avatar',
|
||||||
src: sessionItem.accountInfo.face ?? '',
|
src: sessionItem.accountInfo?.face ?? '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(sessionItem.accountInfo.name),
|
title: Text(sessionItem.accountInfo?.name ?? ''),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
msgStatus == 1
|
msgStatus == 1
|
||||||
? '你撤回了一条消息'
|
? '你撤回了一条消息'
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import 'package:pilipala/utils/utils.dart';
|
|||||||
class RoutePush {
|
class RoutePush {
|
||||||
// 番剧跳转
|
// 番剧跳转
|
||||||
static Future<void> bangumiPush(int? seasonId, int? epId,
|
static Future<void> bangumiPush(int? seasonId, int? epId,
|
||||||
{String? heroTag}) async {
|
{String? heroTag, int? progressIndex}) async {
|
||||||
SmartDialog.showLoading<dynamic>(msg: '获取中...');
|
SmartDialog.showLoading<dynamic>(msg: '获取中...');
|
||||||
try {
|
try {
|
||||||
var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
|
var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
|
||||||
@ -19,7 +19,10 @@ class RoutePush {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final BangumiInfoModel bangumiDetail = result['data'];
|
final BangumiInfoModel bangumiDetail = result['data'];
|
||||||
final EpisodeItem episode = bangumiDetail.episodes!.first;
|
EpisodeItem episode = bangumiDetail.episodes!.first;
|
||||||
|
if (progressIndex != null && progressIndex >= 1) {
|
||||||
|
episode = bangumiDetail.episodes![progressIndex - 1];
|
||||||
|
}
|
||||||
final int epId = episode.id!;
|
final int epId = episode.id!;
|
||||||
final int cid = episode.cid!;
|
final int cid = episode.cid!;
|
||||||
final String bvid = episode.bvid!;
|
final String bvid = episode.bvid!;
|
||||||
@ -31,7 +34,7 @@ class RoutePush {
|
|||||||
};
|
};
|
||||||
arguments['heroTag'] = heroTag ?? Utils.makeHeroTag(cid);
|
arguments['heroTag'] = heroTag ?? Utils.makeHeroTag(cid);
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
'/video?bvid=$bvid&cid=$cid&epId=$epId',
|
'/video?bvid=$bvid&cid=$cid&epId=$epId&seasonId=$seasonId',
|
||||||
arguments: arguments,
|
arguments: arguments,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user