diff --git a/lib/client/plex_client.dart b/lib/client/plex_client.dart index e5a1cd27..c6773d3e 100644 --- a/lib/client/plex_client.dart +++ b/lib/client/plex_client.dart @@ -29,6 +29,8 @@ class PlexClient { connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 30), validateStatus: (status) => status != null && status < 500, + responseType: ResponseType.json, + contentType: 'application/json; charset=utf-8', ), ); @@ -77,6 +79,8 @@ class PlexClient { connectTimeout: timeout, receiveTimeout: timeout, validateStatus: (status) => status != null && status < 500, + responseType: ResponseType.json, + contentType: 'application/json; charset=utf-8', ), ); diff --git a/lib/config/plex_config.dart b/lib/config/plex_config.dart index 9ad50c69..08675587 100644 --- a/lib/config/plex_config.dart +++ b/lib/config/plex_config.dart @@ -51,6 +51,7 @@ class PlexConfig { 'X-Plex-Platform': platform, if (device != null) 'X-Plex-Device': device!, if (acceptJson) 'Accept': 'application/json', + 'Accept-Charset': 'utf-8', }; if (token != null) { diff --git a/lib/screens/libraries_screen.dart b/lib/screens/libraries_screen.dart index aa202bf8..11ee88ae 100644 --- a/lib/screens/libraries_screen.dart +++ b/lib/screens/libraries_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:dio/dio.dart'; import '../client/plex_client.dart'; import '../models/plex_library.dart'; import '../models/plex_metadata.dart'; @@ -9,10 +10,10 @@ import '../providers/plex_client_provider.dart'; import '../providers/settings_provider.dart'; import '../providers/hidden_libraries_provider.dart'; import '../utils/provider_extensions.dart'; +import '../utils/app_logger.dart'; import '../widgets/media_card.dart'; import '../widgets/desktop_app_bar.dart'; import '../widgets/app_bar_back_button.dart'; -import '../widgets/context_menu_wrapper.dart'; import '../services/storage_service.dart'; import '../services/settings_service.dart'; import '../mixins/refreshable.dart'; @@ -50,6 +51,27 @@ class _LibrariesScreenState extends State _loadLibraries(); } + /// Helper method to get user-friendly error message from exception + String _getErrorMessage(dynamic error, String context) { + if (error is DioException) { + // Other Dio errors + switch (error.type) { + case DioExceptionType.connectionTimeout: + case DioExceptionType.receiveTimeout: + return 'Connection timeout while loading $context'; + case DioExceptionType.connectionError: + return 'Unable to connect to Plex server'; + default: + appLogger.e('Error loading $context', error: error); + return 'Failed to load $context: ${error.message}'; + } + } + + // Generic error + appLogger.e('Unexpected error in $context', error: error); + return 'Failed to load $context: $error'; + } + Future _loadLibraries() async { // Extract context dependencies before async gap final clientProvider = Provider.of( @@ -122,7 +144,7 @@ class _LibrariesScreenState extends State } } catch (e) { setState(() { - _errorMessage = 'Failed to load libraries: $e'; + _errorMessage = _getErrorMessage(e, 'libraries'); _isLoadingLibraries = false; }); } @@ -255,7 +277,7 @@ class _LibrariesScreenState extends State }); } catch (e) { setState(() { - _errorMessage = 'Failed to load library content: $e'; + _errorMessage = _getErrorMessage(e, 'library content'); _isLoadingItems = false; }); } @@ -277,6 +299,7 @@ class _LibrariesScreenState extends State _filters = filters; }); } catch (e) { + appLogger.w('Failed to load filters', error: e); setState(() { _filters = []; });