diff --git a/lib/http/api.dart b/lib/http/api.dart index 110262cd7..1757f2fc7 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -214,6 +214,8 @@ class Api { // https://api.bilibili.com/x/polymer/web-dynamic/v1/portal static const String followUp = '/x/polymer/web-dynamic/v1/portal'; + static const String dynUplist = '/x/polymer/web-dynamic/v1/uplist'; + // 关注的up动态 // https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all // https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&page=1&features=itemOpusStyle diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index d3e87af0d..5226cb296 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -68,7 +68,13 @@ class DynamicsHttp { } static Future> followUp() async { - var res = await Request().get(Api.followUp); + var res = await Request().get( + Api.followUp, + queryParameters: { + 'up_list_more': 1, + 'web_location': 333.1365, + }, + ); if (res.data['code'] == 0) { return Success(FollowUpModel.fromJson(res.data['data'])); } else { @@ -76,6 +82,22 @@ class DynamicsHttp { } } + static Future> dynUpList(String? offset) async { + var res = await Request().get( + Api.dynUplist, + queryParameters: { + 'offset': offset, + 'platform': 'web', + 'web_location': 333.1365, + }, + ); + if (res.data['code'] == 0) { + return Success(DynUpList.fromJson(res.data['data'])); + } else { + return Error(res.data['message']); + } + } + // 动态点赞 // static Future likeDynamic({ // required String? dynamicId, diff --git a/lib/models/dynamics/up.dart b/lib/models/dynamics/up.dart index e176a98e3..6650cd14b 100644 --- a/lib/models/dynamics/up.dart +++ b/lib/models/dynamics/up.dart @@ -6,16 +6,34 @@ class FollowUpModel { LiveUsers? liveUsers; late List upList; + bool? hasMore; + String? offset; FollowUpModel.fromJson(Map json) { liveUsers = json['live_users'] != null ? LiveUsers.fromJson(json['live_users']) : null; upList = - (json['up_list'] as List?) + (json['up_list']?['items'] as List?) ?.map((e) => UpItem.fromJson(e)) .toList() ?? []; + hasMore = json['up_list']?['has_more']; + offset = json['up_list']?['offset']; + } +} + +class DynUpList { + List? upList; + bool? hasMore; + String? offset; + + DynUpList.fromJson(Map json) { + upList = (json['items'] as List?) + ?.map((e) => UpItem.fromJson(e)) + .toList(); + hasMore = json['has_more']; + offset = json['offset']; } } diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index f6213e9fc..1710e842f 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -55,27 +55,45 @@ class DynamicsController extends GetxController @override void onInit() { super.onInit(); - if (_showAllUp) { - scrollController.addListener(listener); - } queryFollowUp(); } - void listener() { - if (scrollController.position.pixels >= - scrollController.position.maxScrollExtent - 300) { + void onLoadMoreUp() { + if (_showAllUp) { queryAllUp(); + } else { + queryUpList(); } } - Future queryAllUp() async { - if (isQuerying) return; + Future queryUpList() async { + if (isQuerying || _upEnd) return; isQuerying = true; - if (_upEnd) { - isQuerying = false; - return; + + final res = await DynamicsHttp.dynUpList(upState.value.data.offset); + + if (res.isSuccess) { + final data = res.data; + if (data.hasMore == false || data.offset.isNullOrEmpty) { + _upEnd = true; + } + final upData = upState.value.data + ..hasMore = data.hasMore + ..offset = data.offset; + final list = data.upList; + if (list != null && list.isNotEmpty) { + upData.upList.addAll(list); + upState.refresh(); + } } + isQuerying = false; + } + + Future queryAllUp() async { + if (isQuerying || _upEnd) return; + isQuerying = true; + final res = await FollowHttp.followings( vmid: accountService.mid, pn: _upPage, @@ -110,6 +128,10 @@ class DynamicsController extends GetxController return; } + // reset + _upEnd = false; + if (_showAllUp) _upPage = 1; + final res = await Future.wait([ DynamicsHttp.followUp(), if (_showAllUp) @@ -138,6 +160,11 @@ class DynamicsController extends GetxController _cacheUpList = List.from(list); list.addAll(list1..removeWhere(list.contains)); } + if (!_showAllUp) { + if (data.hasMore == false || data.offset.isNullOrEmpty) { + _upEnd = true; + } + } upState.value = Success(data); } else { upState.value = const Error(null); @@ -201,9 +228,7 @@ class DynamicsController extends GetxController @override void onClose() { tabController.dispose(); - scrollController - ..removeListener(listener) - ..dispose(); + scrollController.dispose(); super.onClose(); } } diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index 724569ef7..0a693e338 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -61,7 +61,16 @@ class _DynamicsPageState extends State child: SizedBox( width: isTop ? null : 64, height: isTop ? 76 : null, - child: Obx(() => _buildUpPanel(_dynamicsController.upState.value)), + child: NotificationListener( + onNotification: (notification) { + final metrics = notification.metrics; + if (metrics.pixels >= metrics.maxScrollExtent - 300) { + _dynamicsController.onLoadMoreUp(); + } + return false; + }, + child: Obx(() => _buildUpPanel(_dynamicsController.upState.value)), + ), ), ); } diff --git a/lib/pages/fav_sort/view.dart b/lib/pages/fav_sort/view.dart index e790591d3..13d7cc3a4 100644 --- a/lib/pages/fav_sort/view.dart +++ b/lib/pages/fav_sort/view.dart @@ -26,43 +26,22 @@ class _FavSortPageState extends State { ); List sort = []; - final ScrollController _scrollController = ScrollController(); - - void listener() { + void onLoadMore() { if (_favDetailController.isEnd) { return; } - if (_scrollController.position.pixels >= - _scrollController.position.maxScrollExtent - 200) { - _favDetailController.onLoadMore().whenComplete(() { - try { - if (_favDetailController.loadingState.value.isSuccess) { - List list = - _favDetailController.loadingState.value.data!; - sortList.addAll(list.sublist(sortList.length)); - if (mounted) { - setState(() {}); - } + _favDetailController.onLoadMore().whenComplete(() { + try { + if (_favDetailController.loadingState.value.isSuccess) { + List list = + _favDetailController.loadingState.value.data!; + sortList.addAll(list.sublist(sortList.length)); + if (mounted) { + setState(() {}); } - } catch (_) {} - }); - } - } - - @override - void initState() { - super.initState(); - if (!_favDetailController.isEnd) { - _scrollController.addListener(listener); - } - } - - @override - void dispose() { - _scrollController - ..removeListener(listener) - ..dispose(); - super.dispose(); + } + } catch (_) {} + }); } @override @@ -119,9 +98,8 @@ class _FavSortPageState extends State { } Widget get _buildBody { - return ReorderableListView.builder( + final child = ReorderableListView.builder( key: _key, - scrollController: _scrollController, onReorder: onReorder, physics: const AlwaysScrollableScrollPhysics(), padding: @@ -137,5 +115,18 @@ class _FavSortPageState extends State { ); }, ); + if (!_favDetailController.isEnd) { + return NotificationListener( + onNotification: (notification) { + final metrics = notification.metrics; + if (metrics.pixels >= metrics.maxScrollExtent - 300) { + onLoadMore(); + } + return false; + }, + child: child, + ); + } + return child; } } diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index c3570f963..60a69971e 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -278,11 +278,10 @@ class LiveRoomController extends GetxController { } void listener() { - if (scrollController.position.userScrollDirection == - ScrollDirection.forward) { + final userScrollDirection = scrollController.position.userScrollDirection; + if (userScrollDirection == ScrollDirection.forward) { disableAutoScroll.value = true; - } else if (scrollController.position.userScrollDirection == - ScrollDirection.reverse) { + } else if (userScrollDirection == ScrollDirection.reverse) { final pos = scrollController.position; if (pos.maxScrollExtent - pos.pixels <= 100) { disableAutoScroll.value = false;