fix: suspend hero animation when not visible
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/// Mixin for screens that need to react to tab visibility changes.
|
||||
///
|
||||
/// Used by MainScreen to pause expensive work (e.g. animation tickers)
|
||||
/// when the screen's tab is no longer visible, and resume it when shown again.
|
||||
mixin TabVisibilityAware {
|
||||
void onTabShown();
|
||||
void onTabHidden();
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import 'profile/profile_switch_screen.dart';
|
||||
import '../providers/user_profile_provider.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../mixins/refreshable.dart';
|
||||
import '../mixins/tab_visibility_aware.dart';
|
||||
import '../i18n/strings.g.dart';
|
||||
import '../mixins/item_updatable.dart';
|
||||
import '../mixins/watch_state_aware.dart';
|
||||
@@ -53,6 +54,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
FullRefreshable,
|
||||
ItemUpdatable,
|
||||
WatchStateAware,
|
||||
TabVisibilityAware,
|
||||
SingleTickerProviderStateMixin,
|
||||
WidgetsBindingObserver {
|
||||
static const Duration _heroAutoScrollDuration = Duration(seconds: 8);
|
||||
@@ -470,6 +472,19 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
_startAutoScroll();
|
||||
}
|
||||
|
||||
@override
|
||||
void onTabHidden() {
|
||||
_autoScrollTimer?.cancel();
|
||||
_indicatorAnimationController.stop();
|
||||
}
|
||||
|
||||
@override
|
||||
void onTabShown() {
|
||||
if (!_isAutoScrollPaused) {
|
||||
_startAutoScroll();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to calculate visible dot range (max 5 dots)
|
||||
({int start, int end}) _getVisibleDotRange() {
|
||||
final totalDots = _onDeck.length;
|
||||
@@ -1277,9 +1292,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
final maxWidth = dotSize * 3; // 24px for normal, 15px for small
|
||||
final fillWidth = dotSize + ((maxWidth - dotSize) * _indicatorAnimationController.value);
|
||||
final onSurface = Theme.of(context).colorScheme.onSurface;
|
||||
return AnimatedContainer(
|
||||
duration: tokens(context).slow,
|
||||
curve: Curves.easeInOut,
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
width: maxWidth,
|
||||
height: dotSize,
|
||||
|
||||
@@ -14,6 +14,7 @@ import '../utils/platform_detector.dart';
|
||||
import '../utils/video_player_navigation.dart';
|
||||
import '../main.dart';
|
||||
import '../mixins/refreshable.dart';
|
||||
import '../mixins/tab_visibility_aware.dart';
|
||||
import '../navigation/navigation_tabs.dart';
|
||||
import '../providers/multi_server_provider.dart';
|
||||
import '../providers/server_state_provider.dart';
|
||||
@@ -495,10 +496,23 @@ class _MainScreenState extends State<MainScreen> with RouteAware, WindowListener
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPushNext() {
|
||||
// Called when a child route is pushed on top (e.g., video player)
|
||||
if (_currentIndex == 0 && !_isOffline) {
|
||||
if (_discoverKey.currentState case final TabVisibilityAware aware) {
|
||||
aware.onTabHidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPopNext() {
|
||||
// Called when returning to this route from a child route (e.g., from video player)
|
||||
if (_currentIndex == 0 && !_isOffline) {
|
||||
if (_discoverKey.currentState case final TabVisibilityAware aware) {
|
||||
aware.onTabShown();
|
||||
}
|
||||
_onDiscoverBecameVisible();
|
||||
}
|
||||
}
|
||||
@@ -593,8 +607,19 @@ class _MainScreenState extends State<MainScreen> with RouteAware, WindowListener
|
||||
|
||||
// Skip online-only screen logic in offline mode
|
||||
if (!_isOffline) {
|
||||
// Pause/resume discover auto-scroll when switching tabs
|
||||
if (previousIndex == 0 && index != 0) {
|
||||
if (_discoverKey.currentState case final TabVisibilityAware aware) {
|
||||
aware.onTabHidden();
|
||||
}
|
||||
}
|
||||
// Notify discover screen when it becomes visible via tab switch
|
||||
if (index == 0) {
|
||||
if (previousIndex != 0) {
|
||||
if (_discoverKey.currentState case final TabVisibilityAware aware) {
|
||||
aware.onTabShown();
|
||||
}
|
||||
}
|
||||
_onDiscoverBecameVisible();
|
||||
}
|
||||
// Ensure the libraries screen applies focus when brought into view
|
||||
|
||||
Reference in New Issue
Block a user