179 lines
6.0 KiB
Dart
179 lines
6.0 KiB
Dart
/*
|
|
* Copyright (c) 2024-2026 Fabian Freund.
|
|
*
|
|
* This file is part of WebLibre
|
|
* (see https://weblibre.eu).
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
import 'package:copy_with_extension/copy_with_extension.dart';
|
|
import 'package:fast_equatable/fast_equatable.dart';
|
|
import 'package:json_annotation/json_annotation.dart';
|
|
import 'package:weblibre/features/gestures/data/models/gesture_action.dart';
|
|
|
|
part 'gesture_settings.g.dart';
|
|
|
|
const defaultGestureStrokeSize = 50;
|
|
const minGestureStrokeSize = 20;
|
|
const maxGestureStrokeSize = 100;
|
|
|
|
const defaultGestureTimeoutMs = 1500;
|
|
const minGestureTimeoutMs = 500;
|
|
const maxGestureTimeoutMs = 3000;
|
|
|
|
const defaultGestureMaxFingers = 1;
|
|
|
|
const defaultGestureIntervalMs = 0;
|
|
const minGestureIntervalMs = 0;
|
|
const maxGestureIntervalMs = 2000;
|
|
|
|
const defaultGestureStrokeIntervalMs = 0;
|
|
const minGestureStrokeIntervalMs = 0;
|
|
const maxGestureStrokeIntervalMs = 500;
|
|
|
|
/// Minimum number of strokes drawn before the live overlay starts suggesting
|
|
/// the other possible completions (mirrors the reference add-on's
|
|
/// `toastMinStroke`).
|
|
const defaultGestureMinSuggestionStroke = 2;
|
|
const minGestureMinSuggestionStroke = 1;
|
|
const maxGestureMinSuggestionStroke = 5;
|
|
|
|
/// Default gesture-to-action bindings, aligned with the reference add-on's
|
|
/// defaults for the actions WebLibre currently supports.
|
|
const defaultGestureBindings = <String, GestureAction>{
|
|
'D-L': GestureAction.forward,
|
|
'D-R': GestureAction.back,
|
|
'R-D': GestureAction.scrollTop,
|
|
'R-U': GestureAction.scrollBottom,
|
|
'D-R-U': GestureAction.reload,
|
|
'L-D-R': GestureAction.closeTab,
|
|
};
|
|
|
|
@CopyWith()
|
|
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
|
class GestureSettings with FastEquatable {
|
|
/// Master switch. When false, gesture recognition is fully disabled and the
|
|
/// quick toggles ([active]) have no effect.
|
|
final bool enabled;
|
|
|
|
/// Runtime toggle exposed via the quick toggles (menu sheet tile, contextual
|
|
/// toolbar button). Lets the user suspend gestures without touching the
|
|
/// master switch. The recognizer runs only when [enabled] && [active].
|
|
final bool active;
|
|
|
|
/// Base stroke length in logical pixels (scaled to the screen by native).
|
|
final int strokeSize;
|
|
|
|
/// Milliseconds of inactivity after which an in-progress gesture is dropped.
|
|
final int timeoutMs;
|
|
|
|
/// Maximum simultaneous pointers a gesture may use.
|
|
final int maxFingers;
|
|
|
|
/// Cooldown in milliseconds after a gesture fires, during which further
|
|
/// gestures are ignored. 0 disables the cooldown.
|
|
final int intervalMs;
|
|
|
|
/// Minimum milliseconds required between two consecutive direction changes
|
|
/// within a single gesture. A faster direction change aborts the in-progress
|
|
/// gesture, guarding against accidental fast scribbles. 0 disables the check.
|
|
final int minStrokeIntervalMs;
|
|
|
|
/// Whether to show the live feedback overlay while a stroke is being drawn
|
|
/// (the in-progress arrows plus the matching/possible actions).
|
|
final bool showFeedback;
|
|
|
|
/// Within the live overlay, also suggest the other possible completions once
|
|
/// at least [minSuggestionStroke] strokes have been drawn.
|
|
final bool suggestNext;
|
|
|
|
/// Minimum strokes drawn before [suggestNext] kicks in.
|
|
final int minSuggestionStroke;
|
|
|
|
/// Hosts on which gestures are disabled. A page is excluded when its host
|
|
/// equals or is a subdomain of any entry (see `hostMatchesRule`).
|
|
final List<String> excludedSites;
|
|
|
|
/// Canonical gesture key → action. Keys follow the grammar documented on
|
|
/// [GestureStroke].
|
|
final Map<String, GestureAction> bindings;
|
|
|
|
GestureSettings({
|
|
required this.enabled,
|
|
required this.active,
|
|
required this.strokeSize,
|
|
required this.timeoutMs,
|
|
required this.maxFingers,
|
|
required this.intervalMs,
|
|
required this.minStrokeIntervalMs,
|
|
required this.showFeedback,
|
|
required this.suggestNext,
|
|
required this.minSuggestionStroke,
|
|
required this.excludedSites,
|
|
required this.bindings,
|
|
});
|
|
|
|
GestureSettings.withDefaults({
|
|
bool? enabled,
|
|
bool? active,
|
|
int? strokeSize,
|
|
int? timeoutMs,
|
|
int? maxFingers,
|
|
int? intervalMs,
|
|
int? minStrokeIntervalMs,
|
|
bool? showFeedback,
|
|
bool? suggestNext,
|
|
int? minSuggestionStroke,
|
|
List<String>? excludedSites,
|
|
Map<String, GestureAction>? bindings,
|
|
}) : enabled = enabled ?? false,
|
|
active = active ?? true,
|
|
strokeSize = strokeSize ?? defaultGestureStrokeSize,
|
|
timeoutMs = timeoutMs ?? defaultGestureTimeoutMs,
|
|
maxFingers = maxFingers ?? defaultGestureMaxFingers,
|
|
intervalMs = intervalMs ?? defaultGestureIntervalMs,
|
|
minStrokeIntervalMs =
|
|
minStrokeIntervalMs ?? defaultGestureStrokeIntervalMs,
|
|
showFeedback = showFeedback ?? true,
|
|
suggestNext = suggestNext ?? true,
|
|
minSuggestionStroke =
|
|
minSuggestionStroke ?? defaultGestureMinSuggestionStroke,
|
|
excludedSites = excludedSites ?? const [],
|
|
bindings = bindings ?? defaultGestureBindings;
|
|
|
|
/// Whether the recognizer should actually run.
|
|
bool get effectiveEnabled => enabled && active;
|
|
|
|
factory GestureSettings.fromJson(Map<String, dynamic> json) =>
|
|
_$GestureSettingsFromJson(json);
|
|
|
|
Map<String, dynamic> toJson() => _$GestureSettingsToJson(this);
|
|
|
|
@override
|
|
List<Object?> get hashParameters => [
|
|
enabled,
|
|
active,
|
|
strokeSize,
|
|
timeoutMs,
|
|
maxFingers,
|
|
intervalMs,
|
|
minStrokeIntervalMs,
|
|
showFeedback,
|
|
suggestNext,
|
|
minSuggestionStroke,
|
|
excludedSites,
|
|
bindings,
|
|
];
|
|
}
|