Add haptic feedback

This commit is contained in:
problematicconsumer
2024-02-16 14:33:03 +03:30
parent 1efcdd7c52
commit e382ae724d
7 changed files with 65 additions and 6 deletions

View File

@@ -186,7 +186,8 @@
"openWorkingDir": "Open Working Directory", "openWorkingDir": "Open Working Directory",
"ignoreBatteryOptimizations": "Disable Battery Optimization", "ignoreBatteryOptimizations": "Disable Battery Optimization",
"ignoreBatteryOptimizationsMsg": "Remove restrictions for optimal VPN performance", "ignoreBatteryOptimizationsMsg": "Remove restrictions for optimal VPN performance",
"dynamicNotification": "Display speed in notification" "dynamicNotification": "Display speed in notification",
"hapticFeedback": "Haptic Feedback"
}, },
"advanced": { "advanced": {
"sectionTitle": "Advanced", "sectionTitle": "Advanced",

View File

@@ -0,0 +1,35 @@
import 'package:flutter/services.dart';
import 'package:hiddify/core/preferences/preferences_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'haptic_service.g.dart';
@Riverpod(keepAlive: true)
class HapticService extends _$HapticService {
@override
bool build() {
return _preferences.getBool(hapticFeedbackPrefKey) ?? true;
}
static const String hapticFeedbackPrefKey = "haptic_feedback";
SharedPreferences get _preferences =>
ref.read(sharedPreferencesProvider).requireValue;
Future<void> updatePreference(bool value) async {
state = value;
await _preferences.setBool(hapticFeedbackPrefKey, value);
}
Future<void> lightImpact() async {
if (state) {
await HapticFeedback.lightImpact();
}
}
Future<void> mediumImpact() async {
if (state) {
await HapticFeedback.mediumImpact();
}
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:hiddify/core/haptic/haptic_service.dart';
import 'package:hiddify/core/preferences/general_preferences.dart'; import 'package:hiddify/core/preferences/general_preferences.dart';
import 'package:hiddify/core/preferences/service_preferences.dart'; import 'package:hiddify/core/preferences/service_preferences.dart';
import 'package:hiddify/features/connection/data/connection_data_providers.dart'; import 'package:hiddify/features/connection/data/connection_data_providers.dart';
@@ -53,14 +54,18 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
} }
Future<void> toggleConnection() async { Future<void> toggleConnection() async {
final haptic = ref.read(hapticServiceProvider.notifier);
if (state case AsyncError()) { if (state case AsyncError()) {
await haptic.lightImpact();
await _connect(); await _connect();
} else if (state case AsyncData(:final value)) { } else if (state case AsyncData(:final value)) {
switch (value) { switch (value) {
case Disconnected(): case Disconnected():
await haptic.lightImpact();
await ref.read(startedByUserProvider.notifier).update(true); await ref.read(startedByUserProvider.notifier).update(true);
await _connect(); await _connect();
case Connected(): case Connected():
await haptic.mediumImpact();
await ref.read(startedByUserProvider.notifier).update(false); await ref.read(startedByUserProvider.notifier).update(false);
await _disconnect(); await _disconnect();
default: default:
@@ -111,7 +116,8 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
) )
.mapLeft((err) async { .mapLeft((err) async {
loggy.warning("error connecting", err); loggy.warning("error connecting", err);
loggy.warning(err);//Go err is not normal object to see the go errors are string and need to be dumped loggy.warning(
err); //Go err is not normal object to see the go errors are string and need to be dumped
if (err.toString().contains("panic")) { if (err.toString().contains("panic")) {
await Sentry.captureException(Exception(err.toString())); await Sentry.captureException(Exception(err.toString()));
} }

View File

@@ -1,5 +1,6 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fpdart/fpdart.dart'; import 'package:fpdart/fpdart.dart';
import 'package:hiddify/core/haptic/haptic_service.dart';
import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/model/failures.dart'; import 'package:hiddify/core/model/failures.dart';
import 'package:hiddify/core/notification/in_app_notification_controller.dart'; import 'package:hiddify/core/notification/in_app_notification_controller.dart';
@@ -127,6 +128,7 @@ class UpdateProfile extends _$UpdateProfile with AppLogger {
Future<void> updateProfile(RemoteProfileEntity profile) async { Future<void> updateProfile(RemoteProfileEntity profile) async {
if (state.isLoading) return; if (state.isLoading) return;
state = const AsyncLoading(); state = const AsyncLoading();
await ref.read(hapticServiceProvider.notifier).lightImpact();
state = await AsyncValue.guard( state = await AsyncValue.guard(
() async { () async {
return await _profilesRepo.updateSubscription(profile).match( return await _profilesRepo.updateSubscription(profile).match(

View File

@@ -1,4 +1,5 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:hiddify/core/haptic/haptic_service.dart';
import 'package:hiddify/core/utils/throttler.dart'; import 'package:hiddify/core/utils/throttler.dart';
import 'package:hiddify/features/connection/notifier/connection_notifier.dart'; import 'package:hiddify/features/connection/notifier/connection_notifier.dart';
import 'package:hiddify/features/proxy/data/proxy_data_providers.dart'; import 'package:hiddify/features/proxy/data/proxy_data_providers.dart';
@@ -40,6 +41,7 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
Future<void> refresh() async { Future<void> refresh() async {
loggy.debug("refreshing"); loggy.debug("refreshing");
await ref.read(hapticServiceProvider.notifier).lightImpact();
ref.invalidateSelf(); ref.invalidateSelf();
} }
} }
@@ -69,6 +71,7 @@ class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger {
() async { () async {
loggy.debug("testing group: [$groupTag]"); loggy.debug("testing group: [$groupTag]");
if (state case AsyncData()) { if (state case AsyncData()) {
await ref.read(hapticServiceProvider.notifier).lightImpact();
await ref await ref
.read(proxyRepositoryProvider) .read(proxyRepositoryProvider)
.urlTest(groupTag) .urlTest(groupTag)

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:combine/combine.dart'; import 'package:combine/combine.dart';
import 'package:dartx/dartx.dart'; import 'package:dartx/dartx.dart';
import 'package:hiddify/core/haptic/haptic_service.dart';
import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/preferences/preferences_provider.dart'; import 'package:hiddify/core/preferences/preferences_provider.dart';
import 'package:hiddify/features/connection/notifier/connection_notifier.dart'; import 'package:hiddify/features/connection/notifier/connection_notifier.dart';
@@ -131,6 +132,7 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
"changing proxy, group: [$groupTag] - outbound: [$outboundTag]", "changing proxy, group: [$groupTag] - outbound: [$outboundTag]",
); );
if (state case AsyncData(value: final outbounds)) { if (state case AsyncData(value: final outbounds)) {
await ref.read(hapticServiceProvider.notifier).lightImpact();
await ref await ref
.read(proxyRepositoryProvider) .read(proxyRepositoryProvider)
.selectProxy(groupTag, outboundTag) .selectProxy(groupTag, outboundTag)
@@ -151,6 +153,7 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
Future<void> urlTest(String groupTag) async { Future<void> urlTest(String groupTag) async {
loggy.debug("testing group: [$groupTag]"); loggy.debug("testing group: [$groupTag]");
if (state case AsyncData()) { if (state case AsyncData()) {
await ref.read(hapticServiceProvider.notifier).lightImpact();
await ref await ref
.read(proxyRepositoryProvider) .read(proxyRepositoryProvider)
.urlTest(groupTag) .urlTest(groupTag)

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hiddify/core/haptic/haptic_service.dart';
import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/preferences/general_preferences.dart'; import 'package:hiddify/core/preferences/general_preferences.dart';
import 'package:hiddify/core/theme/app_theme_mode.dart'; import 'package:hiddify/core/theme/app_theme_mode.dart';
@@ -54,7 +55,7 @@ class GeneralSettingTiles extends HookConsumerWidget {
}, },
), ),
const EnableAnalyticsPrefTile(), const EnableAnalyticsPrefTile(),
if (Platform.isAndroid) if (Platform.isAndroid) ...[
SwitchListTile( SwitchListTile(
title: Text(t.settings.general.dynamicNotification), title: Text(t.settings.general.dynamicNotification),
secondary: const Icon(FluentIcons.top_speed_24_regular), secondary: const Icon(FluentIcons.top_speed_24_regular),
@@ -65,6 +66,14 @@ class GeneralSettingTiles extends HookConsumerWidget {
.update(value); .update(value);
}, },
), ),
SwitchListTile(
title: Text(t.settings.general.hapticFeedback),
secondary: const Icon(FluentIcons.phone_vibrate_24_regular),
value: ref.watch(hapticServiceProvider),
onChanged:
ref.read(hapticServiceProvider.notifier).updatePreference,
),
],
if (PlatformUtils.isDesktop) ...[ if (PlatformUtils.isDesktop) ...[
SwitchListTile( SwitchListTile(
title: Text(t.settings.general.autoStart), title: Text(t.settings.general.autoStart),