mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-10 16:00:28 -07:00
feature: Add actions for media segments (#236)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
f0414439f3
commit
e4b8a050c7
9 changed files with 155 additions and 23 deletions
|
|
@ -1179,5 +1179,9 @@
|
||||||
"qualityOptionsTitle": "Quality options",
|
"qualityOptionsTitle": "Quality options",
|
||||||
"qualityOptionsOriginal": "Original",
|
"qualityOptionsOriginal": "Original",
|
||||||
"qualityOptionsAuto": "Auto",
|
"qualityOptionsAuto": "Auto",
|
||||||
"version": "Version"
|
"version": "Version",
|
||||||
|
"mediaSegmentActions": "Media segment actions",
|
||||||
|
"segmentActionNone": "None",
|
||||||
|
"segmentActionAskToSkip": "Ask to skip",
|
||||||
|
"segmentActionSkip": "Skip"
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +42,28 @@ class MediaSegment with _$MediaSegment {
|
||||||
bool forceShow(Duration position) => (position - start).inSeconds < (end - start).inSeconds * 0.20;
|
bool forceShow(Duration position) => (position - start).inSeconds < (end - start).inSeconds * 0.20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Map<MediaSegmentType, SegmentSkip> defaultSegmentSkipValues = {
|
||||||
|
MediaSegmentType.commercial: SegmentSkip.askToSkip,
|
||||||
|
MediaSegmentType.preview: SegmentSkip.askToSkip,
|
||||||
|
MediaSegmentType.recap: SegmentSkip.askToSkip,
|
||||||
|
MediaSegmentType.outro: SegmentSkip.askToSkip,
|
||||||
|
MediaSegmentType.intro: SegmentSkip.askToSkip,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SegmentSkip {
|
||||||
|
none,
|
||||||
|
askToSkip,
|
||||||
|
skip;
|
||||||
|
|
||||||
|
const SegmentSkip();
|
||||||
|
|
||||||
|
String label(BuildContext context) => switch (this) {
|
||||||
|
SegmentSkip.none => context.localized.segmentActionNone,
|
||||||
|
SegmentSkip.askToSkip => context.localized.segmentActionAskToSkip,
|
||||||
|
SegmentSkip.skip => context.localized.segmentActionSkip,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
enum MediaSegmentType {
|
enum MediaSegmentType {
|
||||||
unknown,
|
unknown,
|
||||||
commercial,
|
commercial,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
import 'package:fladder/models/items/media_segments_model.dart';
|
||||||
import 'package:fladder/util/bitrate_helper.dart';
|
import 'package:fladder/util/bitrate_helper.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
||||||
@Default(Bitrate.original) Bitrate maxHomeBitrate,
|
@Default(Bitrate.original) Bitrate maxHomeBitrate,
|
||||||
@Default(Bitrate.original) Bitrate maxInternetBitrate,
|
@Default(Bitrate.original) Bitrate maxInternetBitrate,
|
||||||
String? audioDevice,
|
String? audioDevice,
|
||||||
|
@Default(defaultSegmentSkipValues) Map<MediaSegmentType, SegmentSkip> segmentSkipSettings,
|
||||||
}) = _VideoPlayerSettingsModel;
|
}) = _VideoPlayerSettingsModel;
|
||||||
|
|
||||||
double get volume => switch (defaultTargetPlatform) {
|
double get volume => switch (defaultTargetPlatform) {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ mixin _$VideoPlayerSettingsModel {
|
||||||
Bitrate get maxHomeBitrate => throw _privateConstructorUsedError;
|
Bitrate get maxHomeBitrate => throw _privateConstructorUsedError;
|
||||||
Bitrate get maxInternetBitrate => throw _privateConstructorUsedError;
|
Bitrate get maxInternetBitrate => throw _privateConstructorUsedError;
|
||||||
String? get audioDevice => throw _privateConstructorUsedError;
|
String? get audioDevice => throw _privateConstructorUsedError;
|
||||||
|
Map<MediaSegmentType, SegmentSkip> get segmentSkipSettings =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Serializes this VideoPlayerSettingsModel to a JSON map.
|
/// Serializes this VideoPlayerSettingsModel to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
@ -63,7 +65,8 @@ abstract class $VideoPlayerSettingsModelCopyWith<$Res> {
|
||||||
AutoNextType nextVideoType,
|
AutoNextType nextVideoType,
|
||||||
Bitrate maxHomeBitrate,
|
Bitrate maxHomeBitrate,
|
||||||
Bitrate maxInternetBitrate,
|
Bitrate maxInternetBitrate,
|
||||||
String? audioDevice});
|
String? audioDevice,
|
||||||
|
Map<MediaSegmentType, SegmentSkip> segmentSkipSettings});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -94,6 +97,7 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
||||||
Object? maxHomeBitrate = null,
|
Object? maxHomeBitrate = null,
|
||||||
Object? maxInternetBitrate = null,
|
Object? maxInternetBitrate = null,
|
||||||
Object? audioDevice = freezed,
|
Object? audioDevice = freezed,
|
||||||
|
Object? segmentSkipSettings = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
screenBrightness: freezed == screenBrightness
|
screenBrightness: freezed == screenBrightness
|
||||||
|
|
@ -144,6 +148,10 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
||||||
? _value.audioDevice
|
? _value.audioDevice
|
||||||
: audioDevice // ignore: cast_nullable_to_non_nullable
|
: audioDevice // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
|
segmentSkipSettings: null == segmentSkipSettings
|
||||||
|
? _value.segmentSkipSettings
|
||||||
|
: segmentSkipSettings // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<MediaSegmentType, SegmentSkip>,
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +177,8 @@ abstract class _$$VideoPlayerSettingsModelImplCopyWith<$Res>
|
||||||
AutoNextType nextVideoType,
|
AutoNextType nextVideoType,
|
||||||
Bitrate maxHomeBitrate,
|
Bitrate maxHomeBitrate,
|
||||||
Bitrate maxInternetBitrate,
|
Bitrate maxInternetBitrate,
|
||||||
String? audioDevice});
|
String? audioDevice,
|
||||||
|
Map<MediaSegmentType, SegmentSkip> segmentSkipSettings});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -199,6 +208,7 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
||||||
Object? maxHomeBitrate = null,
|
Object? maxHomeBitrate = null,
|
||||||
Object? maxInternetBitrate = null,
|
Object? maxInternetBitrate = null,
|
||||||
Object? audioDevice = freezed,
|
Object? audioDevice = freezed,
|
||||||
|
Object? segmentSkipSettings = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$VideoPlayerSettingsModelImpl(
|
return _then(_$VideoPlayerSettingsModelImpl(
|
||||||
screenBrightness: freezed == screenBrightness
|
screenBrightness: freezed == screenBrightness
|
||||||
|
|
@ -249,6 +259,10 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
||||||
? _value.audioDevice
|
? _value.audioDevice
|
||||||
: audioDevice // ignore: cast_nullable_to_non_nullable
|
: audioDevice // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
|
segmentSkipSettings: null == segmentSkipSettings
|
||||||
|
? _value._segmentSkipSettings
|
||||||
|
: segmentSkipSettings // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<MediaSegmentType, SegmentSkip>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,8 +283,11 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
||||||
this.nextVideoType = AutoNextType.smart,
|
this.nextVideoType = AutoNextType.smart,
|
||||||
this.maxHomeBitrate = Bitrate.original,
|
this.maxHomeBitrate = Bitrate.original,
|
||||||
this.maxInternetBitrate = Bitrate.original,
|
this.maxInternetBitrate = Bitrate.original,
|
||||||
this.audioDevice})
|
this.audioDevice,
|
||||||
|
final Map<MediaSegmentType, SegmentSkip> segmentSkipSettings =
|
||||||
|
defaultSegmentSkipValues})
|
||||||
: _allowedOrientations = allowedOrientations,
|
: _allowedOrientations = allowedOrientations,
|
||||||
|
_segmentSkipSettings = segmentSkipSettings,
|
||||||
super._();
|
super._();
|
||||||
|
|
||||||
factory _$VideoPlayerSettingsModelImpl.fromJson(Map<String, dynamic> json) =>
|
factory _$VideoPlayerSettingsModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|
@ -317,10 +334,19 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
||||||
final Bitrate maxInternetBitrate;
|
final Bitrate maxInternetBitrate;
|
||||||
@override
|
@override
|
||||||
final String? audioDevice;
|
final String? audioDevice;
|
||||||
|
final Map<MediaSegmentType, SegmentSkip> _segmentSkipSettings;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
Map<MediaSegmentType, SegmentSkip> get segmentSkipSettings {
|
||||||
|
if (_segmentSkipSettings is EqualUnmodifiableMapView)
|
||||||
|
return _segmentSkipSettings;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableMapView(_segmentSkipSettings);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||||
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, playerOptions: $playerOptions, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, maxHomeBitrate: $maxHomeBitrate, maxInternetBitrate: $maxInternetBitrate, audioDevice: $audioDevice)';
|
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, playerOptions: $playerOptions, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, maxHomeBitrate: $maxHomeBitrate, maxInternetBitrate: $maxInternetBitrate, audioDevice: $audioDevice, segmentSkipSettings: $segmentSkipSettings)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -339,7 +365,8 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
||||||
..add(DiagnosticsProperty('nextVideoType', nextVideoType))
|
..add(DiagnosticsProperty('nextVideoType', nextVideoType))
|
||||||
..add(DiagnosticsProperty('maxHomeBitrate', maxHomeBitrate))
|
..add(DiagnosticsProperty('maxHomeBitrate', maxHomeBitrate))
|
||||||
..add(DiagnosticsProperty('maxInternetBitrate', maxInternetBitrate))
|
..add(DiagnosticsProperty('maxInternetBitrate', maxInternetBitrate))
|
||||||
..add(DiagnosticsProperty('audioDevice', audioDevice));
|
..add(DiagnosticsProperty('audioDevice', audioDevice))
|
||||||
|
..add(DiagnosticsProperty('segmentSkipSettings', segmentSkipSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a copy of VideoPlayerSettingsModel
|
/// Create a copy of VideoPlayerSettingsModel
|
||||||
|
|
@ -361,18 +388,20 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
||||||
|
|
||||||
abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
||||||
factory _VideoPlayerSettingsModel(
|
factory _VideoPlayerSettingsModel(
|
||||||
{final double? screenBrightness,
|
{final double? screenBrightness,
|
||||||
final BoxFit videoFit,
|
final BoxFit videoFit,
|
||||||
final bool fillScreen,
|
final bool fillScreen,
|
||||||
final bool hardwareAccel,
|
final bool hardwareAccel,
|
||||||
final bool useLibass,
|
final bool useLibass,
|
||||||
final PlayerOptions? playerOptions,
|
final PlayerOptions? playerOptions,
|
||||||
final double internalVolume,
|
final double internalVolume,
|
||||||
final Set<DeviceOrientation>? allowedOrientations,
|
final Set<DeviceOrientation>? allowedOrientations,
|
||||||
final AutoNextType nextVideoType,
|
final AutoNextType nextVideoType,
|
||||||
final Bitrate maxHomeBitrate,
|
final Bitrate maxHomeBitrate,
|
||||||
final Bitrate maxInternetBitrate,
|
final Bitrate maxInternetBitrate,
|
||||||
final String? audioDevice}) = _$VideoPlayerSettingsModelImpl;
|
final String? audioDevice,
|
||||||
|
final Map<MediaSegmentType, SegmentSkip> segmentSkipSettings}) =
|
||||||
|
_$VideoPlayerSettingsModelImpl;
|
||||||
_VideoPlayerSettingsModel._() : super._();
|
_VideoPlayerSettingsModel._() : super._();
|
||||||
|
|
||||||
factory _VideoPlayerSettingsModel.fromJson(Map<String, dynamic> json) =
|
factory _VideoPlayerSettingsModel.fromJson(Map<String, dynamic> json) =
|
||||||
|
|
@ -402,6 +431,8 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
||||||
Bitrate get maxInternetBitrate;
|
Bitrate get maxInternetBitrate;
|
||||||
@override
|
@override
|
||||||
String? get audioDevice;
|
String? get audioDevice;
|
||||||
|
@override
|
||||||
|
Map<MediaSegmentType, SegmentSkip> get segmentSkipSettings;
|
||||||
|
|
||||||
/// Create a copy of VideoPlayerSettingsModel
|
/// Create a copy of VideoPlayerSettingsModel
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,12 @@ _$VideoPlayerSettingsModelImpl _$$VideoPlayerSettingsModelImplFromJson(
|
||||||
$enumDecodeNullable(_$BitrateEnumMap, json['maxInternetBitrate']) ??
|
$enumDecodeNullable(_$BitrateEnumMap, json['maxInternetBitrate']) ??
|
||||||
Bitrate.original,
|
Bitrate.original,
|
||||||
audioDevice: json['audioDevice'] as String?,
|
audioDevice: json['audioDevice'] as String?,
|
||||||
|
segmentSkipSettings:
|
||||||
|
(json['segmentSkipSettings'] as Map<String, dynamic>?)?.map(
|
||||||
|
(k, e) => MapEntry($enumDecode(_$MediaSegmentTypeEnumMap, k),
|
||||||
|
$enumDecode(_$SegmentSkipEnumMap, e)),
|
||||||
|
) ??
|
||||||
|
defaultSegmentSkipValues,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
|
Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
|
||||||
|
|
@ -50,6 +56,8 @@ Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
|
||||||
'maxHomeBitrate': _$BitrateEnumMap[instance.maxHomeBitrate]!,
|
'maxHomeBitrate': _$BitrateEnumMap[instance.maxHomeBitrate]!,
|
||||||
'maxInternetBitrate': _$BitrateEnumMap[instance.maxInternetBitrate]!,
|
'maxInternetBitrate': _$BitrateEnumMap[instance.maxInternetBitrate]!,
|
||||||
'audioDevice': instance.audioDevice,
|
'audioDevice': instance.audioDevice,
|
||||||
|
'segmentSkipSettings': instance.segmentSkipSettings.map((k, e) =>
|
||||||
|
MapEntry(_$MediaSegmentTypeEnumMap[k]!, _$SegmentSkipEnumMap[e]!)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const _$BoxFitEnumMap = {
|
const _$BoxFitEnumMap = {
|
||||||
|
|
@ -95,6 +103,21 @@ const _$BitrateEnumMap = {
|
||||||
Bitrate.b4Mbps: 'b4Mbps',
|
Bitrate.b4Mbps: 'b4Mbps',
|
||||||
Bitrate.b3Mbps: 'b3Mbps',
|
Bitrate.b3Mbps: 'b3Mbps',
|
||||||
Bitrate.b1_5Mbps: 'b1_5Mbps',
|
Bitrate.b1_5Mbps: 'b1_5Mbps',
|
||||||
Bitrate.b420Kbps: 'b420Kbps',
|
|
||||||
Bitrate.b720Kbps: 'b720Kbps',
|
Bitrate.b720Kbps: 'b720Kbps',
|
||||||
|
Bitrate.b420Kbps: 'b420Kbps',
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$SegmentSkipEnumMap = {
|
||||||
|
SegmentSkip.none: 'none',
|
||||||
|
SegmentSkip.askToSkip: 'askToSkip',
|
||||||
|
SegmentSkip.skip: 'skip',
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$MediaSegmentTypeEnumMap = {
|
||||||
|
MediaSegmentType.unknown: 'unknown',
|
||||||
|
MediaSegmentType.commercial: 'commercial',
|
||||||
|
MediaSegmentType.preview: 'preview',
|
||||||
|
MediaSegmentType.recap: 'recap',
|
||||||
|
MediaSegmentType.outro: 'outro',
|
||||||
|
MediaSegmentType.intro: 'intro',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'movies_details_provider.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$movieDetailsHash() => r'da07dcdb6e1955119df64f8a6a5634216435982c';
|
String _$movieDetailsHash() => r'872ea61464ef8493c7e6c559c526377f1c8f6a6d';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
import 'package:fladder/models/items/media_segments_model.dart';
|
||||||
import 'package:fladder/models/settings/home_settings_model.dart';
|
import 'package:fladder/models/settings/home_settings_model.dart';
|
||||||
import 'package:fladder/models/settings/video_player_settings.dart';
|
import 'package:fladder/models/settings/video_player_settings.dart';
|
||||||
import 'package:fladder/providers/connectivity_provider.dart';
|
import 'package:fladder/providers/connectivity_provider.dart';
|
||||||
|
|
@ -130,6 +132,40 @@ class _PlayerSettingsPageState extends ConsumerState<PlayerSettingsPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
SettingsLabelDivider(label: context.localized.mediaSegmentActions),
|
||||||
|
...videoSettings.segmentSkipSettings.entries.sorted((a, b) => b.key.index.compareTo(a.key.index)).map(
|
||||||
|
(entry) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
entry.key.label(context),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
EnumBox(
|
||||||
|
current: entry.value.label(context),
|
||||||
|
itemBuilder: (context) => SegmentSkip.values
|
||||||
|
.map(
|
||||||
|
(value) => PopupMenuItem(
|
||||||
|
value: value,
|
||||||
|
child: Text(value.label(context)),
|
||||||
|
onTap: () {
|
||||||
|
final newEntries = videoSettings.segmentSkipSettings.map(
|
||||||
|
(key, currentValue) => MapEntry(key, key == entry.key ? value : currentValue));
|
||||||
|
ref.read(videoPlayerSettingsProvider.notifier).state =
|
||||||
|
ref.read(videoPlayerSettingsProvider).copyWith(segmentSkipSettings: newEntries);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
SettingsLabelDivider(label: context.localized.advanced),
|
SettingsLabelDivider(label: context.localized.advanced),
|
||||||
if (PlayerOptions.available.length != 1)
|
if (PlayerOptions.available.length != 1)
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
|
|
|
||||||
|
|
@ -65,16 +65,22 @@ class OpenQueueButton extends ConsumerWidget {
|
||||||
|
|
||||||
class SkipSegmentButton extends ConsumerWidget {
|
class SkipSegmentButton extends ConsumerWidget {
|
||||||
final MediaSegment? segment;
|
final MediaSegment? segment;
|
||||||
|
final SegmentSkip? skipType;
|
||||||
final bool isOverlayVisible;
|
final bool isOverlayVisible;
|
||||||
|
|
||||||
final Function() pressedSkip;
|
final Function() pressedSkip;
|
||||||
const SkipSegmentButton(
|
const SkipSegmentButton({
|
||||||
{required this.segment, required this.isOverlayVisible, required this.pressedSkip, super.key});
|
required this.segment,
|
||||||
|
this.skipType,
|
||||||
|
required this.isOverlayVisible,
|
||||||
|
required this.pressedSkip,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return AnimatedFadeSize(
|
return AnimatedFadeSize(
|
||||||
child: segment != null
|
child: segment != null && skipType != SegmentSkip.none
|
||||||
? AnimatedOpacity(
|
? AnimatedOpacity(
|
||||||
opacity: isOverlayVisible ? 1 : 0.15,
|
opacity: isOverlayVisible ? 1 : 0.15,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,13 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
||||||
final position = ref.watch(mediaPlaybackProvider.select((value) => value.position));
|
final position = ref.watch(mediaPlaybackProvider.select((value) => value.position));
|
||||||
MediaSegment? segment = mediaSegments?.atPosition(position);
|
MediaSegment? segment = mediaSegments?.atPosition(position);
|
||||||
bool forceShow = segment?.forceShow(position) ?? false;
|
bool forceShow = segment?.forceShow(position) ?? false;
|
||||||
|
final segmentSkipType = ref
|
||||||
|
.watch(videoPlayerSettingsProvider.select((value) => value.segmentSkipSettings[segment?.type]));
|
||||||
|
final autoSkip =
|
||||||
|
forceShow == true && segmentSkipType == SegmentSkip.skip && player.lastState?.buffering == false;
|
||||||
|
if (autoSkip) {
|
||||||
|
skipToSegmentEnd(segment);
|
||||||
|
}
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Align(
|
Align(
|
||||||
|
|
@ -174,6 +181,7 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
child: SkipSegmentButton(
|
child: SkipSegmentButton(
|
||||||
segment: segment,
|
segment: segment,
|
||||||
|
skipType: segmentSkipType,
|
||||||
isOverlayVisible: forceShow ? true : showOverlay,
|
isOverlayVisible: forceShow ? true : showOverlay,
|
||||||
pressedSkip: () => skipToSegmentEnd(segment),
|
pressedSkip: () => skipToSegmentEnd(segment),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue