refa: member fav

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-12-03 12:52:23 +08:00
parent 9c8e5b53e7
commit b7a277a57c
3 changed files with 255 additions and 137 deletions

View File

@@ -11,21 +11,37 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class MemberFavoriteCtr
extends CommonDataController<List<SpaceFavData>?, dynamic> {
extends CommonDataController<List<SpaceFavData>?, List<SpaceFavData>?> {
MemberFavoriteCtr({
required this.mid,
});
final int mid;
Rx<SpaceFavData> first = SpaceFavData().obs;
Rx<SpaceFavData> second = SpaceFavData().obs;
late int favPage = 2;
bool _favExpand = true;
final RxBool favEnd = true.obs;
final Rx<SpaceFavData> favState = SpaceFavData().obs;
RxBool firstEnd = true.obs;
RxBool secondEnd = true.obs;
late int subPage = 2;
bool _subExpand = true;
final RxBool subEnd = true.obs;
final Rx<SpaceFavData> subState = SpaceFavData().obs;
late int page = 2;
late int page1 = 2;
bool isExpand(bool isFav) {
return isFav ? _favExpand : _subExpand;
}
void setExpand(bool isFav) {
if (isFav) {
flag = _favExpand;
_favExpand = !_favExpand;
} else {
_subExpand = !_subExpand;
}
}
bool flag = false;
@override
void onInit() {
@@ -35,8 +51,8 @@ class MemberFavoriteCtr
@override
Future<void> onRefresh() {
page = 2;
page1 = 2;
favPage = 2;
subPage = 2;
return super.onRefresh();
}
@@ -47,13 +63,13 @@ class MemberFavoriteCtr
) {
try {
List<SpaceFavData> res = response.response!;
first.value = res.first;
second.value = res[1];
favState.value = res.first;
subState.value = res[1];
firstEnd.value =
favEnd.value =
(res.first.mediaListResponse?.count ?? -1) <=
(res.first.mediaListResponse?.list?.length ?? -1);
secondEnd.value =
subEnd.value =
(res[1].mediaListResponse?.count ?? -1) <=
(res[1].mediaListResponse?.list?.length ?? -1);
} catch (e) {
@@ -63,62 +79,76 @@ class MemberFavoriteCtr
return true;
}
Future<void> userfavFolder() async {
var res = await Request().get(
Api.userFavFolder,
queryParameters: {
'pn': page,
'ps': 20,
'up_mid': mid,
},
);
if (res.data['code'] == 0) {
page++;
firstEnd.value = res.data['data']['has_more'] == false;
if (res.data['data'] != null) {
List<SpaceFavItemModel> list =
(res.data['data']?['list'] as List<dynamic>?)
?.map((item) => SpaceFavItemModel.fromJson(item))
.toList() ??
<SpaceFavItemModel>[];
first
..value.mediaListResponse?.list?.addAll(list)
..refresh();
Future<void> userFavFolder() async {
try {
final res = await Request().get(
Api.userFavFolder,
queryParameters: {
'pn': favPage,
'ps': 20,
'up_mid': mid,
},
);
if (res.data['code'] == 0) {
favPage++;
final data = res.data['data'];
if (data != null) {
favEnd.value = data['has_more'] == false;
final list = (data['list'] as List<dynamic>?)
?.map((item) => SpaceFavItemModel.fromJson(item))
.toList();
if (list != null && list.isNotEmpty) {
favState
..value.mediaListResponse!.list!.addAll(list)
..refresh();
} else {
favEnd.value = true;
}
} else {
favEnd.value = true;
}
} else {
firstEnd.value = true;
SmartDialog.showToast(res.data['message']);
}
} else {
SmartDialog.showToast(res.data['message'] ?? '账号未登录');
} catch (e) {
SmartDialog.showToast(e.toString());
}
}
Future<void> userSubFolder() async {
var res = await Request().get(
Api.userSubFolder,
queryParameters: {
'up_mid': mid,
'ps': 20,
'pn': page1,
'platform': 'web',
},
);
if (res.data['code'] == 0) {
page++;
secondEnd.value = res.data['data']['has_more'] == false;
if (res.data['data'] != null) {
List<SpaceFavItemModel> list =
(res.data['data']?['list'] as List<dynamic>?)
?.map((item) => SpaceFavItemModel.fromJson(item))
.toList() ??
<SpaceFavItemModel>[];
second
..value.mediaListResponse?.list?.addAll(list)
..refresh();
try {
final res = await Request().get(
Api.userSubFolder,
queryParameters: {
'up_mid': mid,
'ps': 20,
'pn': subPage,
'platform': 'web',
},
);
if (res.data['code'] == 0) {
subPage++;
final data = res.data['data'];
if (data != null) {
subEnd.value = data['has_more'] == false;
final list = (data['list'] as List<dynamic>?)
?.map((item) => SpaceFavItemModel.fromJson(item))
.toList();
if (list != null && list.isNotEmpty) {
subState
..value.mediaListResponse!.list!.addAll(list)
..refresh();
} else {
subEnd.value = true;
}
} else {
subEnd.value = true;
}
} else {
secondEnd.value = true;
SmartDialog.showToast(res.data['message']);
}
} else {
SmartDialog.showToast(res.data['message'] ?? '账号未登录');
} catch (e) {
SmartDialog.showToast(e.toString());
}
}

View File

@@ -1,4 +1,5 @@
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart';
@@ -40,7 +41,7 @@ class _MemberFavoriteState extends State<MemberFavorite>
return refreshIndicator(
onRefresh: _controller.onRefresh,
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
physics: _FavScrollPhysics(controller: _controller),
slivers: [
SliverPadding(
padding: EdgeInsets.only(
@@ -55,7 +56,10 @@ class _MemberFavoriteState extends State<MemberFavorite>
);
}
Widget _buildBody(ThemeData theme, LoadingState loadingState) {
Widget _buildBody(
ThemeData theme,
LoadingState<List<SpaceFavData>?> loadingState,
) {
return switch (loadingState) {
Loading() => SliverPadding(
padding: const EdgeInsets.only(top: 7),
@@ -65,19 +69,21 @@ class _MemberFavoriteState extends State<MemberFavorite>
itemCount: 10,
),
),
Success(:var response) =>
(response as List?)?.isNotEmpty == true
Success(:final response) =>
response?.isNotEmpty == true
? SliverMainAxisGroup(
slivers: [
SliverToBoxAdapter(
child: Obx(
() => _buildItem(theme, _controller.first.value, true),
),
_buildItem(
theme,
data: _controller.favState,
isEnd: _controller.favEnd,
isFav: true,
),
SliverToBoxAdapter(
child: Obx(
() => _buildItem(theme, _controller.second.value, false),
),
_buildItem(
theme,
data: _controller.subState,
isEnd: _controller.subEnd,
isFav: false,
),
],
)
@@ -89,78 +95,159 @@ class _MemberFavoriteState extends State<MemberFavorite>
};
}
Theme _buildItem(ThemeData theme, SpaceFavData data, bool isFirst) {
return Theme(
data: theme.copyWith(
dividerColor: Colors.transparent,
),
child: ExpansionTile(
dense: true,
initiallyExpanded: true,
title: Text.rich(
TextSpan(
children: [
TextSpan(
text: data.name,
style: const TextStyle(fontSize: 14),
),
TextSpan(
text: ' ${data.mediaListResponse?.count}',
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.outline,
),
),
],
),
),
controlAffinity: ListTileControlAffinity.leading,
children: [
...?data.mediaListResponse?.list?.map(
(item) => SizedBox(
height: 98,
child: MemberFavItem(
item: item,
callback: (res) {
if (res == true) {
_controller
..first.value.mediaListResponse?.list?.remove(item)
..first.refresh();
}
Widget _buildItem(
ThemeData theme, {
required Rx<SpaceFavData> data,
required RxBool isEnd,
required bool isFav,
}) {
return SliverMainAxisGroup(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: CustomSliverPersistentHeaderDelegate(
child: Material(
color: theme.colorScheme.surface,
child: Builder(
builder: (context) {
return InkWell(
onTap: () {
_controller.setExpand(isFav);
(context as Element).markNeedsBuild();
data.refresh();
},
child: Container(
height: 45,
alignment: .centerLeft,
padding: const .only(left: 12),
child: Text.rich(
TextSpan(
children: [
WidgetSpan(
alignment: .middle,
child: Icon(
_controller.isExpand(isFav)
? Icons.expand_less
: Icons.expand_more,
color: theme.colorScheme.outline,
),
),
TextSpan(
text: ' ${data.value.name}',
style: const TextStyle(fontSize: 14),
),
TextSpan(
text: ' ${data.value.mediaListResponse?.count}',
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.outline,
),
),
],
),
),
),
);
},
),
),
bgColor: null,
),
Obx(
() =>
(isFirst
? _controller.firstEnd.value
: _controller.secondEnd.value)
? const SizedBox.shrink()
: _buildLoadMoreItem(theme, isFirst),
),
],
),
),
Obx(() {
final list = data.value.mediaListResponse?.list;
if (!_controller.isExpand(isFav)) {
return const SliverToBoxAdapter();
}
final end = isEnd.value;
if (list != null && list.isNotEmpty) {
return SliverList.builder(
itemCount: list.length + (end ? 0 : 1),
itemBuilder: (context, index) {
if (!end && index == list.length) {
return Obx(
() => isEnd.value
? const SizedBox.shrink()
: _buildLoadMoreItem(theme, isFav),
);
}
final item = list[index];
return SizedBox(
height: 98,
child: MemberFavItem(
item: item,
callback: (res) {
if (res == true) {
_controller.favState
..value.mediaListResponse?.list?.remove(item)
..refresh();
}
},
),
);
},
);
}
return const SliverToBoxAdapter();
}),
],
);
}
ListTile _buildLoadMoreItem(ThemeData theme, bool isFirst) {
return ListTile(
dense: true,
onTap: () {
if (isFirst) {
_controller.userfavFolder();
} else {
_controller.userSubFolder();
}
},
title: Text(
'查看更多内容',
textAlign: TextAlign.center,
style: TextStyle(
color: theme.colorScheme.primary,
Widget _buildLoadMoreItem(ThemeData theme, bool isFav) {
return Padding(
padding: const .only(top: 7),
child: InkWell(
onTap: () {
if (isFav) {
_controller.userFavFolder();
} else {
_controller.userSubFolder();
}
},
child: Container(
height: 40,
alignment: .center,
child: Text(
'查看更多内容',
textAlign: TextAlign.center,
style: TextStyle(color: theme.colorScheme.primary),
),
),
),
);
}
}
class _FavScrollPhysics extends AlwaysScrollableScrollPhysics {
const _FavScrollPhysics({super.parent, required this.controller});
final MemberFavoriteCtr controller;
@override
_FavScrollPhysics applyTo(ScrollPhysics? ancestor) {
return _FavScrollPhysics(
parent: buildParent(ancestor),
controller: controller,
);
}
@override
double adjustPositionForNewDimensions({
required ScrollMetrics oldPosition,
required ScrollMetrics newPosition,
required bool isScrolling,
required double velocity,
}) {
if (controller.flag) {
controller.flag = false;
return 0;
}
return super.adjustPositionForNewDimensions(
oldPosition: oldPosition,
newPosition: newPosition,
isScrolling: isScrolling,
velocity: velocity,
);
}
}