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",
|
||||
"settingsDefault": "Default",
|
||||
|
||||
"settingsSearchFieldLabel": "Search settings",
|
||||
"settingsSearchEmpty": "No matching setting",
|
||||
"settingsActionExport": "Export",
|
||||
"settingsActionImport": "Import",
|
||||
|
||||
|
@ -616,6 +618,8 @@
|
|||
"settingsNavigationDrawerAddAlbum": "Add album",
|
||||
|
||||
"settingsSectionThumbnails": "Thumbnails",
|
||||
"settingsThumbnailOverlayTile": "Overlay",
|
||||
"settingsThumbnailOverlayTitle": "Overlay",
|
||||
"settingsThumbnailShowFavouriteIcon": "Show favorite icon",
|
||||
"settingsThumbnailShowLocationIcon": "Show location 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/enums.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';
|
||||
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/common/tile_leading.dart';
|
||||
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AccessibilitySection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const AccessibilitySection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class AccessibilitySection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'accessibility';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.accessibility,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.accessibility),
|
||||
),
|
||||
title: context.l10n.settingsSectionAccessibility,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
SettingsSelectionListTile<AccessibilityAnimations>(
|
||||
values: AccessibilityAnimations.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.accessibilityAnimations,
|
||||
onSelection: (v) => settings.accessibilityAnimations = v,
|
||||
tileTitle: context.l10n.settingsRemoveAnimationsTile,
|
||||
dialogTitle: context.l10n.settingsRemoveAnimationsTitle,
|
||||
),
|
||||
const TimeToTakeActionTile(),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionAccessibility;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
SettingsTileAccessibilityAnimations(),
|
||||
SettingsTileAccessibilityTimeToTakeAction(),
|
||||
];
|
||||
}
|
||||
|
||||
class SettingsTileAccessibilityAnimations extends SettingsTile {
|
||||
@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: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 {
|
||||
final bool Function(BuildContext, Settings) selector;
|
||||
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/enums.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/icons.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/tiles.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class DisplaySection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const DisplaySection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class DisplaySection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'display';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.display,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.display),
|
||||
),
|
||||
title: context.l10n.settingsSectionDisplay,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
SettingsSelectionListTile<AvesThemeBrightness>(
|
||||
values: AvesThemeBrightness.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.themeBrightness,
|
||||
onSelection: (v) => settings.themeBrightness = v,
|
||||
tileTitle: context.l10n.settingsThemeBrightness,
|
||||
dialogTitle: context.l10n.settingsThemeBrightness,
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.themeColorMode == AvesThemeColorMode.polychrome,
|
||||
onChanged: (v) => settings.themeColorMode = v ? AvesThemeColorMode.polychrome : AvesThemeColorMode.monochrome,
|
||||
title: context.l10n.settingsThemeColorHighlights,
|
||||
),
|
||||
SettingsSelectionListTile<DisplayRefreshRateMode>(
|
||||
values: DisplayRefreshRateMode.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.displayRefreshRateMode,
|
||||
onSelection: (v) => settings.displayRefreshRateMode = v,
|
||||
tileTitle: context.l10n.settingsDisplayRefreshRateModeTile,
|
||||
dialogTitle: context.l10n.settingsDisplayRefreshRateModeTitle,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionDisplay;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
SettingsTileDisplayThemeBrightness(),
|
||||
SettingsTileDisplayThemeColorMode(),
|
||||
SettingsTileDisplayDisplayRefreshRateMode(),
|
||||
];
|
||||
}
|
||||
|
||||
class SettingsTileDisplayThemeBrightness extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsThemeBrightness;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSelectionListTile<AvesThemeBrightness>(
|
||||
values: AvesThemeBrightness.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.themeBrightness,
|
||||
onSelection: (v) => settings.themeBrightness = v,
|
||||
tileTitle: title(context),
|
||||
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/enums.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/utils/constants.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/tiles.dart';
|
||||
import 'package:aves/widgets/settings/language/locale.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LanguageSection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const LanguageSection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class LanguageSection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'language';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.language,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.language),
|
||||
),
|
||||
title: l10n.settingsSectionLanguage,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
const LocaleTile(),
|
||||
SettingsSelectionListTile<CoordinateFormat>(
|
||||
values: CoordinateFormat.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.coordinateFormat,
|
||||
onSelection: (v) => settings.coordinateFormat = v,
|
||||
tileTitle: l10n.settingsCoordinateFormatTile,
|
||||
dialogTitle: l10n.settingsCoordinateFormatTitle,
|
||||
optionSubtitleBuilder: (value) => value.format(l10n, Constants.pointNemo),
|
||||
),
|
||||
SettingsSelectionListTile<UnitSystem>(
|
||||
values: UnitSystem.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.unitSystem,
|
||||
onSelection: (v) => settings.unitSystem = v,
|
||||
tileTitle: l10n.settingsUnitSystemTile,
|
||||
dialogTitle: l10n.settingsUnitSystemTitle,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionLanguage;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
SettingsTileLanguageLocale(),
|
||||
SettingsTileLanguageCoordinateFormat(),
|
||||
SettingsTileLanguageUnitSystem(),
|
||||
];
|
||||
}
|
||||
|
||||
class SettingsTileLanguageLocale extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsLanguage;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const LocaleTile();
|
||||
}
|
||||
|
||||
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: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 {
|
||||
static const routeName = '/settings/navigation_confirmation';
|
||||
|
||||
|
|
|
@ -13,26 +13,6 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/material.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 {
|
||||
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/home_page.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/icons.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/tiles.dart';
|
||||
import 'package:aves/widgets/settings/navigation/confirmation_dialogs.dart';
|
||||
import 'package:aves/widgets/settings/navigation/drawer.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NavigationSection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const NavigationSection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class NavigationSection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'navigation';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.home,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.navigation),
|
||||
),
|
||||
title: context.l10n.settingsSectionNavigation,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
SettingsSelectionListTile<HomePageSetting>(
|
||||
values: HomePageSetting.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.homePage,
|
||||
onSelection: (v) => settings.homePage = v,
|
||||
tileTitle: context.l10n.settingsHome,
|
||||
dialogTitle: context.l10n.settingsHome,
|
||||
),
|
||||
const NavigationDrawerTile(),
|
||||
const ConfirmationDialogTile(),
|
||||
SettingsSelectionListTile<KeepScreenOn>(
|
||||
values: KeepScreenOn.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.keepScreenOn,
|
||||
onSelection: (v) => settings.keepScreenOn = v,
|
||||
tileTitle: context.l10n.settingsKeepScreenOnTile,
|
||||
dialogTitle: context.l10n.settingsKeepScreenOnTitle,
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.mustBackTwiceToExit,
|
||||
onChanged: (v) => settings.mustBackTwiceToExit = v,
|
||||
title: context.l10n.settingsDoubleBackExit,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionNavigation;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
|
||||
SettingsTileNavigationHomePage(),
|
||||
SettingsTileNavigationDrawer(),
|
||||
SettingsTileNavigationConfirmationDialog(),
|
||||
SettingsTileNavigationKeepScreenOn(),
|
||||
SettingsTileNavigationDoubleBackExit(),
|
||||
];
|
||||
}
|
||||
|
||||
class SettingsTileNavigationHomePage extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsHome;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSelectionListTile<HomePageSetting>(
|
||||
values: HomePageSetting.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.homePage,
|
||||
onSelection: (v) => settings.homePage = v,
|
||||
tileTitle: title(context),
|
||||
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: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 {
|
||||
static const routeName = '/settings/storage_access';
|
||||
|
||||
|
|
|
@ -14,26 +14,6 @@ import 'package:flutter/scheduler.dart';
|
|||
import 'package:provider/provider.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 {
|
||||
static const routeName = '/settings/hidden_items';
|
||||
|
||||
|
|
|
@ -1,74 +1,126 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/app_flavor.dart';
|
||||
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';
|
||||
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/tiles.dart';
|
||||
import 'package:aves/widgets/settings/privacy/access_grants.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:provider/provider.dart';
|
||||
|
||||
class PrivacySection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const PrivacySection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class PrivacySection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'privacy';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final canEnableErrorReporting = context.select<AppFlavor, bool>((v) => v.canEnableErrorReporting);
|
||||
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.privacy,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.privacy),
|
||||
),
|
||||
title: context.l10n.settingsSectionPrivacy,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.isInstalledAppAccessAllowed,
|
||||
onChanged: (v) => settings.isInstalledAppAccessAllowed = v,
|
||||
title: context.l10n.settingsAllowInstalledAppAccess,
|
||||
subtitle: context.l10n.settingsAllowInstalledAppAccessSubtitle,
|
||||
),
|
||||
if (canEnableErrorReporting)
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.isErrorReportingAllowed,
|
||||
onChanged: (v) => settings.isErrorReportingAllowed = v,
|
||||
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(),
|
||||
],
|
||||
);
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionPrivacy;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||
final canEnableErrorReporting = context.select<AppFlavor, bool>((v) => v.canEnableErrorReporting);
|
||||
return [
|
||||
SettingsTilePrivacyAllowInstalledAppAccess(),
|
||||
if (canEnableErrorReporting) SettingsTilePrivacyAllowErrorReporting(),
|
||||
SettingsTilePrivacySaveSearchHistory(),
|
||||
SettingsTilePrivacyEnableBin(),
|
||||
SettingsTilePrivacyHiddenItems(),
|
||||
if (device.canGrantDirectoryAccess) SettingsTilePrivacyStorageAccess(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
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/icons.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/menu.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/navigation/navigation.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/video/video.dart';
|
||||
import 'package:aves/widgets/settings/viewer/viewer.dart';
|
||||
|
@ -43,6 +46,17 @@ class SettingsPage extends StatefulWidget {
|
|||
class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
||||
final ValueNotifier<String?> _expandedNotifier = ValueNotifier(null);
|
||||
|
||||
static final List<SettingsSection> sections = [
|
||||
NavigationSection(),
|
||||
ThumbnailsSection(),
|
||||
ViewerSection(),
|
||||
VideoSection(),
|
||||
PrivacySection(),
|
||||
AccessibilitySection(),
|
||||
DisplaySection(),
|
||||
LanguageSection(),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
@ -50,8 +64,16 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
|||
return MediaQueryDataProvider(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.l10n.settingsPageTitle),
|
||||
title: InteractiveAppBarTitle(
|
||||
onTap: () => _goToSearch(context),
|
||||
child: Text(context.l10n.settingsPageTitle),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(AIcons.search),
|
||||
onPressed: () => _goToSearch(context),
|
||||
tooltip: MaterialLocalizations.of(context).searchFieldLabel,
|
||||
),
|
||||
MenuIconTheme(
|
||||
child: PopupMenuButton<SettingsAction>(
|
||||
itemBuilder: (context) {
|
||||
|
@ -74,6 +96,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
|||
),
|
||||
),
|
||||
],
|
||||
titleSpacing: 0,
|
||||
),
|
||||
body: GestureAreaProtectorStack(
|
||||
child: SafeArea(
|
||||
|
@ -100,16 +123,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
|||
child: child,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
NavigationSection(expandedNotifier: _expandedNotifier),
|
||||
ThumbnailsSection(expandedNotifier: _expandedNotifier),
|
||||
ViewerSection(expandedNotifier: _expandedNotifier),
|
||||
VideoSection(expandedNotifier: _expandedNotifier),
|
||||
PrivacySection(expandedNotifier: _expandedNotifier),
|
||||
AccessibilitySection(expandedNotifier: _expandedNotifier),
|
||||
DisplaySection(expandedNotifier: _expandedNotifier),
|
||||
LanguageSection(expandedNotifier: _expandedNotifier),
|
||||
],
|
||||
children: sections.map((v) => v.build(context, _expandedNotifier)).toList(),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
@ -206,4 +220,14 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
|
|||
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: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 {
|
||||
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/icons.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/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/overlay.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ThumbnailsSection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const ThumbnailsSection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class ThumbnailsSection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'thumbnails';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final iconSize = IconTheme.of(context).size! * MediaQuery.textScaleFactorOf(context);
|
||||
final iconColor = context.select<AvesColorsData, Color>((v) => v.neutral);
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.grid,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.thumbnails),
|
||||
),
|
||||
title: context.l10n.settingsSectionThumbnails,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
const CollectionActionsTile(),
|
||||
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,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionThumbnails;
|
||||
|
||||
@override
|
||||
List<SettingsTile> tiles(BuildContext context) => [
|
||||
SettingsTileCollectionQuickActions(),
|
||||
SettingsTileThumbnailOverlay(),
|
||||
];
|
||||
}
|
||||
|
||||
class SettingsTileCollectionQuickActions extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsCollectionQuickActionsTile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||
title: title(context),
|
||||
routeName: CollectionActionEditorPage.routeName,
|
||||
builder: (context) => const CollectionActionEditorPage(),
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsTileThumbnailOverlay extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsThumbnailOverlayTile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||
title: title(context),
|
||||
routeName: ThumbnailOverlayPage.routeName,
|
||||
builder: (context) => const ThumbnailOverlayPage(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,26 +5,6 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
|||
import 'package:aves/widgets/settings/common/tiles.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 {
|
||||
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: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 {
|
||||
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/settings/enums/enums.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/icons.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/tiles.dart';
|
||||
import 'package:aves/widgets/settings/settings_definition.dart';
|
||||
import 'package:aves/widgets/settings/video/controls.dart';
|
||||
import 'package:aves/widgets/settings/video/subtitle_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class VideoSection extends StatelessWidget {
|
||||
final ValueNotifier<String?>? expandedNotifier;
|
||||
class VideoSection extends SettingsSection {
|
||||
final bool standalonePage;
|
||||
|
||||
const VideoSection({
|
||||
Key? key,
|
||||
this.expandedNotifier,
|
||||
VideoSection({
|
||||
this.standalonePage = false,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final children = [
|
||||
if (!standalonePage)
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => !s.hiddenFilters.contains(MimeFilter.video),
|
||||
onChanged: (v) => settings.changeFilterVisibility({MimeFilter.video}, v),
|
||||
title: context.l10n.settingsVideoShowVideos,
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
String get key => 'video';
|
||||
|
||||
@override
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.video,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.video),
|
||||
);
|
||||
|
||||
@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,
|
||||
onChanged: (v) => settings.enableVideoHardwareAcceleration = v,
|
||||
title: context.l10n.settingsVideoEnableHardwareAcceleration,
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
title: title(context),
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsTileVideoEnableAutoPlay extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsVideoEnableAutoPlay;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSwitchListTile(
|
||||
selector: (context, s) => s.enableVideoAutoPlay,
|
||||
onChanged: (v) => settings.enableVideoAutoPlay = v,
|
||||
title: context.l10n.settingsVideoEnableAutoPlay,
|
||||
),
|
||||
SettingsSelectionListTile<VideoLoopMode>(
|
||||
title: title(context),
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsTileVideoLoopMode extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsVideoLoopModeTile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSelectionListTile<VideoLoopMode>(
|
||||
values: VideoLoopMode.values,
|
||||
getName: (context, v) => v.getName(context),
|
||||
selector: (context, s) => s.videoLoopMode,
|
||||
onSelection: (v) => settings.videoLoopMode = v,
|
||||
tileTitle: context.l10n.settingsVideoLoopModeTile,
|
||||
tileTitle: title(context),
|
||||
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 {
|
||||
static const routeName = '/settings/video';
|
||||
|
||||
const VideoSettingsPage({Key? key}) : super(key: key);
|
||||
class SettingsTileVideoControls extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsVideoControlsTile;
|
||||
|
||||
@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: const SafeArea(
|
||||
child: VideoSection(
|
||||
standalonePage: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||
title: title(context),
|
||||
routeName: VideoControlsPage.routeName,
|
||||
builder: (context) => const VideoControlsPage(),
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsTileVideoSubtitleTheme extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSubtitleThemeTile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSubPageTile(
|
||||
title: title(context),
|
||||
routeName: SubtitleThemePage.routeName,
|
||||
builder: (context) => const SubtitleThemePage(),
|
||||
);
|
||||
}
|
||||
|
|
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: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 {
|
||||
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/settings.dart';
|
||||
import 'package:aves/services/common/services.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_expansion_tile.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';
|
||||
import 'package:aves/widgets/settings/viewer/entry_background.dart';
|
||||
import 'package:aves/widgets/settings/viewer/overlay.dart';
|
||||
import 'package:aves/widgets/settings/viewer/viewer_actions_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ViewerSection extends StatelessWidget {
|
||||
final ValueNotifier<String?> expandedNotifier;
|
||||
|
||||
const ViewerSection({
|
||||
Key? key,
|
||||
required this.expandedNotifier,
|
||||
}) : super(key: key);
|
||||
class ViewerSection extends SettingsSection {
|
||||
@override
|
||||
String get key => 'viewer';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AvesExpansionTile(
|
||||
leading: SettingsTileLeading(
|
||||
Widget icon(BuildContext context) => SettingsTileLeading(
|
||||
icon: AIcons.image,
|
||||
color: context.select<AvesColorsData, Color>((v) => v.image),
|
||||
),
|
||||
title: context.l10n.settingsSectionViewer,
|
||||
expandedNotifier: expandedNotifier,
|
||||
showHighlight: false,
|
||||
children: [
|
||||
const ViewerActionsTile(),
|
||||
const ViewerOverlayTile(),
|
||||
const _CutoutModeSwitch(),
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.viewerMaxBrightness,
|
||||
onChanged: (v) => settings.viewerMaxBrightness = v,
|
||||
title: context.l10n.settingsViewerMaximumBrightness,
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
selector: (context, s) => s.enableMotionPhotoAutoPlay,
|
||||
onChanged: (v) => settings.enableMotionPhotoAutoPlay = v,
|
||||
title: context.l10n.settingsMotionPhotoAutoPlay,
|
||||
),
|
||||
Selector<Settings, EntryBackground>(
|
||||
selector: (context, s) => s.imageBackground,
|
||||
builder: (context, current, child) => ListTile(
|
||||
title: Text(context.l10n.settingsImageBackground),
|
||||
trailing: EntryBackgroundSelector(
|
||||
getter: () => current,
|
||||
setter: (value) => settings.imageBackground = value,
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsSectionViewer;
|
||||
|
||||
@override
|
||||
FutureOr<List<SettingsTile>> tiles(BuildContext context) async {
|
||||
final canSetCutoutMode = await windowService.canSetCutoutMode();
|
||||
return [
|
||||
SettingsTileViewerQuickActions(),
|
||||
SettingsTileViewerOverlay(),
|
||||
if (canSetCutoutMode) SettingsTileViewerCutoutMode(),
|
||||
SettingsTileViewerMaxBrightness(),
|
||||
SettingsTileViewerMotionPhotoAutoPlay(),
|
||||
SettingsTileViewerImageBackground(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsTileViewerQuickActions extends SettingsTile {
|
||||
@override
|
||||
String title(BuildContext context) => context.l10n.settingsViewerQuickActionsTile;
|
||||
|
||||
@override
|
||||
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: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 {
|
||||
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/video_speed_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/video/controller.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
{
|
||||
"de": [
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsThumbnailOverlayTile",
|
||||
"settingsThumbnailOverlayTitle"
|
||||
],
|
||||
|
||||
"es": [
|
||||
"entryActionShowGeoTiffOnMap",
|
||||
"entryActionConvertMotionPhotoToStillImage",
|
||||
|
@ -9,7 +16,32 @@
|
|||
"coverDialogTabApp",
|
||||
"coverDialogTabColor",
|
||||
"appPickDialogTitle",
|
||||
"appPickDialogNone"
|
||||
"appPickDialogNone",
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsThumbnailOverlayTile",
|
||||
"settingsThumbnailOverlayTitle"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsThumbnailOverlayTile",
|
||||
"settingsThumbnailOverlayTitle"
|
||||
],
|
||||
|
||||
"id": [
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsThumbnailOverlayTile",
|
||||
"settingsThumbnailOverlayTitle"
|
||||
],
|
||||
|
||||
"it": [
|
||||
"settingsSearchFieldLabel",
|
||||
"settingsSearchEmpty",
|
||||
"settingsThumbnailOverlayTile",
|
||||
"settingsThumbnailOverlayTitle"
|
||||
],
|
||||
|
||||
"ja": [
|
||||
|
@ -22,6 +54,38 @@
|
|||
"coverDialogTabApp",
|
||||
"coverDialogTabColor",
|
||||
"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