From e382ae724dc70ca7cf1f86f5175f3582f0aac0de Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Fri, 16 Feb 2024 14:33:03 +0330 Subject: [PATCH] Add haptic feedback --- assets/translations/strings_en.i18n.json | 3 +- lib/core/haptic/haptic_service.dart | 35 +++++++++++++++++++ .../notifier/connection_notifier.dart | 10 ++++-- .../profile/notifier/profile_notifier.dart | 6 ++-- .../proxy/active/active_proxy_notifier.dart | 3 ++ .../overview/proxies_overview_notifier.dart | 3 ++ .../widgets/general_setting_tiles.dart | 11 +++++- 7 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 lib/core/haptic/haptic_service.dart diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json index 09077e53..4934c35b 100644 --- a/assets/translations/strings_en.i18n.json +++ b/assets/translations/strings_en.i18n.json @@ -186,7 +186,8 @@ "openWorkingDir": "Open Working Directory", "ignoreBatteryOptimizations": "Disable Battery Optimization", "ignoreBatteryOptimizationsMsg": "Remove restrictions for optimal VPN performance", - "dynamicNotification": "Display speed in notification" + "dynamicNotification": "Display speed in notification", + "hapticFeedback": "Haptic Feedback" }, "advanced": { "sectionTitle": "Advanced", diff --git a/lib/core/haptic/haptic_service.dart b/lib/core/haptic/haptic_service.dart new file mode 100644 index 00000000..2015a1a7 --- /dev/null +++ b/lib/core/haptic/haptic_service.dart @@ -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 updatePreference(bool value) async { + state = value; + await _preferences.setBool(hapticFeedbackPrefKey, value); + } + + Future lightImpact() async { + if (state) { + await HapticFeedback.lightImpact(); + } + } + + Future mediumImpact() async { + if (state) { + await HapticFeedback.mediumImpact(); + } + } +} diff --git a/lib/features/connection/notifier/connection_notifier.dart b/lib/features/connection/notifier/connection_notifier.dart index 288e77ca..9111bb62 100644 --- a/lib/features/connection/notifier/connection_notifier.dart +++ b/lib/features/connection/notifier/connection_notifier.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:hiddify/core/haptic/haptic_service.dart'; import 'package:hiddify/core/preferences/general_preferences.dart'; import 'package:hiddify/core/preferences/service_preferences.dart'; import 'package:hiddify/features/connection/data/connection_data_providers.dart'; @@ -53,14 +54,18 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger { } Future toggleConnection() async { + final haptic = ref.read(hapticServiceProvider.notifier); if (state case AsyncError()) { + await haptic.lightImpact(); await _connect(); } else if (state case AsyncData(:final value)) { switch (value) { case Disconnected(): + await haptic.lightImpact(); await ref.read(startedByUserProvider.notifier).update(true); await _connect(); case Connected(): + await haptic.mediumImpact(); await ref.read(startedByUserProvider.notifier).update(false); await _disconnect(); default: @@ -111,8 +116,9 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger { ) .mapLeft((err) async { 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 - if (err.toString().contains("panic") ){ + 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")) { await Sentry.captureException(Exception(err.toString())); } await ref.read(startedByUserProvider.notifier).update(false); diff --git a/lib/features/profile/notifier/profile_notifier.dart b/lib/features/profile/notifier/profile_notifier.dart index 0e4abdca..a51b7c99 100644 --- a/lib/features/profile/notifier/profile_notifier.dart +++ b/lib/features/profile/notifier/profile_notifier.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.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/model/failures.dart'; import 'package:hiddify/core/notification/in_app_notification_controller.dart'; @@ -70,8 +71,8 @@ class AddProfile extends _$AddProfile with AppLogger { loggy.debug("adding profile, content"); var name = parsed.name; - while (await _profilesRepo.getByName(name) != null) { - name+= '${randomInt(0, 9).run()}'; + while (await _profilesRepo.getByName(name) != null) { + name += '${randomInt(0, 9).run()}'; } task = _profilesRepo.addByContent( parsed.content, @@ -127,6 +128,7 @@ class UpdateProfile extends _$UpdateProfile with AppLogger { Future updateProfile(RemoteProfileEntity profile) async { if (state.isLoading) return; state = const AsyncLoading(); + await ref.read(hapticServiceProvider.notifier).lightImpact(); state = await AsyncValue.guard( () async { return await _profilesRepo.updateSubscription(profile).match( diff --git a/lib/features/proxy/active/active_proxy_notifier.dart b/lib/features/proxy/active/active_proxy_notifier.dart index 5d5351eb..71006acc 100644 --- a/lib/features/proxy/active/active_proxy_notifier.dart +++ b/lib/features/proxy/active/active_proxy_notifier.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:hiddify/core/haptic/haptic_service.dart'; import 'package:hiddify/core/utils/throttler.dart'; import 'package:hiddify/features/connection/notifier/connection_notifier.dart'; import 'package:hiddify/features/proxy/data/proxy_data_providers.dart'; @@ -40,6 +41,7 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger { Future refresh() async { loggy.debug("refreshing"); + await ref.read(hapticServiceProvider.notifier).lightImpact(); ref.invalidateSelf(); } } @@ -69,6 +71,7 @@ class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger { () async { loggy.debug("testing group: [$groupTag]"); if (state case AsyncData()) { + await ref.read(hapticServiceProvider.notifier).lightImpact(); await ref .read(proxyRepositoryProvider) .urlTest(groupTag) diff --git a/lib/features/proxy/overview/proxies_overview_notifier.dart b/lib/features/proxy/overview/proxies_overview_notifier.dart index 029631c4..4f967e54 100644 --- a/lib/features/proxy/overview/proxies_overview_notifier.dart +++ b/lib/features/proxy/overview/proxies_overview_notifier.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:combine/combine.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/preferences/preferences_provider.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]", ); if (state case AsyncData(value: final outbounds)) { + await ref.read(hapticServiceProvider.notifier).lightImpact(); await ref .read(proxyRepositoryProvider) .selectProxy(groupTag, outboundTag) @@ -151,6 +153,7 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger { Future urlTest(String groupTag) async { loggy.debug("testing group: [$groupTag]"); if (state case AsyncData()) { + await ref.read(hapticServiceProvider.notifier).lightImpact(); await ref .read(proxyRepositoryProvider) .urlTest(groupTag) diff --git a/lib/features/settings/widgets/general_setting_tiles.dart b/lib/features/settings/widgets/general_setting_tiles.dart index 8cd2fd79..fe446d50 100644 --- a/lib/features/settings/widgets/general_setting_tiles.dart +++ b/lib/features/settings/widgets/general_setting_tiles.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:fluentui_system_icons/fluentui_system_icons.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/preferences/general_preferences.dart'; import 'package:hiddify/core/theme/app_theme_mode.dart'; @@ -54,7 +55,7 @@ class GeneralSettingTiles extends HookConsumerWidget { }, ), const EnableAnalyticsPrefTile(), - if (Platform.isAndroid) + if (Platform.isAndroid) ...[ SwitchListTile( title: Text(t.settings.general.dynamicNotification), secondary: const Icon(FluentIcons.top_speed_24_regular), @@ -65,6 +66,14 @@ class GeneralSettingTiles extends HookConsumerWidget { .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) ...[ SwitchListTile( title: Text(t.settings.general.autoStart),