mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 19:12:04 +00:00
Fix Fullscreen mode
This commit is contained in:
parent
e9dfb516ab
commit
d21dbbbc6b
3 changed files with 220 additions and 190 deletions
|
|
@ -56,9 +56,6 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
|
||||||
bool desktopFullScreenPlayer = false;
|
bool desktopFullScreenPlayer = false;
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_isDesktop) {
|
|
||||||
setFullScreen(value: desktopFullScreenPlayer);
|
|
||||||
}
|
|
||||||
for (var infoHash in _infoHashList) {
|
for (var infoHash in _infoHashList) {
|
||||||
MTorrentServer().removeTorrent(infoHash);
|
MTorrentServer().removeTorrent(infoHash);
|
||||||
}
|
}
|
||||||
|
|
@ -169,6 +166,9 @@ class AnimeStreamPage extends riv.ConsumerStatefulWidget {
|
||||||
|
|
||||||
enum _AniSkipPhase { none, opening, ending }
|
enum _AniSkipPhase { none, opening, ending }
|
||||||
|
|
||||||
|
/// When the user first opens a video (on Desktop).
|
||||||
|
bool _firstTime = true;
|
||||||
|
|
||||||
class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
late final GlobalKey<VideoState> _key = GlobalKey<VideoState>();
|
late final GlobalKey<VideoState> _key = GlobalKey<VideoState>();
|
||||||
|
|
@ -196,7 +196,6 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final ValueNotifier<double> _playbackSpeed = ValueNotifier(1.0);
|
final ValueNotifier<double> _playbackSpeed = ValueNotifier(1.0);
|
||||||
final ValueNotifier<bool> _enterFullScreen = ValueNotifier(false);
|
|
||||||
final ValueNotifier<bool> _isDoubleSpeed = ValueNotifier(false);
|
final ValueNotifier<bool> _isDoubleSpeed = ValueNotifier(false);
|
||||||
late final ValueNotifier<Duration> _currentPosition = ValueNotifier(
|
late final ValueNotifier<Duration> _currentPosition = ValueNotifier(
|
||||||
_streamController.geTCurrentPosition(),
|
_streamController.geTCurrentPosition(),
|
||||||
|
|
@ -235,13 +234,16 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the last episode of an Anime has ended, exit fullscreen mode
|
// If the last episode of an Anime has ended, exit fullscreen mode
|
||||||
if (!hasNextEpisode && val && _isDesktop && !_enterFullScreen.value) {
|
final isFullScreen = ref.read(fullscreenProvider);
|
||||||
|
if (!hasNextEpisode && val && _isDesktop && isFullScreen) {
|
||||||
setFullScreen(value: false);
|
setFullScreen(value: false);
|
||||||
|
ref.read(fullscreenProvider.notifier).state = false;
|
||||||
|
widget.desktopFullScreenPlayer.call(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
void pushToNewEpisode(BuildContext context, Chapter episode) {
|
void pushToNewEpisode(BuildContext context, Chapter episode) {
|
||||||
widget.desktopFullScreenPlayer.call(true);
|
widget.desktopFullScreenPlayer.call(ref.read(fullscreenProvider));
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
pushReplacementMangaReaderView(context: context, chapter: episode);
|
pushReplacementMangaReaderView(context: context, chapter: episode);
|
||||||
}
|
}
|
||||||
|
|
@ -305,12 +307,24 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (_isDesktop) {
|
// If player is being launched the first time,
|
||||||
setFullScreen(value: ref.read(fullScreenPlayerStateProvider));
|
// use global "Use Fullscreen" setting.
|
||||||
|
// Else (if user already watches an episode and just changes it),
|
||||||
|
// stay in the same mode, the user left it in.
|
||||||
|
if (_isDesktop && _firstTime) {
|
||||||
|
final globalFullscreen = ref.read(fullScreenPlayerStateProvider);
|
||||||
|
setFullScreen(value: globalFullscreen);
|
||||||
|
Future.microtask(() {
|
||||||
|
ref.read(fullscreenProvider.notifier).state = globalFullscreen;
|
||||||
|
widget.desktopFullScreenPlayer.call(globalFullscreen);
|
||||||
|
});
|
||||||
|
_firstTime = false;
|
||||||
}
|
}
|
||||||
_currentPositionSub = _player.stream.position.listen(
|
_currentPositionSub = _player.stream.position.listen(
|
||||||
_unifiedPositionHandler,
|
_unifiedPositionHandler,
|
||||||
);
|
);
|
||||||
|
_completed;
|
||||||
|
_currentTotalDurationSub;
|
||||||
_loadAndroidFont().then((_) {
|
_loadAndroidFont().then((_) {
|
||||||
_player.open(
|
_player.open(
|
||||||
Media(
|
Media(
|
||||||
|
|
@ -979,6 +993,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
|
|
||||||
/// helper method for _mobileBottomButtonBar() and _desktopBottomButtonBar()
|
/// helper method for _mobileBottomButtonBar() and _desktopBottomButtonBar()
|
||||||
Widget _buildSettingsButtons(BuildContext context) {
|
Widget _buildSettingsButtons(BuildContext context) {
|
||||||
|
final isFullscreen = ref.watch(fullscreenProvider);
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|
@ -1009,20 +1024,19 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (_isDesktop)
|
if (_isDesktop)
|
||||||
CustomMaterialDesktopFullscreenButton(controller: _controller)
|
CustomMaterialDesktopFullscreenButton(
|
||||||
|
controller: _controller,
|
||||||
|
desktopFullScreenPlayer: widget.desktopFullScreenPlayer,
|
||||||
|
)
|
||||||
else
|
else
|
||||||
ValueListenableBuilder<bool>(
|
IconButton(
|
||||||
valueListenable: _enterFullScreen,
|
icon: Icon(isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen),
|
||||||
builder: (context, snapshot, _) {
|
iconSize: 25,
|
||||||
return IconButton(
|
color: Colors.white,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_setLandscapeMode(!snapshot);
|
_setLandscapeMode(!isFullscreen);
|
||||||
_enterFullScreen.value = !snapshot;
|
ref.read(fullscreenProvider.notifier).state = !isFullscreen;
|
||||||
},
|
widget.desktopFullScreenPlayer.call(!isFullscreen);
|
||||||
icon: Icon(snapshot ? Icons.fullscreen_exit : Icons.fullscreen),
|
|
||||||
iconSize: 25,
|
|
||||||
color: Colors.white,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -1030,163 +1044,158 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _topButtonBar(BuildContext context) {
|
Widget _topButtonBar(BuildContext context) {
|
||||||
return ValueListenableBuilder<bool>(
|
final fullScreen = ref.watch(fullscreenProvider);
|
||||||
valueListenable: _enterFullScreen,
|
return Padding(
|
||||||
builder: (context, fullScreen, _) {
|
padding: EdgeInsets.only(
|
||||||
return Padding(
|
top: !_isDesktop && !fullScreen
|
||||||
padding: EdgeInsets.only(
|
? MediaQuery.of(context).padding.top
|
||||||
top: !_isDesktop && !fullScreen
|
: 0,
|
||||||
? MediaQuery.of(context).padding.top
|
),
|
||||||
: 0,
|
child: Row(
|
||||||
|
children: [
|
||||||
|
BackButton(
|
||||||
|
color: Colors.white,
|
||||||
|
onPressed: () {
|
||||||
|
if (_isDesktop && fullScreen) {
|
||||||
|
setFullScreen(value: !fullScreen);
|
||||||
|
ref.read(fullscreenProvider.notifier).state = !fullScreen;
|
||||||
|
widget.desktopFullScreenPlayer.call(!fullScreen);
|
||||||
|
} else {
|
||||||
|
SystemChrome.setEnabledSystemUIMode(
|
||||||
|
SystemUiMode.manual,
|
||||||
|
overlays: SystemUiOverlay.values,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (mounted) {
|
||||||
|
// Set variable to true, so the player uses the global
|
||||||
|
// "Use Fullscreen" setting again.
|
||||||
|
_firstTime = true;
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
child: Row(
|
Flexible(
|
||||||
|
child: ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: SizedBox(
|
||||||
|
width: context.width(0.8),
|
||||||
|
child: Text(
|
||||||
|
widget.episode.manga.value!.name!,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: SizedBox(
|
||||||
|
width: context.width(0.8),
|
||||||
|
child: Text(
|
||||||
|
widget.episode.name!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.white.withValues(alpha: 0.7),
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: ValueListenableBuilder<bool>(
|
||||||
|
valueListenable: _isDoubleSpeed,
|
||||||
|
builder: (context, snapshot, _) {
|
||||||
|
return Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: snapshot
|
||||||
|
? [
|
||||||
|
WidgetSpan(child: Icon(Icons.fast_forward)),
|
||||||
|
TextSpan(text: " 2X"),
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
children: [
|
children: [
|
||||||
BackButton(
|
btnToShowChapterListDialog(
|
||||||
color: Colors.white,
|
context,
|
||||||
onPressed: () async {
|
context.l10n.episodes,
|
||||||
if (_isDesktop) {
|
widget.episode,
|
||||||
if (fullScreen) {
|
onChanged: (v) {
|
||||||
setFullScreen(value: false);
|
if (v) {
|
||||||
} else {
|
_player.play();
|
||||||
if (mounted) {
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
SystemChrome.setEnabledSystemUIMode(
|
_player.pause();
|
||||||
SystemUiMode.manual,
|
}
|
||||||
overlays: SystemUiOverlay.values,
|
},
|
||||||
);
|
iconColor: Colors.white,
|
||||||
if (mounted) {
|
),
|
||||||
Navigator.pop(context);
|
btnToShowShareScreenshot(
|
||||||
}
|
widget.episode,
|
||||||
|
onChanged: (v) {
|
||||||
|
if (v) {
|
||||||
|
_player.play();
|
||||||
|
} else {
|
||||||
|
_player.pause();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Flexible(
|
// IconButton(
|
||||||
child: ListTile(
|
// onPressed: () {
|
||||||
dense: true,
|
// showDialog(
|
||||||
title: SizedBox(
|
// context: context,
|
||||||
width: context.width(0.8),
|
// builder: (context) {
|
||||||
child: Text(
|
// return AlertDialog(
|
||||||
widget.episode.manga.value!.name!,
|
// scrollable: true,
|
||||||
style: const TextStyle(
|
// title: Text("Player Settings"),
|
||||||
fontWeight: FontWeight.bold,
|
// content: SizedBox(
|
||||||
color: Colors.white,
|
// width: context.width(0.8),
|
||||||
),
|
// child: Column(
|
||||||
overflow: TextOverflow.ellipsis,
|
// crossAxisAlignment:
|
||||||
),
|
// CrossAxisAlignment.start,
|
||||||
),
|
// children: [
|
||||||
subtitle: SizedBox(
|
// SwitchListTile(
|
||||||
width: context.width(0.8),
|
// value: false,
|
||||||
child: Text(
|
// title: Text(
|
||||||
widget.episode.name!,
|
// "Enable Volume and Brightness Gestures",
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
fontSize: 12,
|
// color: Theme.of(context)
|
||||||
fontWeight: FontWeight.w400,
|
// .textTheme
|
||||||
color: Colors.white.withValues(alpha: 0.7),
|
// .bodyLarge!
|
||||||
),
|
// .color!
|
||||||
overflow: TextOverflow.ellipsis,
|
// .withValues(alpha: 0.9),
|
||||||
),
|
// fontSize: 14),
|
||||||
),
|
// ),
|
||||||
),
|
// onChanged: (value) {}),
|
||||||
),
|
// SwitchListTile(
|
||||||
Flexible(
|
// value: false,
|
||||||
fit: FlexFit.tight,
|
// title: Text(
|
||||||
child: ValueListenableBuilder<bool>(
|
// "Enable Horizonal Seek Gestures",
|
||||||
valueListenable: _isDoubleSpeed,
|
// style: TextStyle(
|
||||||
builder: (context, snapshot, _) {
|
// color: Theme.of(context)
|
||||||
return Text.rich(
|
// .textTheme
|
||||||
TextSpan(
|
// .bodyLarge!
|
||||||
children: snapshot
|
// .color!
|
||||||
? [
|
// .withValues(alpha: 0.9),
|
||||||
WidgetSpan(child: Icon(Icons.fast_forward)),
|
// fontSize: 14),
|
||||||
TextSpan(text: " 2X"),
|
// ),
|
||||||
]
|
// onChanged: (value) {}),
|
||||||
: [],
|
// ],
|
||||||
),
|
// ),
|
||||||
);
|
// ),
|
||||||
},
|
// );
|
||||||
),
|
// });
|
||||||
),
|
// },
|
||||||
Row(
|
// icon: Icon(Icons.adaptive.more))
|
||||||
children: [
|
|
||||||
btnToShowChapterListDialog(
|
|
||||||
context,
|
|
||||||
context.l10n.episodes,
|
|
||||||
widget.episode,
|
|
||||||
onChanged: (v) {
|
|
||||||
if (v) {
|
|
||||||
_player.play();
|
|
||||||
} else {
|
|
||||||
_player.pause();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
iconColor: Colors.white,
|
|
||||||
),
|
|
||||||
btnToShowShareScreenshot(
|
|
||||||
widget.episode,
|
|
||||||
onChanged: (v) {
|
|
||||||
if (v) {
|
|
||||||
_player.play();
|
|
||||||
} else {
|
|
||||||
_player.pause();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
// IconButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// showDialog(
|
|
||||||
// context: context,
|
|
||||||
// builder: (context) {
|
|
||||||
// return AlertDialog(
|
|
||||||
// scrollable: true,
|
|
||||||
// title: Text("Player Settings"),
|
|
||||||
// content: SizedBox(
|
|
||||||
// width: context.width(0.8),
|
|
||||||
// child: Column(
|
|
||||||
// crossAxisAlignment:
|
|
||||||
// CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// SwitchListTile(
|
|
||||||
// value: false,
|
|
||||||
// title: Text(
|
|
||||||
// "Enable Volume and Brightness Gestures",
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: Theme.of(context)
|
|
||||||
// .textTheme
|
|
||||||
// .bodyLarge!
|
|
||||||
// .color!
|
|
||||||
// .withValues(alpha: 0.9),
|
|
||||||
// fontSize: 14),
|
|
||||||
// ),
|
|
||||||
// onChanged: (value) {}),
|
|
||||||
// SwitchListTile(
|
|
||||||
// value: false,
|
|
||||||
// title: Text(
|
|
||||||
// "Enable Horizonal Seek Gestures",
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: Theme.of(context)
|
|
||||||
// .textTheme
|
|
||||||
// .bodyLarge!
|
|
||||||
// .color!
|
|
||||||
// .withValues(alpha: 0.9),
|
|
||||||
// fontSize: 14),
|
|
||||||
// ),
|
|
||||||
// onChanged: (value) {}),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// icon: Icon(Icons.adaptive.more))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
],
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1235,6 +1244,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
||||||
_isDoubleSpeed.value = value ?? false;
|
_isDoubleSpeed.value = value ?? false;
|
||||||
},
|
},
|
||||||
defaultSkipIntroLength: skipIntroLength,
|
defaultSkipIntroLength: skipIntroLength,
|
||||||
|
desktopFullScreenPlayer: widget.desktopFullScreenPlayer,
|
||||||
)
|
)
|
||||||
: MobileControllerWidget(
|
: MobileControllerWidget(
|
||||||
videoController: _controller,
|
videoController: _controller,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:mangayomi/main.dart';
|
import 'package:mangayomi/main.dart';
|
||||||
import 'package:mangayomi/models/changed.dart';
|
import 'package:mangayomi/models/changed.dart';
|
||||||
|
|
@ -14,6 +15,8 @@ import 'package:mangayomi/utils/chapter_recognition.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
part 'anime_player_controller_provider.g.dart';
|
part 'anime_player_controller_provider.g.dart';
|
||||||
|
|
||||||
|
final fullscreenProvider = StateProvider<bool>((ref) => false);
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class AnimeStreamController extends _$AnimeStreamController {
|
class AnimeStreamController extends _$AnimeStreamController {
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import 'package:media_kit_video/media_kit_video.dart';
|
||||||
import 'package:media_kit_video/media_kit_video_controls/src/controls/extensions/duration.dart';
|
import 'package:media_kit_video/media_kit_video_controls/src/controls/extensions/duration.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class DesktopControllerWidget extends StatefulWidget {
|
class DesktopControllerWidget extends ConsumerStatefulWidget {
|
||||||
final Function(Duration?) tempDuration;
|
final Function(Duration?) tempDuration;
|
||||||
final Function(bool?) doubleSpeed;
|
final Function(bool?) doubleSpeed;
|
||||||
final AnimeStreamController streamController;
|
final AnimeStreamController streamController;
|
||||||
|
|
@ -23,6 +23,7 @@ class DesktopControllerWidget extends StatefulWidget {
|
||||||
final Widget bottomButtonBarWidget;
|
final Widget bottomButtonBarWidget;
|
||||||
final Widget seekToWidget;
|
final Widget seekToWidget;
|
||||||
final int defaultSkipIntroLength;
|
final int defaultSkipIntroLength;
|
||||||
|
final void Function(bool) desktopFullScreenPlayer;
|
||||||
const DesktopControllerWidget({
|
const DesktopControllerWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.videoController,
|
required this.videoController,
|
||||||
|
|
@ -34,14 +35,16 @@ class DesktopControllerWidget extends StatefulWidget {
|
||||||
required this.tempDuration,
|
required this.tempDuration,
|
||||||
required this.doubleSpeed,
|
required this.doubleSpeed,
|
||||||
required this.defaultSkipIntroLength,
|
required this.defaultSkipIntroLength,
|
||||||
|
required this.desktopFullScreenPlayer,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DesktopControllerWidget> createState() =>
|
ConsumerState<DesktopControllerWidget> createState() =>
|
||||||
_DesktopControllerWidgetState();
|
_DesktopControllerWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
|
class _DesktopControllerWidgetState
|
||||||
|
extends ConsumerState<DesktopControllerWidget> {
|
||||||
bool mount = true;
|
bool mount = true;
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
bool cursorVisible = true;
|
bool cursorVisible = true;
|
||||||
|
|
@ -201,9 +204,13 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
|
||||||
final volume = widget.videoController.player.state.volume - 5.0;
|
final volume = widget.videoController.player.state.volume - 5.0;
|
||||||
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0));
|
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0));
|
||||||
},
|
},
|
||||||
const SingleActivator(LogicalKeyboardKey.keyF): () => setFullScreen(),
|
const SingleActivator(LogicalKeyboardKey.keyF): () async {
|
||||||
const SingleActivator(LogicalKeyboardKey.escape): () =>
|
await _changeFullScreen(ref, widget.desktopFullScreenPlayer);
|
||||||
setFullScreen(value: false),
|
},
|
||||||
|
const SingleActivator(LogicalKeyboardKey.escape): () async {
|
||||||
|
final desktopFullScreenPlayer = widget.desktopFullScreenPlayer;
|
||||||
|
await _changeFullScreen(ref, desktopFullScreenPlayer, value: false);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -262,12 +269,13 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
|
||||||
},
|
},
|
||||||
onTapUp: !toggleFullscreenOnDoublePress
|
onTapUp: !toggleFullscreenOnDoublePress
|
||||||
? null
|
? null
|
||||||
: (e) {
|
: (e) async {
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final difference = now.difference(last);
|
final difference = now.difference(last);
|
||||||
last = now;
|
last = now;
|
||||||
if (difference < const Duration(milliseconds: 400)) {
|
if (difference < const Duration(milliseconds: 400)) {
|
||||||
setFullScreen();
|
final fullScreen = widget.desktopFullScreenPlayer;
|
||||||
|
await _changeFullScreen(ref, fullScreen);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPanUpdate: modifyVolumeOnScroll
|
onPanUpdate: modifyVolumeOnScroll
|
||||||
|
|
@ -489,6 +497,16 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _changeFullScreen(
|
||||||
|
WidgetRef ref,
|
||||||
|
void Function(bool) setFullScreenCallback, {
|
||||||
|
bool? value,
|
||||||
|
}) async {
|
||||||
|
final isFullScreen = await setFullScreen(value: value);
|
||||||
|
ref.read(fullscreenProvider.notifier).state = isFullScreen;
|
||||||
|
setFullScreenCallback(isFullScreen);
|
||||||
|
}
|
||||||
|
|
||||||
// BUTTON: VOLUME
|
// BUTTON: VOLUME
|
||||||
|
|
||||||
/// MaterialDesktop design volume button & slider.
|
/// MaterialDesktop design volume button & slider.
|
||||||
|
|
@ -751,36 +769,35 @@ class _CustomTrackShape extends RoundedRectSliderTrackShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomMaterialDesktopFullscreenButton extends StatefulWidget {
|
class CustomMaterialDesktopFullscreenButton extends ConsumerStatefulWidget {
|
||||||
final VideoController controller;
|
final VideoController controller;
|
||||||
|
final void Function(bool) desktopFullScreenPlayer;
|
||||||
|
|
||||||
const CustomMaterialDesktopFullscreenButton({
|
const CustomMaterialDesktopFullscreenButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
|
required this.desktopFullScreenPlayer,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CustomMaterialDesktopFullscreenButton> createState() =>
|
ConsumerState<CustomMaterialDesktopFullscreenButton> createState() =>
|
||||||
_CustomMaterialDesktopFullscreenButtonState();
|
_CustomMaterialDesktopFullscreenButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CustomMaterialDesktopFullscreenButtonState
|
class _CustomMaterialDesktopFullscreenButtonState
|
||||||
extends State<CustomMaterialDesktopFullscreenButton> {
|
extends ConsumerState<CustomMaterialDesktopFullscreenButton> {
|
||||||
bool _isFullscreen = false;
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final isFullScreen = ref.watch(fullscreenProvider);
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: () async {
|
icon: isFullScreen
|
||||||
final isFullScreen = await setFullScreen();
|
|
||||||
setState(() {
|
|
||||||
_isFullscreen = isFullScreen;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: _isFullscreen
|
|
||||||
? const Icon(Icons.fullscreen_exit)
|
? const Icon(Icons.fullscreen_exit)
|
||||||
: const Icon(Icons.fullscreen),
|
: const Icon(Icons.fullscreen),
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
onPressed: () async {
|
||||||
|
await _changeFullScreen(ref, widget.desktopFullScreenPlayer);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -799,5 +816,5 @@ Future<bool> setFullScreen({bool? value}) async {
|
||||||
} else {
|
} else {
|
||||||
await windowManager.setFullScreen(false);
|
await windowManager.setFullScreen(false);
|
||||||
}
|
}
|
||||||
return isFullScreen;
|
return !isFullScreen;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue