Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add customizable skip forward steps setting #413

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const hideFilteredVideo = 'hide-filtered-videos';
const remeberPlaybackSpeed = 'remember-playback-speed';
const lastSpeedSettingName = 'last-speed';
const lockOrientationFullScreen = 'lock-orientation-fullscreen';
const skipStepSettingName = 'skip-step';
const skipExponentialSettingName = 'skip-exponentially';
const fillFullScreen = 'fill-fullscreen';
const appLayoutSettingName = 'app-layout';
const navigationBarLabelBehaviorSettingName = 'navigation-bar-label-behavior';
Expand Down
20 changes: 20 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,26 @@
"@copySettingsAsJsonDescription": {
"description": ""
},
"seeking": "Seeking",
"@seeking": {
"description": "category for settings related to seeking in a video"
},
"skipStep": "Skip forward/backward step",
"@skipStep": {
"description": "Title for the settings to set the skipping step"
},
"skipStepDescription": "Seconds to skip on forward/backward actions",
"@skipStepDescription": {
"description": "Title for the settings to set the skipping step"
},
"exponentialSkip": "Exponential skip forward/backward",
"@exponentialSkip": {
"description": "Title for the setting to enable the exponential skipping"
},
"exponentialSkipDescription": "The more you skip forward, the bigger the step is.",
"@exponentialSkipDescription": {
"description": "Title for the setting to enable the exponential skipping"
},
"enabled": "Enabled",
"@enabled": {
"description": "Text to show something is enabled"
Expand Down
20 changes: 13 additions & 7 deletions lib/player/states/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const double targetHeight = 69;
const double miniPlayerThreshold = 300;
const skipToVideoThrottleName = 'skip-to-video';
const double bigPlayerThreshold = 700;
const defaultStep = 10;
const stepMultiplier = 1.15;

var log = Logger('MiniPlayerController');
Expand Down Expand Up @@ -123,6 +122,9 @@ class PlayerCubit extends Cubit<PlayerState> with WidgetsBindingObserver {
}

onReady() async {
emit(state.copyWith(
forwardStep: settings.state.skipStep,
rewindStep: settings.state.skipStep));
if (!isTv) {
WidgetsBinding.instance.addObserver(this);

Expand Down Expand Up @@ -564,8 +566,8 @@ class PlayerCubit extends Cubit<PlayerState> with WidgetsBindingObserver {

emit(state.copyWith(
position: Duration.zero,
forwardStep: defaultStep,
rewindStep: defaultStep,
forwardStep: settings.state.skipStep,
rewindStep: settings.state.skipStep,
mediaCommand: mediaCommand,
currentlyPlaying: currentlyPlaying,
offlineCurrentlyPlaying: offlineCurrentlyPlaying));
Expand Down Expand Up @@ -779,11 +781,13 @@ class PlayerCubit extends Cubit<PlayerState> with WidgetsBindingObserver {
log.info('fast forward $newPosition - step: ${state.forwardStep}');
emit(state.copyWith(
totalFastForward: state.totalFastForward + state.forwardStep,
forwardStep: (state.forwardStep * stepMultiplier).floor(),
forwardStep: (state.forwardStep *
(settings.state.skipExponentially ? stepMultiplier : 1))
.floor(),
));
EasyDebounce.debounce('fast-forward-step', const Duration(seconds: 1), () {
emit(state.copyWith(
forwardStep: defaultStep,
forwardStep: settings.state.skipStep,
totalFastForward: 0,
));
});
Expand All @@ -793,11 +797,13 @@ class PlayerCubit extends Cubit<PlayerState> with WidgetsBindingObserver {
seek(state.position - Duration(seconds: state.rewindStep));
emit(state.copyWith(
totalRewind: state.totalRewind + state.rewindStep,
rewindStep: (state.rewindStep * stepMultiplier).floor(),
rewindStep: (state.rewindStep *
(settings.state.skipExponentially ? stepMultiplier : 1))
.floor(),
));
EasyDebounce.debounce('fast-rewind-step', const Duration(seconds: 1), () {
emit(state.copyWith(
rewindStep: defaultStep,
rewindStep: settings.state.skipStep,
totalRewind: 0,
));
});
Expand Down
60 changes: 33 additions & 27 deletions lib/player/views/tv/components/player_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ class TvPlayerControls extends StatelessWidget {
child: BlocBuilder<TvPlayerControlsCubit, TvPlayerControlsState>(
builder: (context, _) {
var cubit = context.read<TvPlayerControlsCubit>();
var mpc = player.state;
var currentlyPlaying = context
.select((PlayerCubit value) => value.state.currentlyPlaying);
var videos =
context.select((PlayerCubit value) => value.state.videos);
var isPlaying =
context.select((PlayerCubit value) => value.state.isPlaying);
var position =
context.select((PlayerCubit value) => value.state.position);

return BlocListener<PlayerCubit, PlayerState>(
listenWhen: (previous, current) =>
Expand Down Expand Up @@ -90,7 +97,7 @@ class TvPlayerControls extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
mpc.currentlyPlaying?.title ?? '',
currentlyPlaying?.title ?? '',
style: textTheme.headlineLarge
?.copyWith(color: Colors.white),
),
Expand All @@ -101,9 +108,9 @@ class TvPlayerControls extends StatelessWidget {
children: [
Thumbnail(
thumbnailUrl:
ImageObject.getBestThumbnail(mpc
.currentlyPlaying
?.authorThumbnails)
ImageObject.getBestThumbnail(
currentlyPlaying
?.authorThumbnails)
?.url ??
'',
width: 40,
Expand All @@ -116,8 +123,7 @@ class TvPlayerControls extends StatelessWidget {
padding: const EdgeInsets.only(
left: 8.0, right: 20),
child: Text(
mpc.currentlyPlaying?.author ??
'',
currentlyPlaying?.author ?? '',
style: textTheme.headlineSmall
?.copyWith(
color: Colors.white),
Expand Down Expand Up @@ -161,7 +167,7 @@ class TvPlayerControls extends StatelessWidget {
padding:
const EdgeInsets.all(8.0),
child: Icon(
mpc.isPlaying
isPlaying
? Icons.pause
: Icons.play_arrow,
size: 50,
Expand All @@ -170,7 +176,7 @@ class TvPlayerControls extends StatelessWidget {
),
),
Visibility(
visible: mpc.videos.length > 1,
visible: videos.length > 1,
child: Padding(
padding: const EdgeInsets.only(
right: 16.0),
Expand Down Expand Up @@ -224,7 +230,7 @@ class TvPlayerControls extends StatelessWidget {
),
),
Visibility(
visible: mpc.videos.length > 1,
visible: videos.length > 1,
child: TvButton(
onPressed: (context) =>
player.playNext(),
Expand Down Expand Up @@ -282,7 +288,7 @@ class TvPlayerControls extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
(mpc.currentlyPlaying?.liveNow ?? false)
(currentlyPlaying?.liveNow ?? false)
? Container(
decoration: BoxDecoration(
color: Colors.red,
Expand Down Expand Up @@ -339,11 +345,11 @@ class TvPlayerControls extends StatelessWidget {
),
))
: const SizedBox.shrink()),
if (!(mpc.currentlyPlaying?.liveNow ?? false))
if (!(currentlyPlaying?.liveNow ?? false))
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: Text(
'${prettyDuration(player.state.position)} / ${prettyDuration(player.duration)}',
'${prettyDuration(position)} / ${prettyDuration(player.duration)}',
style: textTheme.titleLarge
?.copyWith(color: Colors.white),
),
Expand Down Expand Up @@ -377,20 +383,20 @@ class TvPlayerControls extends StatelessWidget {
onSelect: (ctx, video) =>
onVideoQueueSelected(
ctx, cubit, video),
paginatedVideoList: FixedItemList(mpc
.videos
.map((e) => VideoInList(
e.title,
e.videoId,
e.lengthSeconds,
null,
e.author,
e.authorId,
e.authorUrl,
null,
null,
e.videoThumbnails))
.toList())),
paginatedVideoList: FixedItemList(
videos
.map((e) => VideoInList(
e.title,
e.videoId,
e.lengthSeconds,
null,
e.author,
e.authorId,
e.authorUrl,
null,
null,
e.videoThumbnails))
.toList())),
],
),
))
Expand Down
25 changes: 25 additions & 0 deletions lib/settings/states/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ part 'settings.freezed.dart';

const String subtitleDefaultSize = '14';
const String searchHistoryDefaultLength = '12';
const skipSteps = [5, 10, 15, 20, 30, 60];
const defaultStep = 10;

enum EnableBackGroundNotificationResponse {
ok,
Expand Down Expand Up @@ -116,6 +118,19 @@ class SettingsCubit extends Cubit<SettingsState> {
appCubit.rebuildApp();
}

changeSkipStep({required bool increase}) {
int index = skipSteps.indexOf(state.skipStep);
if (increase) {
if (index < skipSteps.length - 1) {
skipStep = skipSteps[index + 1];
}
} else {
if (index > 0) {
skipStep = skipSteps[index - 1];
}
}
}

changeSubtitleSize({required bool increase}) {
if (increase) {
subtitleSize = state.subtitleSize + 1;
Expand Down Expand Up @@ -407,6 +422,10 @@ class SettingsCubit extends Cubit<SettingsState> {

set dearrowThumbnails(bool b) => _set(dearrowThumbnailsSettingName, b);

set skipStep(int s) => _set(skipStepSettingName, s);

set skipExponentially(bool b) => _set(skipExponentialSettingName, b);

void _set<T>(String name, T value) {
var settings = Map<String, SettingsValue>.from(state.settings);
if (value == null) {
Expand Down Expand Up @@ -492,6 +511,12 @@ class SettingsState with _$SettingsState {
bool get forceLandscapeFullScreen =>
_get(lockOrientationFullScreen)?.value == 'true';

int get skipStep =>
int.parse(_get(skipStepSettingName)?.value ?? defaultStep.toString());

bool get skipExponentially =>
(_get(skipExponentialSettingName)?.value ?? 'true') == 'true';

ThemeMode get themeMode => ThemeMode.values.firstWhere(
(element) => element.name == _get(themeModeSettingName)?.value,
orElse: () => ThemeMode.system);
Expand Down
27 changes: 27 additions & 0 deletions lib/settings/views/screens/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ class VideoPlayerSettingsScreen extends StatelessWidget {
description: Text(locals.fillFullscreenDescription),
),
]),
SettingsSection(title: Text(locals.seeking), tiles: [
SettingsTile(
leading: const Icon(Icons.fast_forward),
title: Text(locals.skipStep),
description: Text(locals.skipStepDescription),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () =>
cubit.changeSkipStep(increase: false),
icon: const Icon(Icons.remove)),
Text(_.skipStep.floor().toString()),
IconButton(
onPressed: () => cubit.changeSkipStep(increase: true),
icon: const Icon(Icons.add)),
],
),
),
SettingsTile.switchTile(
leading: const Icon(Icons.moving),
initialValue: _.skipExponentially,
onToggle: (value) => cubit.skipExponentially = value,
title: Text(locals.exponentialSkip),
description: Text(locals.exponentialSkipDescription),
),
]),
SettingsSection(title: Text(locals.subtitles), tiles: [
SettingsTile(
leading: const Icon(Icons.format_size),
Expand Down
42 changes: 38 additions & 4 deletions lib/settings/views/tv/screens/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,25 @@ class TVSettingsScreen extends StatelessWidget {
onSelected: (context) => cubit.toggleProxy(!_.useProxy),
trailing: Switch(onChanged: (value) {}, value: _.useProxy),
),
AdjustmentSettingTile(
title: locals.skipStep,
value: _.skipStep.floor(),
description: locals.skipStepDescription,
possibleValues: skipSteps,
onNewValue: (i) => cubit.skipStep = i,
),
SettingsTile(
title: locals.exponentialSkip,
description: locals.exponentialSkipDescription,
onSelected: (context) =>
cubit.skipExponentially = !_.skipExponentially,
trailing:
Switch(onChanged: (value) {}, value: _.skipExponentially),
),
AdjustmentSettingTile(
title: locals.subtitleFontSize,
value: _.subtitleSize.floor(),
step: 1,
description: locals.subtitleFontSizeDescription,
onNewValue: cubit.setSubtitleSize,
),
Expand Down Expand Up @@ -282,7 +298,8 @@ class SettingsTitle extends StatelessWidget {
class AdjustmentSettingTile extends StatelessWidget {
final String title;
final int value;
final int step;
final int? step;
final List<int>? possibleValues;
final String? description;
final Function(int) onNewValue;

Expand All @@ -292,17 +309,34 @@ class AdjustmentSettingTile extends StatelessWidget {
required this.title,
this.description,
required this.value,
this.step = 1});
this.possibleValues,
this.step})
: assert(step == null || possibleValues == null,
'Can\' have both step and possible values');

onKeyEvent(FocusNode node, KeyEvent event, BuildContext ctx) {
if (event is KeyUpEvent) {
log.fine('onTvSelect, ${event.logicalKey}, $event');
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
onNewValue(value - step);
if (step != null) {
onNewValue(value - step!);
} else if (possibleValues != null) {
int index = possibleValues!.indexOf(value);
if (index > 0) {
onNewValue(possibleValues![index - 1]);
}
}
return KeyEventResult.handled;
}
if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
onNewValue(value + step);
if (step != null) {
onNewValue(value + step!);
} else if (possibleValues != null) {
int index = possibleValues!.indexOf(value);
if (index < possibleValues!.length - 1) {
onNewValue(possibleValues![index + 1]);
}
}
return KeyEventResult.handled;
}
}
Expand Down