opt: up panel (#861)

This commit is contained in:
My-Responsitories
2025-05-21 02:11:31 +08:00
committed by GitHub
parent f87957b170
commit acb3784071
6 changed files with 81 additions and 90 deletions

View File

@@ -71,15 +71,12 @@ class DynamicsHttp {
} }
} }
static Future followUp() async { static Future<LoadingState<FollowUpModel>> followUp() async {
var res = await Request().get(Api.followUp); var res = await Request().get(Api.followUp);
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return { return Success(FollowUpModel.fromJson(res.data['data']));
'status': true,
'data': FollowUpModel.fromJson(res.data['data']),
};
} else { } else {
return {'status': false, 'msg': res.data['message']}; return Error(res.data['message']);
} }
} }

View File

@@ -4,7 +4,7 @@ import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/follow/result.dart'; import 'package:PiliPlus/models/follow/result.dart';
class FollowHttp { class FollowHttp {
static Future followings({ static Future<LoadingState<FollowDataModel>> followings({
int? vmid, int? vmid,
int? pn, int? pn,
int? ps, int? ps,
@@ -18,12 +18,11 @@ class FollowHttp {
'order_type': orderType, 'order_type': orderType,
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return { return Success(
'status': true, FollowDataModel.fromJson(res.data['data']),
'data': FollowDataModel.fromJson(res.data['data']) );
};
} else { } else {
return {'status': false, 'msg': res.data['message']}; return Error(res.data['message']);
} }
} }

View File

@@ -38,59 +38,54 @@ class LiveUsers {
} }
} }
class LiveUserItem { sealed class UserItem {
LiveUserItem({
this.face,
this.isReserveRecall,
this.jumpUrl,
this.mid,
this.roomId,
this.title,
this.uname,
});
String? face; String? face;
bool? hasUpdate;
late int mid;
String? uname;
UserItem({
this.face,
this.hasUpdate,
int? mid,
this.uname,
}) : mid = mid ?? -1;
}
class LiveUserItem extends UserItem {
bool? isReserveRecall; bool? isReserveRecall;
String? jumpUrl; String? jumpUrl;
int? mid;
int? roomId; int? roomId;
String? title; String? title;
String? uname;
bool hasUpdate = false;
String type = 'live';
LiveUserItem.fromJson(Map<String, dynamic> json) { LiveUserItem.fromJson(Map<String, dynamic> json) {
face = json['face']; face = json['face'];
isReserveRecall = json['is_reserve_recall']; isReserveRecall = json['is_reserve_recall'];
jumpUrl = json['jump_url']; jumpUrl = json['jump_url'];
mid = json['mid']; mid = json['mid'] ?? -1;
roomId = json['room_id']; roomId = json['room_id'];
title = json['title']; title = json['title'];
uname = json['uname']; uname = json['uname'];
hasUpdate = false;
} }
} }
class UpItem { class UpItem extends UserItem {
UpItem({ UpItem({
this.face, super.face,
this.hasUpdate, super.hasUpdate,
// this.isReserveRecall, // this.isReserveRecall,
this.mid, super.mid,
this.uname, super.uname,
}); });
String? face;
bool? hasUpdate;
// bool? isReserveRecall; // bool? isReserveRecall;
int? mid;
String? uname;
String type = 'up';
UpItem.fromJson(Map<String, dynamic> json) { UpItem.fromJson(Map<String, dynamic> json) {
face = json['face']; face = json['face'];
hasUpdate = json['has_update']; hasUpdate = json['has_update'];
// isReserveRecall = json['is_reserve_recall']; // isReserveRecall = json['is_reserve_recall'];
mid = json['mid']; mid = json['mid'] ?? -1;
uname = json['uname']; uname = json['uname'];
} }
} }

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/dynamics.dart';
import 'package:PiliPlus/http/follow.dart'; import 'package:PiliPlus/http/follow.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart';
import 'package:PiliPlus/models/dynamics/up.dart'; import 'package:PiliPlus/models/dynamics/up.dart';
import 'package:PiliPlus/models/follow/result.dart'; import 'package:PiliPlus/models/follow/result.dart';
@@ -23,15 +24,12 @@ class DynamicsController extends GetxController
Rx<FollowUpModel> upData = FollowUpModel().obs; Rx<FollowUpModel> upData = FollowUpModel().obs;
// 默认获取全部动态 // 默认获取全部动态
RxInt mid = (-1).obs; RxInt mid = (-1).obs;
Rx<UpItem> upInfo = UpItem().obs;
late TabController tabController; late TabController tabController;
Set<int> tempBannedList = <int>{}; Set<int> tempBannedList = <int>{};
late List<Widget> tabsPageList; late List<Widget> tabsPageList;
RxInt initialValue = 0.obs;
RxBool isLogin = false.obs; RxBool isLogin = false.obs;
dynamic ownerMid; dynamic ownerMid;
dynamic face; dynamic face;
RxBool isLoadingDynamic = false.obs;
List<UpItem> hasUpdatedUps = <UpItem>[]; List<UpItem> hasUpdatedUps = <UpItem>[];
int allFollowedUpsPage = 1; int allFollowedUpsPage = 1;
int allFollowedUpsTotal = 0; int allFollowedUpsTotal = 0;
@@ -72,10 +70,6 @@ class DynamicsController extends GetxController
queryFollowUp(); queryFollowUp();
} }
void onSelectType(value) {
initialValue.value = value;
}
Future<void> queryFollowing2() async { Future<void> queryFollowing2() async {
if (upData.value.upList != null && if (upData.value.upList != null &&
upData.value.upList!.length >= allFollowedUpsTotal) { upData.value.upList!.length >= allFollowedUpsTotal) {
@@ -87,13 +81,12 @@ class DynamicsController extends GetxController
ps: 50, ps: 50,
orderType: 'attention', orderType: 'attention',
); );
if (res['status']) { if (res.isSuccess) {
upData.value.upList ??= <UpItem>[]; upData.value.upList ??= <UpItem>[];
upData.value.upList!.addAll( upData.value.upList!.addAll(
res['data'] res.data.list!
.list
.where((e) => hasUpdatedUps.every((e1) => e.mid != e1.mid)) .where((e) => hasUpdatedUps.every((e1) => e.mid != e1.mid))
.map<UpItem>( .map(
(FollowItemModel e) => UpItem( (FollowItemModel e) => UpItem(
face: e.face, face: e.face,
mid: e.mid, mid: e.mid,
@@ -103,10 +96,10 @@ class DynamicsController extends GetxController
), ),
); );
allFollowedUpsPage += 1; allFollowedUpsPage += 1;
allFollowedUpsTotal = res['data'].total; allFollowedUpsTotal = res.data.total!;
upData.refresh(); upData.refresh();
} else { } else {
SmartDialog.showToast(res['msg']); res.toast();
} }
} }
@@ -122,30 +115,31 @@ class DynamicsController extends GetxController
if (GStorage.setting if (GStorage.setting
.get(SettingBoxKey.dynamicsShowAllFollowedUp, defaultValue: false)) { .get(SettingBoxKey.dynamicsShowAllFollowedUp, defaultValue: false)) {
allFollowedUpsPage = 1; allFollowedUpsPage = 1;
Future f1 = DynamicsHttp.followUp(); final f1 = DynamicsHttp.followUp();
Future f2 = FollowHttp.followings( final f2 = FollowHttp.followings(
vmid: ownerMid, vmid: ownerMid,
pn: allFollowedUpsPage, pn: allFollowedUpsPage,
ps: 50, ps: 50,
orderType: 'attention', orderType: 'attention',
); );
List<dynamic> ress = await Future.wait([f1, f2]); final res0 = await f1;
if (!ress[0]['status']) { if (!res0.isSuccess) {
SmartDialog.showToast("获取关注动态失败:${ress[0]['msg']}"); SmartDialog.showToast("获取关注动态失败:$res0");
upData.value.errMsg = ress[0]['msg']; upData.value.errMsg = (res0 as Error).errMsg;
upData.refresh(); upData.refresh();
} else { } else {
upData.value.liveUsers = ress[0]['data'].liveUsers; upData.value.liveUsers = res0.data.liveUsers;
upData.refresh(); upData.refresh();
hasUpdatedUps = ress[0]['data'].upList!; hasUpdatedUps = res0.data.upList!;
} }
List<UpItem> allFollowedUps = <UpItem>[]; List<UpItem> allFollowedUps = <UpItem>[];
if (!ress[1]['status']) { final res1 = await f2;
SmartDialog.showToast("获取关注列表失败:${ress[1]['msg']}"); if (!res1.isSuccess) {
SmartDialog.showToast("获取关注列表失败:$res1");
} else { } else {
allFollowedUps = (ress[1]['data'].list as List) allFollowedUps = res1.data.list!
.where((e) => hasUpdatedUps.every((e1) => e.mid != e1.mid)) .where((e) => hasUpdatedUps.every((e1) => e.mid != e1.mid))
.map<UpItem>( .map(
(e) => UpItem( (e) => UpItem(
face: e.face, face: e.face,
mid: e.mid, mid: e.mid,
@@ -155,27 +149,27 @@ class DynamicsController extends GetxController
) )
.toList(); .toList();
allFollowedUpsPage += 1; allFollowedUpsPage += 1;
allFollowedUpsTotal = ress[1]['data'].total; allFollowedUpsTotal = res1.data.total!;
} }
upData.value.upList = hasUpdatedUps + allFollowedUps; upData.value.upList = hasUpdatedUps + allFollowedUps;
upData.refresh(); upData.refresh();
} else { } else {
var res = await DynamicsHttp.followUp(); var res = await DynamicsHttp.followUp();
if (res['status']) { if (res.isSuccess) {
upData.value = res['data']; upData.value = res.data;
if (upData.value.upList!.isEmpty) { if (upData.value.upList!.isEmpty) {
mid.value = -1; mid.value = -1;
} }
} else { } else {
upData.value.errMsg = res['msg']; upData.value.errMsg = (res as Error).errMsg;
upData.refresh(); upData.refresh();
} }
} }
isQuerying = false; isQuerying = false;
} }
void onSelectUp(mid) { void onSelectUp(int mid) {
if (this.mid == mid) { if (this.mid.value == mid) {
tabController.index = (mid == -1 ? 0 : 4); tabController.index = (mid == -1 ? 0 : 4);
if (mid == -1) { if (mid == -1) {
queryFollowUp(); queryFollowUp();

View File

@@ -123,28 +123,34 @@ class _UpPanelState extends State<UpPanel> {
); );
} }
Widget upItemBuild(theme, data) { void _onSelect(UserItem data) {
widget.dynamicsController.currentMid = data.mid;
widget.dynamicsController.onSelectUp(data.mid);
data.hasUpdate = false;
setState(() {});
}
Widget upItemBuild(ThemeData theme, UserItem data) {
bool isCurrent = widget.dynamicsController.currentMid == data.mid || bool isCurrent = widget.dynamicsController.currentMid == data.mid ||
widget.dynamicsController.currentMid == -1; widget.dynamicsController.currentMid == -1;
final isLive = data is LiveUserItem;
return SizedBox( return SizedBox(
height: 76, height: 76,
width: isTop ? 70 : null, width: isTop ? 70 : null,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
feedBack(); feedBack();
if (data.type == 'up') { switch (data) {
widget.dynamicsController.currentMid = data.mid; case UpItem():
widget.dynamicsController _onSelect(data);
..upInfo.value = data break;
..onSelectUp(data.mid); case LiveUserItem():
Get.toNamed('/liveRoom?roomid=${data.roomId}');
data.hasUpdate = false;
setState(() {});
} else if (data.type == 'live') {
Get.toNamed('/liveRoom?roomid=${data.roomId}');
} }
}, },
onDoubleTap: data is LiveUserItem ? () => _onSelect(data) : null,
onLongPress: () { onLongPress: () {
if (data.mid == -1) { if (data.mid == -1) {
return; return;
@@ -181,16 +187,16 @@ class _UpPanelState extends State<UpPanel> {
), ),
), ),
Positioned( Positioned(
top: data.type == 'live' && !isTop ? -5 : 0, top: isLive && !isTop ? -5 : 0,
right: data.type == 'live' ? -6 : 4, right: isLive ? -6 : 4,
child: Badge( child: Badge(
smallSize: 8, smallSize: 8,
label: data.type == 'live' ? const Text(' Live ') : null, label: isLive ? const Text(' Live ') : null,
textColor: theme.colorScheme.onSecondaryContainer, textColor: theme.colorScheme.onSecondaryContainer,
alignment: AlignmentDirectional.topStart, alignment: AlignmentDirectional.topStart,
isLabelVisible: data.type == 'live' || isLabelVisible: isLive ||
(data.type == 'up' && (data.hasUpdate ?? false)), (data is UpItem && (data.hasUpdate ?? false)),
backgroundColor: data.type == 'live' backgroundColor: isLive
? theme.colorScheme.secondaryContainer ? theme.colorScheme.secondaryContainer
.withValues(alpha: 0.75) .withValues(alpha: 0.75)
: theme.colorScheme.primary, : theme.colorScheme.primary,
@@ -202,7 +208,7 @@ class _UpPanelState extends State<UpPanel> {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text( child: Text(
isTop ? '${data.uname}\n' : data.uname, isTop ? '${data.uname}\n' : data.uname!,
maxLines: 2, maxLines: 2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(

View File

@@ -46,7 +46,7 @@ class HomeController extends GetxController
super.onInit(); super.onInit();
final userInfo = GStorage.userInfo.get('userInfoCache'); final userInfo = GStorage.userInfo.get('userInfoCache');
isLogin.value = userInfo != null; isLogin.value = userInfo != null;
userFace.value = userInfo != null ? userInfo.face : ''; userFace.value = userInfo != null ? userInfo.face! : '';
hideSearchBar = hideSearchBar =
GStorage.setting.get(SettingBoxKey.hideSearchBar, defaultValue: true); GStorage.setting.get(SettingBoxKey.hideSearchBar, defaultValue: true);