refactor: adjust video controls button sizes
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// A standardized button for video player controls with improved tap targets.
|
||||
///
|
||||
/// This widget ensures consistent tap target sizing across all video control
|
||||
/// buttons without changing their visual appearance. The larger tap area makes
|
||||
/// buttons easier to interact with, especially on mobile devices.
|
||||
class VideoControlButton extends StatelessWidget {
|
||||
/// The icon to display in the button.
|
||||
final IconData icon;
|
||||
|
||||
/// Called when the button is tapped.
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
/// The color of the icon. Defaults to white, or amber if [isActive] is true.
|
||||
final Color? color;
|
||||
|
||||
/// Optional tooltip text shown on hover or long press.
|
||||
final String? tooltip;
|
||||
|
||||
/// Whether this button represents an active state (e.g., a feature is enabled).
|
||||
/// When true, the icon color defaults to amber instead of white.
|
||||
final bool isActive;
|
||||
|
||||
const VideoControlButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.onPressed,
|
||||
this.color,
|
||||
this.tooltip,
|
||||
this.isActive = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Determine the effective color: explicit color > active amber > default white
|
||||
final effectiveColor = color ?? (isActive ? Colors.amber : Colors.white);
|
||||
|
||||
return IconButton(
|
||||
icon: Icon(icon, color: effectiveColor),
|
||||
onPressed: onPressed,
|
||||
tooltip: tooltip,
|
||||
constraints: const BoxConstraints(minWidth: 40, minHeight: 56),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import 'sheets/chapter_sheet.dart';
|
||||
import 'sheets/subtitle_track_sheet.dart';
|
||||
import 'sheets/version_sheet.dart';
|
||||
import 'sheets/video_settings_sheet.dart';
|
||||
import 'video_control_button.dart';
|
||||
|
||||
/// Custom video controls builder for Plex with chapter, audio, and subtitle support
|
||||
Widget plexVideoControlsBuilder(
|
||||
@@ -374,9 +375,11 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
|
||||
initialData: widget.player.state.tracks,
|
||||
builder: (context, snapshot) {
|
||||
final tracks = snapshot.data;
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
return IntrinsicHeight(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Unified settings button (speed, sleep timer, audio sync, subtitle sync)
|
||||
ListenableBuilder(
|
||||
listenable: SleepTimerService(),
|
||||
@@ -386,11 +389,9 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
|
||||
sleepTimer.isActive ||
|
||||
_audioSyncOffset != 0 ||
|
||||
_subtitleSyncOffset != 0;
|
||||
return IconButton(
|
||||
icon: Icon(
|
||||
Icons.tune,
|
||||
color: isActive ? Colors.amber : Colors.white,
|
||||
),
|
||||
return VideoControlButton(
|
||||
icon: Icons.tune,
|
||||
isActive: isActive,
|
||||
onPressed: () async {
|
||||
await VideoSettingsSheet.show(
|
||||
context,
|
||||
@@ -407,19 +408,18 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
|
||||
},
|
||||
),
|
||||
if (_hasMultipleAudioTracks(tracks))
|
||||
IconButton(
|
||||
icon: const Icon(Icons.audiotrack, color: Colors.white),
|
||||
VideoControlButton(
|
||||
icon: Icons.audiotrack,
|
||||
onPressed: () => AudioTrackSheet.show(context, widget.player),
|
||||
),
|
||||
if (_hasSubtitles(tracks))
|
||||
IconButton(
|
||||
icon: const Icon(Icons.subtitles, color: Colors.white),
|
||||
onPressed: () =>
|
||||
SubtitleTrackSheet.show(context, widget.player),
|
||||
VideoControlButton(
|
||||
icon: Icons.subtitles,
|
||||
onPressed: () => SubtitleTrackSheet.show(context, widget.player),
|
||||
),
|
||||
if (_chapters.isNotEmpty)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.video_library, color: Colors.white),
|
||||
VideoControlButton(
|
||||
icon: Icons.video_library,
|
||||
onPressed: () => ChapterSheet.show(
|
||||
context,
|
||||
widget.player,
|
||||
@@ -428,8 +428,8 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
|
||||
),
|
||||
),
|
||||
if (widget.availableVersions.length > 1)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.video_file, color: Colors.white),
|
||||
VideoControlButton(
|
||||
icon: Icons.video_file,
|
||||
onPressed: () => VersionSheet.show(
|
||||
context,
|
||||
widget.availableVersions,
|
||||
@@ -439,34 +439,26 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
|
||||
),
|
||||
// BoxFit mode cycle button
|
||||
if (widget.onCycleBoxFitMode != null)
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_getBoxFitIcon(widget.boxFitMode),
|
||||
color: Colors.white,
|
||||
),
|
||||
VideoControlButton(
|
||||
icon: _getBoxFitIcon(widget.boxFitMode),
|
||||
tooltip: _getBoxFitTooltip(widget.boxFitMode),
|
||||
onPressed: widget.onCycleBoxFitMode,
|
||||
),
|
||||
// Rotation lock toggle (mobile only)
|
||||
if (PlatformDetector.isMobile(context))
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isRotationLocked ? Icons.screen_lock_rotation : Icons.screen_rotation,
|
||||
color: Colors.white,
|
||||
),
|
||||
VideoControlButton(
|
||||
icon: _isRotationLocked ? Icons.screen_lock_rotation : Icons.screen_rotation,
|
||||
tooltip: _isRotationLocked ? 'Unlock rotation' : 'Lock rotation',
|
||||
onPressed: _toggleRotationLock,
|
||||
),
|
||||
// Fullscreen toggle (desktop only)
|
||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS)
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||
color: Colors.white,
|
||||
),
|
||||
VideoControlButton(
|
||||
icon: _isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||
onPressed: _toggleFullscreen,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user