settings search
This commit is contained in:
parent
9747ea98bc
commit
21938ab1b1
26 changed files with 1014 additions and 632 deletions
|
@ -588,6 +588,8 @@
|
||||||
"settingsSystemDefault": "System",
|
"settingsSystemDefault": "System",
|
||||||
"settingsDefault": "Default",
|
"settingsDefault": "Default",
|
||||||
|
|
||||||
|
"settingsSearchFieldLabel": "Search settings",
|
||||||
|
"settingsSearchEmpty": "No matching setting",
|
||||||
"settingsActionExport": "Export",
|
"settingsActionExport": "Export",
|
||||||
"settingsActionImport": "Import",
|
"settingsActionImport": "Import",
|
||||||
|
|
||||||
|
@ -616,6 +618,8 @@
|
||||||
"settingsNavigationDrawerAddAlbum": "Add album",
|
"settingsNavigationDrawerAddAlbum": "Add album",
|
||||||
|
|
||||||
"settingsSectionThumbnails": "Thumbnails",
|
"settingsSectionThumbnails": "Thumbnails",
|
||||||
|
"settingsThumbnailOverlayTile": "Overlay",
|
||||||
|
"settingsThumbnailOverlayTitle": "Overlay",
|
||||||
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
||||||
"settingsThumbnailShowLocationIcon": "Show location icon",
|
"settingsThumbnailShowLocationIcon": "Show location icon",
|
||||||
"settingsThumbnailShowMotionPhotoIcon": "Show motion photo icon",
|
"settingsThumbnailShowMotionPhotoIcon": "Show motion photo icon",
|
||||||
|
|
|
@ -1,45 +1,57 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/accessibility/time_to_take_action.dart';
|
import 'package:aves/widgets/settings/accessibility/time_to_take_action.dart';
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class AccessibilitySection extends StatelessWidget {
|
class AccessibilitySection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'accessibility';
|
||||||
const AccessibilitySection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.accessibility,
|
icon: AIcons.accessibility,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.accessibility),
|
color: context.select<AvesColorsData, Color>((v) => v.accessibility),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionAccessibility,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionAccessibility;
|
||||||
children: [
|
|
||||||
SettingsSelectionListTile<AccessibilityAnimations>(
|
@override
|
||||||
values: AccessibilityAnimations.values,
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||||
getName: (context, v) => v.getName(context),
|
SettingsTileAccessibilityAnimations(),
|
||||||
selector: (context, s) => s.accessibilityAnimations,
|
SettingsTileAccessibilityTimeToTakeAction(),
|
||||||
onSelection: (v) => settings.accessibilityAnimations = v,
|
];
|
||||||
tileTitle: context.l10n.settingsRemoveAnimationsTile,
|
}
|
||||||
dialogTitle: context.l10n.settingsRemoveAnimationsTitle,
|
|
||||||
),
|
class SettingsTileAccessibilityAnimations extends SettingsTile {
|
||||||
const TimeToTakeActionTile(),
|
@override
|
||||||
],
|
String title(BuildContext context) => context.l10n.settingsRemoveAnimationsTile;
|
||||||
);
|
|
||||||
}
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<AccessibilityAnimations>(
|
||||||
|
values: AccessibilityAnimations.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => s.accessibilityAnimations,
|
||||||
|
onSelection: (v) => settings.accessibilityAnimations = v,
|
||||||
|
tileTitle: title(context),
|
||||||
|
dialogTitle: context.l10n.settingsRemoveAnimationsTitle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileAccessibilityTimeToTakeAction extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsTimeToTakeActionTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => const TimeToTakeActionTile();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,34 @@ import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SettingsSubPageTile extends StatelessWidget {
|
||||||
|
final String title, routeName;
|
||||||
|
final WidgetBuilder builder;
|
||||||
|
|
||||||
|
const SettingsSubPageTile({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.routeName,
|
||||||
|
required this.builder,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(title),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
settings: RouteSettings(name: routeName),
|
||||||
|
builder: builder,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SettingsSwitchListTile extends StatelessWidget {
|
class SettingsSwitchListTile extends StatelessWidget {
|
||||||
final bool Function(BuildContext, Settings) selector;
|
final bool Function(BuildContext, Settings) selector;
|
||||||
final ValueChanged<bool> onChanged;
|
final ValueChanged<bool> onChanged;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
|
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/theme_brightness.dart';
|
import 'package:aves/model/settings/enums/theme_brightness.dart';
|
||||||
|
@ -5,53 +7,71 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DisplaySection extends StatelessWidget {
|
class DisplaySection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'display';
|
||||||
const DisplaySection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.display,
|
icon: AIcons.display,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.display),
|
color: context.select<AvesColorsData, Color>((v) => v.display),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionDisplay,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionDisplay;
|
||||||
children: [
|
|
||||||
SettingsSelectionListTile<AvesThemeBrightness>(
|
@override
|
||||||
values: AvesThemeBrightness.values,
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||||
getName: (context, v) => v.getName(context),
|
SettingsTileDisplayThemeBrightness(),
|
||||||
selector: (context, s) => s.themeBrightness,
|
SettingsTileDisplayThemeColorMode(),
|
||||||
onSelection: (v) => settings.themeBrightness = v,
|
SettingsTileDisplayDisplayRefreshRateMode(),
|
||||||
tileTitle: context.l10n.settingsThemeBrightness,
|
];
|
||||||
dialogTitle: context.l10n.settingsThemeBrightness,
|
}
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
class SettingsTileDisplayThemeBrightness extends SettingsTile {
|
||||||
selector: (context, s) => s.themeColorMode == AvesThemeColorMode.polychrome,
|
@override
|
||||||
onChanged: (v) => settings.themeColorMode = v ? AvesThemeColorMode.polychrome : AvesThemeColorMode.monochrome,
|
String title(BuildContext context) => context.l10n.settingsThemeBrightness;
|
||||||
title: context.l10n.settingsThemeColorHighlights,
|
|
||||||
),
|
@override
|
||||||
SettingsSelectionListTile<DisplayRefreshRateMode>(
|
Widget build(BuildContext context) => SettingsSelectionListTile<AvesThemeBrightness>(
|
||||||
values: DisplayRefreshRateMode.values,
|
values: AvesThemeBrightness.values,
|
||||||
getName: (context, v) => v.getName(context),
|
getName: (context, v) => v.getName(context),
|
||||||
selector: (context, s) => s.displayRefreshRateMode,
|
selector: (context, s) => s.themeBrightness,
|
||||||
onSelection: (v) => settings.displayRefreshRateMode = v,
|
onSelection: (v) => settings.themeBrightness = v,
|
||||||
tileTitle: context.l10n.settingsDisplayRefreshRateModeTile,
|
tileTitle: title(context),
|
||||||
dialogTitle: context.l10n.settingsDisplayRefreshRateModeTitle,
|
dialogTitle: context.l10n.settingsThemeBrightness,
|
||||||
),
|
);
|
||||||
],
|
}
|
||||||
);
|
|
||||||
}
|
class SettingsTileDisplayThemeColorMode extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsThemeColorHighlights;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.themeColorMode == AvesThemeColorMode.polychrome,
|
||||||
|
onChanged: (v) => settings.themeColorMode = v ? AvesThemeColorMode.polychrome : AvesThemeColorMode.monochrome,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileDisplayDisplayRefreshRateMode extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsDisplayRefreshRateModeTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<DisplayRefreshRateMode>(
|
||||||
|
values: DisplayRefreshRateMode.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => s.displayRefreshRateMode,
|
||||||
|
onSelection: (v) => settings.displayRefreshRateMode = v,
|
||||||
|
tileTitle: title(context),
|
||||||
|
dialogTitle: context.l10n.settingsDisplayRefreshRateModeTitle,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/unit_system.dart';
|
import 'package:aves/model/settings/enums/unit_system.dart';
|
||||||
|
@ -6,57 +8,69 @@ import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:aves/widgets/settings/language/locale.dart';
|
import 'package:aves/widgets/settings/language/locale.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class LanguageSection extends StatelessWidget {
|
class LanguageSection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'language';
|
||||||
const LanguageSection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
final l10n = context.l10n;
|
|
||||||
return AvesExpansionTile(
|
|
||||||
// key is expected by test driver
|
|
||||||
key: const Key('section-language'),
|
|
||||||
// use a fixed value instead of the title to identify this expansion tile
|
|
||||||
// so that the tile state is kept when the language is modified
|
|
||||||
value: 'language',
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.language,
|
icon: AIcons.language,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.language),
|
color: context.select<AvesColorsData, Color>((v) => v.language),
|
||||||
),
|
);
|
||||||
title: l10n.settingsSectionLanguage,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionLanguage;
|
||||||
children: [
|
|
||||||
const LocaleTile(),
|
@override
|
||||||
SettingsSelectionListTile<CoordinateFormat>(
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||||
values: CoordinateFormat.values,
|
SettingsTileLanguageLocale(),
|
||||||
getName: (context, v) => v.getName(context),
|
SettingsTileLanguageCoordinateFormat(),
|
||||||
selector: (context, s) => s.coordinateFormat,
|
SettingsTileLanguageUnitSystem(),
|
||||||
onSelection: (v) => settings.coordinateFormat = v,
|
];
|
||||||
tileTitle: l10n.settingsCoordinateFormatTile,
|
}
|
||||||
dialogTitle: l10n.settingsCoordinateFormatTitle,
|
|
||||||
optionSubtitleBuilder: (value) => value.format(l10n, Constants.pointNemo),
|
class SettingsTileLanguageLocale extends SettingsTile {
|
||||||
),
|
@override
|
||||||
SettingsSelectionListTile<UnitSystem>(
|
String title(BuildContext context) => context.l10n.settingsLanguage;
|
||||||
values: UnitSystem.values,
|
|
||||||
getName: (context, v) => v.getName(context),
|
@override
|
||||||
selector: (context, s) => s.unitSystem,
|
Widget build(BuildContext context) => const LocaleTile();
|
||||||
onSelection: (v) => settings.unitSystem = v,
|
}
|
||||||
tileTitle: l10n.settingsUnitSystemTile,
|
|
||||||
dialogTitle: l10n.settingsUnitSystemTitle,
|
class SettingsTileLanguageCoordinateFormat extends SettingsTile {
|
||||||
),
|
@override
|
||||||
],
|
String title(BuildContext context) => context.l10n.settingsCoordinateFormatTile;
|
||||||
);
|
|
||||||
}
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<CoordinateFormat>(
|
||||||
|
values: CoordinateFormat.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => s.coordinateFormat,
|
||||||
|
onSelection: (v) => settings.coordinateFormat = v,
|
||||||
|
tileTitle: title(context),
|
||||||
|
dialogTitle: context.l10n.settingsCoordinateFormatTitle,
|
||||||
|
optionSubtitleBuilder: (value) => value.format(context.l10n, Constants.pointNemo),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileLanguageUnitSystem extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsUnitSystemTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<UnitSystem>(
|
||||||
|
values: UnitSystem.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => s.unitSystem,
|
||||||
|
onSelection: (v) => settings.unitSystem = v,
|
||||||
|
tileTitle: title(context),
|
||||||
|
dialogTitle: context.l10n.settingsUnitSystemTitle,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,6 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ConfirmationDialogTile extends StatelessWidget {
|
|
||||||
const ConfirmationDialogTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsConfirmationDialogTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: ConfirmationDialogPage.routeName),
|
|
||||||
builder: (context) => const ConfirmationDialogPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConfirmationDialogPage extends StatelessWidget {
|
class ConfirmationDialogPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/navigation_confirmation';
|
static const routeName = '/settings/navigation_confirmation';
|
||||||
|
|
||||||
|
|
|
@ -13,26 +13,6 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class NavigationDrawerTile extends StatelessWidget {
|
|
||||||
const NavigationDrawerTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsNavigationDrawerTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: NavigationDrawerEditorPage.routeName),
|
|
||||||
builder: (context) => const NavigationDrawerEditorPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NavigationDrawerEditorPage extends StatefulWidget {
|
class NavigationDrawerEditorPage extends StatefulWidget {
|
||||||
static const routeName = '/settings/navigation_drawer';
|
static const routeName = '/settings/navigation_drawer';
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/home_page.dart';
|
import 'package:aves/model/settings/enums/home_page.dart';
|
||||||
import 'package:aves/model/settings/enums/screen_on.dart';
|
import 'package:aves/model/settings/enums/screen_on.dart';
|
||||||
|
@ -5,57 +7,99 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:aves/widgets/settings/navigation/confirmation_dialogs.dart';
|
import 'package:aves/widgets/settings/navigation/confirmation_dialogs.dart';
|
||||||
import 'package:aves/widgets/settings/navigation/drawer.dart';
|
import 'package:aves/widgets/settings/navigation/drawer.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class NavigationSection extends StatelessWidget {
|
class NavigationSection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'navigation';
|
||||||
const NavigationSection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.home,
|
icon: AIcons.home,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.navigation),
|
color: context.select<AvesColorsData, Color>((v) => v.navigation),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionNavigation,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionNavigation;
|
||||||
children: [
|
|
||||||
SettingsSelectionListTile<HomePageSetting>(
|
@override
|
||||||
values: HomePageSetting.values,
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||||
getName: (context, v) => v.getName(context),
|
SettingsTileNavigationHomePage(),
|
||||||
selector: (context, s) => s.homePage,
|
SettingsTileNavigationDrawer(),
|
||||||
onSelection: (v) => settings.homePage = v,
|
SettingsTileNavigationConfirmationDialog(),
|
||||||
tileTitle: context.l10n.settingsHome,
|
SettingsTileNavigationKeepScreenOn(),
|
||||||
dialogTitle: context.l10n.settingsHome,
|
SettingsTileNavigationDoubleBackExit(),
|
||||||
),
|
];
|
||||||
const NavigationDrawerTile(),
|
}
|
||||||
const ConfirmationDialogTile(),
|
|
||||||
SettingsSelectionListTile<KeepScreenOn>(
|
class SettingsTileNavigationHomePage extends SettingsTile {
|
||||||
values: KeepScreenOn.values,
|
@override
|
||||||
getName: (context, v) => v.getName(context),
|
String title(BuildContext context) => context.l10n.settingsHome;
|
||||||
selector: (context, s) => s.keepScreenOn,
|
|
||||||
onSelection: (v) => settings.keepScreenOn = v,
|
@override
|
||||||
tileTitle: context.l10n.settingsKeepScreenOnTile,
|
Widget build(BuildContext context) => SettingsSelectionListTile<HomePageSetting>(
|
||||||
dialogTitle: context.l10n.settingsKeepScreenOnTitle,
|
values: HomePageSetting.values,
|
||||||
),
|
getName: (context, v) => v.getName(context),
|
||||||
SettingsSwitchListTile(
|
selector: (context, s) => s.homePage,
|
||||||
selector: (context, s) => s.mustBackTwiceToExit,
|
onSelection: (v) => settings.homePage = v,
|
||||||
onChanged: (v) => settings.mustBackTwiceToExit = v,
|
tileTitle: title(context),
|
||||||
title: context.l10n.settingsDoubleBackExit,
|
dialogTitle: context.l10n.settingsHome,
|
||||||
),
|
);
|
||||||
],
|
}
|
||||||
);
|
|
||||||
}
|
class SettingsTileNavigationDrawer extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsNavigationDrawerTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
|
title: title(context),
|
||||||
|
routeName: NavigationDrawerEditorPage.routeName,
|
||||||
|
builder: (context) => const NavigationDrawerEditorPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileNavigationConfirmationDialog extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsConfirmationDialogTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
|
title: title(context),
|
||||||
|
routeName: ConfirmationDialogPage.routeName,
|
||||||
|
builder: (context) => const ConfirmationDialogPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileNavigationKeepScreenOn extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsKeepScreenOnTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<KeepScreenOn>(
|
||||||
|
values: KeepScreenOn.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => s.keepScreenOn,
|
||||||
|
onSelection: (v) => settings.keepScreenOn = v,
|
||||||
|
tileTitle: title(context),
|
||||||
|
dialogTitle: context.l10n.settingsKeepScreenOnTitle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileNavigationDoubleBackExit extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsDoubleBackExit;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.mustBackTwiceToExit,
|
||||||
|
onChanged: (v) => settings.mustBackTwiceToExit = v,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,6 @@ import 'package:aves/widgets/common/identity/empty.dart';
|
||||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StorageAccessTile extends StatelessWidget {
|
|
||||||
const StorageAccessTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsStorageAccessTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: StorageAccessPage.routeName),
|
|
||||||
builder: (context) => const StorageAccessPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StorageAccessPage extends StatefulWidget {
|
class StorageAccessPage extends StatefulWidget {
|
||||||
static const routeName = '/settings/storage_access';
|
static const routeName = '/settings/storage_access';
|
||||||
|
|
||||||
|
|
|
@ -14,26 +14,6 @@ import 'package:flutter/scheduler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class HiddenItemsTile extends StatelessWidget {
|
|
||||||
const HiddenItemsTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsHiddenItemsTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: HiddenItemsPage.routeName),
|
|
||||||
builder: (context) => const HiddenItemsPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HiddenItemsPage extends StatelessWidget {
|
class HiddenItemsPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/hidden_items';
|
static const routeName = '/settings/hidden_items';
|
||||||
|
|
||||||
|
|
|
@ -1,74 +1,126 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/app_flavor.dart';
|
import 'package:aves/app_flavor.dart';
|
||||||
import 'package:aves/model/device.dart';
|
import 'package:aves/model/device.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:aves/widgets/settings/privacy/access_grants.dart';
|
import 'package:aves/widgets/settings/privacy/access_grants.dart';
|
||||||
import 'package:aves/widgets/settings/privacy/hidden_items.dart';
|
import 'package:aves/widgets/settings/privacy/hidden_items.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class PrivacySection extends StatelessWidget {
|
class PrivacySection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'privacy';
|
||||||
const PrivacySection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
final canEnableErrorReporting = context.select<AppFlavor, bool>((v) => v.canEnableErrorReporting);
|
|
||||||
|
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.privacy,
|
icon: AIcons.privacy,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.privacy),
|
color: context.select<AvesColorsData, Color>((v) => v.privacy),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionPrivacy,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionPrivacy;
|
||||||
children: [
|
|
||||||
SettingsSwitchListTile(
|
@override
|
||||||
selector: (context, s) => s.isInstalledAppAccessAllowed,
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||||
onChanged: (v) => settings.isInstalledAppAccessAllowed = v,
|
final canEnableErrorReporting = context.select<AppFlavor, bool>((v) => v.canEnableErrorReporting);
|
||||||
title: context.l10n.settingsAllowInstalledAppAccess,
|
return [
|
||||||
subtitle: context.l10n.settingsAllowInstalledAppAccessSubtitle,
|
SettingsTilePrivacyAllowInstalledAppAccess(),
|
||||||
),
|
if (canEnableErrorReporting) SettingsTilePrivacyAllowErrorReporting(),
|
||||||
if (canEnableErrorReporting)
|
SettingsTilePrivacySaveSearchHistory(),
|
||||||
SettingsSwitchListTile(
|
SettingsTilePrivacyEnableBin(),
|
||||||
selector: (context, s) => s.isErrorReportingAllowed,
|
SettingsTilePrivacyHiddenItems(),
|
||||||
onChanged: (v) => settings.isErrorReportingAllowed = v,
|
if (device.canGrantDirectoryAccess) SettingsTilePrivacyStorageAccess(),
|
||||||
title: context.l10n.settingsAllowErrorReporting,
|
];
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.saveSearchHistory,
|
|
||||||
onChanged: (v) {
|
|
||||||
settings.saveSearchHistory = v;
|
|
||||||
if (!v) {
|
|
||||||
settings.searchHistory = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: context.l10n.settingsSaveSearchHistory,
|
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.enableBin,
|
|
||||||
onChanged: (v) {
|
|
||||||
settings.enableBin = v;
|
|
||||||
if (!v) {
|
|
||||||
settings.searchHistory = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: context.l10n.settingsEnableBin,
|
|
||||||
subtitle: context.l10n.settingsEnableBinSubtitle,
|
|
||||||
),
|
|
||||||
const HiddenItemsTile(),
|
|
||||||
if (device.canGrantDirectoryAccess) const StorageAccessTile(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacyAllowInstalledAppAccess extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsAllowInstalledAppAccess;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.isInstalledAppAccessAllowed,
|
||||||
|
onChanged: (v) => settings.isInstalledAppAccessAllowed = v,
|
||||||
|
title: title(context),
|
||||||
|
subtitle: context.l10n.settingsAllowInstalledAppAccessSubtitle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacyAllowErrorReporting extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsAllowErrorReporting;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.isErrorReportingAllowed,
|
||||||
|
onChanged: (v) => settings.isErrorReportingAllowed = v,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacySaveSearchHistory extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsSaveSearchHistory;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.saveSearchHistory,
|
||||||
|
onChanged: (v) {
|
||||||
|
settings.saveSearchHistory = v;
|
||||||
|
if (!v) {
|
||||||
|
settings.searchHistory = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacyEnableBin extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsEnableBin;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.enableBin,
|
||||||
|
onChanged: (v) {
|
||||||
|
settings.enableBin = v;
|
||||||
|
if (!v) {
|
||||||
|
settings.searchHistory = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: title(context),
|
||||||
|
subtitle: context.l10n.settingsEnableBinSubtitle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacyHiddenItems extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsHiddenItemsTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
|
title: title(context),
|
||||||
|
routeName: HiddenItemsPage.routeName,
|
||||||
|
builder: (context) => const HiddenItemsPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTilePrivacyStorageAccess extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsStorageAccessTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
|
title: title(context),
|
||||||
|
routeName: StorageAccessPage.routeName,
|
||||||
|
builder: (context) => const StorageAccessPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
43
lib/widgets/settings/settings_definition.dart
Normal file
43
lib/widgets/settings/settings_definition.dart
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
abstract class SettingsSection {
|
||||||
|
String get key;
|
||||||
|
|
||||||
|
Widget icon(BuildContext context);
|
||||||
|
|
||||||
|
String title(BuildContext context);
|
||||||
|
|
||||||
|
FutureOr<List<SettingsTile>> tiles(BuildContext context);
|
||||||
|
|
||||||
|
Widget build(BuildContext context, ValueNotifier<String?> expandedNotifier) {
|
||||||
|
return FutureBuilder<List<SettingsTile>>(
|
||||||
|
future: Future.value(tiles(context)),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final tiles = snapshot.data;
|
||||||
|
if (tiles == null) return const SizedBox();
|
||||||
|
|
||||||
|
return AvesExpansionTile(
|
||||||
|
// key is expected by test driver
|
||||||
|
key: Key('section-$key'),
|
||||||
|
// use a fixed value instead of the title to identify this expansion tile
|
||||||
|
// so that the tile state is kept when the language is modified
|
||||||
|
value: key,
|
||||||
|
leading: icon(context),
|
||||||
|
title: title(context),
|
||||||
|
expandedNotifier: expandedNotifier,
|
||||||
|
showHighlight: false,
|
||||||
|
children: tiles.map((v) => v.build(context)).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SettingsTile {
|
||||||
|
String title(BuildContext context);
|
||||||
|
|
||||||
|
Widget build(BuildContext context);
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
|
import 'package:aves/widgets/common/app_bar_title.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
import 'package:aves/widgets/common/basic/menu.dart';
|
import 'package:aves/widgets/common/basic/menu.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
@ -21,6 +22,8 @@ import 'package:aves/widgets/settings/display/display.dart';
|
||||||
import 'package:aves/widgets/settings/language/language.dart';
|
import 'package:aves/widgets/settings/language/language.dart';
|
||||||
import 'package:aves/widgets/settings/navigation/navigation.dart';
|
import 'package:aves/widgets/settings/navigation/navigation.dart';
|
||||||
import 'package:aves/widgets/settings/privacy/privacy.dart';
|
import 'package:aves/widgets/settings/privacy/privacy.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_search.dart';
|
||||||
import 'package:aves/widgets/settings/thumbnails/thumbnails.dart';
|
import 'package:aves/widgets/settings/thumbnails/thumbnails.dart';
|
||||||
import 'package:aves/widgets/settings/video/video.dart';
|
import 'package:aves/widgets/settings/video/video.dart';
|
||||||
import 'package:aves/widgets/settings/viewer/viewer.dart';
|
import 'package:aves/widgets/settings/viewer/viewer.dart';
|
||||||
|
@ -43,6 +46,17 @@ class SettingsPage extends StatefulWidget {
|
||||||
class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||||
final ValueNotifier<String?> _expandedNotifier = ValueNotifier(null);
|
final ValueNotifier<String?> _expandedNotifier = ValueNotifier(null);
|
||||||
|
|
||||||
|
static final List<SettingsSection> sections = [
|
||||||
|
NavigationSection(),
|
||||||
|
ThumbnailsSection(),
|
||||||
|
ViewerSection(),
|
||||||
|
VideoSection(),
|
||||||
|
PrivacySection(),
|
||||||
|
AccessibilitySection(),
|
||||||
|
DisplaySection(),
|
||||||
|
LanguageSection(),
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
@ -50,8 +64,16 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||||
return MediaQueryDataProvider(
|
return MediaQueryDataProvider(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.l10n.settingsPageTitle),
|
title: InteractiveAppBarTitle(
|
||||||
|
onTap: () => _goToSearch(context),
|
||||||
|
child: Text(context.l10n.settingsPageTitle),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(AIcons.search),
|
||||||
|
onPressed: () => _goToSearch(context),
|
||||||
|
tooltip: MaterialLocalizations.of(context).searchFieldLabel,
|
||||||
|
),
|
||||||
MenuIconTheme(
|
MenuIconTheme(
|
||||||
child: PopupMenuButton<SettingsAction>(
|
child: PopupMenuButton<SettingsAction>(
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
|
@ -74,6 +96,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
titleSpacing: 0,
|
||||||
),
|
),
|
||||||
body: GestureAreaProtectorStack(
|
body: GestureAreaProtectorStack(
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
|
@ -100,16 +123,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
children: [
|
children: sections.map((v) => v.build(context, _expandedNotifier)).toList(),
|
||||||
NavigationSection(expandedNotifier: _expandedNotifier),
|
|
||||||
ThumbnailsSection(expandedNotifier: _expandedNotifier),
|
|
||||||
ViewerSection(expandedNotifier: _expandedNotifier),
|
|
||||||
VideoSection(expandedNotifier: _expandedNotifier),
|
|
||||||
PrivacySection(expandedNotifier: _expandedNotifier),
|
|
||||||
AccessibilitySection(expandedNotifier: _expandedNotifier),
|
|
||||||
DisplaySection(expandedNotifier: _expandedNotifier),
|
|
||||||
LanguageSection(expandedNotifier: _expandedNotifier),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
@ -206,4 +220,14 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _goToSearch(BuildContext context) {
|
||||||
|
showSearch(
|
||||||
|
context: context,
|
||||||
|
delegate: SettingsSearchDelegate(
|
||||||
|
searchFieldLabel: context.l10n.settingsSearchFieldLabel,
|
||||||
|
sections: sections,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
114
lib/widgets/settings/settings_search.dart
Normal file
114
lib/widgets/settings/settings_search.dart
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/animated_icons_fix.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/identity/empty.dart';
|
||||||
|
import 'package:aves/widgets/common/identity/highlight_title.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SettingsSearchDelegate extends SearchDelegate {
|
||||||
|
final List<SettingsSection> sections;
|
||||||
|
|
||||||
|
SettingsSearchDelegate({
|
||||||
|
required String searchFieldLabel,
|
||||||
|
required this.sections,
|
||||||
|
}) : super(
|
||||||
|
searchFieldLabel: searchFieldLabel,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildLeading(BuildContext context) {
|
||||||
|
return IconButton(
|
||||||
|
// TODO TLAD [rtl] replace to regular `AnimatedIcon` when this is fixed: https://github.com/flutter/flutter/issues/60521
|
||||||
|
icon: AnimatedIconFixIssue60521(
|
||||||
|
icon: AnimatedIconsFixIssue60521.menu_arrow,
|
||||||
|
progress: transitionAnimation,
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Widget> buildActions(BuildContext context) {
|
||||||
|
return [
|
||||||
|
if (query.isNotEmpty)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(AIcons.clear),
|
||||||
|
onPressed: () {
|
||||||
|
query = '';
|
||||||
|
showSuggestions(context);
|
||||||
|
},
|
||||||
|
tooltip: context.l10n.clearTooltip,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildSuggestions(BuildContext context) => const SizedBox();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildResults(BuildContext context) {
|
||||||
|
if (query.isEmpty) {
|
||||||
|
showSuggestions(context);
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
final upQuery = query.toUpperCase().trim();
|
||||||
|
|
||||||
|
bool testKey(String key) => key.toUpperCase().contains(upQuery);
|
||||||
|
|
||||||
|
final loader = Future.wait(sections.map((section) async {
|
||||||
|
final allTiles = await section.tiles(context);
|
||||||
|
final filteredTiles = testKey(section.title(context)) ? allTiles : allTiles.where((v) => testKey(v.title(context))).toList();
|
||||||
|
if (filteredTiles.isEmpty) return null;
|
||||||
|
|
||||||
|
return (context) {
|
||||||
|
return <Widget>[
|
||||||
|
Padding(
|
||||||
|
// match header layout in Settings page
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 13),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
section.icon(context),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: HighlightTitle(
|
||||||
|
title: section.title(context),
|
||||||
|
showHighlight: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...filteredTiles.map((v) => v.build(context)),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
return MediaQueryDataProvider(
|
||||||
|
child: SafeArea(
|
||||||
|
child: FutureBuilder<List<List<Widget> Function(BuildContext)?>>(
|
||||||
|
future: loader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final loaders = snapshot.data;
|
||||||
|
if (loaders == null) return const SizedBox();
|
||||||
|
|
||||||
|
final children = loaders.whereNotNull().expand((builder) => builder(context)).toList();
|
||||||
|
return children.isEmpty
|
||||||
|
? EmptyContent(
|
||||||
|
icon: AIcons.settings,
|
||||||
|
text: context.l10n.settingsSearchEmpty,
|
||||||
|
)
|
||||||
|
: ListView(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,26 +6,6 @@ import 'package:aves/widgets/settings/common/quick_actions/editor_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class CollectionActionsTile extends StatelessWidget {
|
|
||||||
const CollectionActionsTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsCollectionQuickActionsTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: CollectionActionEditorPage.routeName),
|
|
||||||
builder: (context) => const CollectionActionEditorPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CollectionActionEditorPage extends StatelessWidget {
|
class CollectionActionEditorPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/collection_actions';
|
static const routeName = '/settings/collection_actions';
|
||||||
|
|
||||||
|
|
93
lib/widgets/settings/thumbnails/overlay.dart
Normal file
93
lib/widgets/settings/thumbnails/overlay.dart
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
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/common/identity/aves_icons.dart';
|
||||||
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ThumbnailOverlayPage extends StatelessWidget {
|
||||||
|
static const routeName = '/settings/thumbnail_overlay';
|
||||||
|
|
||||||
|
const ThumbnailOverlayPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final iconSize = IconTheme.of(context).size! * MediaQuery.textScaleFactorOf(context);
|
||||||
|
final iconColor = context.select<AvesColorsData, Color>((v) => v.neutral);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(context.l10n.settingsThumbnailOverlayTitle),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailFavourite,
|
||||||
|
onChanged: (v) => settings.showThumbnailFavourite = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowFavouriteIcon,
|
||||||
|
trailing: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: iconSize * (1 - FavouriteIcon.scale) / 2),
|
||||||
|
child: Icon(
|
||||||
|
AIcons.favourite,
|
||||||
|
size: iconSize * FavouriteIcon.scale,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailLocation,
|
||||||
|
onChanged: (v) => settings.showThumbnailLocation = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowLocationIcon,
|
||||||
|
trailing: Icon(
|
||||||
|
AIcons.location,
|
||||||
|
size: iconSize,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailMotionPhoto,
|
||||||
|
onChanged: (v) => settings.showThumbnailMotionPhoto = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowMotionPhotoIcon,
|
||||||
|
trailing: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: iconSize * (1 - MotionPhotoIcon.scale) / 2),
|
||||||
|
child: Icon(
|
||||||
|
AIcons.motionPhoto,
|
||||||
|
size: iconSize * MotionPhotoIcon.scale,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailRating,
|
||||||
|
onChanged: (v) => settings.showThumbnailRating = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowRating,
|
||||||
|
trailing: Icon(
|
||||||
|
AIcons.rating,
|
||||||
|
size: iconSize,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailRaw,
|
||||||
|
onChanged: (v) => settings.showThumbnailRaw = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowRawIcon,
|
||||||
|
trailing: Icon(
|
||||||
|
AIcons.raw,
|
||||||
|
size: iconSize,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.showThumbnailVideoDuration,
|
||||||
|
onChanged: (v) => settings.showThumbnailVideoDuration = v,
|
||||||
|
title: context.l10n.settingsThumbnailShowVideoDuration,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,99 +1,54 @@
|
||||||
import 'package:aves/model/settings/settings.dart';
|
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/common/identity/aves_icons.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:aves/widgets/settings/thumbnails/collection_actions_editor.dart';
|
import 'package:aves/widgets/settings/thumbnails/collection_actions_editor.dart';
|
||||||
|
import 'package:aves/widgets/settings/thumbnails/overlay.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ThumbnailsSection extends StatelessWidget {
|
class ThumbnailsSection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'thumbnails';
|
||||||
const ThumbnailsSection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
final iconSize = IconTheme.of(context).size! * MediaQuery.textScaleFactorOf(context);
|
|
||||||
final iconColor = context.select<AvesColorsData, Color>((v) => v.neutral);
|
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.grid,
|
icon: AIcons.grid,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.thumbnails),
|
color: context.select<AvesColorsData, Color>((v) => v.thumbnails),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionThumbnails,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionThumbnails;
|
||||||
children: [
|
|
||||||
const CollectionActionsTile(),
|
@override
|
||||||
SettingsSwitchListTile(
|
List<SettingsTile> tiles(BuildContext context) => [
|
||||||
selector: (context, s) => s.showThumbnailFavourite,
|
SettingsTileCollectionQuickActions(),
|
||||||
onChanged: (v) => settings.showThumbnailFavourite = v,
|
SettingsTileThumbnailOverlay(),
|
||||||
title: context.l10n.settingsThumbnailShowFavouriteIcon,
|
];
|
||||||
trailing: Padding(
|
}
|
||||||
padding: EdgeInsets.symmetric(horizontal: iconSize * (1 - FavouriteIcon.scale) / 2),
|
|
||||||
child: Icon(
|
class SettingsTileCollectionQuickActions extends SettingsTile {
|
||||||
AIcons.favourite,
|
@override
|
||||||
size: iconSize * FavouriteIcon.scale,
|
String title(BuildContext context) => context.l10n.settingsCollectionQuickActionsTile;
|
||||||
color: iconColor,
|
|
||||||
),
|
@override
|
||||||
),
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
),
|
title: title(context),
|
||||||
SettingsSwitchListTile(
|
routeName: CollectionActionEditorPage.routeName,
|
||||||
selector: (context, s) => s.showThumbnailLocation,
|
builder: (context) => const CollectionActionEditorPage(),
|
||||||
onChanged: (v) => settings.showThumbnailLocation = v,
|
);
|
||||||
title: context.l10n.settingsThumbnailShowLocationIcon,
|
}
|
||||||
trailing: Icon(
|
|
||||||
AIcons.location,
|
class SettingsTileThumbnailOverlay extends SettingsTile {
|
||||||
size: iconSize,
|
@override
|
||||||
color: iconColor,
|
String title(BuildContext context) => context.l10n.settingsThumbnailOverlayTile;
|
||||||
),
|
|
||||||
),
|
@override
|
||||||
SettingsSwitchListTile(
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
selector: (context, s) => s.showThumbnailMotionPhoto,
|
title: title(context),
|
||||||
onChanged: (v) => settings.showThumbnailMotionPhoto = v,
|
routeName: ThumbnailOverlayPage.routeName,
|
||||||
title: context.l10n.settingsThumbnailShowMotionPhotoIcon,
|
builder: (context) => const ThumbnailOverlayPage(),
|
||||||
trailing: Padding(
|
);
|
||||||
padding: EdgeInsets.symmetric(horizontal: iconSize * (1 - MotionPhotoIcon.scale) / 2),
|
|
||||||
child: Icon(
|
|
||||||
AIcons.motionPhoto,
|
|
||||||
size: iconSize * MotionPhotoIcon.scale,
|
|
||||||
color: iconColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.showThumbnailRating,
|
|
||||||
onChanged: (v) => settings.showThumbnailRating = v,
|
|
||||||
title: context.l10n.settingsThumbnailShowRating,
|
|
||||||
trailing: Icon(
|
|
||||||
AIcons.rating,
|
|
||||||
size: iconSize,
|
|
||||||
color: iconColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.showThumbnailRaw,
|
|
||||||
onChanged: (v) => settings.showThumbnailRaw = v,
|
|
||||||
title: context.l10n.settingsThumbnailShowRawIcon,
|
|
||||||
trailing: Icon(
|
|
||||||
AIcons.raw,
|
|
||||||
size: iconSize,
|
|
||||||
color: iconColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.showThumbnailVideoDuration,
|
|
||||||
onChanged: (v) => settings.showThumbnailVideoDuration = v,
|
|
||||||
title: context.l10n.settingsThumbnailShowVideoDuration,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,6 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class VideoControlsTile extends StatelessWidget {
|
|
||||||
const VideoControlsTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsVideoControlsTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: VideoControlsPage.routeName),
|
|
||||||
builder: (context) => const VideoControlsPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VideoControlsPage extends StatelessWidget {
|
class VideoControlsPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/video/controls';
|
static const routeName = '/settings/video/controls';
|
||||||
|
|
||||||
|
|
|
@ -7,26 +7,6 @@ import 'package:aves/widgets/settings/video/subtitle_sample.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class SubtitleThemeTile extends StatelessWidget {
|
|
||||||
const SubtitleThemeTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsSubtitleThemeTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: SubtitleThemePage.routeName),
|
|
||||||
builder: (context) => const SubtitleThemePage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubtitleThemePage extends StatelessWidget {
|
class SubtitleThemePage extends StatelessWidget {
|
||||||
static const routeName = '/settings/video/subtitle_theme';
|
static const routeName = '/settings/video/subtitle_theme';
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/filters/mime.dart';
|
import 'package:aves/model/filters/mime.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/video_loop_mode.dart';
|
import 'package:aves/model/settings/enums/video_loop_mode.dart';
|
||||||
|
@ -5,100 +7,117 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:aves/widgets/settings/video/controls.dart';
|
import 'package:aves/widgets/settings/video/controls.dart';
|
||||||
import 'package:aves/widgets/settings/video/subtitle_theme.dart';
|
import 'package:aves/widgets/settings/video/subtitle_theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class VideoSection extends StatelessWidget {
|
class VideoSection extends SettingsSection {
|
||||||
final ValueNotifier<String?>? expandedNotifier;
|
|
||||||
final bool standalonePage;
|
final bool standalonePage;
|
||||||
|
|
||||||
const VideoSection({
|
VideoSection({
|
||||||
Key? key,
|
|
||||||
this.expandedNotifier,
|
|
||||||
this.standalonePage = false,
|
this.standalonePage = false,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
String get key => 'video';
|
||||||
final children = [
|
|
||||||
if (!standalonePage)
|
@override
|
||||||
SettingsSwitchListTile(
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
selector: (context, s) => !s.hiddenFilters.contains(MimeFilter.video),
|
icon: AIcons.video,
|
||||||
onChanged: (v) => settings.changeFilterVisibility({MimeFilter.video}, v),
|
color: context.select<AvesColorsData, Color>((v) => v.video),
|
||||||
title: context.l10n.settingsVideoShowVideos,
|
);
|
||||||
),
|
|
||||||
SettingsSwitchListTile(
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsSectionVideo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||||
|
return [
|
||||||
|
if (!standalonePage) SettingsTileVideoShowVideos(),
|
||||||
|
SettingsTileVideoEnableHardwareAcceleration(),
|
||||||
|
SettingsTileVideoEnableAutoPlay(),
|
||||||
|
SettingsTileVideoLoopMode(),
|
||||||
|
SettingsTileVideoControls(),
|
||||||
|
SettingsTileVideoSubtitleTheme(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileVideoShowVideos extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsVideoShowVideos;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => !s.hiddenFilters.contains(MimeFilter.video),
|
||||||
|
onChanged: (v) => settings.changeFilterVisibility({MimeFilter.video}, v),
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileVideoEnableHardwareAcceleration extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsVideoEnableHardwareAcceleration;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
selector: (context, s) => s.enableVideoHardwareAcceleration,
|
selector: (context, s) => s.enableVideoHardwareAcceleration,
|
||||||
onChanged: (v) => settings.enableVideoHardwareAcceleration = v,
|
onChanged: (v) => settings.enableVideoHardwareAcceleration = v,
|
||||||
title: context.l10n.settingsVideoEnableHardwareAcceleration,
|
title: title(context),
|
||||||
),
|
);
|
||||||
SettingsSwitchListTile(
|
}
|
||||||
|
|
||||||
|
class SettingsTileVideoEnableAutoPlay extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsVideoEnableAutoPlay;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
selector: (context, s) => s.enableVideoAutoPlay,
|
selector: (context, s) => s.enableVideoAutoPlay,
|
||||||
onChanged: (v) => settings.enableVideoAutoPlay = v,
|
onChanged: (v) => settings.enableVideoAutoPlay = v,
|
||||||
title: context.l10n.settingsVideoEnableAutoPlay,
|
title: title(context),
|
||||||
),
|
);
|
||||||
SettingsSelectionListTile<VideoLoopMode>(
|
}
|
||||||
|
|
||||||
|
class SettingsTileVideoLoopMode extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsVideoLoopModeTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSelectionListTile<VideoLoopMode>(
|
||||||
values: VideoLoopMode.values,
|
values: VideoLoopMode.values,
|
||||||
getName: (context, v) => v.getName(context),
|
getName: (context, v) => v.getName(context),
|
||||||
selector: (context, s) => s.videoLoopMode,
|
selector: (context, s) => s.videoLoopMode,
|
||||||
onSelection: (v) => settings.videoLoopMode = v,
|
onSelection: (v) => settings.videoLoopMode = v,
|
||||||
tileTitle: context.l10n.settingsVideoLoopModeTile,
|
tileTitle: title(context),
|
||||||
dialogTitle: context.l10n.settingsVideoLoopModeTitle,
|
dialogTitle: context.l10n.settingsVideoLoopModeTitle,
|
||||||
),
|
);
|
||||||
const VideoControlsTile(),
|
|
||||||
const SubtitleThemeTile(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return standalonePage
|
|
||||||
? ListView(
|
|
||||||
children: children,
|
|
||||||
)
|
|
||||||
: AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.video,
|
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.video),
|
|
||||||
),
|
|
||||||
title: context.l10n.settingsSectionVideo,
|
|
||||||
expandedNotifier: expandedNotifier,
|
|
||||||
showHighlight: false,
|
|
||||||
children: children,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class VideoSettingsPage extends StatelessWidget {
|
class SettingsTileVideoControls extends SettingsTile {
|
||||||
static const routeName = '/settings/video';
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsVideoControlsTile;
|
||||||
const VideoSettingsPage({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
final theme = Theme.of(context);
|
title: title(context),
|
||||||
return MediaQueryDataProvider(
|
routeName: VideoControlsPage.routeName,
|
||||||
child: Scaffold(
|
builder: (context) => const VideoControlsPage(),
|
||||||
appBar: AppBar(
|
);
|
||||||
title: Text(context.l10n.settingsVideoPageTitle),
|
}
|
||||||
),
|
|
||||||
body: Theme(
|
class SettingsTileVideoSubtitleTheme extends SettingsTile {
|
||||||
data: theme.copyWith(
|
@override
|
||||||
textTheme: theme.textTheme.copyWith(
|
String title(BuildContext context) => context.l10n.settingsSubtitleThemeTile;
|
||||||
// dense style font for tile subtitles, without modifying title font
|
|
||||||
bodyText2: const TextStyle(fontSize: 12),
|
@override
|
||||||
),
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
),
|
title: title(context),
|
||||||
child: const SafeArea(
|
routeName: SubtitleThemePage.routeName,
|
||||||
child: VideoSection(
|
builder: (context) => const SubtitleThemePage(),
|
||||||
standalonePage: true,
|
);
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
51
lib/widgets/settings/video/video_settings_page.dart
Normal file
51
lib/widgets/settings/video/video_settings_page.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
|
import 'package:aves/widgets/settings/video/video.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VideoSettingsPage extends StatefulWidget {
|
||||||
|
static const routeName = '/settings/video';
|
||||||
|
|
||||||
|
const VideoSettingsPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoSettingsPage> createState() => _VideoSettingsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoSettingsPageState extends State<VideoSettingsPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return MediaQueryDataProvider(
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(context.l10n.settingsVideoPageTitle),
|
||||||
|
),
|
||||||
|
body: Theme(
|
||||||
|
data: theme.copyWith(
|
||||||
|
textTheme: theme.textTheme.copyWith(
|
||||||
|
// dense style font for tile subtitles, without modifying title font
|
||||||
|
bodyText2: const TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
child: FutureBuilder<List<SettingsTile>>(
|
||||||
|
future: Future.value(VideoSection(standalonePage: true).tiles(context)),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final tiles = snapshot.data;
|
||||||
|
if (tiles == null) return const SizedBox();
|
||||||
|
|
||||||
|
return ListView(
|
||||||
|
children: tiles.map((v) => v.build(context)).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,26 +5,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class ViewerOverlayTile extends StatelessWidget {
|
|
||||||
const ViewerOverlayTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsViewerOverlayTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: ViewerOverlayPage.routeName),
|
|
||||||
builder: (context) => const ViewerOverlayPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewerOverlayPage extends StatelessWidget {
|
class ViewerOverlayPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/viewer_overlay';
|
static const routeName = '/settings/viewer_overlay';
|
||||||
|
|
||||||
|
|
|
@ -1,95 +1,120 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
|
||||||
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
import 'package:aves/widgets/settings/common/tile_leading.dart';
|
||||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
|
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||||
import 'package:aves/widgets/settings/viewer/entry_background.dart';
|
import 'package:aves/widgets/settings/viewer/entry_background.dart';
|
||||||
import 'package:aves/widgets/settings/viewer/overlay.dart';
|
import 'package:aves/widgets/settings/viewer/overlay.dart';
|
||||||
import 'package:aves/widgets/settings/viewer/viewer_actions_editor.dart';
|
import 'package:aves/widgets/settings/viewer/viewer_actions_editor.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ViewerSection extends StatelessWidget {
|
class ViewerSection extends SettingsSection {
|
||||||
final ValueNotifier<String?> expandedNotifier;
|
@override
|
||||||
|
String get key => 'viewer';
|
||||||
const ViewerSection({
|
|
||||||
Key? key,
|
|
||||||
required this.expandedNotifier,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||||
return AvesExpansionTile(
|
|
||||||
leading: SettingsTileLeading(
|
|
||||||
icon: AIcons.image,
|
icon: AIcons.image,
|
||||||
color: context.select<AvesColorsData, Color>((v) => v.image),
|
color: context.select<AvesColorsData, Color>((v) => v.image),
|
||||||
),
|
);
|
||||||
title: context.l10n.settingsSectionViewer,
|
|
||||||
expandedNotifier: expandedNotifier,
|
@override
|
||||||
showHighlight: false,
|
String title(BuildContext context) => context.l10n.settingsSectionViewer;
|
||||||
children: [
|
|
||||||
const ViewerActionsTile(),
|
@override
|
||||||
const ViewerOverlayTile(),
|
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||||
const _CutoutModeSwitch(),
|
final canSetCutoutMode = await windowService.canSetCutoutMode();
|
||||||
SettingsSwitchListTile(
|
return [
|
||||||
selector: (context, s) => s.viewerMaxBrightness,
|
SettingsTileViewerQuickActions(),
|
||||||
onChanged: (v) => settings.viewerMaxBrightness = v,
|
SettingsTileViewerOverlay(),
|
||||||
title: context.l10n.settingsViewerMaximumBrightness,
|
if (canSetCutoutMode) SettingsTileViewerCutoutMode(),
|
||||||
),
|
SettingsTileViewerMaxBrightness(),
|
||||||
SettingsSwitchListTile(
|
SettingsTileViewerMotionPhotoAutoPlay(),
|
||||||
selector: (context, s) => s.enableMotionPhotoAutoPlay,
|
SettingsTileViewerImageBackground(),
|
||||||
onChanged: (v) => settings.enableMotionPhotoAutoPlay = v,
|
];
|
||||||
title: context.l10n.settingsMotionPhotoAutoPlay,
|
}
|
||||||
),
|
}
|
||||||
Selector<Settings, EntryBackground>(
|
|
||||||
selector: (context, s) => s.imageBackground,
|
class SettingsTileViewerQuickActions extends SettingsTile {
|
||||||
builder: (context, current, child) => ListTile(
|
@override
|
||||||
title: Text(context.l10n.settingsImageBackground),
|
String title(BuildContext context) => context.l10n.settingsViewerQuickActionsTile;
|
||||||
trailing: EntryBackgroundSelector(
|
|
||||||
getter: () => current,
|
@override
|
||||||
setter: (value) => settings.imageBackground = value,
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
),
|
title: title(context),
|
||||||
|
routeName: ViewerActionEditorPage.routeName,
|
||||||
|
builder: (context) => const ViewerActionEditorPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileViewerOverlay extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsViewerOverlayTile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||||
|
title: title(context),
|
||||||
|
routeName: ViewerOverlayPage.routeName,
|
||||||
|
builder: (context) => const ViewerOverlayPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileViewerCutoutMode extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsViewerUseCutout;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.viewerUseCutout,
|
||||||
|
onChanged: (v) => settings.viewerUseCutout = v,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileViewerMaxBrightness extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsViewerMaximumBrightness;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.viewerMaxBrightness,
|
||||||
|
onChanged: (v) => settings.viewerMaxBrightness = v,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileViewerMotionPhotoAutoPlay extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsMotionPhotoAutoPlay;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.enableMotionPhotoAutoPlay,
|
||||||
|
onChanged: (v) => settings.enableMotionPhotoAutoPlay = v,
|
||||||
|
title: title(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsTileViewerImageBackground extends SettingsTile {
|
||||||
|
@override
|
||||||
|
String title(BuildContext context) => context.l10n.settingsImageBackground;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Selector<Settings, EntryBackground>(
|
||||||
|
selector: (context, s) => s.imageBackground,
|
||||||
|
builder: (context, current, child) => ListTile(
|
||||||
|
title: Text(title(context)),
|
||||||
|
trailing: EntryBackgroundSelector(
|
||||||
|
getter: () => current,
|
||||||
|
setter: (value) => settings.imageBackground = value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CutoutModeSwitch extends StatefulWidget {
|
|
||||||
const _CutoutModeSwitch({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_CutoutModeSwitch> createState() => _CutoutModeSwitchState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CutoutModeSwitchState extends State<_CutoutModeSwitch> {
|
|
||||||
late Future<bool> _canSet;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_canSet = windowService.canSetCutoutMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder<bool>(
|
|
||||||
future: _canSet,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData && snapshot.data!) {
|
|
||||||
return SettingsSwitchListTile(
|
|
||||||
selector: (context, s) => s.viewerUseCutout,
|
|
||||||
onChanged: (v) => settings.viewerUseCutout = v,
|
|
||||||
title: context.l10n.settingsViewerUseCutout,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,6 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/settings/common/quick_actions/editor_page.dart';
|
import 'package:aves/widgets/settings/common/quick_actions/editor_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ViewerActionsTile extends StatelessWidget {
|
|
||||||
const ViewerActionsTile({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(context.l10n.settingsViewerQuickActionsTile),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
settings: const RouteSettings(name: ViewerActionEditorPage.routeName),
|
|
||||||
builder: (context) => const ViewerActionEditorPage(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewerActionEditorPage extends StatelessWidget {
|
class ViewerActionEditorPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/viewer_actions';
|
static const routeName = '/settings/viewer_actions';
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
import 'package:aves/widgets/dialogs/video_speed_dialog.dart';
|
import 'package:aves/widgets/dialogs/video_speed_dialog.dart';
|
||||||
import 'package:aves/widgets/dialogs/video_stream_selection_dialog.dart';
|
import 'package:aves/widgets/dialogs/video_stream_selection_dialog.dart';
|
||||||
import 'package:aves/widgets/settings/video/video.dart';
|
import 'package:aves/widgets/settings/video/video_settings_page.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/notifications.dart';
|
import 'package:aves/widgets/viewer/overlay/notifications.dart';
|
||||||
import 'package:aves/widgets/viewer/video/controller.dart';
|
import 'package:aves/widgets/viewer/video/controller.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
{
|
{
|
||||||
|
"de": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
"entryActionShowGeoTiffOnMap",
|
"entryActionShowGeoTiffOnMap",
|
||||||
"entryActionConvertMotionPhotoToStillImage",
|
"entryActionConvertMotionPhotoToStillImage",
|
||||||
|
@ -9,7 +16,32 @@
|
||||||
"coverDialogTabApp",
|
"coverDialogTabApp",
|
||||||
"coverDialogTabColor",
|
"coverDialogTabColor",
|
||||||
"appPickDialogTitle",
|
"appPickDialogTitle",
|
||||||
"appPickDialogNone"
|
"appPickDialogNone",
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fr": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"id": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
|
@ -22,6 +54,38 @@
|
||||||
"coverDialogTabApp",
|
"coverDialogTabApp",
|
||||||
"coverDialogTabColor",
|
"coverDialogTabColor",
|
||||||
"appPickDialogTitle",
|
"appPickDialogTitle",
|
||||||
"appPickDialogNone"
|
"appPickDialogNone",
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ko": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pt": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ru": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
|
],
|
||||||
|
|
||||||
|
"zh": [
|
||||||
|
"settingsSearchFieldLabel",
|
||||||
|
"settingsSearchEmpty",
|
||||||
|
"settingsThumbnailOverlayTile",
|
||||||
|
"settingsThumbnailOverlayTitle"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue