chore: format
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
/// Shader preset types available in the app
|
||||
enum ShaderPresetType {
|
||||
none,
|
||||
nvscaler,
|
||||
anime4k,
|
||||
}
|
||||
enum ShaderPresetType { none, nvscaler, anime4k }
|
||||
|
||||
/// Quality tiers for Anime4K presets
|
||||
enum Anime4KQuality {
|
||||
@@ -40,10 +36,7 @@ class Anime4KConfig {
|
||||
final Anime4KQuality quality;
|
||||
final Anime4KMode mode;
|
||||
|
||||
const Anime4KConfig({
|
||||
required this.quality,
|
||||
required this.mode,
|
||||
});
|
||||
const Anime4KConfig({required this.quality, required this.mode});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
@@ -54,21 +47,12 @@ class Anime4KConfig {
|
||||
@override
|
||||
int get hashCode => quality.hashCode ^ mode.hashCode;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'quality': quality.name,
|
||||
'mode': mode.name,
|
||||
};
|
||||
Map<String, dynamic> toJson() => {'quality': quality.name, 'mode': mode.name};
|
||||
|
||||
factory Anime4KConfig.fromJson(Map<String, dynamic> json) {
|
||||
return Anime4KConfig(
|
||||
quality: Anime4KQuality.values.firstWhere(
|
||||
(e) => e.name == json['quality'],
|
||||
orElse: () => Anime4KQuality.fast,
|
||||
),
|
||||
mode: Anime4KMode.values.firstWhere(
|
||||
(e) => e.name == json['mode'],
|
||||
orElse: () => Anime4KMode.modeA,
|
||||
),
|
||||
quality: Anime4KQuality.values.firstWhere((e) => e.name == json['quality'], orElse: () => Anime4KQuality.fast),
|
||||
mode: Anime4KMode.values.firstWhere((e) => e.name == json['mode'], orElse: () => Anime4KMode.modeA),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -78,9 +62,7 @@ class NVScalerConfig {
|
||||
/// Whether to automatically skip NVScaler on HDR content
|
||||
final bool autoHdrSkip;
|
||||
|
||||
const NVScalerConfig({
|
||||
this.autoHdrSkip = true,
|
||||
});
|
||||
const NVScalerConfig({this.autoHdrSkip = true});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
@@ -91,14 +73,10 @@ class NVScalerConfig {
|
||||
@override
|
||||
int get hashCode => autoHdrSkip.hashCode;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'autoHdrSkip': autoHdrSkip,
|
||||
};
|
||||
Map<String, dynamic> toJson() => {'autoHdrSkip': autoHdrSkip};
|
||||
|
||||
factory NVScalerConfig.fromJson(Map<String, dynamic> json) {
|
||||
return NVScalerConfig(
|
||||
autoHdrSkip: json['autoHdrSkip'] as bool? ?? true,
|
||||
);
|
||||
return NVScalerConfig(autoHdrSkip: json['autoHdrSkip'] as bool? ?? true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,11 +97,7 @@ class ShaderPreset {
|
||||
});
|
||||
|
||||
/// No shader preset (off)
|
||||
static const none = ShaderPreset(
|
||||
id: 'none',
|
||||
name: 'Off',
|
||||
type: ShaderPresetType.none,
|
||||
);
|
||||
static const none = ShaderPreset(id: 'none', name: 'Off', type: ShaderPresetType.none);
|
||||
|
||||
/// NVScaler default preset with auto HDR skip
|
||||
static const nvscalerDefault = ShaderPreset(
|
||||
@@ -214,12 +188,12 @@ class ShaderPreset {
|
||||
int get hashCode => id.hashCode;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'type': type.name,
|
||||
if (anime4kConfig != null) 'anime4kConfig': anime4kConfig!.toJson(),
|
||||
if (nvscalerConfig != null) 'nvscalerConfig': nvscalerConfig!.toJson(),
|
||||
};
|
||||
'id': id,
|
||||
'name': name,
|
||||
'type': type.name,
|
||||
if (anime4kConfig != null) 'anime4kConfig': anime4kConfig!.toJson(),
|
||||
if (nvscalerConfig != null) 'nvscalerConfig': nvscalerConfig!.toJson(),
|
||||
};
|
||||
|
||||
factory ShaderPreset.fromJson(Map<String, dynamic> json) {
|
||||
// Try to find by ID first for built-in presets
|
||||
@@ -233,10 +207,7 @@ class ShaderPreset {
|
||||
return ShaderPreset(
|
||||
id: id ?? 'custom',
|
||||
name: json['name'] as String? ?? 'Custom',
|
||||
type: ShaderPresetType.values.firstWhere(
|
||||
(e) => e.name == json['type'],
|
||||
orElse: () => ShaderPresetType.none,
|
||||
),
|
||||
type: ShaderPresetType.values.firstWhere((e) => e.name == json['type'], orElse: () => ShaderPresetType.none),
|
||||
anime4kConfig: json['anime4kConfig'] != null ? Anime4KConfig.fromJson(json['anime4kConfig']) : null,
|
||||
nvscalerConfig: json['nvscalerConfig'] != null ? NVScalerConfig.fromJson(json['nvscalerConfig']) : null,
|
||||
);
|
||||
|
||||
@@ -1344,14 +1344,12 @@ class _LibraryManagementSheetState extends State<_LibraryManagementSheet> {
|
||||
if (targetTop >= viewportTop && targetBottom <= viewportBottom) return;
|
||||
|
||||
// Place item at ~25% from top of viewport
|
||||
final double destination = (targetTop - viewportHeight * 0.25)
|
||||
.clamp(0.0, _dialogScrollController.position.maxScrollExtent);
|
||||
|
||||
_dialogScrollController.animateTo(
|
||||
destination,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
curve: Curves.easeOut,
|
||||
final double destination = (targetTop - viewportHeight * 0.25).clamp(
|
||||
0.0,
|
||||
_dialogScrollController.position.maxScrollExtent,
|
||||
);
|
||||
|
||||
_dialogScrollController.animateTo(destination, duration: const Duration(milliseconds: 150), curve: Curves.easeOut);
|
||||
}
|
||||
|
||||
KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) {
|
||||
@@ -1576,7 +1574,10 @@ class _LibraryManagementSheetState extends State<_LibraryManagementSheet> {
|
||||
),
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
IconButton(icon: const AppIcon(Symbols.close_rounded, fill: 1), onPressed: () => Navigator.pop(context)),
|
||||
IconButton(
|
||||
icon: const AppIcon(Symbols.close_rounded, fill: 1),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Focus(
|
||||
@@ -1757,7 +1758,10 @@ class _LibraryManagementSheetState extends State<_LibraryManagementSheet> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
decoration: FocusTheme.focusBackgroundDecoration(isFocused: isVisibilityButtonFocused, borderRadius: 20),
|
||||
decoration: FocusTheme.focusBackgroundDecoration(
|
||||
isFocused: isVisibilityButtonFocused,
|
||||
borderRadius: 20,
|
||||
),
|
||||
child: IconButton(
|
||||
icon: AppIcon(isHidden ? Symbols.visibility_off_rounded : Symbols.visibility_rounded, fill: 1),
|
||||
tooltip: isHidden ? t.libraries.showLibrary : t.libraries.hideLibrary,
|
||||
|
||||
@@ -92,7 +92,10 @@ class PlaylistItemCard extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(2, 8, 6, 8),
|
||||
decoration: isDragHandleFocused
|
||||
? BoxDecoration(color: colorScheme.primaryContainer, borderRadius: BorderRadius.circular(8))
|
||||
? BoxDecoration(
|
||||
color: colorScheme.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
)
|
||||
: null,
|
||||
child: AppIcon(
|
||||
isMoving ? Symbols.swap_vert_rounded : Symbols.drag_indicator_rounded,
|
||||
|
||||
@@ -58,32 +58,24 @@ class ProfileSwitchScreen extends StatelessWidget {
|
||||
)
|
||||
else
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final user = users[index];
|
||||
final isCurrentUser = user.uuid == userProvider.currentUser?.uuid;
|
||||
final isFirstSelectable = !isCurrentUser &&
|
||||
!users.take(index).any((u) => u.uuid != userProvider.currentUser?.uuid);
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
final user = users[index];
|
||||
final isCurrentUser = user.uuid == userProvider.currentUser?.uuid;
|
||||
final isFirstSelectable =
|
||||
!isCurrentUser && !users.take(index).any((u) => u.uuid != userProvider.currentUser?.uuid);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: index == 0 ? 16 : 0,
|
||||
bottom: 8,
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, top: index == 0 ? 16 : 0, bottom: 8),
|
||||
child: Card(
|
||||
child: ProfileListTile(
|
||||
user: user,
|
||||
isCurrentUser: isCurrentUser,
|
||||
autofocus: isFirstSelectable,
|
||||
onTap: () => _switchToUser(context, user),
|
||||
),
|
||||
child: Card(
|
||||
child: ProfileListTile(
|
||||
user: user,
|
||||
isCurrentUser: isCurrentUser,
|
||||
autofocus: isFirstSelectable,
|
||||
onTap: () => _switchToUser(context, user),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: users.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
}, childCount: users.length),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -759,9 +759,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
});
|
||||
|
||||
// Find current episode in the sorted list
|
||||
final currentIdx = sorted.indexWhere(
|
||||
(ep) => ep.ratingKey == widget.metadata.ratingKey,
|
||||
);
|
||||
final currentIdx = sorted.indexWhere((ep) => ep.ratingKey == widget.metadata.ratingKey);
|
||||
|
||||
if (currentIdx == -1) return;
|
||||
|
||||
@@ -1630,7 +1628,12 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
// If player isn't available, navigate without preserving settings
|
||||
if (player == null) {
|
||||
if (mounted) {
|
||||
navigateToVideoPlayer(context, metadata: episodeMetadata, usePushReplacement: true, isOffline: widget.isOffline);
|
||||
navigateToVideoPlayer(
|
||||
context,
|
||||
metadata: episodeMetadata,
|
||||
usePushReplacement: true,
|
||||
isOffline: widget.isOffline,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1640,7 +1643,12 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
if (currentPlayer == null) {
|
||||
// Player already disposed, navigate without preserving settings
|
||||
if (mounted) {
|
||||
navigateToVideoPlayer(context, metadata: episodeMetadata, usePushReplacement: true, isOffline: widget.isOffline);
|
||||
navigateToVideoPlayer(
|
||||
context,
|
||||
metadata: episodeMetadata,
|
||||
usePushReplacement: true,
|
||||
isOffline: widget.isOffline,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1707,9 +1715,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
focusNode: _screenFocusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (node, event) => KeyEventResult.handled,
|
||||
child: _isPlayerInitialized && player != null
|
||||
? _buildVideoPlayer(context)
|
||||
: _buildLoadingSpinner(),
|
||||
child: _isPlayerInitialized && player != null ? _buildVideoPlayer(context) : _buildLoadingSpinner(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,9 +93,7 @@ class GamepadService {
|
||||
void _handleGamepadEvent(GamepadEvent event) {
|
||||
switch (event) {
|
||||
case GamepadConnectionEvent e:
|
||||
appLogger.i(
|
||||
'GamepadService: Gamepad ${e.connected ? "connected" : "disconnected"}: ${e.info.name}',
|
||||
);
|
||||
appLogger.i('GamepadService: Gamepad ${e.connected ? "connected" : "disconnected"}: ${e.info.name}');
|
||||
case GamepadButtonEvent e:
|
||||
_handleButton(e);
|
||||
case GamepadAxisEvent e:
|
||||
|
||||
@@ -95,7 +95,12 @@ Future<MediaNavigationResult> navigateToMediaItem(
|
||||
continue defaultCase;
|
||||
|
||||
case PlexMediaType.season:
|
||||
await Navigator.push(context, MaterialPageRoute(builder: (context) => SeasonDetailScreen(season: metadata, isOffline: isOffline)));
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SeasonDetailScreen(season: metadata, isOffline: isOffline),
|
||||
),
|
||||
);
|
||||
onRefresh?.call(metadata.ratingKey);
|
||||
return MediaNavigationResult.navigated;
|
||||
|
||||
|
||||
@@ -180,12 +180,7 @@ class PlexImageHelper {
|
||||
}
|
||||
|
||||
try {
|
||||
return buildTranscodeUrl(
|
||||
client: client,
|
||||
originalPath: basePath,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
return buildTranscodeUrl(client: client, originalPath: basePath, width: width, height: height);
|
||||
} catch (e) {
|
||||
// Fallback to original URL on any error
|
||||
return client.getThumbnailUrl(basePath);
|
||||
|
||||
@@ -501,10 +501,7 @@ class _VideoSettingsSheetState extends State<VideoSettingsSheet> {
|
||||
final isSelected = preset.id == currentPreset.id;
|
||||
|
||||
return FocusableListTile(
|
||||
title: Text(
|
||||
preset.name,
|
||||
style: TextStyle(color: isSelected ? Colors.amber : Colors.white),
|
||||
),
|
||||
title: Text(preset.name, style: TextStyle(color: isSelected ? Colors.amber : Colors.white)),
|
||||
subtitle: _getShaderSubtitle(preset) != null
|
||||
? Text(_getShaderSubtitle(preset)!, style: const TextStyle(color: Colors.white54, fontSize: 12))
|
||||
: null,
|
||||
@@ -530,7 +527,9 @@ class _VideoSettingsSheetState extends State<VideoSettingsSheet> {
|
||||
return t.shaders.nvscalerDescription;
|
||||
case ShaderPresetType.anime4k:
|
||||
if (preset.anime4kConfig != null) {
|
||||
final quality = preset.anime4kConfig!.quality == Anime4KQuality.fast ? t.shaders.qualityFast : t.shaders.qualityHQ;
|
||||
final quality = preset.anime4kConfig!.quality == Anime4KQuality.fast
|
||||
? t.shaders.qualityFast
|
||||
: t.shaders.qualityHQ;
|
||||
final mode = preset.modeDisplayName;
|
||||
return '$quality - ${t.shaders.mode} $mode';
|
||||
}
|
||||
@@ -551,7 +550,9 @@ class _VideoSettingsSheetState extends State<VideoSettingsSheet> {
|
||||
child: BaseVideoControlSheet(
|
||||
title: _getTitle(),
|
||||
icon: _getIcon(),
|
||||
iconColor: isIconActive ? Colors.amber : (_currentView == _SettingsView.shader && isShaderActive ? Colors.amber : Colors.white),
|
||||
iconColor: isIconActive
|
||||
? Colors.amber
|
||||
: (_currentView == _SettingsView.shader && isShaderActive ? Colors.amber : Colors.white),
|
||||
onBack: _currentView != _SettingsView.menu ? _navigateBack : null,
|
||||
child: () {
|
||||
switch (_currentView) {
|
||||
|
||||
@@ -477,7 +477,9 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
|
||||
// Currently off - restore saved preset
|
||||
final shaderProvider = context.read<ShaderProvider>();
|
||||
final saved = shaderProvider.savedPreset;
|
||||
final targetPreset = saved.isEnabled ? saved : ShaderPreset.allPresets.firstWhere((p) => p.isEnabled, orElse: () => ShaderPreset.allPresets[1]);
|
||||
final targetPreset = saved.isEnabled
|
||||
? saved
|
||||
: ShaderPreset.allPresets.firstWhere((p) => p.isEnabled, orElse: () => ShaderPreset.allPresets[1]);
|
||||
shaderService.applyPreset(targetPreset).then((_) {
|
||||
shaderProvider.setCurrentPreset(targetPreset);
|
||||
if (mounted) setState(() {});
|
||||
@@ -1702,7 +1704,9 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
|
||||
onTogglePIPMode: (_isPipSupported && Platform.isAndroid)
|
||||
? widget.onTogglePIPMode
|
||||
: null,
|
||||
onCycleBoxFitMode: widget.player.playerType != 'exoplayer' ? widget.onCycleBoxFitMode : null,
|
||||
onCycleBoxFitMode: widget.player.playerType != 'exoplayer'
|
||||
? widget.onCycleBoxFitMode
|
||||
: null,
|
||||
onToggleFullscreen: _toggleFullscreen,
|
||||
onToggleAlwaysOnTop: _toggleAlwaysOnTop,
|
||||
onSwitchVersion: _switchMediaVersion,
|
||||
|
||||
Reference in New Issue
Block a user