feature: Video quality options (#234)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-02-23 13:29:59 +01:00 committed by GitHub
parent 957ad6c991
commit 935d6fe176
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 644 additions and 232 deletions

View file

@ -19,12 +19,14 @@ import 'package:fladder/providers/video_player_provider.dart';
import 'package:fladder/screens/collections/add_to_collection.dart';
import 'package:fladder/screens/metadata/info_screen.dart';
import 'package:fladder/screens/playlists/add_to_playlists.dart';
import 'package:fladder/screens/video_player/components/video_player_quality_controls.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/map_bool_helper.dart';
import 'package:fladder/util/refresh_state.dart';
import 'package:fladder/util/string_extensions.dart';
import 'package:fladder/widgets/shared/enum_selection.dart';
@ -63,6 +65,7 @@ class _VideoOptionsMobileState extends ConsumerState<VideoOptions> {
final currentItem = ref.watch(playBackModel.select((value) => value?.item));
final videoSettings = ref.watch(videoPlayerSettingsProvider);
final currentMediaStreams = ref.watch(playBackModel.select((value) => value?.mediaStreams));
final bitRateOptions = ref.watch(playBackModel.select((value) => value?.bitRateOptions));
Widget mainPage() {
return ListView(
@ -202,6 +205,24 @@ class _VideoOptionsMobileState extends ConsumerState<VideoOptions> {
],
),
),
if (bitRateOptions?.isNotEmpty == true)
ListTile(
title: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
flex: 3,
child: Text(context.localized.qualityOptionsTitle),
),
const Spacer(),
Text(bitRateOptions?.enabledFirst.keys.firstOrNull?.label(context) ?? "")
],
),
onTap: () {
Navigator.of(context).pop();
openQualityOptions(context);
},
)
],
);
}

View file

@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/playback/playback_model.dart';
import 'package:fladder/providers/video_player_provider.dart';
import 'package:fladder/util/localization_helper.dart';
Future<void> openQualityOptions(BuildContext context) async {
return showDialog(
context: context,
builder: (context) => const _QualityOptionsDialogue(),
);
}
class _QualityOptionsDialogue extends ConsumerWidget {
const _QualityOptionsDialogue();
@override
Widget build(BuildContext context, WidgetRef ref) {
final playbackModel = ref.watch(playBackModel);
final qualityOptions = playbackModel?.bitRateOptions;
return Dialog(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 6),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
context.localized.qualityOptionsTitle,
style: Theme.of(context).textTheme.titleLarge,
),
),
const SizedBox(height: 6),
const Divider(),
Flexible(
child: ListView(
shrinkWrap: true,
children: qualityOptions?.entries
.map(
(entry) => RadioListTile(
value: entry.value,
groupValue: true,
onChanged: (value) async {
final newModel = await playbackModel?.setQualityOption(
qualityOptions.map(
(key, value) => MapEntry(key, key == entry.key ? true : false),
),
);
ref.read(playBackModel.notifier).update((state) => newModel);
if (newModel != null) {
await ref.read(playbackModelHelper).shouldReload(newModel);
}
context.router.maybePop();
},
title: Text(entry.key.label(context)),
),
)
.toList() ??
[],
),
),
],
),
);
}
}