diff --git a/lib/main.dart b/lib/main.dart index 5280f6b6..fc02657e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,7 +19,6 @@ import 'services/discord_rpc_service.dart'; import 'services/gamepad_service.dart'; import 'providers/user_profile_provider.dart'; import 'providers/multi_server_provider.dart'; -import 'providers/server_state_provider.dart'; import 'providers/theme_provider.dart'; import 'providers/settings_provider.dart'; import 'providers/hidden_libraries_provider.dart'; @@ -326,7 +325,6 @@ class _MainAppState extends State with WidgetsBindingObserver { return MultiProvider( providers: [ ChangeNotifierProvider(create: (context) => MultiServerProvider(_serverManager, _aggregationService)), - ChangeNotifierProvider(create: (context) => ServerStateProvider()), // Offline mode provider - depends on MultiServerProvider ChangeNotifierProxyProvider( create: (_) { diff --git a/lib/providers/libraries_provider.dart b/lib/providers/libraries_provider.dart index 20658d42..64ea08df 100644 --- a/lib/providers/libraries_provider.dart +++ b/lib/providers/libraries_provider.dart @@ -80,17 +80,12 @@ class LibrariesProvider extends ChangeNotifier { } } - /// Refresh libraries by clearing cache and reloading. + /// Refresh libraries by reloading from the connected servers. Future refresh() async { if (_aggregationService == null) { appLogger.w('LibrariesProvider: Cannot refresh - not initialized'); return; } - - // Clear aggregation service cache - _aggregationService!.clearCache(); - - // Reload libraries await loadLibraries(); } diff --git a/lib/providers/multi_server_provider.dart b/lib/providers/multi_server_provider.dart index 35737917..dd83ac49 100644 --- a/lib/providers/multi_server_provider.dart +++ b/lib/providers/multi_server_provider.dart @@ -87,7 +87,6 @@ class MultiServerProvider extends ChangeNotifier { /// Clear all server connections void clearAllConnections() { _serverManager.disconnectAll(); - _aggregationService.clearCache(); // Clear cached data when servers change appLogger.d('MultiServerProvider: All connections cleared'); notifyListeners(); } @@ -97,7 +96,6 @@ class MultiServerProvider extends ChangeNotifier { Future reconnectWithServers(List servers, {String? clientIdentifier}) async { // Clear existing connections first _serverManager.disconnectAll(); - _aggregationService.clearCache(); // Clear cached data when servers change appLogger.d('MultiServerProvider: Cleared connections, reconnecting to ${servers.length} servers'); // Connect with new server tokens diff --git a/lib/providers/server_state_provider.dart b/lib/providers/server_state_provider.dart deleted file mode 100644 index 59a8f74d..00000000 --- a/lib/providers/server_state_provider.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/foundation.dart'; - -/// Provider for tracking server-specific UI state -/// Manages which server is currently in context for detail views -class ServerStateProvider extends ChangeNotifier { - String? _currentServerId; - - /// Get the currently selected server ID (for detail views) - String? get currentServerId => _currentServerId; - - /// Set the current server context (e.g., when viewing a library from a specific server) - void setCurrentServer(String? serverId) { - if (_currentServerId != serverId) { - _currentServerId = serverId; - notifyListeners(); - } - } - - /// Clear the current server selection - void clearCurrentServer() { - if (_currentServerId != null) { - _currentServerId = null; - notifyListeners(); - } - } - - /// Reset all state - void reset() { - _currentServerId = null; - notifyListeners(); - } -} diff --git a/lib/providers/user_profile_provider.dart b/lib/providers/user_profile_provider.dart index eb0577d1..0f19474a 100644 --- a/lib/providers/user_profile_provider.dart +++ b/lib/providers/user_profile_provider.dart @@ -375,86 +375,6 @@ class UserProfileProvider extends ChangeNotifier { } } - /// Refresh provider for new server context - /// Call this when switching servers to ensure provider state is synchronized - Future refreshForNewServer([BuildContext? context]) async { - appLogger.d('UserProfileProvider: Refreshing for new server context'); - - _setLoading(true); - - try { - // Clear cached data from previous server (both memory and storage) - _home = null; - _currentUser = null; - _profileSettings = null; - _clearError(); - - // Re-initialize services with current storage state - _authService = await PlexAuthService.create(); - _storageService = await StorageService.getInstance(); - - // Clear storage state that's specific to the previous server context - await Future.wait([ - // Clear home users cache (server-specific) - _storageService!.clearHomeUsersCache(), - // Clear current user UUID (profile-specific, should not persist across servers) - _storageService!.clearCurrentUserUUID(), - ]); - - appLogger.d('UserProfileProvider: Cleared previous server storage state'); - - // Load fresh data for the new server (should be empty after clearing cache) - await _loadCachedData(); - - // Load from API since we cleared the cache - appLogger.d('UserProfileProvider: Loading fresh home users for new server'); - - // Store context reference before async operations to avoid build context warnings - final contextForSwitch = context; - - try { - await loadHomeUsers(); - - // After loading home users, if a current user was set (admin user), - // perform a complete profile switch to ensure tokens are properly updated - if (_currentUser != null && contextForSwitch != null) { - appLogger.d( - 'UserProfileProvider: Performing complete profile switch to ${_currentUser!.displayName} for new server', - ); - - // Perform full profile switch which includes API calls and token updates - final userToSwitchTo = _currentUser!; - // ignore: use_build_context_synchronously - context is checked via mounted guard above - final success = await switchToUser(userToSwitchTo, contextForSwitch); - - if (success) { - appLogger.d('UserProfileProvider: Successfully switched to admin user for new server'); - } else { - appLogger.w('UserProfileProvider: Failed to complete profile switch for new server'); - } - } else if (_currentUser != null && contextForSwitch == null) { - appLogger.w('UserProfileProvider: Cannot perform complete profile switch - no context provided'); - // Still try to fetch profile settings even without full switch - try { - await refreshProfileSettings(); - } catch (e) { - appLogger.w('UserProfileProvider: Failed to refresh profile settings for new server', error: e); - } - } - } catch (e) { - appLogger.w('UserProfileProvider: Failed to load home users for new server', error: e); - // Don't set error as it's not critical - } - - appLogger.d('UserProfileProvider: Refresh for new server complete'); - } catch (e) { - appLogger.e('UserProfileProvider: Failed to refresh for new server', error: e); - _setError('Failed to refresh for new server'); - } finally { - _setLoading(false); - } - } - void _setLoading(bool loading) { _isLoading = loading; notifyListeners(); diff --git a/lib/screens/discover_screen.dart b/lib/screens/discover_screen.dart index 73d6c858..13cc081c 100644 --- a/lib/screens/discover_screen.dart +++ b/lib/screens/discover_screen.dart @@ -17,7 +17,6 @@ import '../models/plex_metadata.dart'; import '../utils/content_utils.dart'; import '../models/plex_hub.dart'; import '../providers/multi_server_provider.dart'; -import '../providers/server_state_provider.dart'; import '../providers/hidden_libraries_provider.dart'; import '../providers/playback_state_provider.dart'; import 'profile/user_avatar_widget.dart'; @@ -742,14 +741,12 @@ class _DiscoverScreenState extends State // Use comprehensive logout through UserProfileProvider final userProfileProvider = Provider.of(context, listen: false); final multiServerProvider = context.read(); - final serverStateProvider = context.read(); final hiddenLibrariesProvider = context.read(); final playbackStateProvider = context.read(); // Clear all user data and provider states await userProfileProvider.logout(); multiServerProvider.clearAllConnections(); - serverStateProvider.reset(); await hiddenLibrariesProvider.refresh(); playbackStateProvider.clearShuffle(); diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index c068d779..5920293a 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -21,7 +21,6 @@ import '../widgets/overlay_sheet.dart'; import '../mixins/tab_visibility_aware.dart'; import '../navigation/navigation_tabs.dart'; import '../providers/multi_server_provider.dart'; -import '../providers/server_state_provider.dart'; import '../providers/hidden_libraries_provider.dart'; import '../providers/libraries_provider.dart'; import '../providers/playback_state_provider.dart'; @@ -826,7 +825,6 @@ class _MainScreenState extends State with RouteAware, WindowListener // Get all providers final multiServerProvider = context.read(); - final serverStateProvider = context.read(); final hiddenLibrariesProvider = context.read(); final librariesProvider = context.read(); final playbackStateProvider = context.read(); @@ -854,7 +852,6 @@ class _MainScreenState extends State with RouteAware, WindowListener } // Reset other provider states - serverStateProvider.reset(); hiddenLibrariesProvider.refresh(); playbackStateProvider.clearShuffle(); diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index e115e283..58913cee 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -2694,6 +2694,8 @@ class VideoPlayerScreenState extends State with WidgetsBindin onTogglePIPMode: _togglePIPMode, boxFitMode: _videoFilterManager?.boxFitMode ?? 0, onCycleBoxFitMode: _cycleBoxFitMode, + onCycleAudioTrack: _cycleAudioTrack, + onCycleSubtitleTrack: _cycleSubtitleTrack, onAudioTrackChanged: _onAudioTrackChanged, onSubtitleTrackChanged: _onSubtitleTrackChanged, onSecondarySubtitleTrackChanged: _onSecondarySubtitleTrackChanged, diff --git a/lib/services/data_aggregation_service.dart b/lib/services/data_aggregation_service.dart index 3e9db13d..26278d25 100644 --- a/lib/services/data_aggregation_service.dart +++ b/lib/services/data_aggregation_service.dart @@ -15,10 +15,6 @@ class DataAggregationService { DataAggregationService(this._serverManager); - /// Clear any cached data (for compatibility with existing callers) - // ignore: no-empty-block - stub, no cache to clear in current implementation - void clearCache() {} - /// Fetch libraries from all online servers /// Libraries are automatically tagged with server info by PlexClient Future> getLibrariesFromAllServers() async { diff --git a/lib/widgets/video_controls/video_controls.dart b/lib/widgets/video_controls/video_controls.dart index 992a434a..a6633085 100644 --- a/lib/widgets/video_controls/video_controls.dart +++ b/lib/widgets/video_controls/video_controls.dart @@ -69,6 +69,8 @@ Widget plexVideoControlsBuilder( VoidCallback? onTogglePIPMode, int boxFitMode = 0, VoidCallback? onCycleBoxFitMode, + VoidCallback? onCycleAudioTrack, + VoidCallback? onCycleSubtitleTrack, Function(AudioTrack)? onAudioTrackChanged, Function(SubtitleTrack)? onSubtitleTrackChanged, Function(SubtitleTrack)? onSecondarySubtitleTrackChanged, @@ -96,6 +98,8 @@ Widget plexVideoControlsBuilder( boxFitMode: boxFitMode, onTogglePIPMode: onTogglePIPMode, onCycleBoxFitMode: onCycleBoxFitMode, + onCycleAudioTrack: onCycleAudioTrack, + onCycleSubtitleTrack: onCycleSubtitleTrack, onAudioTrackChanged: onAudioTrackChanged, onSubtitleTrackChanged: onSubtitleTrackChanged, onSecondarySubtitleTrackChanged: onSecondarySubtitleTrackChanged, @@ -125,6 +129,8 @@ class PlexVideoControls extends StatefulWidget { final int boxFitMode; final VoidCallback? onTogglePIPMode; final VoidCallback? onCycleBoxFitMode; + final VoidCallback? onCycleAudioTrack; + final VoidCallback? onCycleSubtitleTrack; final Function(AudioTrack)? onAudioTrackChanged; final Function(SubtitleTrack)? onSubtitleTrackChanged; final Function(SubtitleTrack)? onSecondarySubtitleTrackChanged; @@ -179,6 +185,8 @@ class PlexVideoControls extends StatefulWidget { this.boxFitMode = 0, this.onTogglePIPMode, this.onCycleBoxFitMode, + this.onCycleAudioTrack, + this.onCycleSubtitleTrack, this.onAudioTrackChanged, this.onSubtitleTrackChanged, this.onSecondarySubtitleTrackChanged, @@ -610,11 +618,15 @@ class _PlexVideoControlsState extends State with WindowListen } } - // ignore: no-empty-block - stub for future track cycling implementation - void _nextAudioTrack() {} + void _nextAudioTrack() { + if (!widget.canControl) return; + widget.onCycleAudioTrack?.call(); + } - // ignore: no-empty-block - stub for future track cycling implementation - void _nextSubtitleTrack() {} + void _nextSubtitleTrack() { + if (!widget.canControl) return; + widget.onCycleSubtitleTrack?.call(); + } void _nextChapter() { // Go to next chapter - this would use your existing chapter navigation