#316 wallpaper: scroll effect option

This commit is contained in:
Thibault Deckers 2022-09-29 10:41:25 +02:00
parent 38b9f84af0
commit 3d0e079df2
8 changed files with 160 additions and 44 deletions

View file

@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- Stats: open full top listings - Stats: open full top listings
- Slideshow: option for no transition - Slideshow: option for no transition
- Widget: tap action setting - Widget: tap action setting
- Wallpaper: scroll effect option
### Fixed ### Fixed

View file

@ -861,6 +861,8 @@
"viewerInfoSearchSuggestionResolution": "Resolution", "viewerInfoSearchSuggestionResolution": "Resolution",
"viewerInfoSearchSuggestionRights": "Rights", "viewerInfoSearchSuggestionRights": "Rights",
"wallpaperUseScrollEffect": "Use scroll effect on home screen",
"tagEditorPageTitle": "Edit Tags", "tagEditorPageTitle": "Edit Tags",
"tagEditorPageNewTagFieldLabel": "New tag", "tagEditorPageNewTagFieldLabel": "New tag",
"tagEditorPageAddTagTooltip": "Add tag", "tagEditorPageAddTagTooltip": "Add tag",

View file

@ -676,6 +676,8 @@
"viewerInfoSearchSuggestionResolution": "Résolution", "viewerInfoSearchSuggestionResolution": "Résolution",
"viewerInfoSearchSuggestionRights": "Droits", "viewerInfoSearchSuggestionRights": "Droits",
"wallpaperUseScrollEffect": "Utiliser leffet de défilement sur lécran daccueil",
"tagEditorPageTitle": "Modifier les libellés", "tagEditorPageTitle": "Modifier les libellés",
"tagEditorPageNewTagFieldLabel": "Nouveau libellé", "tagEditorPageNewTagFieldLabel": "Nouveau libellé",
"tagEditorPageAddTagTooltip": "Ajouter le libellé", "tagEditorPageAddTagTooltip": "Ajouter le libellé",

View file

@ -676,6 +676,8 @@
"viewerInfoSearchSuggestionResolution": "해상도", "viewerInfoSearchSuggestionResolution": "해상도",
"viewerInfoSearchSuggestionRights": "권리", "viewerInfoSearchSuggestionRights": "권리",
"wallpaperUseScrollEffect": "홈 화면에 스크롤 효과 사용",
"tagEditorPageTitle": "태그 수정", "tagEditorPageTitle": "태그 수정",
"tagEditorPageNewTagFieldLabel": "새 태그", "tagEditorPageNewTagFieldLabel": "새 태그",
"tagEditorPageAddTagTooltip": "태그 추가", "tagEditorPageAddTagTooltip": "태그 추가",

View file

@ -67,7 +67,21 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Text(message), child: Text(message),
), ),
...widget.options.entries.map((kv) => _buildRadioListTile(kv.key, kv.value, needConfirmation)), ...widget.options.entries.map((kv) {
final value = kv.key;
final title = kv.value;
return SelectionRadioListTile(
// key is expected by test driver
key: Key(value.toString()),
value: value,
title: title,
optionSubtitleBuilder: widget.optionSubtitleBuilder,
needConfirmation: needConfirmation,
dense: widget.dense,
getGroupValue: () => _selectedValue,
setGroupValue: (v) => setState(() => _selectedValue = v),
);
}),
], ],
actions: [ actions: [
TextButton( TextButton(
@ -82,17 +96,39 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
], ],
); );
} }
}
Widget _buildRadioListTile(T value, String title, bool needConfirmation) { class SelectionRadioListTile<T> extends StatelessWidget {
final subtitle = widget.optionSubtitleBuilder?.call(value); final T value;
final String title;
final TextBuilder<T>? optionSubtitleBuilder;
final bool needConfirmation;
final bool? dense;
final T Function() getGroupValue;
final void Function(T value) setGroupValue;
const SelectionRadioListTile({
super.key,
required this.value,
required this.title,
this.optionSubtitleBuilder,
required this.needConfirmation,
this.dense,
required this.getGroupValue,
required this.setGroupValue,
});
@override
Widget build(BuildContext context) {
final subtitle = optionSubtitleBuilder?.call(value);
return ReselectableRadioListTile<T>( return ReselectableRadioListTile<T>(
// key is expected by test driver // key is expected by test driver
key: Key(value.toString()), key: Key(value.toString()),
value: value, value: value,
groupValue: _selectedValue, groupValue: getGroupValue(),
onChanged: (v) { onChanged: (v) {
if (needConfirmation) { if (needConfirmation) {
setState(() => _selectedValue = v as T); setGroupValue(v as T);
} else { } else {
Navigator.pop(context, v); Navigator.pop(context, v);
} }
@ -112,7 +148,7 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
maxLines: 1, maxLines: 1,
) )
: null, : null,
dense: widget.dense, dense: dense,
); );
} }
} }

