Skip to content

Commit ab45180

Browse files
feat: allow configuring widgets that own haptic feedback
1 parent a87bbc5 commit ab45180

6 files changed

Lines changed: 85 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [1.8.3-dev](https://github.com/Solvro/lib-mobile-solvro-config/compare/v1.8.2-dev.2...v1.8.3-dev) (2026-06-07)
4+
5+
6+
### Features
7+
8+
* allow configuring widgets that own haptic feedback
9+
310
## [1.8.2-dev.2](https://github.com/Solvro/lib-mobile-solvro-config/compare/v1.8.2-dev.1...v1.8.2-dev.2) (2026-06-07)
411

512

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ $ solvro_config --version
2525
$ solvro_config --help
2626
```
2727

28-
## Custom haptic wrappers
28+
## Haptic feedback
2929

3030
The `add_haptic_feedback_on_user_interaction` rule accepts custom haptic wrappers in `analysis_options.yaml`:
3131

@@ -37,3 +37,14 @@ plugins:
3737
- HapticFeedback.
3838
- AppHaptics.
3939
```
40+
41+
Reusable widgets that trigger haptics internally can be listed as haptic-owning widgets. Callback arguments passed to these widgets will not be reported by the rule, so callers can keep callbacks business-only:
42+
43+
```yaml
44+
plugins:
45+
solvro_config:
46+
version: ^1.8.0
47+
haptic_owning_widgets:
48+
- MySplashTile
49+
- WideTileCard
50+
```

lib/solvro_forks/solvro_custom_linter.dart

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class AddHapticFeedbackOnUserInteractionRule extends _SolvroRule {
315315
RuleContext context,
316316
) {
317317
final hapticWrappers = _configuredHapticWrappers(context);
318+
final hapticOwningWidgets = _configuredHapticOwningWidgets(context);
318319

319320
registry.addNamedExpression(
320321
this,
@@ -326,6 +327,11 @@ class AddHapticFeedbackOnUserInteractionRule extends _SolvroRule {
326327
}.contains(node.name.label.name)) {
327328
return;
328329
}
330+
331+
if (_isCallbackInHapticOwningWidget(node, hapticOwningWidgets)) {
332+
return;
333+
}
334+
329335
final source = node.expression.toString();
330336
if (!hapticWrappers.any(source.contains)) {
331337
reportAtNode(node);
@@ -334,28 +340,66 @@ class AddHapticFeedbackOnUserInteractionRule extends _SolvroRule {
334340
);
335341
}
336342

343+
static bool _isCallbackInHapticOwningWidget(
344+
NamedExpression node,
345+
List<String> hapticOwningWidgets,
346+
) {
347+
final argumentList = node.parent;
348+
final creation = argumentList?.parent;
349+
if (argumentList is! ArgumentList ||
350+
creation is! InstanceCreationExpression) {
351+
return false;
352+
}
353+
354+
final widgetName = creation.constructorName.type.name.lexeme;
355+
return hapticOwningWidgets.contains(widgetName);
356+
}
357+
337358
static List<String> _configuredHapticWrappers(RuleContext context) {
359+
return _configuredStrings(
360+
context,
361+
singularName: "haptic_wrapper",
362+
pluralName: "haptic_wrappers",
363+
defaultValues: _defaultHapticWrappers,
364+
);
365+
}
366+
367+
static List<String> _configuredHapticOwningWidgets(RuleContext context) {
368+
return _configuredStrings(
369+
context,
370+
singularName: "haptic_owning_widget",
371+
pluralName: "haptic_owning_widgets",
372+
defaultValues: const [],
373+
);
374+
}
375+
376+
static List<String> _configuredStrings(
377+
RuleContext context, {
378+
required String singularName,
379+
required String pluralName,
380+
required List<String> defaultValues,
381+
}) {
338382
final package = context.package;
339383
if (package == null) {
340-
return _defaultHapticWrappers;
384+
return defaultValues;
341385
}
342386

343387
final optionsFile = package.root.getChildAssumingFile(
344388
"analysis_options.yaml",
345389
);
346390
if (!optionsFile.exists) {
347-
return _defaultHapticWrappers;
391+
return defaultValues;
348392
}
349393

350394
try {
351395
final options = loadYamlNode(optionsFile.readAsStringSync());
352396
if (options is! YamlMap) {
353-
return _defaultHapticWrappers;
397+
return defaultValues;
354398
}
355399

356400
final plugins = options["plugins"];
357401
if (plugins is! YamlMap) {
358-
return _defaultHapticWrappers;
402+
return defaultValues;
359403
}
360404

361405
for (final pluginName in ["solvro_config", "solvro_custom_linter"]) {
@@ -364,33 +408,36 @@ class AddHapticFeedbackOnUserInteractionRule extends _SolvroRule {
364408
continue;
365409
}
366410

367-
final wrappers = <String>[];
368-
_addConfiguredWrappers(wrappers, pluginConfig["haptic_wrapper"]);
369-
_addConfiguredWrappers(wrappers, pluginConfig["haptic_wrappers"]);
411+
final configuredStrings = <String>[];
412+
_addConfiguredStrings(configuredStrings, pluginConfig[singularName]);
413+
_addConfiguredStrings(configuredStrings, pluginConfig[pluralName]);
370414

371-
if (wrappers.isNotEmpty) {
372-
return wrappers;
415+
if (configuredStrings.isNotEmpty) {
416+
return configuredStrings;
373417
}
374418
}
375419
} on YamlException {
376-
return _defaultHapticWrappers;
420+
return defaultValues;
377421
} on Exception {
378-
return _defaultHapticWrappers;
422+
return defaultValues;
379423
}
380424

381-
return _defaultHapticWrappers;
425+
return defaultValues;
382426
}
383427

384-
static void _addConfiguredWrappers(List<String> wrappers, Object? value) {
428+
static void _addConfiguredStrings(
429+
List<String> configuredStrings,
430+
Object? value,
431+
) {
385432
if (value is String && value.isNotEmpty) {
386-
wrappers.add(value);
433+
configuredStrings.add(value);
387434
return;
388435
}
389436

390437
if (value is YamlList) {
391438
for (final item in value) {
392439
if (item is String && item.isNotEmpty) {
393-
wrappers.add(item);
440+
configuredStrings.add(item);
394441
}
395442
}
396443
}

lib/src/install_solvro/add_linter.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ const _solvroCustomLinterPlugin = """
2626
provider_dependencies: false # this works weirdly
2727
haptic_wrappers:
2828
- HapticFeedback. # todo: you can change this if you need a custom haptic wrapper. if the default is fine, you can remove this section
29+
haptic_owning_widgets:
30+
- MySplashTile # todo: list reusable widgets that fire haptics internally, so callers can pass business-only callbacks
2931
""";

lib/src/version.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: solvro_config
22
description: A Dart linter/config package for Solvro projects.
3-
version: 1.8.2-dev.2
3+
version: 1.8.3-dev
44

55
repository: https://github.com/Solvro/lib-mobile-solvro-config
66

0 commit comments

Comments
 (0)