tv: handle more media key events
This commit is contained in:
parent
beb65a8d51
commit
1521db29a5
7 changed files with 39 additions and 39 deletions
|
@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
|
||||||
- Vaults: custom pattern lock
|
- Vaults: custom pattern lock
|
||||||
- Video: picture-in-picture
|
- Video: picture-in-picture
|
||||||
- Video: handle skip next/previous media buttons
|
- Video: handle skip next/previous media buttons
|
||||||
|
- TV: more media controls
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import 'package:aves/model/source/enums/enums.dart';
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/file_utils.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/widgets/common/basic/markdown_container.dart';
|
import 'package:aves/widgets/common/basic/markdown_container.dart';
|
||||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||||
import 'package:aves/widgets/common/behaviour/intents.dart';
|
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -17,7 +16,6 @@ class PolicyPage extends StatefulWidget {
|
||||||
|
|
||||||
class _PolicyPageState extends State<PolicyPage> {
|
class _PolicyPageState extends State<PolicyPage> {
|
||||||
late Future<String> _termsLoader;
|
late Future<String> _termsLoader;
|
||||||
final ScrollController _scrollController = ScrollController();
|
|
||||||
|
|
||||||
static const termsPath = 'assets/terms.md';
|
static const termsPath = 'assets/terms.md';
|
||||||
static const termsDirection = TextDirection.ltr;
|
static const termsDirection = TextDirection.ltr;
|
||||||
|
@ -39,11 +37,8 @@ class _PolicyPageState extends State<PolicyPage> {
|
||||||
child: FocusableActionDetector(
|
child: FocusableActionDetector(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
shortcuts: const {
|
shortcuts: const {
|
||||||
SingleActivator(LogicalKeyboardKey.arrowUp): VerticalScrollIntent.up(),
|
SingleActivator(LogicalKeyboardKey.arrowUp): ScrollIntent(direction: AxisDirection.up, type: ScrollIncrementType.page),
|
||||||
SingleActivator(LogicalKeyboardKey.arrowDown): VerticalScrollIntent.down(),
|
SingleActivator(LogicalKeyboardKey.arrowDown): ScrollIntent(direction: AxisDirection.down, type: ScrollIncrementType.page),
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
VerticalScrollIntent: VerticalScrollIntentAction(scrollController: _scrollController),
|
|
||||||
},
|
},
|
||||||
child: Center(
|
child: Center(
|
||||||
child: FutureBuilder<String>(
|
child: FutureBuilder<String>(
|
||||||
|
@ -54,7 +49,7 @@ class _PolicyPageState extends State<PolicyPage> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: MarkdownContainer(
|
child: MarkdownContainer(
|
||||||
scrollController: _scrollController,
|
scrollController: PrimaryScrollController.of(context),
|
||||||
data: terms,
|
data: terms,
|
||||||
textDirection: termsDirection,
|
textDirection: termsDirection,
|
||||||
),
|
),
|
||||||
|
|
|
@ -244,7 +244,9 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
final darkTheme = themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent, initialized) : Themes.darkTheme(darkAccent, initialized);
|
final darkTheme = themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent, initialized) : Themes.darkTheme(darkAccent, initialized);
|
||||||
return Shortcuts(
|
return Shortcuts(
|
||||||
shortcuts: {
|
shortcuts: {
|
||||||
// handle Android TV remote `select` button
|
// handle Android TV remote `select` button (KEYCODE_DPAD_CENTER)
|
||||||
|
// the following keys are already handled by default:
|
||||||
|
// KEYCODE_ENTER, KEYCODE_BUTTON_A, KEYCODE_NUMPAD_ENTER
|
||||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||||
},
|
},
|
||||||
child: MediaQuery.fromWindow(
|
child: MediaQuery.fromWindow(
|
||||||
|
|
|
@ -1,37 +1,22 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
class VerticalScrollIntent extends Intent {
|
class ScrollControllerAction extends CallbackAction<ScrollIntent> {
|
||||||
const VerticalScrollIntent({
|
ScrollControllerAction({
|
||||||
required this.type,
|
|
||||||
});
|
|
||||||
|
|
||||||
const VerticalScrollIntent.up() : type = VerticalScrollDirection.up;
|
|
||||||
|
|
||||||
const VerticalScrollIntent.down() : type = VerticalScrollDirection.down;
|
|
||||||
|
|
||||||
final VerticalScrollDirection type;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum VerticalScrollDirection {
|
|
||||||
up,
|
|
||||||
down,
|
|
||||||
}
|
|
||||||
|
|
||||||
class VerticalScrollIntentAction extends CallbackAction<VerticalScrollIntent> {
|
|
||||||
VerticalScrollIntentAction({
|
|
||||||
required ScrollController scrollController,
|
required ScrollController scrollController,
|
||||||
}) : super(onInvoke: (intent) => _onScrollIntent(intent, scrollController));
|
}) : super(onInvoke: (intent) => _onScrollIntent(intent, scrollController));
|
||||||
|
|
||||||
static void _onScrollIntent(
|
static void _onScrollIntent(
|
||||||
VerticalScrollIntent intent,
|
ScrollIntent intent,
|
||||||
ScrollController scrollController,
|
ScrollController scrollController,
|
||||||
) {
|
) {
|
||||||
late int factor;
|
late int factor;
|
||||||
switch (intent.type) {
|
switch (intent.direction) {
|
||||||
case VerticalScrollDirection.up:
|
case AxisDirection.up:
|
||||||
|
case AxisDirection.left:
|
||||||
factor = -1;
|
factor = -1;
|
||||||
break;
|
break;
|
||||||
case VerticalScrollDirection.down:
|
case AxisDirection.down:
|
||||||
|
case AxisDirection.right:
|
||||||
factor = 1;
|
factor = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,15 +184,33 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
||||||
Widget _buildImagePage() {
|
Widget _buildImagePage() {
|
||||||
final useTvLayout = settings.useTvLayout;
|
final useTvLayout = settings.useTvLayout;
|
||||||
|
|
||||||
Widget? child;
|
// cf https://developer.android.com/training/tv/start/controllers#media-events
|
||||||
Map<ShortcutActivator, Intent>? shortcuts = {
|
Map<ShortcutActivator, Intent>? shortcuts = {
|
||||||
const SingleActivator(LogicalKeyboardKey.arrowUp): useTvLayout ? const TvShowLessInfoIntent() : const _LeaveIntent(),
|
const SingleActivator(LogicalKeyboardKey.arrowUp): useTvLayout ? const TvShowLessInfoIntent() : const _LeaveIntent(),
|
||||||
const SingleActivator(LogicalKeyboardKey.arrowDown): useTvLayout ? const _TvShowMoreInfoIntent() : const _ShowInfoIntent(),
|
const SingleActivator(LogicalKeyboardKey.arrowDown): useTvLayout ? const _TvShowMoreInfoIntent() : const _ShowInfoIntent(),
|
||||||
const SingleActivator(LogicalKeyboardKey.mediaPause): const _PlayPauseIntent.pause(),
|
// KEYCODE_MEDIA_PLAY_PAUSE / 85 / play/pause
|
||||||
const SingleActivator(LogicalKeyboardKey.mediaPlay): const _PlayPauseIntent.play(),
|
|
||||||
const SingleActivator(LogicalKeyboardKey.mediaPlayPause): const _PlayPauseIntent.toggle(),
|
const SingleActivator(LogicalKeyboardKey.mediaPlayPause): const _PlayPauseIntent.toggle(),
|
||||||
|
// KEYCODE_MEDIA_STOP / 86 / stop
|
||||||
|
const SingleActivator(LogicalKeyboardKey.mediaStop): const _PlayPauseIntent.pause(),
|
||||||
|
// KEYCODE_MEDIA_NEXT / 87 / skip to next
|
||||||
|
const SingleActivator(LogicalKeyboardKey.mediaTrackNext): const _ShowNextIntent(),
|
||||||
|
// KEYCODE_MEDIA_PREVIOUS / 88 / skip to previous
|
||||||
|
const SingleActivator(LogicalKeyboardKey.mediaTrackPrevious): const _ShowPreviousIntent(),
|
||||||
|
// KEYCODE_MEDIA_PLAY / 126 / play
|
||||||
|
const SingleActivator(LogicalKeyboardKey.mediaPlay): const _PlayPauseIntent.play(),
|
||||||
|
// KEYCODE_MEDIA_PAUSE / 127 / pause
|
||||||
|
const SingleActivator(LogicalKeyboardKey.mediaPause): const _PlayPauseIntent.pause(),
|
||||||
|
// KEYCODE_BUTTON_L1 / 102 / skip to previous
|
||||||
|
const SingleActivator(LogicalKeyboardKey.gameButtonLeft1): const _ShowPreviousIntent(),
|
||||||
|
// KEYCODE_BUTTON_R1 / 103 / skip to next
|
||||||
|
const SingleActivator(LogicalKeyboardKey.gameButtonRight1): const _ShowNextIntent(),
|
||||||
|
// KEYCODE_BUTTON_START / 108 / pause
|
||||||
|
const SingleActivator(LogicalKeyboardKey.gameButtonStart): const _PlayPauseIntent.pause(),
|
||||||
|
// KEYCODE_BUTTON_SELECT / 109 / play/pause
|
||||||
|
const SingleActivator(LogicalKeyboardKey.gameButtonSelect): const _PlayPauseIntent.toggle(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Widget? child;
|
||||||
if (hasCollection) {
|
if (hasCollection) {
|
||||||
shortcuts.addAll(const {
|
shortcuts.addAll(const {
|
||||||
SingleActivator(LogicalKeyboardKey.arrowLeft): _ShowPreviousIntent(),
|
SingleActivator(LogicalKeyboardKey.arrowLeft): _ShowPreviousIntent(),
|
||||||
|
|
|
@ -97,11 +97,11 @@ class _TvMetadataPageState extends State<TvMetadataPage> {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FocusableActionDetector(
|
child: FocusableActionDetector(
|
||||||
shortcuts: const {
|
shortcuts: const {
|
||||||
SingleActivator(LogicalKeyboardKey.arrowUp): VerticalScrollIntent.up(),
|
SingleActivator(LogicalKeyboardKey.arrowUp): ScrollIntent(direction: AxisDirection.up, type: ScrollIncrementType.page),
|
||||||
SingleActivator(LogicalKeyboardKey.arrowDown): VerticalScrollIntent.down(),
|
SingleActivator(LogicalKeyboardKey.arrowDown): ScrollIntent(direction: AxisDirection.down, type: ScrollIncrementType.page),
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
VerticalScrollIntent: VerticalScrollIntentAction(scrollController: _detailsScrollController),
|
ScrollIntent: ScrollControllerAction(scrollController: _detailsScrollController),
|
||||||
},
|
},
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _detailsScrollController,
|
controller: _detailsScrollController,
|
||||||
|
|
Loading…
Reference in a new issue