tv layout on non-tv devices
This commit is contained in:
parent
4c6a4e3568
commit
b343e32db0
42 changed files with 379 additions and 237 deletions
|
@ -1,16 +1,21 @@
|
|||
package deckers.thibault.aves.channel.calls
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.session.PlaybackState
|
||||
import android.net.Uri
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
import android.support.v4.media.session.PlaybackStateCompat
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import androidx.media.session.MediaButtonReceiver
|
||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safeSuspend
|
||||
import deckers.thibault.aves.utils.FlutterUtils
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.getParcelableExtraCompat
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
|
@ -74,7 +79,9 @@ class MediaSessionHandler(private val context: Context) : MethodCallHandler {
|
|||
|
||||
var session = sessions[uri]
|
||||
if (session == null) {
|
||||
session = MediaSessionCompat(context, "aves-$uri")
|
||||
val mbrIntent = MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PLAY_PAUSE)
|
||||
val mbrName = ComponentName(context, MediaButtonReceiver::class.java)
|
||||
session = MediaSessionCompat(context, "aves-$uri", mbrName, mbrIntent)
|
||||
sessions[uri] = session
|
||||
|
||||
val metadata = MediaMetadataCompat.Builder()
|
||||
|
@ -86,6 +93,12 @@ class MediaSessionHandler(private val context: Context) : MethodCallHandler {
|
|||
session.setMetadata(metadata)
|
||||
|
||||
val callback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {
|
||||
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
|
||||
val keyEvent = mediaButtonEvent.getParcelableExtraCompat<KeyEvent?>(Intent.EXTRA_KEY_EVENT) ?: return false
|
||||
Log.d(LOG_TAG, "TLAD onMediaButtonEvent keyEvent=$keyEvent")
|
||||
return super.onMediaButtonEvent(mediaButtonEvent)
|
||||
}
|
||||
|
||||
override fun onPlay() {
|
||||
super.onPlay()
|
||||
Log.d(LOG_TAG, "TLAD onPlay uri=$uri")
|
||||
|
|
|
@ -656,6 +656,7 @@
|
|||
"settingsSystemDefault": "System default",
|
||||
"settingsDefault": "Default",
|
||||
"settingsDisabled": "Disabled",
|
||||
"settingsModificationWarningDialogMessage": "Other settings will be modified.",
|
||||
|
||||
"settingsSearchFieldLabel": "Search settings",
|
||||
"settingsSearchEmpty": "No matching setting",
|
||||
|
@ -816,6 +817,7 @@
|
|||
"settingsThemeEnableDynamicColor": "Dynamic color",
|
||||
"settingsDisplayRefreshRateModeTile": "Display refresh rate",
|
||||
"settingsDisplayRefreshRateModeDialogTitle": "Refresh Rate",
|
||||
"settingsDisplayUseTvInterface": "Android TV interface",
|
||||
|
||||
"settingsLanguageSectionTitle": "Language & Formats",
|
||||
"settingsLanguageTile": "Language",
|
||||
|
|
|
@ -24,6 +24,7 @@ class SettingsDefaults {
|
|||
static const themeColorMode = AvesThemeColorMode.polychrome;
|
||||
static const enableDynamicColor = false;
|
||||
static const enableBlurEffect = true; // `enableBlurEffect` has a contextual default value
|
||||
static const forceTvLayout = false;
|
||||
|
||||
// navigation
|
||||
static const mustBackTwiceToExit = true;
|
||||
|
|
|
@ -70,6 +70,7 @@ class Settings extends ChangeNotifier {
|
|||
static const themeColorModeKey = 'theme_color_mode';
|
||||
static const enableDynamicColorKey = 'dynamic_color';
|
||||
static const enableBlurEffectKey = 'enable_overlay_blur_effect';
|
||||
static const forceTvLayoutKey = 'force_tv_layout';
|
||||
|
||||
// navigation
|
||||
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
||||
|
@ -240,7 +241,11 @@ class Settings extends ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
if (device.isTelevision) {
|
||||
applyTvSettings();
|
||||
}
|
||||
|
||||
void applyTvSettings() {
|
||||
if (settings.useTvLayout) {
|
||||
themeBrightness = AvesThemeBrightness.dark;
|
||||
mustBackTwiceToExit = false;
|
||||
// address `TV-BU` / `TV-BY` requirements from https://developer.android.com/docs/quality-guidelines/tv-app-quality
|
||||
|
@ -392,6 +397,12 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set enableBlurEffect(bool newValue) => setAndNotify(enableBlurEffectKey, newValue);
|
||||
|
||||
bool get forceTvLayout => getBool(forceTvLayoutKey) ?? SettingsDefaults.forceTvLayout;
|
||||
|
||||
set forceTvLayout(bool newValue) => setAndNotify(forceTvLayoutKey, newValue);
|
||||
|
||||
bool get useTvLayout => device.isTelevision || forceTvLayout;
|
||||
|
||||
// navigation
|
||||
|
||||
bool get mustBackTwiceToExit => getBool(mustBackTwiceToExitKey) ?? SettingsDefaults.mustBackTwiceToExit;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/about/app_ref.dart';
|
||||
import 'package:aves/widgets/about/bug_report.dart';
|
||||
import 'package:aves/widgets/about/credits.dart';
|
||||
|
@ -28,7 +28,7 @@ class AboutPage extends StatelessWidget {
|
|||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
const AppReference(),
|
||||
if (!device.isTelevision) ...[
|
||||
if (!settings.useTvLayout) ...[
|
||||
const Divider(),
|
||||
const BugReport(),
|
||||
],
|
||||
|
@ -46,7 +46,8 @@ class AboutPage extends StatelessWidget {
|
|||
],
|
||||
);
|
||||
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
final isRtl = context.isRtl;
|
||||
return Scaffold(
|
||||
body: AvesPopScope(
|
||||
handlers: const [TvNavigationPopHandler.pop],
|
||||
|
@ -55,7 +56,13 @@ class AboutPage extends StatelessWidget {
|
|||
TvRail(
|
||||
controller: context.read<TvRailController>(),
|
||||
),
|
||||
Expanded(child: body),
|
||||
Expanded(
|
||||
child: SafeArea(
|
||||
left: isRtl,
|
||||
right: !isRtl,
|
||||
child: body,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -416,17 +416,20 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
await device.init();
|
||||
if (device.isTelevision) {
|
||||
await mobileServices.init();
|
||||
await settings.init(monitorPlatformSettings: true);
|
||||
settings.isRotationLocked = await windowService.isRotationLocked();
|
||||
settings.areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
if (settings.useTvLayout) {
|
||||
_pageTransitionsBuilderNotifier.value = const TvPageTransitionsBuilder();
|
||||
_tvMediaQueryModifierNotifier.value = (mq) => mq.copyWith(
|
||||
textScaleFactor: 1.1,
|
||||
navigationMode: NavigationMode.directional,
|
||||
);
|
||||
if (settings.forceTvLayout) {
|
||||
await windowService.requestOrientation(Orientation.landscape);
|
||||
}
|
||||
}
|
||||
await mobileServices.init();
|
||||
await settings.init(monitorPlatformSettings: true);
|
||||
settings.isRotationLocked = await windowService.isRotationLocked();
|
||||
settings.areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
_monitorSettings();
|
||||
|
||||
FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
|
@ -448,15 +451,28 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
void applyKeepScreenOn() => settings.keepScreenOn.apply();
|
||||
|
||||
void applyIsRotationLocked() {
|
||||
if (!settings.isRotationLocked) {
|
||||
if (!settings.isRotationLocked && !settings.useTvLayout) {
|
||||
windowService.requestOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
void applyForceTvLayout() {
|
||||
settings.applyTvSettings();
|
||||
windowService.requestOrientation(settings.forceTvLayout ? Orientation.landscape : null);
|
||||
AvesApp.navigatorKey.currentState!.pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
settings: const RouteSettings(name: HomePage.routeName),
|
||||
builder: (_) => _getFirstPage(),
|
||||
),
|
||||
(route) => false,
|
||||
);
|
||||
}
|
||||
|
||||
settings.updateStream.where((event) => event.key == Settings.isInstalledAppAccessAllowedKey).listen((_) => applyIsInstalledAppAccessAllowed());
|
||||
settings.updateStream.where((event) => event.key == Settings.displayRefreshRateModeKey).listen((_) => applyDisplayRefreshRateMode());
|
||||
settings.updateStream.where((event) => event.key == Settings.keepScreenOnKey).listen((_) => applyKeepScreenOn());
|
||||
settings.updateStream.where((event) => event.key == Settings.platformAccelerometerRotationKey).listen((_) => applyIsRotationLocked());
|
||||
settings.updateStream.where((event) => event.key == Settings.forceTvLayoutKey).listen((_) => applyForceTvLayout());
|
||||
|
||||
applyDisplayRefreshRateMode();
|
||||
applyKeepScreenOn();
|
||||
|
|
|
@ -151,70 +151,75 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
final selection = context.watch<Selection<AvesEntry>>();
|
||||
final isSelecting = selection.isSelecting;
|
||||
_isSelectingNotifier.value = isSelecting;
|
||||
return AnimatedBuilder(
|
||||
animation: collection.filterChangeNotifier,
|
||||
builder: (context, child) {
|
||||
final removableFilters = appMode != AppMode.pickMediaInternal;
|
||||
return Selector<Query, bool>(
|
||||
selector: (context, query) => query.enabled,
|
||||
builder: (context, queryEnabled, child) {
|
||||
return Selector<Settings, List<EntrySetAction>>(
|
||||
selector: (context, s) => s.collectionBrowsingQuickActions,
|
||||
builder: (context, _, child) {
|
||||
final isTelevision = device.isTelevision;
|
||||
final actions = _buildActions(context, selection);
|
||||
final onFilterTap = removableFilters ? collection.removeFilter : null;
|
||||
return AvesAppBar(
|
||||
contentHeight: appBarContentHeight,
|
||||
leading: _buildAppBarLeading(
|
||||
hasDrawer: appMode.canNavigate,
|
||||
isSelecting: isSelecting,
|
||||
),
|
||||
title: _buildAppBarTitle(isSelecting),
|
||||
actions: isTelevision ? [] : actions,
|
||||
bottom: Column(
|
||||
children: [
|
||||
if (isTelevision)
|
||||
SizedBox(
|
||||
height: CaptionedButton.getTelevisionButtonHeight(context),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: actions,
|
||||
return NotificationListener<ScrollNotification>(
|
||||
// cancel notification bubbling so that the draggable scroll bar
|
||||
// does not misinterpret filter bar scrolling for collection scrolling
|
||||
onNotification: (notification) => true,
|
||||
child: AnimatedBuilder(
|
||||
animation: collection.filterChangeNotifier,
|
||||
builder: (context, child) {
|
||||
final removableFilters = appMode != AppMode.pickMediaInternal;
|
||||
return Selector<Query, bool>(
|
||||
selector: (context, query) => query.enabled,
|
||||
builder: (context, queryEnabled, child) {
|
||||
return Selector<Settings, List<EntrySetAction>>(
|
||||
selector: (context, s) => s.collectionBrowsingQuickActions,
|
||||
builder: (context, _, child) {
|
||||
final useTvLayout = settings.useTvLayout;
|
||||
final actions = _buildActions(context, selection);
|
||||
final onFilterTap = removableFilters ? collection.removeFilter : null;
|
||||
return AvesAppBar(
|
||||
contentHeight: appBarContentHeight,
|
||||
leading: _buildAppBarLeading(
|
||||
hasDrawer: appMode.canNavigate,
|
||||
isSelecting: isSelecting,
|
||||
),
|
||||
title: _buildAppBarTitle(isSelecting),
|
||||
actions: useTvLayout ? [] : actions,
|
||||
bottom: Column(
|
||||
children: [
|
||||
if (useTvLayout)
|
||||
SizedBox(
|
||||
height: CaptionedButton.getTelevisionButtonHeight(context),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: actions,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showFilterBar)
|
||||
NotificationListener<ReverseFilterNotification>(
|
||||
onNotification: (notification) {
|
||||
collection.addFilter(notification.reversedFilter);
|
||||
return true;
|
||||
},
|
||||
child: FilterBar(
|
||||
filters: visibleFilters,
|
||||
onTap: onFilterTap,
|
||||
onRemove: onFilterTap,
|
||||
if (showFilterBar)
|
||||
NotificationListener<ReverseFilterNotification>(
|
||||
onNotification: (notification) {
|
||||
collection.addFilter(notification.reversedFilter);
|
||||
return true;
|
||||
},
|
||||
child: FilterBar(
|
||||
filters: visibleFilters,
|
||||
onTap: onFilterTap,
|
||||
onRemove: onFilterTap,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (queryEnabled)
|
||||
EntryQueryBar(
|
||||
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
|
||||
focusNode: _queryBarFocusNode,
|
||||
),
|
||||
],
|
||||
),
|
||||
transitionKey: isSelecting,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
if (queryEnabled)
|
||||
EntryQueryBar(
|
||||
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
|
||||
focusNode: _queryBarFocusNode,
|
||||
),
|
||||
],
|
||||
),
|
||||
transitionKey: isSelecting,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double get appBarContentHeight {
|
||||
double height = kToolbarHeight;
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
height += CaptionedButton.getTelevisionButtonHeight(context);
|
||||
}
|
||||
if (showFilterBar) {
|
||||
|
@ -227,7 +232,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
}
|
||||
|
||||
Widget? _buildAppBarLeading({required bool hasDrawer, required bool isSelecting}) {
|
||||
if (device.isTelevision) return null;
|
||||
if (settings.useTvLayout) return null;
|
||||
|
||||
if (!hasDrawer) {
|
||||
return const CloseButton();
|
||||
|
@ -309,7 +314,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
selectedItemCount: selectedItemCount,
|
||||
);
|
||||
|
||||
return device.isTelevision
|
||||
return settings.useTvLayout
|
||||
? _buildTelevisionActions(
|
||||
context: context,
|
||||
appMode: appMode,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/favourite.dart';
|
||||
|
@ -57,7 +56,7 @@ class CollectionGrid extends StatefulWidget {
|
|||
static const double fixedExtentLayoutSpacing = 2;
|
||||
static const double mosaicLayoutSpacing = 4;
|
||||
|
||||
static int get columnCountDefault => device.isTelevision ? 6 : 4;
|
||||
static int get columnCountDefault => settings.useTvLayout ? 6 : 4;
|
||||
|
||||
const CollectionGrid({
|
||||
super.key,
|
||||
|
@ -176,7 +175,7 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
|||
tileLayout: tileLayout,
|
||||
isScrollingNotifier: _isScrollingNotifier,
|
||||
);
|
||||
if (!device.isTelevision) return tile;
|
||||
if (!settings.useTvLayout) return tile;
|
||||
|
||||
return Focus(
|
||||
onFocusChange: (focused) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/filters/query.dart';
|
||||
|
@ -122,7 +121,7 @@ class _CollectionPageState extends State<CollectionPage> {
|
|||
);
|
||||
|
||||
Widget page;
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
page = Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
|
|
|
@ -69,7 +69,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
return isSelecting && selectedItemCount == itemCount;
|
||||
// browsing
|
||||
case EntrySetAction.searchCollection:
|
||||
return !device.isTelevision && appMode.canNavigate && !isSelecting;
|
||||
return !settings.useTvLayout && appMode.canNavigate && !isSelecting;
|
||||
case EntrySetAction.toggleTitleSearch:
|
||||
return !isSelecting;
|
||||
case EntrySetAction.addShortcut:
|
||||
|
@ -82,7 +82,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
case EntrySetAction.stats:
|
||||
return isMain;
|
||||
case EntrySetAction.rescan:
|
||||
return !device.isTelevision && isMain && !isTrash;
|
||||
return !settings.useTvLayout && isMain && !isTrash;
|
||||
// selecting
|
||||
case EntrySetAction.share:
|
||||
case EntrySetAction.toggleFavourite:
|
||||
|
|
|
@ -82,20 +82,15 @@ class _FilterBarState extends State<FilterBar> {
|
|||
// chip border clipping when the floating app bar is fading
|
||||
color: Colors.transparent,
|
||||
height: FilterBar.preferredHeight,
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
// cancel notification bubbling so that the draggable scroll bar
|
||||
// does not misinterpret filter bar scrolling for collection scrolling
|
||||
onNotification: (notification) => true,
|
||||
child: AnimatedList(
|
||||
key: _animatedListKey,
|
||||
initialItemCount: filters.length,
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: FilterBar.rowPadding,
|
||||
itemBuilder: (context, index, animation) {
|
||||
if (index >= filters.length) return const SizedBox();
|
||||
return _buildChip(filters.toList()[index]);
|
||||
},
|
||||
),
|
||||
child: AnimatedList(
|
||||
key: _animatedListKey,
|
||||
initialItemCount: filters.length,
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: FilterBar.rowPadding,
|
||||
itemBuilder: (context, index, animation) {
|
||||
if (index >= filters.length) return const SizedBox();
|
||||
return _buildChip(filters.toList()[index]);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/fx/borders.dart';
|
||||
|
@ -72,13 +72,13 @@ class _ColorPickerDialogState extends State<ColorPickerDialog> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isTelevision = device.isTelevision;
|
||||
final useTvLayout = settings.useTvLayout;
|
||||
return AvesDialog(
|
||||
scrollableContent: [
|
||||
ColorPicker(
|
||||
color: color,
|
||||
onColorChanged: (v) => color = v,
|
||||
pickersEnabled: isTelevision
|
||||
pickersEnabled: useTvLayout
|
||||
? const {
|
||||
ColorPickerType.primary: true,
|
||||
ColorPickerType.accent: false,
|
||||
|
@ -90,7 +90,7 @@ class _ColorPickerDialogState extends State<ColorPickerDialog> {
|
|||
},
|
||||
hasBorder: true,
|
||||
borderRadius: 20,
|
||||
subheading: isTelevision ? const SizedBox(height: 16) : null,
|
||||
subheading: useTvLayout ? const SizedBox(height: 16) : null,
|
||||
)
|
||||
],
|
||||
actions: [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/common/extensions/media_query.dart';
|
||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||
|
@ -127,7 +127,7 @@ class TvTileGridBottomPaddingSliver extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: device.isTelevision ? context.select<TileExtentController, double>((controller) => controller.spacing) : 0,
|
||||
height: settings.useTvLayout ? context.select<TileExtentController, double>((controller) => controller.spacing) : 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/home_page.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
|
@ -13,7 +12,7 @@ import 'package:provider/provider.dart';
|
|||
// address `TV-DB` requirement from https://developer.android.com/docs/quality-guidelines/tv-app-quality
|
||||
class TvNavigationPopHandler {
|
||||
static bool pop(BuildContext context) {
|
||||
if (!device.isTelevision || _isHome(context)) {
|
||||
if (!settings.useTvLayout || _isHome(context)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/selection.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/section_keys.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
@ -33,7 +33,7 @@ class SectionHeader<T> extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget child = _buildContent(context);
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
child = Material(
|
||||
type: MaterialType.transparency,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/colors.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
@ -34,7 +33,7 @@ class AvesAppBar extends StatelessWidget {
|
|||
selector: (context, mq) => mq.padding.top,
|
||||
builder: (context, mqPaddingTop, child) {
|
||||
return SliverPersistentHeader(
|
||||
floating: !device.isTelevision,
|
||||
floating: !settings.useTvLayout,
|
||||
pinned: false,
|
||||
delegate: _SliverAppBarDelegate(
|
||||
height: mqPaddingTop + appBarHeightForContentHeight(contentHeight),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
@ -36,7 +35,7 @@ class MapButtonPanel extends StatelessWidget {
|
|||
Widget? navigationButton;
|
||||
switch (context.select<MapThemeData, MapNavigationButton>((v) => v.navigationButton)) {
|
||||
case MapNavigationButton.back:
|
||||
if (!device.isTelevision) {
|
||||
if (!settings.useTvLayout) {
|
||||
navigationButton = MapOverlayButton(
|
||||
icon: const BackButtonIcon(),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/search/route.dart';
|
||||
|
@ -20,7 +20,7 @@ abstract class AvesSearchDelegate extends SearchDelegate {
|
|||
|
||||
@override
|
||||
Widget? buildLeading(BuildContext context) {
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
return const Icon(AIcons.search);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/actions/chip_set_actions.dart';
|
||||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -83,7 +82,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
|||
return isSelecting && selectedItemCount == itemCount;
|
||||
// browsing
|
||||
case ChipSetAction.search:
|
||||
return !device.isTelevision && appMode.canNavigate && !isSelecting;
|
||||
return !settings.useTvLayout && appMode.canNavigate && !isSelecting;
|
||||
case ChipSetAction.toggleTitleSearch:
|
||||
return !isSelecting;
|
||||
case ChipSetAction.createAlbum:
|
||||
|
|
|
@ -2,10 +2,10 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/actions/chip_set_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/query.dart';
|
||||
import 'package:aves/model/selection.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/widgets/common/action_controls/togglers/title_search.dart';
|
||||
|
@ -125,47 +125,52 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
|||
final selection = context.watch<Selection<FilterGridItem<T>>>();
|
||||
final isSelecting = selection.isSelecting;
|
||||
_isSelectingNotifier.value = isSelecting;
|
||||
return Selector<Query, bool>(
|
||||
selector: (context, query) => query.enabled,
|
||||
builder: (context, queryEnabled, child) {
|
||||
ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions;
|
||||
final isTelevision = device.isTelevision;
|
||||
final actions = actionsBuilder(context, appMode, selection, widget.actionDelegate);
|
||||
return AvesAppBar(
|
||||
contentHeight: appBarContentHeight,
|
||||
leading: _buildAppBarLeading(
|
||||
hasDrawer: appMode.canNavigate,
|
||||
isSelecting: isSelecting,
|
||||
),
|
||||
title: _buildAppBarTitle(isSelecting),
|
||||
actions: isTelevision ? [] : actions,
|
||||
bottom: Column(
|
||||
children: [
|
||||
if (isTelevision)
|
||||
SizedBox(
|
||||
height: CaptionedButton.getTelevisionButtonHeight(context),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: actions,
|
||||
return NotificationListener<ScrollNotification>(
|
||||
// cancel notification bubbling so that the draggable scroll bar
|
||||
// does not misinterpret filter bar scrolling for collection scrolling
|
||||
onNotification: (notification) => true,
|
||||
child: Selector<Query, bool>(
|
||||
selector: (context, query) => query.enabled,
|
||||
builder: (context, queryEnabled, child) {
|
||||
ActionsBuilder<T, CSAD> actionsBuilder = widget.actionsBuilder ?? _buildActions;
|
||||
final useTvLayout = settings.useTvLayout;
|
||||
final actions = actionsBuilder(context, appMode, selection, widget.actionDelegate);
|
||||
return AvesAppBar(
|
||||
contentHeight: appBarContentHeight,
|
||||
leading: _buildAppBarLeading(
|
||||
hasDrawer: appMode.canNavigate,
|
||||
isSelecting: isSelecting,
|
||||
),
|
||||
title: _buildAppBarTitle(isSelecting),
|
||||
actions: useTvLayout ? [] : actions,
|
||||
bottom: Column(
|
||||
children: [
|
||||
if (useTvLayout)
|
||||
SizedBox(
|
||||
height: CaptionedButton.getTelevisionButtonHeight(context),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: actions,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (queryEnabled)
|
||||
FilterQueryBar<T>(
|
||||
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
|
||||
focusNode: _queryBarFocusNode,
|
||||
),
|
||||
],
|
||||
),
|
||||
transitionKey: isSelecting,
|
||||
);
|
||||
},
|
||||
if (queryEnabled)
|
||||
FilterQueryBar<T>(
|
||||
queryNotifier: context.select<Query, ValueNotifier<String>>((query) => query.queryNotifier),
|
||||
focusNode: _queryBarFocusNode,
|
||||
),
|
||||
],
|
||||
),
|
||||
transitionKey: isSelecting,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double get appBarContentHeight {
|
||||
double height = kToolbarHeight;
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
height += CaptionedButton.getTelevisionButtonHeight(context);
|
||||
}
|
||||
if (context.read<Query>().enabled) {
|
||||
|
@ -175,7 +180,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
|||
}
|
||||
|
||||
Widget? _buildAppBarLeading({required bool hasDrawer, required bool isSelecting}) {
|
||||
if (device.isTelevision) return null;
|
||||
if (settings.useTvLayout) return null;
|
||||
|
||||
if (!hasDrawer) {
|
||||
return const CloseButton();
|
||||
|
@ -251,7 +256,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
|
|||
selectedFilters: selectedFilters,
|
||||
);
|
||||
|
||||
return device.isTelevision
|
||||
return settings.useTvLayout
|
||||
? _buildTelevisionActions(
|
||||
context: context,
|
||||
selection: selection,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/model/query.dart';
|
||||
|
@ -113,7 +112,7 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
return Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
|
@ -202,7 +201,7 @@ class _FilterGridState<T extends CollectionFilter> extends State<_FilterGrid<T>>
|
|||
Widget build(BuildContext context) {
|
||||
_tileExtentController ??= TileExtentController(
|
||||
settingsRouteKey: widget.settingsRouteKey ?? context.currentRouteName!,
|
||||
columnCountDefault: device.isTelevision ? 4 : 3,
|
||||
columnCountDefault: settings.useTvLayout ? 4 : 3,
|
||||
extentMin: 60,
|
||||
extentMax: 300,
|
||||
spacing: 8,
|
||||
|
@ -356,7 +355,7 @@ class _FilterGridContentState<T extends CollectionFilter> extends State<_FilterG
|
|||
banner: _getFilterBanner(context, gridItem.filter),
|
||||
heroType: widget.heroType,
|
||||
);
|
||||
if (!device.isTelevision) return tile;
|
||||
if (!settings.useTvLayout) return tile;
|
||||
|
||||
return Focus(
|
||||
onFocusChange: (focused) {
|
||||
|
|
|
@ -109,25 +109,28 @@ class _TvRailState extends State<TvRail> {
|
|||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
header,
|
||||
const SizedBox(height: 4),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(minHeight: constraints.maxHeight),
|
||||
child: IntrinsicHeight(child: rail),
|
||||
),
|
||||
);
|
||||
},
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
header,
|
||||
const SizedBox(height: 4),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(minHeight: constraints.maxHeight),
|
||||
child: IntrinsicHeight(child: rail),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
|
@ -29,7 +28,7 @@ class AccessibilitySection extends SettingsSection {
|
|||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
if (!device.isTelevision) SettingsTileAccessibilityShowPinchGestureAlternatives(),
|
||||
if (!settings.useTvLayout) SettingsTileAccessibilityShowPinchGestureAlternatives(),
|
||||
SettingsTileAccessibilityAnimations(),
|
||||
SettingsTileAccessibilityTimeToTakeAction(),
|
||||
];
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/theme/colors.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
|
@ -29,11 +30,12 @@ class DisplaySection extends SettingsSection {
|
|||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
if (!device.isTelevision) SettingsTileDisplayThemeBrightness(),
|
||||
if (!settings.useTvLayout) SettingsTileDisplayThemeBrightness(),
|
||||
SettingsTileDisplayThemeColorMode(),
|
||||
if (device.isDynamicColorAvailable) SettingsTileDisplayEnableDynamicColor(),
|
||||
SettingsTileDisplayEnableBlurEffect(),
|
||||
if (!device.isTelevision) SettingsTileDisplayDisplayRefreshRateMode(),
|
||||
if (!settings.useTvLayout) SettingsTileDisplayRefreshRateMode(),
|
||||
if (!device.isTelevision) SettingsTileDisplayForceTvLayout(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -88,7 +90,7 @@ class SettingsTileDisplayEnableBlurEffect extends SettingsTile {
|
|||
);
|
||||
}
|
||||
|
||||
class SettingsTileDisplayDisplayRefreshRateMode extends SettingsTile {
|
||||
class SettingsTileDisplayRefreshRateMode extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsDisplayRefreshRateModeTile;
|
||||
|
||||
|
@ -102,3 +104,41 @@ class SettingsTileDisplayDisplayRefreshRateMode extends SettingsTile {
|
|||
dialogTitle: context.l10n.settingsDisplayRefreshRateModeDialogTitle,
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsTileDisplayForceTvLayout extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsDisplayUseTvInterface;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||
selector: (context, s) => s.forceTvLayout,
|
||||
onChanged: (v) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
final l10n = context.l10n;
|
||||
return AvesDialog(
|
||||
content: Text([
|
||||
l10n.settingsModificationWarningDialogMessage,
|
||||
l10n.genericDangerWarningDialogMessage,
|
||||
].join('\n\n')),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(l10n.applyButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (confirmed == null || !confirmed) return;
|
||||
|
||||
settings.forceTvLayout = v;
|
||||
},
|
||||
title: title(context),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/home_page.dart';
|
||||
import 'package:aves/model/settings/enums/screen_on.dart';
|
||||
|
@ -32,11 +31,11 @@ class NavigationSection extends SettingsSection {
|
|||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
SettingsTileNavigationHomePage(),
|
||||
if (!device.isTelevision) SettingsTileNavigationKeepScreenOn(),
|
||||
if (!device.isTelevision) SettingsTileShowBottomNavigationBar(),
|
||||
if (!device.isTelevision) SettingsTileNavigationDoubleBackExit(),
|
||||
if (!settings.useTvLayout) SettingsTileNavigationKeepScreenOn(),
|
||||
if (!settings.useTvLayout) SettingsTileShowBottomNavigationBar(),
|
||||
if (!settings.useTvLayout) SettingsTileNavigationDoubleBackExit(),
|
||||
SettingsTileNavigationDrawer(),
|
||||
if (!device.isTelevision) SettingsTileNavigationConfirmationDialog(),
|
||||
if (!settings.useTvLayout) SettingsTileNavigationConfirmationDialog(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ class PrivacySection extends SettingsSection {
|
|||
return [
|
||||
SettingsTilePrivacyAllowInstalledAppAccess(),
|
||||
if (canEnableErrorReporting) SettingsTilePrivacyAllowErrorReporting(),
|
||||
if (!device.isTelevision && device.canRequestManageMedia) SettingsTilePrivacyManageMedia(),
|
||||
if (!settings.useTvLayout && device.canRequestManageMedia) SettingsTilePrivacyManageMedia(),
|
||||
SettingsTilePrivacySaveSearchHistory(),
|
||||
if (!device.isTelevision) SettingsTilePrivacyEnableBin(),
|
||||
if (!settings.useTvLayout) SettingsTilePrivacyEnableBin(),
|
||||
SettingsTilePrivacyHiddenItems(),
|
||||
if (!device.isTelevision && device.canGrantDirectoryAccess) SettingsTilePrivacyStorageAccess(),
|
||||
if (!settings.useTvLayout && device.canGrantDirectoryAccess) SettingsTilePrivacyStorageAccess(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:aves/model/actions/settings_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
@ -73,7 +73,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
|||
Widget build(BuildContext context) {
|
||||
final appBarTitle = Text(context.l10n.settingsPageTitle);
|
||||
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
return Scaffold(
|
||||
body: AvesPopScope(
|
||||
handlers: const [TvNavigationPopHandler.pop],
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/colors.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
|
@ -25,7 +25,7 @@ class ThumbnailsSection extends SettingsSection {
|
|||
|
||||
@override
|
||||
List<SettingsTile> tiles(BuildContext context) => [
|
||||
if (!device.isTelevision) SettingsTileCollectionQuickActions(),
|
||||
if (!settings.useTvLayout) SettingsTileCollectionQuickActions(),
|
||||
SettingsTileThumbnailOverlay(),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/filters/mime.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/video_auto_play_mode.dart';
|
||||
|
@ -43,7 +42,7 @@ class VideoSection extends SettingsSection {
|
|||
SettingsTileVideoEnableHardwareAcceleration(),
|
||||
SettingsTileVideoEnableAutoPlay(),
|
||||
SettingsTileVideoLoopMode(),
|
||||
if (!device.isTelevision) SettingsTileVideoControls(),
|
||||
if (!settings.useTvLayout) SettingsTileVideoControls(),
|
||||
SettingsTileVideoSubtitleTheme(),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||
|
@ -20,7 +19,7 @@ class ViewerOverlayPage extends StatelessWidget {
|
|||
body: SafeArea(
|
||||
child: ListView(
|
||||
children: [
|
||||
if (!device.isTelevision)
|
||||
if (!settings.useTvLayout)
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.showOverlayOnOpening,
|
||||
onChanged: (v) => settings.showOverlayOnOpening = v,
|
||||
|
@ -68,13 +67,13 @@ class ViewerOverlayPage extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
),
|
||||
if (!device.isTelevision)
|
||||
if (!settings.useTvLayout)
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.showOverlayMinimap,
|
||||
onChanged: (v) => settings.showOverlayMinimap = v,
|
||||
title: context.l10n.settingsViewerShowMinimap,
|
||||
),
|
||||
if (!device.isTelevision)
|
||||
if (!settings.useTvLayout)
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.showOverlayThumbnailPreview,
|
||||
onChanged: (v) => settings.showOverlayThumbnailPreview = v,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
@ -34,12 +33,12 @@ class ViewerSection extends SettingsSection {
|
|||
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||
final isCutoutAware = await windowService.isCutoutAware();
|
||||
return [
|
||||
if (!device.isTelevision) SettingsTileViewerQuickActions(),
|
||||
if (!settings.useTvLayout) SettingsTileViewerQuickActions(),
|
||||
SettingsTileViewerOverlay(),
|
||||
SettingsTileViewerSlideshow(),
|
||||
if (!device.isTelevision) SettingsTileViewerGestureSideTapNext(),
|
||||
if (!device.isTelevision && isCutoutAware) SettingsTileViewerUseCutout(),
|
||||
if (!device.isTelevision) SettingsTileViewerMaxBrightness(),
|
||||
if (!settings.useTvLayout) SettingsTileViewerGestureSideTapNext(),
|
||||
if (!settings.useTvLayout && isCutoutAware) SettingsTileViewerUseCutout(),
|
||||
if (!settings.useTvLayout) SettingsTileViewerMaxBrightness(),
|
||||
SettingsTileViewerMotionPhotoAutoPlay(),
|
||||
SettingsTileViewerImageBackground(),
|
||||
];
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -226,7 +225,7 @@ class _StatsPageState extends State<StatsPage> {
|
|||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: !device.isTelevision,
|
||||
automaticallyImplyLeading: !settings.useTvLayout,
|
||||
title: Text(l10n.statsPageTitle),
|
||||
),
|
||||
body: GestureAreaProtectorStack(
|
||||
|
@ -356,7 +355,7 @@ class StatsTopPage extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: !device.isTelevision,
|
||||
automaticallyImplyLeading: !settings.useTvLayout,
|
||||
title: Text(title),
|
||||
),
|
||||
body: GestureAreaProtectorStack(
|
||||
|
|
|
@ -93,7 +93,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.videoCaptureFrame:
|
||||
return canWrite && targetEntry.isVideo;
|
||||
case EntryAction.videoToggleMute:
|
||||
return !device.isTelevision && targetEntry.isVideo;
|
||||
return !settings.useTvLayout && targetEntry.isVideo;
|
||||
case EntryAction.videoSelectStreams:
|
||||
case EntryAction.videoSetSpeed:
|
||||
case EntryAction.videoSettings:
|
||||
|
@ -103,13 +103,13 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.openVideo:
|
||||
return targetEntry.isVideo;
|
||||
case EntryAction.rotateScreen:
|
||||
return !device.isTelevision && settings.isRotationLocked;
|
||||
return !settings.useTvLayout && settings.isRotationLocked;
|
||||
case EntryAction.addShortcut:
|
||||
return device.canPinShortcut;
|
||||
case EntryAction.edit:
|
||||
return canWrite;
|
||||
case EntryAction.copyToClipboard:
|
||||
return !device.isTelevision;
|
||||
return !settings.useTvLayout;
|
||||
case EntryAction.info:
|
||||
case EntryAction.open:
|
||||
case EntryAction.setAs:
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'dart:ui';
|
|||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/actions/entry_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
|
@ -181,12 +180,12 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
|||
}
|
||||
|
||||
Widget _buildImagePage() {
|
||||
final isTelevision = device.isTelevision;
|
||||
final useTvLayout = settings.useTvLayout;
|
||||
|
||||
Widget? child;
|
||||
Map<ShortcutActivator, Intent>? shortcuts = {
|
||||
const SingleActivator(LogicalKeyboardKey.arrowUp): isTelevision ? const TvShowLessInfoIntent() : const _LeaveIntent(),
|
||||
const SingleActivator(LogicalKeyboardKey.arrowDown): isTelevision ? const _TvShowMoreInfoIntent() : const _ShowInfoIntent(),
|
||||
const SingleActivator(LogicalKeyboardKey.arrowUp): useTvLayout ? const TvShowLessInfoIntent() : const _LeaveIntent(),
|
||||
const SingleActivator(LogicalKeyboardKey.arrowDown): useTvLayout ? const _TvShowMoreInfoIntent() : const _ShowInfoIntent(),
|
||||
const SingleActivator(LogicalKeyboardKey.mediaPause): const _PlayPauseIntent.pause(),
|
||||
const SingleActivator(LogicalKeyboardKey.mediaPlay): const _PlayPauseIntent.play(),
|
||||
const SingleActivator(LogicalKeyboardKey.mediaPlayPause): const _PlayPauseIntent.toggle(),
|
||||
|
@ -211,7 +210,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
|||
);
|
||||
}
|
||||
if (child != null) {
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
child = ValueListenableBuilder<bool>(
|
||||
valueListenable: _isImageFocusedNotifier,
|
||||
builder: (context, isImageFocused, child) {
|
||||
|
@ -238,7 +237,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
|||
_TvShowMoreInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowMoreInfoNotification().dispatch(context)),
|
||||
_PlayPauseIntent: CallbackAction<_PlayPauseIntent>(onInvoke: (intent) => _onPlayPauseIntent(intent, entry)),
|
||||
ActivateIntent: CallbackAction<Intent>(onInvoke: (intent) {
|
||||
if (isTelevision) {
|
||||
if (useTvLayout) {
|
||||
final _entry = entry;
|
||||
if (_entry != null && _entry.isVideo) {
|
||||
// address `TV-PC` requirement from https://developer.android.com/docs/quality-guidelines/tv-app-quality
|
||||
|
|
|
@ -689,7 +689,9 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
await windowService.requestOrientation();
|
||||
if (!settings.useTvLayout) {
|
||||
await windowService.requestOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
// overlay
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/actions/entry_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
@ -37,7 +37,7 @@ class InfoAppBar extends StatelessWidget {
|
|||
final formatSpecificActions = EntryActions.formatSpecificMetadataActions.where((v) => actionDelegate.isVisible(entry, v));
|
||||
|
||||
return SliverAppBar(
|
||||
leading: device.isTelevision
|
||||
leading: settings.useTvLayout
|
||||
? null
|
||||
: IconButton(
|
||||
// key is expected by test driver
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
|
@ -186,7 +185,7 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
|
|||
final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero);
|
||||
final viewerButtonRow = FocusableActionDetector(
|
||||
focusNode: _buttonRowFocusScopeNode,
|
||||
shortcuts: device.isTelevision ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null,
|
||||
shortcuts: settings.useTvLayout ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null,
|
||||
actions: {TvShowLessInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context))},
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/actions/slideshow_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/common/identity/buttons/captioned_button.dart';
|
||||
import 'package:aves/widgets/common/identity/buttons/overlay_button.dart';
|
||||
import 'package:aves/widgets/viewer/entry_vertical_pager.dart';
|
||||
|
@ -70,9 +70,9 @@ class _SlideshowButtonsState extends State<SlideshowButtons> {
|
|||
Widget build(BuildContext context) {
|
||||
return FocusableActionDetector(
|
||||
focusNode: _buttonRowFocusScopeNode,
|
||||
shortcuts: device.isTelevision ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null,
|
||||
shortcuts: settings.useTvLayout ? const {SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent()} : null,
|
||||
actions: {TvShowLessInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context))},
|
||||
child: device.isTelevision
|
||||
child: settings.useTvLayout
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:aves/model/actions/entry_actions.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
|
@ -51,7 +50,7 @@ class ViewerButtons extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final actionDelegate = EntryActionDelegate(mainEntry, pageEntry, collection);
|
||||
|
||||
if (device.isTelevision) {
|
||||
if (settings.useTvLayout) {
|
||||
return _TvButtonRowContent(
|
||||
actionDelegate: actionDelegate,
|
||||
scale: scale,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/panorama.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/common/basic/insets.dart';
|
||||
|
@ -110,7 +110,7 @@ class _PanoramaPageState extends State<PanoramaPage> {
|
|||
}
|
||||
|
||||
Widget _buildOverlay(BuildContext context) {
|
||||
if (device.isTelevision) return const SizedBox();
|
||||
if (settings.useTvLayout) return const SizedBox();
|
||||
|
||||
return TooltipTheme(
|
||||
data: TooltipTheme.of(context).copyWith(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:aves/app_flavor.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/defaults.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
@ -71,7 +70,7 @@ class _WelcomePageState extends State<WelcomePage> {
|
|||
child: child,
|
||||
),
|
||||
),
|
||||
children: device.isTelevision
|
||||
children: settings.useTvLayout
|
||||
? [
|
||||
..._buildHeader(context, isPortrait: isPortrait),
|
||||
Padding(
|
||||
|
|
|
@ -387,6 +387,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionExport",
|
||||
|
@ -526,6 +527,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -592,21 +594,29 @@
|
|||
],
|
||||
|
||||
"cs": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"de": [
|
||||
"columnCount",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"el": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"es": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"fa": [
|
||||
|
@ -867,6 +877,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionImport",
|
||||
|
@ -1002,6 +1013,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -1074,6 +1086,11 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"gl": [
|
||||
"columnCount",
|
||||
"entryActionShareImageOnly",
|
||||
|
@ -1329,6 +1346,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionExport",
|
||||
|
@ -1468,6 +1486,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -1543,11 +1562,15 @@
|
|||
],
|
||||
|
||||
"id": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"it": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"ja": [
|
||||
|
@ -1559,16 +1582,25 @@
|
|||
"keepScreenOnVideoPlayback",
|
||||
"subtitlePositionTop",
|
||||
"subtitlePositionBottom",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsWidgetDisplayedItem"
|
||||
],
|
||||
|
||||
"ko": [
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"lt": [
|
||||
"columnCount",
|
||||
"keepScreenOnVideoPlayback",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"nb": [
|
||||
|
@ -1577,8 +1609,10 @@
|
|||
"entryActionShareVideoOnly",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"keepScreenOnVideoPlayback",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"nl": [
|
||||
|
@ -1595,11 +1629,13 @@
|
|||
"subtitlePositionBottom",
|
||||
"widgetDisplayedItemRandom",
|
||||
"widgetDisplayedItemMostRecent",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowRatingTags",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsSubtitleThemeTextPositionTile",
|
||||
"settingsSubtitleThemeTextPositionDialogTitle",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsWidgetDisplayedItem"
|
||||
],
|
||||
|
||||
|
@ -1841,6 +1877,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionExport",
|
||||
|
@ -1980,6 +2017,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -2349,6 +2387,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionExport",
|
||||
|
@ -2488,6 +2527,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -2576,16 +2616,25 @@
|
|||
"subtitlePositionBottom",
|
||||
"widgetDisplayedItemRandom",
|
||||
"widgetDisplayedItemMostRecent",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowRatingTags",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsSubtitleThemeTextPositionTile",
|
||||
"settingsSubtitleThemeTextPositionDialogTitle",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsWidgetDisplayedItem"
|
||||
],
|
||||
|
||||
"ro": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"ru": [
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"th": [
|
||||
|
@ -2718,6 +2767,7 @@
|
|||
"settingsSystemDefault",
|
||||
"settingsDefault",
|
||||
"settingsDisabled",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsActionExport",
|
||||
|
@ -2857,6 +2907,7 @@
|
|||
"settingsThemeEnableDynamicColor",
|
||||
"settingsDisplayRefreshRateModeTile",
|
||||
"settingsDisplayRefreshRateModeDialogTitle",
|
||||
"settingsDisplayUseTvInterface",
|
||||
"settingsLanguageSectionTitle",
|
||||
"settingsLanguageTile",
|
||||
"settingsLanguagePageTitle",
|
||||
|
@ -2932,21 +2983,29 @@
|
|||
],
|
||||
|
||||
"tr": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"uk": [
|
||||
"settingsViewerShowDescription"
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"zh": [
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface"
|
||||
],
|
||||
|
||||
"zh_Hant": [
|
||||
"columnCount",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsViewerShowDescription",
|
||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||
"settingsDisplayUseTvInterface"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue