From 867992e96ba101a64b1b4f1830fe2d97fccb0589 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sat, 13 Dec 2025 04:21:39 +0100 Subject: [PATCH] refactor: fix warnings --- lib/focus/input_mode_tracker.dart | 8 -- lib/models/download_progress.dart | 3 +- lib/providers/offline_mode_provider.dart | 5 +- lib/screens/discover_screen.dart | 6 ++ lib/screens/libraries/libraries_screen.dart | 3 + lib/screens/libraries/sort_bottom_sheet.dart | 94 ++++++++++--------- .../libraries/tabs/library_browse_tab.dart | 53 ++++++----- lib/screens/main_screen.dart | 45 +-------- lib/screens/media_detail_screen.dart | 8 +- lib/screens/search_screen.dart | 2 + lib/screens/season_detail_screen.dart | 14 +-- lib/utils/log_redaction_manager.dart | 8 +- lib/widgets/deletion_progress_dialog.dart | 10 +- lib/widgets/download_tree_item.dart | 13 ++- lib/widgets/download_tree_view.dart | 16 ++-- lib/widgets/focusable_filter_chip.dart | 1 - lib/widgets/focusable_list_tile.dart | 15 +-- lib/widgets/focusable_tab_chip.dart | 1 - lib/widgets/media_card.dart | 2 +- .../sheets/video_settings_sheet.dart | 2 +- .../video_controls/video_control_button.dart | 1 - .../widgets/timeline_slider.dart | 2 - .../widgets/video_timeline_bar.dart | 1 - 23 files changed, 141 insertions(+), 172 deletions(-) diff --git a/lib/focus/input_mode_tracker.dart b/lib/focus/input_mode_tracker.dart index e4357df8..da06e873 100644 --- a/lib/focus/input_mode_tracker.dart +++ b/lib/focus/input_mode_tracker.dart @@ -56,7 +56,6 @@ class _InputModeTrackerState extends State { _updateFocusHighlightStrategy(_mode); // Listen to hardware keyboard events globally HardwareKeyboard.instance.addHandler(_handleKeyEvent); - RawKeyboard.instance.addListener(_handleRawKeyEvent); // Register callback for gamepad input to switch to keyboard mode GamepadService.onGamepadInput = () => _setMode(InputMode.keyboard); @@ -65,7 +64,6 @@ class _InputModeTrackerState extends State { @override void dispose() { HardwareKeyboard.instance.removeHandler(_handleKeyEvent); - RawKeyboard.instance.removeListener(_handleRawKeyEvent); GamepadService.onGamepadInput = null; super.dispose(); } @@ -79,12 +77,6 @@ class _InputModeTrackerState extends State { return false; } - void _handleRawKeyEvent(RawKeyEvent event) { - if (event is RawKeyDownEvent) { - _setMode(InputMode.keyboard); - } - } - void _setMode(InputMode mode) { if (_mode != mode) { setState(() => _mode = mode); diff --git a/lib/models/download_progress.dart b/lib/models/download_progress.dart index 2d42e7ed..82ffc7aa 100644 --- a/lib/models/download_progress.dart +++ b/lib/models/download_progress.dart @@ -40,8 +40,9 @@ class DownloadProgress { String _formatBytes(int bytes) { if (bytes < 1024) return '$bytes B'; if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB'; - if (bytes < 1024 * 1024 * 1024) + if (bytes < 1024 * 1024 * 1024) { return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; + } return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB'; } diff --git a/lib/providers/offline_mode_provider.dart b/lib/providers/offline_mode_provider.dart index 4c4159b7..99aaa933 100644 --- a/lib/providers/offline_mode_provider.dart +++ b/lib/providers/offline_mode_provider.dart @@ -11,10 +11,11 @@ class OfflineModeProvider extends ChangeNotifier { StreamSubscription>? _serverStatusSubscription; bool _hasNetworkConnection = true; - bool _hasServerConnection = false; + late bool _hasServerConnection; bool _isInitialized = false; - OfflineModeProvider(this._serverManager); + OfflineModeProvider(this._serverManager) + : _hasServerConnection = _serverManager.onlineServerIds.isNotEmpty; /// Whether the app is currently in offline mode /// Offline = no network OR no servers reachable diff --git a/lib/screens/discover_screen.dart b/lib/screens/discover_screen.dart index 7cd368d5..18d58036 100644 --- a/lib/screens/discover_screen.dart +++ b/lib/screens/discover_screen.dart @@ -26,6 +26,7 @@ import '../utils/app_logger.dart'; import '../utils/provider_extensions.dart'; import '../utils/video_player_navigation.dart'; import '../utils/content_rating_formatter.dart'; +import '../utils/layout_constants.dart'; import '../focus/dpad_navigator.dart'; import 'auth_screen.dart'; @@ -467,6 +468,8 @@ class _DiscoverScreenState extends State // Wait for libraries and then fetch hubs final librariesByServer = await librariesFuture; + if (!mounted) return; + // Get hidden libraries to filter from hubs final hiddenLibrariesProvider = Provider.of( context, @@ -494,6 +497,7 @@ class _DiscoverScreenState extends State appLogger.d( 'Received ${onDeck.length} on deck items and ${filteredHubs.length} hubs from all servers', ); + if (!mounted) return; setState(() { _hubs = filteredHubs; _areHubsLoading = false; @@ -554,6 +558,7 @@ class _DiscoverScreenState extends State } // Public method to fully reload all content (for profile switches) + @override void fullRefresh() { appLogger.d('DiscoverScreen.fullRefresh() called - reloading all content'); // Reload all content including On Deck and content hubs @@ -782,6 +787,7 @@ class _DiscoverScreenState extends State ), ], ).then((value) { + if (!context.mounted) return; if (value == 'switch_profile') { _handleSwitchProfile(context); } else if (value == 'logout') { diff --git a/lib/screens/libraries/libraries_screen.dart b/lib/screens/libraries/libraries_screen.dart index 9921aca9..eb7dfc82 100644 --- a/lib/screens/libraries/libraries_screen.dart +++ b/lib/screens/libraries/libraries_screen.dart @@ -244,6 +244,7 @@ class _LibrariesScreenState extends State /// If the active tab has already loaded data (often the case after preloading /// while on another main tab), re-request focus so the first item is focused /// once the screen is actually shown. + @override void focusActiveTabIfReady() { if (_selectedLibraryGlobalKey == null) return; _focusCurrentTab(); @@ -452,6 +453,7 @@ class _LibrariesScreenState extends State } /// Public method to load a library by key (called from MainScreen side nav) + @override void loadLibraryByKey(String libraryGlobalKey) { _loadLibraryContent(libraryGlobalKey); } @@ -716,6 +718,7 @@ class _LibrariesScreenState extends State } // Public method to fully reload all content (for profile switches) + @override void fullRefresh() { appLogger.d('LibrariesScreen.fullRefresh() called - reloading all content'); // Reload libraries and clear any selected library/filters diff --git a/lib/screens/libraries/sort_bottom_sheet.dart b/lib/screens/libraries/sort_bottom_sheet.dart index 357f9f56..70928087 100644 --- a/lib/screens/libraries/sort_bottom_sheet.dart +++ b/lib/screens/libraries/sort_bottom_sheet.dart @@ -86,53 +86,55 @@ class _SortBottomSheetState extends State { : null, ), Expanded( - child: ListView.builder( - controller: scrollController, - padding: const EdgeInsets.symmetric(vertical: 8), - itemCount: widget.sortOptions.length, - itemBuilder: (context, index) { - final sort = widget.sortOptions[index]; - final isSelected = _currentSort?.key == sort.key; - - return FocusableRadioListTile( - focusNode: index == 0 ? _initialFocusNode : null, - title: Text(sort.title), - value: sort, - groupValue: _currentSort, - onChanged: (value) { - if (value != null) { - _handleSortChange(value, value.isDefaultDescending); - } - }, - secondary: isSelected - ? SegmentedButton( - showSelectedIcon: false, - segments: const [ - ButtonSegment( - value: false, - icon: AppIcon( - Symbols.arrow_upward_rounded, - fill: 1, - size: 16, - ), - ), - ButtonSegment( - value: true, - icon: AppIcon( - Symbols.arrow_downward_rounded, - fill: 1, - size: 16, - ), - ), - ], - selected: {_currentDescending}, - onSelectionChanged: (Set newSelection) { - _handleSortChange(sort, newSelection.first); - }, - ) - : null, - ); + child: RadioGroup( + groupValue: _currentSort, + onChanged: (value) { + if (value != null) { + _handleSortChange(value, value.isDefaultDescending); + } }, + child: ListView.builder( + controller: scrollController, + padding: const EdgeInsets.symmetric(vertical: 8), + itemCount: widget.sortOptions.length, + itemBuilder: (context, index) { + final sort = widget.sortOptions[index]; + final isSelected = _currentSort?.key == sort.key; + + return FocusableRadioListTile( + focusNode: index == 0 ? _initialFocusNode : null, + title: Text(sort.title), + value: sort, + secondary: isSelected + ? SegmentedButton( + showSelectedIcon: false, + segments: const [ + ButtonSegment( + value: false, + icon: AppIcon( + Symbols.arrow_upward_rounded, + fill: 1, + size: 16, + ), + ), + ButtonSegment( + value: true, + icon: AppIcon( + Symbols.arrow_downward_rounded, + fill: 1, + size: 16, + ), + ), + ], + selected: {_currentDescending}, + onSelectionChanged: (Set newSelection) { + _handleSortChange(sort, newSelection.first); + }, + ) + : null, + ); + }, + ), ), ), ], diff --git a/lib/screens/libraries/tabs/library_browse_tab.dart b/lib/screens/libraries/tabs/library_browse_tab.dart index a29a0c67..ace75f75 100644 --- a/lib/screens/libraries/tabs/library_browse_tab.dart +++ b/lib/screens/libraries/tabs/library_browse_tab.dart @@ -365,35 +365,36 @@ class _LibraryBrowseTabState context: context, builder: (sheetContext) { final options = _getGroupingOptions(); - return ListView.builder( - shrinkWrap: true, - itemCount: options.length, - itemBuilder: (context, index) { - final grouping = options[index]; - return RadioListTile( - title: Text(_getGroupingLabel(grouping)), - value: grouping, - groupValue: _selectedGrouping, - onChanged: (value) async { - if (value != null) { - setState(() { - _selectedGrouping = value; - }); + return RadioGroup( + groupValue: _selectedGrouping, + onChanged: (value) async { + if (value == null) return; + setState(() { + _selectedGrouping = value; + }); - final storage = await StorageService.getInstance(); - await storage.saveLibraryGrouping( - widget.library.globalKey, - value, - ); - - if (!sheetContext.mounted) return; - - Navigator.pop(sheetContext); - _loadItems(); - } - }, + final storage = await StorageService.getInstance(); + await storage.saveLibraryGrouping( + widget.library.globalKey, + value, ); + + if (!sheetContext.mounted || !mounted) return; + + Navigator.pop(sheetContext); + _loadItems(); }, + child: ListView.builder( + shrinkWrap: true, + itemCount: options.length, + itemBuilder: (context, index) { + final grouping = options[index]; + return RadioListTile( + title: Text(_getGroupingLabel(grouping)), + value: grouping, + ); + }, + ), ); }, ); diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 357758aa..18747e4a 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:plezy/widgets/app_icon.dart'; -import 'package:material_symbols_icons/symbols.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../../services/plex_client.dart'; -import '../i18n/strings.g.dart'; import '../utils/app_logger.dart'; import '../utils/provider_extensions.dart'; import '../utils/platform_detector.dart'; @@ -313,7 +310,8 @@ class _MainScreenState extends State with RouteAware { ); // Trigger watch state sync now that servers are connected - if (connectedCount > 0 && context.mounted) { + if (connectedCount > 0) { + if (!mounted) return; context.read().onServersConnected(); } } @@ -460,42 +458,3 @@ class _MainScreenState extends State with RouteAware { ); } } - -/// Placeholder widget shown for network-dependent screens when offline -class _OfflinePlaceholder extends StatelessWidget { - const _OfflinePlaceholder(); - - @override - Widget build(BuildContext context) { - return Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AppIcon( - Symbols.cloud_off_rounded, - fill: 1, - size: 64, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - const SizedBox(height: 16), - Text( - t.messages.youAreOffline, - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - const SizedBox(height: 8), - Text( - t.messages.offlineFeatureUnavailable, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ); - } -} diff --git a/lib/screens/media_detail_screen.dart b/lib/screens/media_detail_screen.dart index b7ca0a5b..4df162ea 100644 --- a/lib/screens/media_detail_screen.dart +++ b/lib/screens/media_detail_screen.dart @@ -99,7 +99,10 @@ class _MediaDetailScreenState extends State { value: 1.0, strokeWidth: 2.0, valueColor: AlwaysStoppedAnimation( - Theme.of(context).colorScheme.primary.withOpacity(0.2), + Theme.of(context) + .colorScheme + .primary + .withValues(alpha: 0.2), ), ), // Progress circle (indeterminate if no progress, determinate otherwise) @@ -368,6 +371,8 @@ class _MediaDetailScreenState extends State { await Future.delayed(const Duration(milliseconds: 100)); } + if (!mounted) return; + if (_seasons.isEmpty) { if (mounted) { ScaffoldMessenger.of( @@ -382,6 +387,7 @@ class _MediaDetailScreenState extends State { // Get episodes of the first season List episodes; + if (!mounted) return; if (widget.isOffline) { // In offline mode, get episodes from downloads final downloadProvider = context.read(); diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart index 28729830..0462147e 100644 --- a/lib/screens/search_screen.dart +++ b/lib/screens/search_screen.dart @@ -131,6 +131,7 @@ class _SearchScreenState extends State } /// Focus the search input field + @override void focusSearchInput() { WidgetsBinding.instance.addPostFrameCallback((_) { _searchFocusNode.requestFocus(); @@ -138,6 +139,7 @@ class _SearchScreenState extends State } // Public method to fully reload all content (for profile switches) + @override void fullRefresh() { appLogger.d( 'SearchScreen.fullRefresh() called - clearing search and reloading', diff --git a/lib/screens/season_detail_screen.dart b/lib/screens/season_detail_screen.dart index 99d17350..78897efc 100644 --- a/lib/screens/season_detail_screen.dart +++ b/lib/screens/season_detail_screen.dart @@ -479,14 +479,14 @@ class _EpisodeCard extends StatelessWidget { children: [ // Background circle CircularProgressIndicator( - value: 1.0, - strokeWidth: 1.5, - valueColor: AlwaysStoppedAnimation( - getMutedColor( - Colors.blue, - ).withOpacity(0.3), - ), + value: 1.0, + strokeWidth: 1.5, + valueColor: AlwaysStoppedAnimation( + getMutedColor( + Colors.blue, + ).withValues(alpha: 0.3), ), + ), // Progress circle CircularProgressIndicator( value: progress?.progressPercent, diff --git a/lib/utils/log_redaction_manager.dart b/lib/utils/log_redaction_manager.dart index 1c201845..841be727 100644 --- a/lib/utils/log_redaction_manager.dart +++ b/lib/utils/log_redaction_manager.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - class LogRedactionManager { // Size limits for bounded sets (FIFO eviction when exceeded) static const int _maxTokens = 50; @@ -7,9 +5,9 @@ class LogRedactionManager { static const int _maxCustomValues = 50; // Use LinkedHashSet for FIFO ordering - static final Set _tokens = LinkedHashSet(); - static final Set _urls = LinkedHashSet(); - static final Set _customValues = LinkedHashSet(); + static final Set _tokens = {}; + static final Set _urls = {}; + static final Set _customValues = {}; static final RegExp _ipv4Pattern = RegExp( r'\b(\d{1,3})([.-])(\d{1,3})\2(\d{1,3})\2(\d{1,3})\b', diff --git a/lib/widgets/deletion_progress_dialog.dart b/lib/widgets/deletion_progress_dialog.dart index c371b1b0..c335a1d0 100644 --- a/lib/widgets/deletion_progress_dialog.dart +++ b/lib/widgets/deletion_progress_dialog.dart @@ -65,10 +65,12 @@ class DeletionProgressDialog extends StatelessWidget { Text( progress.currentOperation!, style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of( - context, - ).textTheme.bodySmall?.color?.withOpacity(0.7), - ), + color: Theme.of(context) + .textTheme + .bodySmall + ?.color + ?.withValues(alpha: 0.7), + ), textAlign: TextAlign.center, ), ], diff --git a/lib/widgets/download_tree_item.dart b/lib/widgets/download_tree_item.dart index 86f65a61..b39890b5 100644 --- a/lib/widgets/download_tree_item.dart +++ b/lib/widgets/download_tree_item.dart @@ -48,13 +48,17 @@ class DownloadTreeNode { // Aggregate status from children final statuses = children.map((c) => c.status).toSet(); - if (statuses.contains(DownloadStatus.downloading)) + if (statuses.contains(DownloadStatus.downloading)) { return DownloadStatus.downloading; + } if (statuses.contains(DownloadStatus.queued)) return DownloadStatus.queued; if (statuses.contains(DownloadStatus.paused)) return DownloadStatus.paused; - if (statuses.contains(DownloadStatus.failed)) return DownloadStatus.failed; - if (statuses.every((s) => s == DownloadStatus.completed)) + if (statuses.contains(DownloadStatus.failed)) { + return DownloadStatus.failed; + } + if (statuses.every((s) => s == DownloadStatus.completed)) { return DownloadStatus.completed; + } return DownloadStatus.queued; } } @@ -146,7 +150,8 @@ class DownloadTreeItem extends StatelessWidget { CircularProgressIndicator( value: 1.0, strokeWidth: 3.0, - valueColor: AlwaysStoppedAnimation(color.withOpacity(0.2)), + valueColor: + AlwaysStoppedAnimation(color.withValues(alpha: 0.2)), ), // Progress circle CircularProgressIndicator( diff --git a/lib/widgets/download_tree_view.dart b/lib/widgets/download_tree_view.dart index 814d58e6..01af2b1d 100644 --- a/lib/widgets/download_tree_view.dart +++ b/lib/widgets/download_tree_view.dart @@ -397,13 +397,14 @@ class _DownloadTreeViewState extends State { if (canExpand) ...[ const SizedBox(height: 4), - Text( - _getNodeSummary(node), - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurface.withOpacity(0.6), - ), + Text( + _getNodeSummary(node), + style: theme.textTheme.bodySmall?.copyWith( + color: + theme.colorScheme.onSurface.withValues(alpha: 0.6), ), - ], + ), + ], // Progress bar if (node.status == DownloadStatus.downloading || @@ -418,7 +419,8 @@ class _DownloadTreeViewState extends State { Text( '${(node.progress * 100).toStringAsFixed(1)}% - ${node.downloadProgress!.speedFormatted}', style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurface.withOpacity(0.6), + color: + theme.colorScheme.onSurface.withValues(alpha: 0.6), ), ), ], diff --git a/lib/widgets/focusable_filter_chip.dart b/lib/widgets/focusable_filter_chip.dart index 87ac3912..df5fb211 100644 --- a/lib/widgets/focusable_filter_chip.dart +++ b/lib/widgets/focusable_filter_chip.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:plezy/widgets/app_icon.dart'; -import 'package:flutter/services.dart'; import '../focus/focusable_chip_mixin.dart'; import '../focus/input_mode_tracker.dart'; diff --git a/lib/widgets/focusable_list_tile.dart b/lib/widgets/focusable_list_tile.dart index 37b059a0..1082ba75 100644 --- a/lib/widgets/focusable_list_tile.dart +++ b/lib/widgets/focusable_list_tile.dart @@ -92,12 +92,6 @@ class FocusableRadioListTile extends StatelessWidget { /// The value represented by this radio button. final T value; - /// The currently selected value for this group of radio buttons. - final T? groupValue; - - /// Called when the user selects this radio button. - final ValueChanged? onChanged; - /// Whether this radio button is part of a vertically dense list. final bool dense; @@ -107,17 +101,19 @@ class FocusableRadioListTile extends StatelessWidget { /// Whether this tile should autofocus when first built. final bool autofocus; + /// Whether the radio tile is interactive. + final bool? enabled; + const FocusableRadioListTile({ super.key, this.title, this.subtitle, this.secondary, required this.value, - required this.groupValue, - required this.onChanged, this.dense = false, this.focusNode, this.autofocus = false, + this.enabled, }); @override @@ -127,11 +123,10 @@ class FocusableRadioListTile extends StatelessWidget { subtitle: subtitle, secondary: secondary, value: value, - groupValue: groupValue, - onChanged: onChanged, dense: dense, focusNode: focusNode, autofocus: autofocus, + enabled: enabled, ); } } diff --git a/lib/widgets/focusable_tab_chip.dart b/lib/widgets/focusable_tab_chip.dart index 8f01cc25..da082262 100644 --- a/lib/widgets/focusable_tab_chip.dart +++ b/lib/widgets/focusable_tab_chip.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import '../focus/focusable_chip_mixin.dart'; import '../focus/input_mode_tracker.dart'; diff --git a/lib/widgets/media_card.dart b/lib/widgets/media_card.dart index 7cde1457..85f16799 100644 --- a/lib/widgets/media_card.dart +++ b/lib/widgets/media_card.dart @@ -124,7 +124,7 @@ class MediaCardState extends State { isOffline: widget.isOffline, ); - if (!mounted) return; + if (!context.mounted) return; switch (result) { case MediaNavigationResult.unsupported: diff --git a/lib/widgets/video_controls/sheets/video_settings_sheet.dart b/lib/widgets/video_controls/sheets/video_settings_sheet.dart index d9329218..66bb7cdc 100644 --- a/lib/widgets/video_controls/sheets/video_settings_sheet.dart +++ b/lib/widgets/video_controls/sheets/video_settings_sheet.dart @@ -278,7 +278,7 @@ class _VideoSettingsSheetState extends State { trailing: Switch( value: _enableHDR, onChanged: (_) => _toggleHDR(), - activeColor: Colors.amber, + activeThumbColor: Colors.amber, ), onTap: _toggleHDR, ), diff --git a/lib/widgets/video_controls/video_control_button.dart b/lib/widgets/video_controls/video_control_button.dart index 82194561..860b061e 100644 --- a/lib/widgets/video_controls/video_control_button.dart +++ b/lib/widgets/video_controls/video_control_button.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:plezy/widgets/app_icon.dart'; -import 'package:flutter/services.dart'; import '../../focus/focusable_wrapper.dart'; diff --git a/lib/widgets/video_controls/widgets/timeline_slider.dart b/lib/widgets/video_controls/widgets/timeline_slider.dart index 9c441e90..c9534bb5 100644 --- a/lib/widgets/video_controls/widgets/timeline_slider.dart +++ b/lib/widgets/video_controls/widgets/timeline_slider.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - import '../../../models/plex_media_info.dart'; import '../../../i18n/strings.g.dart'; import '../../../focus/focusable_wrapper.dart'; diff --git a/lib/widgets/video_controls/widgets/video_timeline_bar.dart b/lib/widgets/video_controls/widgets/video_timeline_bar.dart index 4b36f03f..fa9aa472 100644 --- a/lib/widgets/video_controls/widgets/video_timeline_bar.dart +++ b/lib/widgets/video_controls/widgets/video_timeline_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import '../../../mpv/mpv.dart'; import '../../../models/plex_media_info.dart';