View file

@ -0,0 +1,53 @@
import 'package:aves/model/device.dart';
import 'package:aves/model/wallpaper_target.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
import 'package:flutter/material.dart';
import 'package:tuple/tuple.dart';
import 'aves_dialog.dart';
class WallpaperSettingsDialog extends StatefulWidget {
const WallpaperSettingsDialog({super.key});
@override
State<WallpaperSettingsDialog> createState() => _WallpaperSettingsDialogState();
}
class _WallpaperSettingsDialogState extends State<WallpaperSettingsDialog> {
WallpaperTarget _selectedTarget = WallpaperTarget.home;
bool _useScrollEffect = true;
@override
Widget build(BuildContext context) {
return AvesDialog(
scrollableContent: [
if (device.canSetLockScreenWallpaper)
...WallpaperTarget.values.map((value) {
return SelectionRadioListTile(
value: value,
title: value.getName(context),
needConfirmation: true,
getGroupValue: () => _selectedTarget,
setGroupValue: (v) => setState(() => _selectedTarget = v),
);
}),
SwitchListTile(
value: _useScrollEffect,
onChanged: (v) => setState(() => _useScrollEffect = v),
title: Text(context.l10n.wallpaperUseScrollEffect),
)
],
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
),
TextButton(
onPressed: () => Navigator.pop(context, Tuple2<WallpaperTarget, bool>(_selectedTarget, _useScrollEffect)),
child: Text(context.l10n.applyButtonLabel),
),
],
);
}
}

View file

