From 04438c8e45b7b4cbfb649d7e8ab708ab5871a457 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sun, 15 Feb 2026 03:14:04 +0100 Subject: [PATCH] refactor: code quality & format --- analysis_options.yaml | 56 ++- lib/database/app_database.dart | 9 +- lib/focus/focusable_chip_mixin.dart | 2 +- lib/focus/input_mode_tracker.dart | 4 +- lib/main.dart | 4 +- lib/mixins/tab_navigation_mixin.dart | 1 + .../recent_remote_session.dart | 2 +- .../companion_remote/remote_command.dart | 5 +- lib/models/external_player_models.dart | 6 +- lib/models/livetv_dvr.dart | 7 +- lib/models/livetv_hub_result.dart | 6 +- lib/models/livetv_program.dart | 8 +- lib/models/livetv_subscription.dart | 8 +- lib/models/plex_file_info.dart | 6 +- lib/models/plex_media_version.dart | 2 +- lib/models/shader_preset.dart | 6 +- lib/mpv/player/player_android.dart | 2 +- lib/mpv/player/player_base.dart | 38 +- lib/mpv/player/player_native.dart | 3 +- lib/mpv/player/video_rect_support.dart | 4 +- lib/mpv/video.dart | 2 +- lib/providers/companion_remote_provider.dart | 18 +- lib/providers/multi_server_provider.dart | 6 +- lib/providers/playback_state_provider.dart | 16 +- lib/providers/user_profile_provider.dart | 6 +- lib/screens/auth_screen.dart | 7 + lib/screens/collection_detail_screen.dart | 2 +- .../mobile_remote_screen.dart | 86 ++-- .../companion_remote/pairing_screen.dart | 50 ++- lib/screens/discover_screen.dart | 120 +++--- .../focusable_detail_screen_mixin.dart | 9 +- lib/screens/hub_detail_screen.dart | 5 + .../libraries/filters_bottom_sheet.dart | 2 + lib/screens/libraries/folder_tree_item.dart | 7 +- lib/screens/libraries/libraries_screen.dart | 73 ++-- .../libraries/tabs/base_library_tab.dart | 13 +- .../libraries/tabs/library_browse_tab.dart | 17 +- .../libraries/tabs/library_playlists_tab.dart | 2 +- .../tabs/library_recommended_tab.dart | 4 +- lib/screens/livetv/dvr_recordings_screen.dart | 45 ++- lib/screens/livetv/live_tv_screen.dart | 155 ++++---- .../livetv/live_tv_show_schedule_screen.dart | 10 +- lib/screens/livetv/program_details_sheet.dart | 7 +- lib/screens/livetv/tabs/guide_tab.dart | 241 +++++------- lib/screens/livetv/tabs/whats_on_tab.dart | 43 +- lib/screens/main_screen.dart | 26 +- lib/screens/media_detail_screen.dart | 150 +++---- .../playlist/playlist_detail_screen.dart | 8 +- lib/screens/playlist/playlist_item_card.dart | 14 +- lib/screens/profile/pin_entry_dialog.dart | 31 +- lib/screens/profile/profile_list_tile.dart | 41 +- .../profile/profile_switch_screen.dart | 1 + lib/screens/profile/user_avatar_widget.dart | 22 +- lib/screens/search_screen.dart | 12 +- lib/screens/season_detail_screen.dart | 58 +-- lib/screens/settings/about_screen.dart | 1 + .../settings/external_player_screen.dart | 89 +++-- .../settings/hotkey_recorder_widget.dart | 4 +- lib/screens/settings/logs_screen.dart | 6 +- lib/screens/settings/mpv_config_screen.dart | 8 +- lib/screens/settings/settings_screen.dart | 14 +- .../settings/subtitle_styling_screen.dart | 11 +- lib/screens/video_player_screen.dart | 86 ++-- .../companion_remote_peer_service.dart | 10 +- .../companion_remote_receiver.dart | 2 +- lib/services/data_aggregation_service.dart | 24 +- lib/services/download_manager_service.dart | 39 +- lib/services/download_storage_service.dart | 6 +- lib/services/episode_navigation_service.dart | 7 +- lib/services/external_player_service.dart | 5 +- lib/services/in_app_review_service.dart | 3 +- lib/services/macos_window_delegate.dart | 4 + lib/services/multi_server_manager.dart | 9 +- lib/services/offline_watch_sync_service.dart | 58 +-- lib/services/play_queue_launcher.dart | 2 +- lib/services/plex_client.dart | 371 +++++++++--------- lib/services/server_registry.dart | 2 +- lib/services/settings_service.dart | 4 +- lib/services/storage_service.dart | 2 +- lib/services/track_selection_service.dart | 14 +- lib/services/update_service.dart | 7 +- lib/services/watch_next_service.dart | 2 +- lib/theme/mono_theme.dart | 59 +-- lib/utils/desktop_window_padding.dart | 22 +- lib/utils/dialogs.dart | 2 +- lib/utils/formatters.dart | 20 +- lib/utils/layout_constants.dart | 2 +- lib/utils/library_refresh_notifier.dart | 4 +- lib/utils/live_tv_player_navigation.dart | 11 +- lib/utils/player_utils.dart | 9 +- lib/utils/plex_cache_parser.dart | 2 +- lib/utils/sliver_adaptive_media_builder.dart | 52 ++- lib/utils/smart_deletion_handler.dart | 2 +- lib/utils/video_player_navigation.dart | 6 +- lib/utils/watch_state_notifier.dart | 2 +- lib/watch_together/models/sync_message.dart | 6 +- .../providers/watch_together_provider.dart | 15 +- .../screens/watch_together_screen.dart | 4 +- .../services/watch_together_sync_manager.dart | 4 +- .../widgets/watch_together_overlay.dart | 33 +- lib/widgets/alpha_jump_bar.dart | 39 +- lib/widgets/alpha_scroll_handle.dart | 20 +- lib/widgets/collapsible_text.dart | 2 +- .../remote_session_dialog.dart | 42 +- lib/widgets/download_tree_view.dart | 6 +- lib/widgets/focus_builders.dart | 1 - lib/widgets/focusable_filter_chip.dart | 1 - lib/widgets/focusable_tab_chip.dart | 1 - lib/widgets/hotkey_recorder.dart | 9 +- lib/widgets/hub_section.dart | 39 +- lib/widgets/media_context_menu.dart | 97 +++-- lib/widgets/media_grid_sliver.dart | 2 +- lib/widgets/placeholder_container.dart | 4 +- lib/widgets/plex_optimized_image.dart | 4 +- lib/widgets/side_navigation_rail.dart | 197 +++++----- lib/widgets/tv_color_picker.dart | 18 +- lib/widgets/tv_number_spinner.dart | 14 +- .../desktop_video_controls.dart | 32 +- .../video_controls/mobile_video_controls.dart | 11 +- .../video_controls/sheets/chapter_sheet.dart | 12 +- .../sheets/track_selection_sheet.dart | 124 +++--- .../sheets/video_settings_sheet.dart | 16 +- .../video_controls/video_controls.dart | 277 +++++++------ .../performance_overlay.dart | 2 +- .../performance_stats_service.dart | 2 +- .../widgets/sync_offset_control.dart | 6 +- .../widgets/timeline_slider.dart | 13 +- .../widgets/track_chapter_controls.dart | 2 +- .../widgets/video_timeline_bar.dart | 8 +- .../widgets/volume_control.dart | 9 +- 130 files changed, 1840 insertions(+), 1703 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 3de9f1c9..f6b14e01 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -8,8 +8,62 @@ analyzer: - dart_code_linter dart_code_linter: + extends: + - package:dart_code_linter/presets/recommended.yaml + rules: - - avoid-unused-parameters + # --- Flutter rules (on top of recommended) --- + - avoid-border-all + - avoid-shrink-wrap-in-lists + - avoid-expanded-as-spacer + - avoid-wrapping-in-padding + - prefer-const-border-radius + - prefer-correct-edge-insets-constructor + - prefer-define-hero-tag + - use-setstate-synchronously + + # --- Additional useful Dart rules --- + - avoid-cascade-after-if-null + - avoid-collection-methods-with-unrelated-types + - avoid-unnecessary-type-assertions + - avoid-unrelated-type-assertions + - double-literal-format + - prefer-first + - prefer-last + - prefer-enums-by-name + - prefer-commenting-analyzer-ignores + + # --- Disable noisy rules from recommended preset --- + - no-magic-number: false + - avoid-dynamic: false + - format-comment: false + - newline-before-return: false + - prefer-moving-to-variable: false + - member-ordering: false + - prefer-extracting-callbacks: false + - avoid-returning-widgets: false + - no-equal-arguments: false + - avoid-passing-async-when-sync-expected: false + - avoid-redundant-async: false + - no-empty-block: false + - prefer-trailing-comma: false + - avoid-non-null-assertion: false + - prefer-conditional-expressions: false + + metrics: + cyclomatic-complexity: 70 + halstead-volume: 16000 + maintainability-index: 8 + maximum-nesting-level: 7 + number-of-parameters: 25 + number-of-methods: 150 + source-lines-of-code: 500 + + anti-patterns: + - long-method: + lines-of-code: 500 + - long-parameter-list: + number-of-parameters: 25 formatter: page_width: 120 diff --git a/lib/database/app_database.dart b/lib/database/app_database.dart index ed635ff1..e97610d5 100644 --- a/lib/database/app_database.dart +++ b/lib/database/app_database.dart @@ -200,12 +200,9 @@ class AppDatabase extends _$AppDatabase { LazyDatabase _openConnection() { return LazyDatabase(() async { - final Directory dbFolder; - if (Platform.isAndroid || Platform.isIOS) { - dbFolder = await getApplicationDocumentsDirectory(); - } else { - dbFolder = await getApplicationSupportDirectory(); - } + final dbFolder = (Platform.isAndroid || Platform.isIOS) + ? await getApplicationDocumentsDirectory() + : await getApplicationSupportDirectory(); final file = File(p.join(dbFolder.path, 'plezy_downloads.db')); diff --git a/lib/focus/focusable_chip_mixin.dart b/lib/focus/focusable_chip_mixin.dart index 0cbbff85..f28e0a86 100644 --- a/lib/focus/focusable_chip_mixin.dart +++ b/lib/focus/focusable_chip_mixin.dart @@ -102,7 +102,7 @@ mixin FocusableChipStateMixin on State { /// /// Returns [KeyEventResult.handled] if the event was consumed, /// [KeyEventResult.ignored] otherwise. - KeyEventResult handleChipKeyEvent(FocusNode node, KeyEvent event, ChipKeyCallbacks callbacks) { + KeyEventResult handleChipKeyEvent(FocusNode _, KeyEvent event, ChipKeyCallbacks callbacks) { final key = event.logicalKey; if (callbacks.onBack != null) { diff --git a/lib/focus/input_mode_tracker.dart b/lib/focus/input_mode_tracker.dart index c1752ae9..fe57c942 100644 --- a/lib/focus/input_mode_tracker.dart +++ b/lib/focus/input_mode_tracker.dart @@ -119,9 +119,7 @@ class _InputModeTrackerState extends State { onPointerHover: (_) => _setMode(InputMode.pointer), behavior: HitTestBehavior.translucent, child: MouseRegion( - cursor: _mode == InputMode.keyboard - ? SystemMouseCursors.none - : MouseCursor.defer, + cursor: _mode == InputMode.keyboard ? SystemMouseCursors.none : MouseCursor.defer, child: IgnorePointer( ignoring: _mode == InputMode.keyboard, child: _InputModeProvider(mode: _mode, child: widget.child), diff --git a/lib/main.dart b/lib/main.dart index 8dadf4f9..3a92545c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -90,7 +90,7 @@ void main() async { // Initialize TV detection and PiP service for Android if (Platform.isAndroid) { - futures.add(TvDetectionService.getInstance().then((_) {})); + futures.add(TvDetectionService.getInstance()); // Initialize PiP service to listen for PiP state changes PipService(); } @@ -99,7 +99,7 @@ void main() async { futures.add(MacOSTitlebarService.setupCustomTitlebar()); // Initialize storage service - futures.add(StorageService.getInstance().then((_) {})); + futures.add(StorageService.getInstance()); // Initialize language codes for track selection futures.add(LanguageCodes.initialize()); diff --git a/lib/mixins/tab_navigation_mixin.dart b/lib/mixins/tab_navigation_mixin.dart index 59df4516..555dfe66 100644 --- a/lib/mixins/tab_navigation_mixin.dart +++ b/lib/mixins/tab_navigation_mixin.dart @@ -65,6 +65,7 @@ mixin TabNavigationMixin on State, SingleTickerProv /// Called when the tab index changes. Override to add custom behaviour /// (e.g. persisting the tab index), then call `super.onTabChanged()`. void onTabChanged() { + // ignore: no-empty-block - setState triggers rebuild to reflect new tab setState(() {}); } diff --git a/lib/models/companion_remote/recent_remote_session.dart b/lib/models/companion_remote/recent_remote_session.dart index 18a72877..43e0ecc9 100644 --- a/lib/models/companion_remote/recent_remote_session.dart +++ b/lib/models/companion_remote/recent_remote_session.dart @@ -32,7 +32,7 @@ class RecentRemoteSession { throw FormatException('Invalid QR code format - expected ip|port|sessionId|pin'); } - final ip = parts[0]; + final ip = parts.first; final port = parts[1]; final sessionId = parts[2]; final pin = parts[3]; diff --git a/lib/models/companion_remote/remote_command.dart b/lib/models/companion_remote/remote_command.dart index d301da2c..233c63fd 100644 --- a/lib/models/companion_remote/remote_command.dart +++ b/lib/models/companion_remote/remote_command.dart @@ -15,10 +15,7 @@ class RemoteCommand { } Map toJson() { - return { - 't': type.index, - if (data != null) 'd': data, - }; + return {'t': type.index, if (data != null) 'd': data}; } @override diff --git a/lib/models/external_player_models.dart b/lib/models/external_player_models.dart index 9d6f59d9..c2ae6a9f 100644 --- a/lib/models/external_player_models.dart +++ b/lib/models/external_player_models.dart @@ -81,7 +81,7 @@ class ExternalPlayer { // --- Launch helpers --- -Future _launchWithUrl(String url) async { +Future _launchWithUrl(String url) { return launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); } @@ -158,7 +158,7 @@ class KnownPlayers { name: 'VLC', iconAsset: 'assets/player_icons/vlc.svg', isAvailable: Platform.isAndroid || Platform.isIOS || Platform.isMacOS || Platform.isLinux || Platform.isWindows, - launch: (url) async { + launch: (url) { if (Platform.isAndroid) return _launchAndroidIntent(url, package: 'org.videolan.vlc'); if (Platform.isIOS) return _launchUrlScheme('vlc://', url); if (Platform.isMacOS) return _launchMacApp('VLC', url); @@ -170,7 +170,7 @@ class KnownPlayers { name: 'mpv', iconAsset: 'assets/player_icons/mpv.svg', isAvailable: Platform.isAndroid || Platform.isMacOS || Platform.isLinux || Platform.isWindows, - launch: (url) async { + launch: (url) { if (Platform.isAndroid) return _launchAndroidIntent(url, package: 'is.xyz.mpv'); return _launchCommand('mpv', url); }, diff --git a/lib/models/livetv_dvr.dart b/lib/models/livetv_dvr.dart index f087e0fb..07cc8280 100644 --- a/lib/models/livetv_dvr.dart +++ b/lib/models/livetv_dvr.dart @@ -68,12 +68,7 @@ class ChannelMapping { final bool? enabled; final String? lineupIdentifier; - ChannelMapping({ - this.channelKey, - this.deviceIdentifier, - this.enabled, - this.lineupIdentifier, - }); + ChannelMapping({this.channelKey, this.deviceIdentifier, this.enabled, this.lineupIdentifier}); factory ChannelMapping.fromJson(Map json) { return ChannelMapping( diff --git a/lib/models/livetv_hub_result.dart b/lib/models/livetv_hub_result.dart index a5093feb..642e1d62 100644 --- a/lib/models/livetv_hub_result.dart +++ b/lib/models/livetv_hub_result.dart @@ -7,11 +7,7 @@ class LiveTvHubResult { final String hubKey; final List entries; - LiveTvHubResult({ - required this.title, - required this.hubKey, - required this.entries, - }); + LiveTvHubResult({required this.title, required this.hubKey, required this.entries}); } /// A single item in a live TV hub, holding both display metadata and EPG timing. diff --git a/lib/models/livetv_program.dart b/lib/models/livetv_program.dart index 9ef7275c..1114bfa7 100644 --- a/lib/models/livetv_program.dart +++ b/lib/models/livetv_program.dart @@ -63,11 +63,9 @@ class LiveTvProgram { parentIndex: (json['parentIndex'] as num?)?.toInt(), thumb: json['thumb'] as String? ?? json['grandparentThumb'] as String?, art: json['art'] as String?, - channelIdentifier: json['channelIdentifier'] as String? - ?? media?['channelIdentifier']?.toString() - ?? channel?['id']?.toString(), - channelCallSign: json['channelCallSign'] as String? - ?? media?['channelCallSign'] as String?, + channelIdentifier: + json['channelIdentifier'] as String? ?? media?['channelIdentifier']?.toString() ?? channel?['id']?.toString(), + channelCallSign: json['channelCallSign'] as String? ?? media?['channelCallSign'] as String?, live: json['live'] == true || json['live'] == 1 || json['live'] == '1', premiere: json['premiere'] == true || json['premiere'] == 1 || json['premiere'] == '1', ); diff --git a/lib/models/livetv_subscription.dart b/lib/models/livetv_subscription.dart index 707b3cfb..a0fa5b2d 100644 --- a/lib/models/livetv_subscription.dart +++ b/lib/models/livetv_subscription.dart @@ -59,8 +59,7 @@ class LiveTvSubscription { } /// Creation time as DateTime - DateTime? get createdAtTime => - createdAt != null ? DateTime.fromMillisecondsSinceEpoch(createdAt! * 1000) : null; + DateTime? get createdAtTime => createdAt != null ? DateTime.fromMillisecondsSinceEpoch(createdAt! * 1000) : null; } /// Represents a setting within a DVR subscription @@ -93,10 +92,7 @@ class SubscriptionSetting { final parts = (json['enumValues'] as String).split('|'); options = parts.map((part) { final kv = part.split(':'); - return SubscriptionSettingOption( - value: kv[0], - label: kv.length > 1 ? kv[1] : kv[0], - ); + return SubscriptionSettingOption(value: kv.first, label: kv.length > 1 ? kv[1] : kv.first); }).toList(); } diff --git a/lib/models/plex_file_info.dart b/lib/models/plex_file_info.dart index 567206c3..54676308 100644 --- a/lib/models/plex_file_info.dart +++ b/lib/models/plex_file_info.dart @@ -75,11 +75,7 @@ class PlexFileInfo { final minutes = (seconds % 3600) ~/ 60; final secs = seconds % 60; - if (hours > 0) { - return '${hours}h ${minutes}m ${secs}s'; - } else { - return '${minutes}m ${secs}s'; - } + return hours > 0 ? '${hours}h ${minutes}m ${secs}s' : '${minutes}m ${secs}s'; } /// Format bitrate in Mbps or Kbps diff --git a/lib/models/plex_media_version.dart b/lib/models/plex_media_version.dart index 85676b05..a03466ed 100644 --- a/lib/models/plex_media_version.dart +++ b/lib/models/plex_media_version.dart @@ -26,7 +26,7 @@ class PlexMediaVersion { factory PlexMediaVersion.fromJson(Map json) { // Get the first Part key for playback final parts = json['Part'] as List?; - final partKey = parts != null && parts.isNotEmpty ? parts[0]['key'] as String? ?? '' : ''; + final partKey = parts != null && parts.isNotEmpty ? parts.first['key'] as String? ?? '' : ''; return PlexMediaVersion( id: json['id'] as int? ?? 0, diff --git a/lib/models/shader_preset.dart b/lib/models/shader_preset.dart index 1d4a4b10..95dcb254 100644 --- a/lib/models/shader_preset.dart +++ b/lib/models/shader_preset.dart @@ -51,8 +51,8 @@ class Anime4KConfig { factory Anime4KConfig.fromJson(Map 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.asNameMap()[json['quality']] ?? Anime4KQuality.fast, + mode: Anime4KMode.values.asNameMap()[json['mode']] ?? Anime4KMode.modeA, ); } } @@ -207,7 +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.asNameMap()[json['type']] ?? ShaderPresetType.none, anime4kConfig: json['anime4kConfig'] != null ? Anime4KConfig.fromJson(json['anime4kConfig']) : null, nvscalerConfig: json['nvscalerConfig'] != null ? NVScalerConfig.fromJson(json['nvscalerConfig']) : null, ); diff --git a/lib/mpv/player/player_android.dart b/lib/mpv/player/player_android.dart index 07f5d7c4..7850bc21 100644 --- a/lib/mpv/player/player_android.dart +++ b/lib/mpv/player/player_android.dart @@ -232,7 +232,7 @@ class PlayerAndroid extends PlayerBase { // Handle MPV commands by translating to ExoPlayer equivalents if (args.isEmpty) return; - switch (args[0]) { + switch (args.first) { case 'loadfile': if (args.length > 1) { await open(Media(args[1])); diff --git a/lib/mpv/player/player_base.dart b/lib/mpv/player/player_base.dart index e47098c3..3604788f 100644 --- a/lib/mpv/player/player_base.dart +++ b/lib/mpv/player/player_base.dart @@ -298,11 +298,9 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { final id = trackId?.toString(); SubtitleTrack? selectedTrack; - if (id == null || id == 'no') { - selectedTrack = SubtitleTrack.off; - } else { - selectedTrack = _state.tracks.subtitle.cast().firstWhere((t) => t?.id == id, orElse: () => null); - } + selectedTrack = (id == null || id == 'no') + ? SubtitleTrack.off + : _state.tracks.subtitle.cast().firstWhere((t) => t?.id == id, orElse: () => null); _state = _state.copyWith(track: _state.track.copyWith(subtitle: selectedTrack)); trackController.add(_state.track); @@ -347,19 +345,16 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { } @override - Future updateFrame() async { - // Default no-op, overridden by platforms that need it - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future updateFrame() async {} @override - Future setVideoFrameRate(double fps, int durationMs) async { - // Default no-op, overridden by platforms that support it - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future setVideoFrameRate(double fps, int durationMs) async {} @override - Future clearVideoFrameRate() async { - // Default no-op, overridden by platforms that support it - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future clearVideoFrameRate() async {} @override Future requestAudioFocus() async { @@ -368,19 +363,16 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { } @override - Future abandonAudioFocus() async { - // Default no-op, overridden by Android - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future abandonAudioFocus() async {} @override - Future setAudioDevice(AudioDevice device) async { - // Default no-op, overridden by platforms that support it - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future setAudioDevice(AudioDevice device) async {} @override - Future setAudioPassthrough(bool enabled) async { - // Default no-op, overridden by platforms that support it - } + // ignore: no-empty-block - base no-op, overridden by platform subclasses + Future setAudioPassthrough(bool enabled) async {} // ============================================ // Lifecycle diff --git a/lib/mpv/player/player_native.dart b/lib/mpv/player/player_native.dart index 7f3acd7b..a45c9539 100644 --- a/lib/mpv/player/player_native.dart +++ b/lib/mpv/player/player_native.dart @@ -88,8 +88,7 @@ class PlayerNative extends PlayerBase { /// Returns null if the call fails. Future _openContentFd(String contentUri) async { try { - final fd = await methodChannel.invokeMethod('openContentFd', {'uri': contentUri}); - return fd; + return await methodChannel.invokeMethod('openContentFd', {'uri': contentUri}); } catch (e) { return null; } diff --git a/lib/mpv/player/video_rect_support.dart b/lib/mpv/player/video_rect_support.dart index 17770faa..1fab6574 100644 --- a/lib/mpv/player/video_rect_support.dart +++ b/lib/mpv/player/video_rect_support.dart @@ -1,9 +1,11 @@ +import 'player.dart'; + /// Mixin for players that support video rect positioning. /// /// Players that render video behind the Flutter view (e.g., using /// native window embedding or GtkGLArea) implement this mixin to /// receive layout updates from the [Video] widget. -mixin VideoRectSupport { +mixin VideoRectSupport on Player { /// Updates the video rendering area. /// /// Called by the [Video] widget when the layout changes. diff --git a/lib/mpv/video.dart b/lib/mpv/video.dart index 00589eb7..5389f9a0 100644 --- a/lib/mpv/video.dart +++ b/lib/mpv/video.dart @@ -89,7 +89,7 @@ class _VideoState extends State