mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-06-12 12:47:37 +02:00
feat: add haptic feedback (#1459)
Co-authored-by: Ushie <ushiekane@gmail.com> Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
This commit is contained in:
@ -5,6 +5,8 @@ import 'package:revanced_manager/models/patch.dart';
|
||||
import 'package:revanced_manager/services/manager_api.dart';
|
||||
import 'package:revanced_manager/services/toast.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_custom_card.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class PatchItem extends StatefulWidget {
|
||||
@ -56,7 +58,7 @@ class _PatchItemState extends State<PatchItem> {
|
||||
widget._managerAPI.isVersionCompatibilityCheckEnabled() == true
|
||||
? 0.5
|
||||
: 1,
|
||||
child: CustomCard(
|
||||
child: HapticCustomCard(
|
||||
padding: EdgeInsets.only(
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
@ -88,7 +90,7 @@ class _PatchItemState extends State<PatchItem> {
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: 1.2,
|
||||
child: Checkbox(
|
||||
child: HapticCheckbox(
|
||||
value: widget.isSelected,
|
||||
activeColor: Theme.of(context).colorScheme.primary,
|
||||
checkColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_i18n/widgets/I18nText.dart';
|
||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
|
||||
|
||||
class SAutoUpdatePatches extends StatefulWidget {
|
||||
const SAutoUpdatePatches({super.key});
|
||||
@ -14,7 +15,7 @@ final _settingsViewModel = SettingsViewModel();
|
||||
class _SAutoUpdatePatchesState extends State<SAutoUpdatePatches> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
return HapticSwitchListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
title: I18nText(
|
||||
'settingsView.autoUpdatePatchesLabel',
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_i18n/widgets/I18nText.dart';
|
||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
|
||||
|
||||
class SEnablePatchesSelection extends StatefulWidget {
|
||||
const SEnablePatchesSelection({super.key});
|
||||
@ -15,7 +16,7 @@ final _settingsViewModel = SettingsViewModel();
|
||||
class _SEnablePatchesSelectionState extends State<SEnablePatchesSelection> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
return HapticSwitchListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
title: I18nText(
|
||||
'settingsView.enablePatchesSelectionLabel',
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_i18n/widgets/I18nText.dart';
|
||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
|
||||
|
||||
class SRequireSuggestedAppVersion extends StatefulWidget {
|
||||
const SRequireSuggestedAppVersion({super.key});
|
||||
@ -16,7 +17,7 @@ class _SRequireSuggestedAppVersionState
|
||||
extends State<SRequireSuggestedAppVersion> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
return HapticSwitchListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
title: I18nText(
|
||||
'settingsView.requireSuggestedAppVersionLabel',
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_i18n/widgets/I18nText.dart';
|
||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
|
||||
|
||||
class SUniversalPatches extends StatefulWidget {
|
||||
const SUniversalPatches({super.key});
|
||||
@ -18,7 +19,7 @@ final _patcherViewModel = PatcherViewModel();
|
||||
class _SUniversalPatchesState extends State<SUniversalPatches> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
return HapticSwitchListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
title: I18nText(
|
||||
'settingsView.universalPatchesLabel',
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_i18n/widgets/I18nText.dart';
|
||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
|
||||
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
|
||||
|
||||
class SVersionCompatibilityCheck extends StatefulWidget {
|
||||
@ -21,7 +22,7 @@ class _SVersionCompatibilityCheckState
|
||||
extends State<SVersionCompatibilityCheck> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
return HapticSwitchListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
title: I18nText(
|
||||
'settingsView.versionCompatibilityCheckLabel',
|
||||
|
32
lib/ui/widgets/shared/haptics/haptic_checkbox.dart
Normal file
32
lib/ui/widgets/shared/haptics/haptic_checkbox.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HapticCheckbox extends StatelessWidget {
|
||||
const HapticCheckbox({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
this.activeColor,
|
||||
this.checkColor,
|
||||
this.side,
|
||||
});
|
||||
final bool value;
|
||||
final Function(bool?)? onChanged;
|
||||
final Color? activeColor;
|
||||
final Color? checkColor;
|
||||
final BorderSide? side;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Checkbox(
|
||||
value: value,
|
||||
onChanged: (value) => {
|
||||
HapticFeedback.selectionClick(),
|
||||
if (onChanged != null) onChanged!(value),
|
||||
},
|
||||
activeColor: activeColor,
|
||||
checkColor: checkColor,
|
||||
side: side,
|
||||
);
|
||||
}
|
||||
}
|
32
lib/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart
Normal file
32
lib/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HapticCheckboxListTile extends StatelessWidget {
|
||||
const HapticCheckboxListTile({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
this.title,
|
||||
this.subtitle,
|
||||
this.contentPadding,
|
||||
});
|
||||
final bool value;
|
||||
final Function(bool?)? onChanged;
|
||||
final Widget? title;
|
||||
final Widget? subtitle;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CheckboxListTile(
|
||||
contentPadding: contentPadding ?? EdgeInsets.zero,
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
value: value,
|
||||
onChanged: (value) => {
|
||||
HapticFeedback.lightImpact(),
|
||||
if (onChanged != null) onChanged!(value),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
33
lib/ui/widgets/shared/haptics/haptic_custom_card.dart
Normal file
33
lib/ui/widgets/shared/haptics/haptic_custom_card.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||
|
||||
class HapticCustomCard extends StatelessWidget {
|
||||
const HapticCustomCard({
|
||||
super.key,
|
||||
this.isFilled = true,
|
||||
required this.child,
|
||||
this.onTap,
|
||||
this.padding,
|
||||
this.backgroundColor,
|
||||
});
|
||||
final bool isFilled;
|
||||
final Widget child;
|
||||
final Function()? onTap;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final Color? backgroundColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomCard(
|
||||
isFilled: isFilled,
|
||||
onTap: () => {
|
||||
HapticFeedback.selectionClick(),
|
||||
if (onTap != null) onTap!(),
|
||||
},
|
||||
padding: padding,
|
||||
backgroundColor: backgroundColor,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HapticFloatingActionButtonExtended extends StatelessWidget {
|
||||
const HapticFloatingActionButtonExtended({
|
||||
super.key,
|
||||
required this.onPressed,
|
||||
required this.label,
|
||||
this.icon,
|
||||
this.elevation,
|
||||
});
|
||||
final Function()? onPressed;
|
||||
final Widget label;
|
||||
final Widget? icon;
|
||||
final double? elevation;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FloatingActionButton.extended(
|
||||
onPressed: () => {
|
||||
HapticFeedback.lightImpact(),
|
||||
if (onPressed != null) onPressed!(),
|
||||
},
|
||||
label: label,
|
||||
icon: icon,
|
||||
elevation: elevation,
|
||||
);
|
||||
}
|
||||
}
|
38
lib/ui/widgets/shared/haptics/haptic_radio_list_tile.dart
Normal file
38
lib/ui/widgets/shared/haptics/haptic_radio_list_tile.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HapticRadioListTile extends StatelessWidget {
|
||||
const HapticRadioListTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.groupValue,
|
||||
this.subtitle,
|
||||
this.onChanged,
|
||||
this.contentPadding,
|
||||
});
|
||||
final Widget title;
|
||||
final Widget? subtitle;
|
||||
final int value;
|
||||
final Function(int?)? onChanged;
|
||||
final int groupValue;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RadioListTile(
|
||||
contentPadding: contentPadding ?? EdgeInsets.zero,
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
value: value,
|
||||
groupValue: groupValue,
|
||||
onChanged: (val) => {
|
||||
if (val == value) {
|
||||
HapticFeedback.lightImpact(),
|
||||
},
|
||||
|
||||
if (onChanged != null) onChanged!(val),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
36
lib/ui/widgets/shared/haptics/haptic_switch_list_tile.dart
Normal file
36
lib/ui/widgets/shared/haptics/haptic_switch_list_tile.dart
Normal file
@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HapticSwitchListTile extends StatelessWidget {
|
||||
const HapticSwitchListTile({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
this.title,
|
||||
this.subtitle,
|
||||
this.contentPadding,
|
||||
});
|
||||
final bool value;
|
||||
final Function(bool)? onChanged;
|
||||
final Widget? title;
|
||||
final Widget? subtitle;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
contentPadding: contentPadding ?? EdgeInsets.zero,
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
value: value,
|
||||
onChanged: (value) => {
|
||||
if (value) {
|
||||
HapticFeedback.mediumImpact(),
|
||||
} else {
|
||||
HapticFeedback.lightImpact(),
|
||||
},
|
||||
if (onChanged != null) onChanged!(value),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user