diff --git a/lib/client/plex_client.dart b/lib/client/plex_client.dart index d13d2340..0ebed970 100644 --- a/lib/client/plex_client.dart +++ b/lib/client/plex_client.dart @@ -508,10 +508,7 @@ class PlexClient { if (metadataJson != null && metadataJson['Chapter'] != null) { final chapterList = metadataJson['Chapter'] as List; - final markerList = [ - chapterList.first, - chapterList[chapterList.length - 2], - ]; + final markerList = [chapterList.first, chapterList.last]; return markerList.map((marker) { return PlexMarker( id: marker['id'] as int, diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index 36612372..00e608ae 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -1,24 +1,26 @@ import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; -import 'package:provider/provider.dart'; import 'package:os_media_controls/os_media_controls.dart'; +import 'package:provider/provider.dart'; + +import '../models/plex_media_version.dart'; import '../models/plex_metadata.dart'; import '../models/plex_user_profile.dart'; -import '../providers/plex_client_provider.dart'; import '../providers/playback_state_provider.dart'; +import '../providers/plex_client_provider.dart'; import '../providers/settings_provider.dart'; -import '../utils/provider_extensions.dart'; -import '../widgets/video_controls/video_controls.dart'; -import '../utils/language_codes.dart'; -import '../utils/app_logger.dart'; import '../services/settings_service.dart'; +import '../utils/app_logger.dart'; +import '../utils/language_codes.dart'; import '../utils/orientation_helper.dart'; -import '../utils/video_player_navigation.dart'; import '../utils/platform_detector.dart'; -import '../models/plex_media_version.dart'; +import '../utils/provider_extensions.dart'; +import '../utils/video_player_navigation.dart'; +import '../widgets/video_controls/video_controls.dart'; class VideoPlayerScreen extends StatefulWidget { final PlexMetadata metadata; @@ -240,7 +242,6 @@ class VideoPlayerScreenState extends State { } } - Future _loadAdjacentEpisodes() async { if (widget.metadata.type.toLowerCase() != 'episode') { return; @@ -269,7 +270,9 @@ class VideoPlayerScreenState extends State { widget.metadata.ratingKey, loopQueue: loopQueue, ); - previous = playbackState.getPreviousEpisode(widget.metadata.ratingKey); + previous = playbackState.getPreviousEpisode( + widget.metadata.ratingKey, + ); } else { // Use chronological order even in shuffle mode next = await client.findAdjacentEpisode(widget.metadata, 1); @@ -1204,7 +1207,9 @@ class VideoPlayerScreenState extends State { // Get artwork URL String? artworkUrl; if (client == null) { - appLogger.w('Cannot get artwork URL for media controls: Plex client is null'); + appLogger.w( + 'Cannot get artwork URL for media controls: Plex client is null', + ); } else { final thumbUrl = metadata.type.toLowerCase() == 'episode' ? metadata.grandparentThumb ?? metadata.thumb @@ -1235,15 +1240,17 @@ class VideoPlayerScreenState extends State { } } - await OsMediaControls.setMetadata(MediaMetadata( - title: title, - artist: artist, - album: album, - duration: metadata.duration != null - ? Duration(milliseconds: metadata.duration!) - : null, - artworkUrl: artworkUrl, - )); + await OsMediaControls.setMetadata( + MediaMetadata( + title: title, + artist: artist, + album: album, + duration: metadata.duration != null + ? Duration(milliseconds: metadata.duration!) + : null, + artworkUrl: artworkUrl, + ), + ); // Set initial playback state _updateMediaControlsPlaybackState(); @@ -1252,11 +1259,15 @@ class VideoPlayerScreenState extends State { void _updateMediaControlsPlaybackState() { if (player == null) return; - OsMediaControls.setPlaybackState(MediaPlaybackState( - state: player!.state.playing ? PlaybackState.playing : PlaybackState.paused, - position: player!.state.position, - speed: player!.state.rate, - )); + OsMediaControls.setPlaybackState( + MediaPlaybackState( + state: player!.state.playing + ? PlaybackState.playing + : PlaybackState.paused, + position: player!.state.position, + speed: player!.state.rate, + ), + ); } void _updateMediaControlsPosition() { @@ -1264,11 +1275,13 @@ class VideoPlayerScreenState extends State { // Only update if playing to avoid excessive updates if (player!.state.playing) { - OsMediaControls.setPlaybackState(MediaPlaybackState( - state: PlaybackState.playing, - position: player!.state.position, - speed: player!.state.rate, - )); + OsMediaControls.setPlaybackState( + MediaPlaybackState( + state: PlaybackState.playing, + position: player!.state.position, + speed: player!.state.rate, + ), + ); } } diff --git a/lib/widgets/video_controls/video_controls.dart b/lib/widgets/video_controls/video_controls.dart index 5cf5a1e9..e7a628e8 100644 --- a/lib/widgets/video_controls/video_controls.dart +++ b/lib/widgets/video_controls/video_controls.dart @@ -926,12 +926,22 @@ class _PlexVideoControlsState extends State } Widget _buildSkipMarkerButton() { - final markerType = _currentMarker!.isIntro ? 'Intro' : 'Credits'; + final isCredits = _currentMarker!.isCredits; + final hasNextEpisode = widget.onNext != null; + + // Show "Next Episode" for credits when next episode is available + final bool showNextEpisode = isCredits && hasNextEpisode; + final String buttonText = showNextEpisode + ? 'Next Episode' + : (isCredits ? 'Skip Credits' : 'Skip Intro'); + final IconData buttonIcon = showNextEpisode + ? Icons.skip_next + : Icons.fast_forward; return Material( color: Colors.transparent, child: InkWell( - onTap: _skipMarker, + onTap: showNextEpisode ? widget.onNext : _skipMarker, borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), @@ -950,7 +960,7 @@ class _PlexVideoControlsState extends State mainAxisSize: MainAxisSize.min, children: [ Text( - 'Skip $markerType', + buttonText, style: const TextStyle( color: Colors.black, fontSize: 16, @@ -958,7 +968,7 @@ class _PlexVideoControlsState extends State ), ), const SizedBox(width: 8), - const Icon(Icons.fast_forward, color: Colors.black, size: 20), + Icon(buttonIcon, color: Colors.black, size: 20), ], ), ),