Merge branch 'main' into feature/library-reordering-6

# Conflicts:
#	lib/screens/libraries_screen.dart
#	lib/services/storage_service.dart
This commit is contained in:
edde746
2025-11-04 06:56:21 +01:00
20 changed files with 1436 additions and 104 deletions
+4 -2
View File
@@ -179,8 +179,9 @@ class PlexAuthService {
/// Switch to a different user in the home
Future<UserSwitchResponse> switchToUser(
String userUUID,
String currentToken,
) async {
String currentToken, {
String? pin,
}) async {
final queryParams = {
'includeSubscriptions': '1',
'includeProviders': '1',
@@ -193,6 +194,7 @@ class PlexAuthService {
'X-Plex-Platform-Version': '3.8.1',
'X-Plex-Token': currentToken,
'X-Plex-Language': 'en',
if (pin != null) 'pin': pin,
};
final queryString = queryParams.entries
+30
View File
@@ -5,6 +5,8 @@ import 'package:hotkey_manager/hotkey_manager.dart';
enum ThemeMode { system, light, dark }
enum LibraryDensity { compact, normal, comfortable }
class SettingsService {
static const String _keyThemeMode = 'theme_mode';
static const String _keyEnableDebugLogging = 'enable_debug_logging';
@@ -14,6 +16,8 @@ class SettingsService {
static const String _keyEnableHardwareDecoding = 'enable_hardware_decoding';
static const String _keyPreferredVideoCodec = 'preferred_video_codec';
static const String _keyPreferredAudioCodec = 'preferred_audio_codec';
static const String _keyLibraryDensity = 'library_density';
static const String _keyUseSeasonPoster = 'use_season_poster';
static SettingsService? _instance;
late SharedPreferences _prefs;
@@ -91,6 +95,28 @@ class SettingsService {
return _prefs.getString(_keyPreferredAudioCodec) ?? 'auto';
}
// Library Density
Future<void> setLibraryDensity(LibraryDensity density) async {
await _prefs.setString(_keyLibraryDensity, density.name);
}
LibraryDensity getLibraryDensity() {
final densityString = _prefs.getString(_keyLibraryDensity);
return LibraryDensity.values.firstWhere(
(density) => density.name == densityString,
orElse: () => LibraryDensity.normal,
);
}
// Use Season Poster
Future<void> setUseSeasonPoster(bool enabled) async {
await _prefs.setBool(_keyUseSeasonPoster, enabled);
}
bool getUseSeasonPoster() {
return _prefs.getBool(_keyUseSeasonPoster) ?? false; // Default: false (use series poster)
}
// Keyboard Shortcuts (Legacy String-based)
Map<String, String> getDefaultKeyboardShortcuts() {
return {
@@ -553,6 +579,8 @@ class SettingsService {
_prefs.remove(_keyEnableHardwareDecoding),
_prefs.remove(_keyPreferredVideoCodec),
_prefs.remove(_keyPreferredAudioCodec),
_prefs.remove(_keyLibraryDensity),
_prefs.remove(_keyUseSeasonPoster),
]);
}
@@ -575,6 +603,8 @@ class SettingsService {
'enableHardwareDecoding': getEnableHardwareDecoding(),
'preferredVideoCodec': getPreferredVideoCodec(),
'preferredAudioCodec': getPreferredAudioCodec(),
'libraryDensity': getLibraryDensity().name,
'useSeasonPoster': getUseSeasonPoster(),
'keyboardShortcuts': getKeyboardShortcuts(),
'keyboardHotkeys': hotkeys.map(
(key, value) => MapEntry(key, _serializeHotKey(value)),
+47 -1
View File
@@ -8,12 +8,14 @@ class StorageService {
static const String _keyServerData = 'server_data';
static const String _keyClientId = 'client_identifier';
static const String _keySelectedLibraryIndex = 'selected_library_index';
static const String _keySelectedLibraryKey = 'selected_library_key';
static const String _keyLibraryFilters = 'library_filters';
static const String _keyLibraryOrder = 'library_order';
static const String _keyUserProfile = 'user_profile';
static const String _keyCurrentUserUUID = 'current_user_uuid';
static const String _keyHomeUsersCache = 'home_users_cache';
static const String _keyHomeUsersCacheExpiry = 'home_users_cache_expiry';
static const String _keyHiddenLibraries = 'hidden_libraries';
static StorageService? _instance;
late SharedPreferences _prefs;
@@ -136,7 +138,7 @@ class StorageService {
};
}
// Selected Library Index
// Selected Library Index (deprecated - use library key instead)
Future<void> saveSelectedLibraryIndex(int index) async {
await _prefs.setInt(_keySelectedLibraryIndex, index);
}
@@ -145,6 +147,15 @@ class StorageService {
return _prefs.getInt(_keySelectedLibraryIndex);
}
// Selected Library Key (replaces index-based selection)
Future<void> saveSelectedLibraryKey(String key) async {
await _prefs.setString(_keySelectedLibraryKey, key);
}
String? getSelectedLibraryKey() {
return _prefs.getString(_keySelectedLibraryKey);
}
// Library Filters (stored as JSON string)
Future<void> saveLibraryFilters(Map<String, String> filters) async {
final jsonString = json.encode(filters);
@@ -163,13 +174,48 @@ class StorageService {
}
}
// Library Sort (per-library, stored individually)
Future<void> saveLibrarySort(String sectionId, String sortKey) async {
await _prefs.setString('library_sort_$sectionId', sortKey);
}
String getLibrarySort(String sectionId) {
// Return saved sort or default to titleSort (alphabetical)
return _prefs.getString('library_sort_$sectionId') ?? 'titleSort';
}
// Hidden Libraries (stored as JSON array of library section IDs)
Future<void> saveHiddenLibraries(Set<String> libraryKeys) async {
final list = libraryKeys.toList();
final jsonString = json.encode(list);
await _prefs.setString(_keyHiddenLibraries, jsonString);
}
Set<String> getHiddenLibraries() {
final jsonString = _prefs.getString(_keyHiddenLibraries);
if (jsonString == null) return {};
try {
final list = json.decode(jsonString) as List<dynamic>;
return list.map((e) => e.toString()).toSet();
} catch (e) {
return {};
}
}
// Clear library preferences
Future<void> clearLibraryPreferences() async {
await Future.wait([
_prefs.remove(_keySelectedLibraryIndex),
_prefs.remove(_keyLibraryFilters),
_prefs.remove(_keyLibraryOrder),
_prefs.remove(_keyHiddenLibraries),
]);
// Also clear all library sort preferences
final keys = _prefs.getKeys();
final sortKeys = keys.where((key) => key.startsWith('library_sort_'));
await Future.wait(sortKeys.map((key) => _prefs.remove(key)));
}
// Library Order (stored as JSON list of library keys)