mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
Merge branch 'develop' of https://github.com/DonutWare/Fladder into develop
This commit is contained in:
commit
98130f953e
11 changed files with 170 additions and 5 deletions
|
|
@ -1099,5 +1099,11 @@
|
|||
"deleteFilterConfirmation": "Are you sure you want to delete this filter?",
|
||||
"libraryFiltersLimitReached" : "Filter limit reached (10) remove some filters",
|
||||
"libraryFiltersRemoveAll": "Remove all filters",
|
||||
"libraryFiltersRemoveAllConfirm": "This will delete all saved filters for every library"
|
||||
"libraryFiltersRemoveAllConfirm": "This will delete all saved filters for every library",
|
||||
"playerSettingsOrientationTitle": "Player orientation",
|
||||
"playerSettingsOrientationDesc": "Force the video player into certain orientations",
|
||||
"deviceOrientationPortraitUp": "Portrait Up",
|
||||
"deviceOrientationPortraitDown": "Portrait Down",
|
||||
"deviceOrientationLandscapeLeft": "Landscape Left",
|
||||
"deviceOrientationLandscapeRight": "Landscape Right"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
|
@ -20,6 +21,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
|
|||
@Default(true) bool hardwareAccel,
|
||||
@Default(false) bool useLibass,
|
||||
@Default(100) double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
@Default(AutoNextType.static) AutoNextType nextVideoType,
|
||||
String? audioDevice,
|
||||
}) = _VideoPlayerSettingsModel;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ mixin _$VideoPlayerSettingsModel {
|
|||
bool get hardwareAccel => throw _privateConstructorUsedError;
|
||||
bool get useLibass => throw _privateConstructorUsedError;
|
||||
double get internalVolume => throw _privateConstructorUsedError;
|
||||
Set<DeviceOrientation>? get allowedOrientations =>
|
||||
throw _privateConstructorUsedError;
|
||||
AutoNextType get nextVideoType => throw _privateConstructorUsedError;
|
||||
String? get audioDevice => throw _privateConstructorUsedError;
|
||||
|
||||
|
|
@ -53,6 +55,7 @@ abstract class $VideoPlayerSettingsModelCopyWith<$Res> {
|
|||
bool hardwareAccel,
|
||||
bool useLibass,
|
||||
double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
AutoNextType nextVideoType,
|
||||
String? audioDevice});
|
||||
}
|
||||
|
|
@ -79,6 +82,7 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
|||
Object? hardwareAccel = null,
|
||||
Object? useLibass = null,
|
||||
Object? internalVolume = null,
|
||||
Object? allowedOrientations = freezed,
|
||||
Object? nextVideoType = null,
|
||||
Object? audioDevice = freezed,
|
||||
}) {
|
||||
|
|
@ -107,6 +111,10 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
|
|||
? _value.internalVolume
|
||||
: internalVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
allowedOrientations: freezed == allowedOrientations
|
||||
? _value.allowedOrientations
|
||||
: allowedOrientations // ignore: cast_nullable_to_non_nullable
|
||||
as Set<DeviceOrientation>?,
|
||||
nextVideoType: null == nextVideoType
|
||||
? _value.nextVideoType
|
||||
: nextVideoType // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -135,6 +143,7 @@ abstract class _$$VideoPlayerSettingsModelImplCopyWith<$Res>
|
|||
bool hardwareAccel,
|
||||
bool useLibass,
|
||||
double internalVolume,
|
||||
Set<DeviceOrientation>? allowedOrientations,
|
||||
AutoNextType nextVideoType,
|
||||
String? audioDevice});
|
||||
}
|
||||
|
|
@ -160,6 +169,7 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
|||
Object? hardwareAccel = null,
|
||||
Object? useLibass = null,
|
||||
Object? internalVolume = null,
|
||||
Object? allowedOrientations = freezed,
|
||||
Object? nextVideoType = null,
|
||||
Object? audioDevice = freezed,
|
||||
}) {
|
||||
|
|
@ -188,6 +198,10 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
|
|||
? _value.internalVolume
|
||||
: internalVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
allowedOrientations: freezed == allowedOrientations
|
||||
? _value._allowedOrientations
|
||||
: allowedOrientations // ignore: cast_nullable_to_non_nullable
|
||||
as Set<DeviceOrientation>?,
|
||||
nextVideoType: null == nextVideoType
|
||||
? _value.nextVideoType
|
||||
: nextVideoType // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -211,9 +225,11 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
this.hardwareAccel = true,
|
||||
this.useLibass = false,
|
||||
this.internalVolume = 100,
|
||||
final Set<DeviceOrientation>? allowedOrientations,
|
||||
this.nextVideoType = AutoNextType.static,
|
||||
this.audioDevice})
|
||||
: super._();
|
||||
: _allowedOrientations = allowedOrientations,
|
||||
super._();
|
||||
|
||||
factory _$VideoPlayerSettingsModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$VideoPlayerSettingsModelImplFromJson(json);
|
||||
|
|
@ -235,6 +251,17 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
@override
|
||||
@JsonKey()
|
||||
final double internalVolume;
|
||||
final Set<DeviceOrientation>? _allowedOrientations;
|
||||
@override
|
||||
Set<DeviceOrientation>? get allowedOrientations {
|
||||
final value = _allowedOrientations;
|
||||
if (value == null) return null;
|
||||
if (_allowedOrientations is EqualUnmodifiableSetView)
|
||||
return _allowedOrientations;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableSetView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final AutoNextType nextVideoType;
|
||||
|
|
@ -243,7 +270,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, internalVolume: $internalVolume, nextVideoType: $nextVideoType, audioDevice: $audioDevice)';
|
||||
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, audioDevice: $audioDevice)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -257,6 +284,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
|
|||
..add(DiagnosticsProperty('hardwareAccel', hardwareAccel))
|
||||
..add(DiagnosticsProperty('useLibass', useLibass))
|
||||
..add(DiagnosticsProperty('internalVolume', internalVolume))
|
||||
..add(DiagnosticsProperty('allowedOrientations', allowedOrientations))
|
||||
..add(DiagnosticsProperty('nextVideoType', nextVideoType))
|
||||
..add(DiagnosticsProperty('audioDevice', audioDevice));
|
||||
}
|
||||
|
|
@ -286,6 +314,7 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
|||
final bool hardwareAccel,
|
||||
final bool useLibass,
|
||||
final double internalVolume,
|
||||
final Set<DeviceOrientation>? allowedOrientations,
|
||||
final AutoNextType nextVideoType,
|
||||
final String? audioDevice}) = _$VideoPlayerSettingsModelImpl;
|
||||
_VideoPlayerSettingsModel._() : super._();
|
||||
|
|
@ -306,6 +335,8 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
|
|||
@override
|
||||
double get internalVolume;
|
||||
@override
|
||||
Set<DeviceOrientation>? get allowedOrientations;
|
||||
@override
|
||||
AutoNextType get nextVideoType;
|
||||
@override
|
||||
String? get audioDevice;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ _$VideoPlayerSettingsModelImpl _$$VideoPlayerSettingsModelImplFromJson(
|
|||
hardwareAccel: json['hardwareAccel'] as bool? ?? true,
|
||||
useLibass: json['useLibass'] as bool? ?? false,
|
||||
internalVolume: (json['internalVolume'] as num?)?.toDouble() ?? 100,
|
||||
allowedOrientations: (json['allowedOrientations'] as List<dynamic>?)
|
||||
?.map((e) => $enumDecode(_$DeviceOrientationEnumMap, e))
|
||||
.toSet(),
|
||||
nextVideoType:
|
||||
$enumDecodeNullable(_$AutoNextTypeEnumMap, json['nextVideoType']) ??
|
||||
AutoNextType.static,
|
||||
|
|
@ -31,6 +34,9 @@ Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
|
|||
'hardwareAccel': instance.hardwareAccel,
|
||||
'useLibass': instance.useLibass,
|
||||
'internalVolume': instance.internalVolume,
|
||||
'allowedOrientations': instance.allowedOrientations
|
||||
?.map((e) => _$DeviceOrientationEnumMap[e]!)
|
||||
.toList(),
|
||||
'nextVideoType': _$AutoNextTypeEnumMap[instance.nextVideoType]!,
|
||||
'audioDevice': instance.audioDevice,
|
||||
};
|
||||
|
|
@ -45,6 +51,13 @@ const _$BoxFitEnumMap = {
|
|||
BoxFit.scaleDown: 'scaleDown',
|
||||
};
|
||||
|
||||
const _$DeviceOrientationEnumMap = {
|
||||
DeviceOrientation.portraitUp: 'portraitUp',
|
||||
DeviceOrientation.landscapeLeft: 'landscapeLeft',
|
||||
DeviceOrientation.portraitDown: 'portraitDown',
|
||||
DeviceOrientation.landscapeRight: 'landscapeRight',
|
||||
};
|
||||
|
||||
const _$AutoNextTypeEnumMap = {
|
||||
AutoNextType.off: 'off',
|
||||
AutoNextType.smart: 'smart',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'library_filters_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$libraryFiltersHash() => r'7b4661651df7e0c019dca5bb7eb6433bcd8b3ebb';
|
||||
String _$libraryFiltersHash() => r'fd98699d8d7c1db6daefa6e53d5d90f989a8f776';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:screen_brightness/screen_brightness.dart';
|
||||
|
|
@ -63,4 +64,7 @@ class VideoPlayerSettingsProviderNotifier extends StateNotifier<VideoPlayerSetti
|
|||
state = state.copyWith(internalVolume: value);
|
||||
ref.read(videoPlayerProvider).setVolume(value);
|
||||
}
|
||||
|
||||
void toggleOrientation(Set<DeviceOrientation>? orientation) =>
|
||||
state = state.copyWith(allowedOrientations: orientation);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ final showSyncButtonProviderProvider = AutoDisposeProvider<bool>.internal(
|
|||
);
|
||||
|
||||
typedef ShowSyncButtonProviderRef = AutoDisposeProviderRef<bool>;
|
||||
String _$userHash() => r'418b3d4ade830479db9f48c7793ac5b646778b82';
|
||||
String _$userHash() => r'e83369c0d569d5a862aa1b92f3f0a45a9d1fe446';
|
||||
|
||||
/// See also [User].
|
||||
@ProviderFor(User)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:fladder/screens/settings/widgets/settings_label_divider.dart';
|
|||
import 'package:fladder/screens/settings/widgets/settings_message_box.dart';
|
||||
import 'package:fladder/screens/settings/widgets/subtitle_editor.dart';
|
||||
import 'package:fladder/screens/shared/animated_fade_size.dart';
|
||||
import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/box_fit_extension.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
|
|
@ -151,6 +152,12 @@ class _PlayerSettingsPageState extends ConsumerState<PlayerSettingsPage> {
|
|||
);
|
||||
},
|
||||
),
|
||||
if (!AdaptiveLayout.of(context).isDesktop && !kIsWeb)
|
||||
SettingsListTile(
|
||||
label: Text(context.localized.playerSettingsOrientationTitle),
|
||||
subLabel: Text(context.localized.playerSettingsOrientationDesc),
|
||||
onTap: () => showOrientationOptions(context, ref),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:ficonsax/ficonsax.dart';
|
||||
|
|
@ -19,6 +21,7 @@ import 'package:fladder/screens/playlists/add_to_playlists.dart';
|
|||
import 'package:fladder/screens/video_player/components/video_player_queue.dart';
|
||||
import 'package:fladder/screens/video_player/components/video_subtitle_controls.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/device_orientation_extension.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:fladder/util/refresh_state.dart';
|
||||
|
|
@ -176,6 +179,11 @@ class _VideoOptionsMobileState extends ConsumerState<VideoOptions> {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (!AdaptiveLayout.of(context).isDesktop && !kIsWeb)
|
||||
SpacedListTile(
|
||||
title: Text(context.localized.playerSettingsOrientationTitle),
|
||||
onTap: () => showOrientationOptions(context, ref),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
|
@ -492,3 +500,70 @@ Future<void> showPlaybackSpeed(BuildContext context) {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> showOrientationOptions(BuildContext context, WidgetRef ref) async {
|
||||
Set<DeviceOrientation> orientations = ref
|
||||
.read(videoPlayerSettingsProvider
|
||||
.select((value) => value.allowedOrientations ?? Set.from(DeviceOrientation.values)))
|
||||
.toSet();
|
||||
|
||||
void toggleOrientation(DeviceOrientation orientation) {
|
||||
if (orientations.contains(orientation) && orientations.length > 1) {
|
||||
orientations.remove(orientation);
|
||||
} else {
|
||||
orientations.add(orientation);
|
||||
}
|
||||
}
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(builder: (context, state) {
|
||||
return SimpleDialog(
|
||||
contentPadding: const EdgeInsets.only(top: 8, bottom: 24),
|
||||
title: Row(children: [Text(context.localized.playbackRate)]),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12).copyWith(top: 6),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Divider(),
|
||||
...DeviceOrientation.values.map(
|
||||
(orientation) => CheckboxListTile.adaptive(
|
||||
title: Text(orientation.label(context)),
|
||||
value: orientations.contains(orientation),
|
||||
onChanged: (value) {
|
||||
state(() => toggleOrientation(orientation));
|
||||
},
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(context.localized.cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
ref.read(videoPlayerSettingsProvider.notifier).toggleOrientation(orientations);
|
||||
},
|
||||
child: Text(context.localized.save),
|
||||
),
|
||||
].addInBetween(const SizedBox(width: 8)),
|
||||
)
|
||||
].addInBetween(const SizedBox(width: 8)),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
|
|
@ -49,6 +50,7 @@ class _VideoPlayerState extends ConsumerState<VideoPlayer> with WidgetsBindingOb
|
|||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
SystemChrome.setPreferredOrientations(DeviceOrientation.values);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +60,9 @@ class _VideoPlayerState extends ConsumerState<VideoPlayer> with WidgetsBindingOb
|
|||
WidgetsBinding.instance.addObserver(this);
|
||||
Future.microtask(() {
|
||||
ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.fullScreen));
|
||||
final orientations = ref.read(videoPlayerSettingsProvider.select((value) => value.allowedOrientations));
|
||||
SystemChrome.setPreferredOrientations(
|
||||
orientations?.isNotEmpty == true ? orientations!.toList() : DeviceOrientation.values);
|
||||
return ref.read(videoPlayerSettingsProvider.notifier).setSavedBrightness();
|
||||
});
|
||||
}
|
||||
|
|
@ -70,6 +75,15 @@ class _VideoPlayerState extends ConsumerState<VideoPlayer> with WidgetsBindingOb
|
|||
|
||||
final playerController = ref.watch(videoPlayerProvider.select((value) => value.controller));
|
||||
|
||||
ref.listen(
|
||||
videoPlayerSettingsProvider.select((value) => value.allowedOrientations),
|
||||
(previous, next) {
|
||||
if (previous != next) {
|
||||
SystemChrome.setPreferredOrientations(next?.isNotEmpty == true ? next!.toList() : DeviceOrientation.values);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return Material(
|
||||
color: Colors.black,
|
||||
child: Theme(
|
||||
|
|
|
|||
13
lib/util/device_orientation_extension.dart
Normal file
13
lib/util/device_orientation_extension.dart
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
|
||||
extension DeviceOrientationExtension on DeviceOrientation {
|
||||
String label(BuildContext context) => switch (this) {
|
||||
DeviceOrientation.portraitUp => context.localized.deviceOrientationPortraitUp,
|
||||
DeviceOrientation.landscapeLeft => context.localized.deviceOrientationLandscapeLeft,
|
||||
DeviceOrientation.portraitDown => context.localized.deviceOrientationPortraitDown,
|
||||
DeviceOrientation.landscapeRight => context.localized.deviceOrientationLandscapeRight,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue