fix(recommend): 首屏不再兜出重试空态
This commit is contained in:
1 parent
9117bf58b8
commit
d206465ee1
3 files changed
+302
-30
No files matched your search
@@ -33,6 +33,7 @@ class HomeFeedController extends ChangeNotifier {
|
||||
String? get cursor => _state(_channel).cursor;
|
||||
bool get hasMore => _state(_channel).hasMore;
|
||||
bool get loaded => _state(_channel).loaded;
|
||||
bool get isLoading => _state(_channel).loading;
|
||||
bool get loadingMore => _state(_channel).loadingMore;
|
||||
bool get loadingFirstPage => !loaded && _state(_channel).loading;
|
||||
|
||||
|
||||
@@ -49,10 +49,16 @@ class RecommendPage extends StatefulWidget {
|
||||
|
||||
class _RecommendPageState extends State<RecommendPage>
|
||||
with AutomaticKeepAliveClientMixin<RecommendPage> {
|
||||
static const Duration _recommendRetryDelay = Duration(milliseconds: 1500);
|
||||
static const int _maxRecommendRetries = 3;
|
||||
|
||||
RecommendInnerTab _tab = RecommendInnerTab.feed;
|
||||
final PageController _pageController = PageController();
|
||||
int _scrubCancelRequest = 0;
|
||||
bool _recommendDataRefreshScheduled = false;
|
||||
bool _recommendRefreshInFlight = false;
|
||||
int _recommendRetryAttempts = 0;
|
||||
Timer? _recommendRetryTimer;
|
||||
HomeFeedChannel? _observedFeedChannel;
|
||||
|
||||
@override
|
||||
@@ -71,9 +77,13 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.feedController != widget.feedController) {
|
||||
oldWidget.feedController.removeListener(_handleFeedControllerChanged);
|
||||
_cancelRecommendRetries();
|
||||
_observedFeedChannel = widget.feedController.channel;
|
||||
widget.feedController.addListener(_handleFeedControllerChanged);
|
||||
}
|
||||
if (oldWidget.active && !widget.active) {
|
||||
_cancelRecommendRetries();
|
||||
}
|
||||
if (_requiresRecommendDataRefresh(oldWidget)) {
|
||||
_scheduleRecommendData();
|
||||
}
|
||||
@@ -88,9 +98,32 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
|
||||
void _handleFeedControllerChanged() {
|
||||
final channel = widget.feedController.channel;
|
||||
if (channel == _observedFeedChannel) return;
|
||||
_observedFeedChannel = channel;
|
||||
if (widget.active) _scheduleRecommendData();
|
||||
if (channel != _observedFeedChannel) {
|
||||
_observedFeedChannel = channel;
|
||||
_cancelRecommendRetries();
|
||||
if (widget.active) _scheduleRecommendData();
|
||||
return;
|
||||
}
|
||||
_handleRecommendFeedState();
|
||||
}
|
||||
|
||||
void _handleRecommendFeedState() {
|
||||
if (!mounted || !widget.active) return;
|
||||
final feed = widget.feedController;
|
||||
if (feed.dramas.isNotEmpty) {
|
||||
_cancelRecommendRetries();
|
||||
return;
|
||||
}
|
||||
if (feed.loaded &&
|
||||
feed.lastError == null &&
|
||||
!feed.isLoading &&
|
||||
!_recommendRefreshInFlight) {
|
||||
_cancelRecommendRetries();
|
||||
return;
|
||||
}
|
||||
if (feed.loaded && feed.lastError != null && !_recommendRefreshInFlight) {
|
||||
_scheduleRecommendRetry();
|
||||
}
|
||||
}
|
||||
|
||||
void _scheduleRecommendData() {
|
||||
@@ -100,8 +133,15 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
_recommendDataRefreshScheduled = false;
|
||||
if (!mounted || !widget.active) return;
|
||||
final feed = widget.feedController;
|
||||
if (!feed.loaded && !feed.loadingFirstPage) {
|
||||
unawaited(feed.refreshCurrent());
|
||||
if (feed.dramas.isEmpty || feed.lastError != null) {
|
||||
_recommendRetryAttempts = 0;
|
||||
if (!feed.isLoading && !_recommendRefreshInFlight) {
|
||||
if (feed.loaded) {
|
||||
_scheduleRecommendRetry();
|
||||
} else {
|
||||
unawaited(_refreshRecommendData());
|
||||
}
|
||||
}
|
||||
}
|
||||
final playlists = _readPlaylists();
|
||||
if (playlists != null && !playlists.loaded && !playlists.loading) {
|
||||
@@ -110,9 +150,51 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
});
|
||||
}
|
||||
|
||||
void _scheduleRecommendRetry() {
|
||||
if (!mounted ||
|
||||
!widget.active ||
|
||||
_recommendRefreshInFlight ||
|
||||
_recommendRetryTimer != null ||
|
||||
_recommendRetryAttempts >= _maxRecommendRetries) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_recommendRetryTimer = Timer(_recommendRetryDelay, () {
|
||||
_recommendRetryTimer = null;
|
||||
if (!mounted || !widget.active) return;
|
||||
_recommendRetryAttempts += 1;
|
||||
unawaited(_refreshRecommendData());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _refreshRecommendData() async {
|
||||
if (!mounted || !widget.active || _recommendRefreshInFlight) return;
|
||||
setState(() => _recommendRefreshInFlight = true);
|
||||
final succeeded = await widget.feedController.refreshCurrent();
|
||||
if (!mounted) return;
|
||||
_recommendRefreshInFlight = false;
|
||||
if (!widget.active) return;
|
||||
final feed = widget.feedController;
|
||||
if (succeeded || (feed.loaded && feed.lastError == null)) {
|
||||
_cancelRecommendRetries();
|
||||
setState(() {});
|
||||
return;
|
||||
}
|
||||
setState(() {});
|
||||
_scheduleRecommendRetry();
|
||||
}
|
||||
|
||||
void _cancelRecommendRetries() {
|
||||
_recommendRetryTimer?.cancel();
|
||||
_recommendRetryTimer = null;
|
||||
_recommendRetryAttempts = 0;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.feedController.removeListener(_handleFeedControllerChanged);
|
||||
_cancelRecommendRetries();
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -199,39 +281,51 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
}
|
||||
|
||||
Widget _recommendFeed(BuildContext context) {
|
||||
final feed = widget.feedController;
|
||||
final dramas = widget.feedController.dramas;
|
||||
if (dramas.isEmpty) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
if (widget.feedController.loadingFirstPage) {
|
||||
return const _RecommendFeedSkeleton();
|
||||
}
|
||||
if (dramas.isNotEmpty) {
|
||||
return PlayerPage(
|
||||
key: const Key('recommend-feed-player'),
|
||||
homeMode: true,
|
||||
embedded: true,
|
||||
active: widget.active && _tab == RecommendInnerTab.feed,
|
||||
showHomeFeedHeader: false,
|
||||
drama: dramas.first,
|
||||
initialIndex: 0,
|
||||
feedDramas: dramas,
|
||||
feedChannel: widget.feedController.channel,
|
||||
onOpenFullPlayer: (drama, episode) =>
|
||||
_openDrama(drama, episodeId: episode.id),
|
||||
onRefreshFeed: widget.feedController.refreshCurrent,
|
||||
onLoadMore: widget.feedController.loadMore,
|
||||
onImmersiveChanged: widget.onImmersiveChanged,
|
||||
scrubCancelRequest: _scrubCancelRequest,
|
||||
);
|
||||
}
|
||||
if (!feed.loaded ||
|
||||
feed.isLoading ||
|
||||
_recommendRefreshInFlight ||
|
||||
_recommendRetryTimer != null) {
|
||||
return const _RecommendFeedSkeleton();
|
||||
}
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
if (feed.lastError != null) {
|
||||
return ColoredBox(
|
||||
color: AppColors.mediaBlack,
|
||||
child: EmptyState(
|
||||
key: const Key('recommend-feed-empty'),
|
||||
icon: Icons.movie_outlined,
|
||||
title: l10n.noStories,
|
||||
actionLabel: l10n.retry,
|
||||
onAction: () => unawaited(widget.feedController.refreshCurrent()),
|
||||
icon: Icons.wifi_off_rounded,
|
||||
title: l10n.networkError,
|
||||
),
|
||||
);
|
||||
}
|
||||
return PlayerPage(
|
||||
key: const Key('recommend-feed-player'),
|
||||
homeMode: true,
|
||||
embedded: true,
|
||||
active: widget.active && _tab == RecommendInnerTab.feed,
|
||||
showHomeFeedHeader: false,
|
||||
drama: dramas.first,
|
||||
initialIndex: 0,
|
||||
feedDramas: dramas,
|
||||
feedChannel: widget.feedController.channel,
|
||||
onOpenFullPlayer: (drama, episode) =>
|
||||
_openDrama(drama, episodeId: episode.id),
|
||||
onRefreshFeed: widget.feedController.refreshCurrent,
|
||||
onLoadMore: widget.feedController.loadMore,
|
||||
onImmersiveChanged: widget.onImmersiveChanged,
|
||||
scrubCancelRequest: _scrubCancelRequest,
|
||||
return ColoredBox(
|
||||
color: AppColors.mediaBlack,
|
||||
child: EmptyState(
|
||||
key: const Key('recommend-feed-empty'),
|
||||
icon: Icons.movie_outlined,
|
||||
title: l10n.noStories,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user