优化:卡片预览的稳定性

This commit is contained in:
ivan 2026-03-30 00:15:28 +08:00
parent 2ae2c19024
commit fb4d1b78d6

View File

@ -41,6 +41,8 @@ class _HomeScreenState extends State<HomeScreen> {
/// [index] -> visibility [VisibilityInfo.visibleFraction] /// [index] -> visibility [VisibilityInfo.visibleFraction]
final Map<int, double> _cardVisibleFraction = {}; final Map<int, double> _cardVisibleFraction = {};
bool _visibilityReconcileScheduled = false; bool _visibilityReconcileScheduled = false;
/// vs
bool _visibilityHadMeaningfulReport = false;
/// IndexedStack [homePlaybackResumeNonce] [VisibilityDetector] /// IndexedStack [homePlaybackResumeNonce] [VisibilityDetector]
/// [notifyNow] Modal / pop My Gallery + /// [notifyNow] Modal / pop My Gallery +
@ -62,6 +64,17 @@ class _HomeScreenState extends State<HomeScreen> {
}); });
Future<void>.delayed(const Duration(milliseconds: 80), notify); Future<void>.delayed(const Duration(milliseconds: 80), notify);
Future<void>.delayed(const Duration(milliseconds: 220), notify); Future<void>.delayed(const Duration(milliseconds: 220), notify);
// Grid /Texture
Future<void>.delayed(const Duration(milliseconds: 450), notify);
Future<void>.delayed(const Duration(milliseconds: 720), notify);
Future<void>.delayed(const Duration(milliseconds: 950), () {
if (!mounted || !widget.isActive) return;
VisibilityDetectorController.instance.notifyNow();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted || !widget.isActive) return;
_seedFirstScreenVideoIndicesIfStillEmpty();
});
});
} }
@override @override
@ -76,6 +89,21 @@ class _HomeScreenState extends State<HomeScreen> {
if (widget.isActive) refreshAccount(); if (widget.isActive) refreshAccount();
} }
void _seedFirstScreenVideoIndicesIfStillEmpty() {
if (!mounted || !widget.isActive) return;
if (_visibleVideoIndices.isNotEmpty) return;
if (_visibilityHadMeaningfulReport) return;
final tasks = _displayTasks;
if (tasks.isEmpty) return;
final seed = <int>{};
for (var i = 0; i < tasks.length && seed.length < _maxConcurrentHomeVideos; i++) {
final u = tasks[i].previewVideoUrl;
if (u != null && u.isNotEmpty) seed.add(i);
}
if (seed.isEmpty) return;
setState(() => _visibleVideoIndices = seed);
}
@override @override
void dispose() { void dispose() {
homePlaybackResumeNonce.removeListener(_onHomePlaybackResumeSignal); homePlaybackResumeNonce.removeListener(_onHomePlaybackResumeSignal);
@ -94,6 +122,10 @@ class _HomeScreenState extends State<HomeScreen> {
void _onExtConfigChanged() { void _onExtConfigChanged() {
if (mounted) setState(() {}); if (mounted) setState(() {});
// Timer listener cancel notify
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && widget.isActive) _scheduleVisibilityRefresh();
});
} }
void _onHomeReloadNonce() { void _onHomeReloadNonce() {
@ -110,6 +142,7 @@ class _HomeScreenState extends State<HomeScreen> {
if (!mounted) return; if (!mounted) return;
if (info.visibleFraction >= _videoVisibilityThreshold) { if (info.visibleFraction >= _videoVisibilityThreshold) {
_cardVisibleFraction[index] = info.visibleFraction; _cardVisibleFraction[index] = info.visibleFraction;
_visibilityHadMeaningfulReport = true;
} else { } else {
_cardVisibleFraction.remove(index); _cardVisibleFraction.remove(index);
} }
@ -133,6 +166,16 @@ class _HomeScreenState extends State<HomeScreen> {
scored.add(MapEntry(i, e.value)); scored.add(MapEntry(i, e.value));
} }
} }
if (scored.isEmpty) {
//
if (!_visibilityHadMeaningfulReport) return;
_userPausedVideoIndices.clear();
if (!_setsEqual(_visibleVideoIndices, {})) {
setState(() => _visibleVideoIndices = {});
}
return;
}
scored.sort((a, b) => b.value.compareTo(a.value)); scored.sort((a, b) => b.value.compareTo(a.value));
final next = scored final next = scored
.take(_maxConcurrentHomeVideos) .take(_maxConcurrentHomeVideos)
@ -255,6 +298,10 @@ class _HomeScreenState extends State<HomeScreen> {
print('HomeScreen: Failed to load categories'); print('HomeScreen: Failed to load categories');
} }
setState(() => _categoriesLoading = false); setState(() => _categoriesLoading = false);
// pets [_loadTasks]
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && widget.isActive) _scheduleVisibilityRefresh();
});
} }
} }
@ -271,6 +318,7 @@ class _HomeScreenState extends State<HomeScreen> {
_userPausedVideoIndices.clear(); _userPausedVideoIndices.clear();
_visibleVideoIndices = {}; _visibleVideoIndices = {};
_cardVisibleFraction.clear(); _cardVisibleFraction.clear();
_visibilityHadMeaningfulReport = false;
}); });
} else { } else {
setState(() { setState(() {
@ -278,6 +326,7 @@ class _HomeScreenState extends State<HomeScreen> {
_userPausedVideoIndices.clear(); _userPausedVideoIndices.clear();
_visibleVideoIndices = {}; _visibleVideoIndices = {};
_cardVisibleFraction.clear(); _cardVisibleFraction.clear();
_visibilityHadMeaningfulReport = false;
}); });
} }
setState(() => _tasksLoading = false); setState(() => _tasksLoading = false);
@ -300,6 +349,7 @@ class _HomeScreenState extends State<HomeScreen> {
_userPausedVideoIndices.clear(); _userPausedVideoIndices.clear();
_visibleVideoIndices = {}; _visibleVideoIndices = {};
_cardVisibleFraction.clear(); _cardVisibleFraction.clear();
_visibilityHadMeaningfulReport = false;
}); });
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && widget.isActive) _scheduleVisibilityRefresh(); if (mounted && widget.isActive) _scheduleVisibilityRefresh();