@ -2,14 +2,13 @@ import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:aves/model/device.dart';
import 'package:aves/model/entry.dart'; import 'package:aves/model/entry.dart';
import 'package:aves/model/entry_images.dart'; import 'package:aves/model/entry_images.dart';
import 'package:aves/model/wallpaper_target.dart'; import 'package:aves/model/wallpaper_target.dart';
import 'package:aves/services/wallpaper_service.dart'; import 'package:aves/services/wallpaper_service.dart';
import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/action_mixins/feedback.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart'; import 'package:aves/widgets/dialogs/wallpaper_settings_dialog.dart';
import 'package:aves/widgets/viewer/overlay/common.dart'; import 'package:aves/widgets/viewer/overlay/common.dart';
import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart'; import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart';
import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/video/conductor.dart';
@ -18,6 +17,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class WallpaperButtons extends StatelessWidget with FeedbackMixin { class WallpaperButtons extends StatelessWidget with FeedbackMixin {
final AvesEntry entry; final AvesEntry entry;
@ -56,19 +56,14 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
Future<void> _setWallpaper(BuildContext context) async { Future<void> _setWallpaper(BuildContext context) async {
final l10n = context.l10n; final l10n = context.l10n;
var target = WallpaperTarget.home; final value = await showDialog<Tuple2<WallpaperTarget, bool>>(
if (device.canSetLockScreenWallpaper) {
final value = await showDialog<WallpaperTarget>(
context: context, context: context,
builder: (context) => AvesSelectionDialog<WallpaperTarget>( builder: (context) => const WallpaperSettingsDialog(),
initialValue: WallpaperTarget.home,
options: Map.fromEntries(WallpaperTarget.values.map((v) => MapEntry(v, v.getName(context)))),
confirmationButtonLabel: l10n.continueButtonLabel,
),
); );
if (value == null) return; if (value == null) return;
target = value;
} final target = value.item1;
final useScrollEffect = value.item2;
final reportController = StreamController.broadcast(); final reportController = StreamController.broadcast();
unawaited(showOpReport( unawaited(showOpReport(
@ -76,17 +71,15 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
opStream: reportController.stream, opStream: reportController.stream,
)); ));
final viewState = context.read<ViewStateConductor>().getOrCreateController(entry).value; var region = _getVisibleRegion(context);
final viewportSize = viewState.viewportSize; if (region == null) return;
final contentSize = viewState.contentSize;
final scale = viewState.scale;
if (viewportSize == null || contentSize == null || contentSize.isEmpty || scale == null) return;
final center = (contentSize / 2 - viewState.position / scale) as Size; if (useScrollEffect) {
final regionSize = viewportSize / scale; final deltaX = min(region.left, entry.displaySize.width - region.right);
final regionTopLeft = (center - regionSize / 2) as Offset; region = Rect.fromLTRB(region.left - deltaX, region.top, region.right + deltaX, region.bottom);
final region = Rect.fromLTWH(regionTopLeft.dx, regionTopLeft.dy, regionSize.width, regionSize.height); }
final bytes = await _getBytes(context, scale, region);
final bytes = await _getBytes(context, region);
final success = bytes != null && await WallpaperService.set(bytes, target); final success = bytes != null && await WallpaperService.set(bytes, target);
unawaited(reportController.close()); unawaited(reportController.close());
@ -98,9 +91,25 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
} }
} }
Future<Uint8List?> _getBytes(BuildContext context, double scale, Rect displayRegion) async { Rect? _getVisibleRegion(BuildContext context) {
final viewState = context.read<ViewStateConductor>().getOrCreateController(entry).value;
final viewportSize = viewState.viewportSize;
final contentSize = viewState.contentSize;
final scale = viewState.scale;
if (viewportSize == null || contentSize == null || contentSize.isEmpty || scale == null) return null;
final center = (contentSize / 2 - viewState.position / scale) as Size;
final regionSize = viewportSize / scale;
final regionTopLeft = (center - regionSize / 2) as Offset;
return Rect.fromLTWH(regionTopLeft.dx, regionTopLeft.dy, regionSize.width, regionSize.height);
}
Future<Uint8List?> _getBytes(BuildContext context, Rect displayRegion) async {
final viewState = context.read<ViewStateConductor>().getOrCreateController(entry).value;
final scale = viewState.scale;
final displaySize = entry.displaySize; final displaySize = entry.displaySize;
if (displaySize.isEmpty) return null; if (displaySize.isEmpty || scale == null) return null;
var storageRegion = Rectangle( var storageRegion = Rectangle(
displayRegion.left, displayRegion.left,

View file

@ -9,7 +9,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"el": [ "el": [
@ -22,7 +23,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"es": [ "es": [
@ -51,7 +53,8 @@
"settingsConfirmationAfterMoveToBinItems", "settingsConfirmationAfterMoveToBinItems",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle", "statsTopAlbumsSectionTitle",
"viewerInfoLabelDescription" "viewerInfoLabelDescription",
"wallpaperUseScrollEffect"
], ],
"id": [ "id": [
@ -64,7 +67,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"it": [ "it": [
@ -77,7 +81,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"ja": [ "ja": [
@ -107,7 +112,8 @@
"settingsViewerGestureSideTapNext", "settingsViewerGestureSideTapNext",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle", "statsTopAlbumsSectionTitle",
"viewerInfoLabelDescription" "viewerInfoLabelDescription",
"wallpaperUseScrollEffect"
], ],
"nl": [ "nl": [
@ -120,7 +126,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"pt": [ "pt": [
@ -133,7 +140,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"ru": [ "ru": [
@ -146,7 +154,8 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
], ],
"tr": [ "tr": [
@ -204,7 +213,8 @@
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle", "statsTopAlbumsSectionTitle",
"viewerSetWallpaperButtonLabel", "viewerSetWallpaperButtonLabel",
"viewerInfoLabelDescription" "viewerInfoLabelDescription",
"wallpaperUseScrollEffect"
], ],
"zh": [ "zh": [
@ -217,6 +227,7 @@
"albumGroupType", "albumGroupType",
"albumMimeTypeMixed", "albumMimeTypeMixed",
"settingsWidgetOpenPage", "settingsWidgetOpenPage",
"statsTopAlbumsSectionTitle" "statsTopAlbumsSectionTitle",
"wallpaperUseScrollEffect"
] ]
} }