Add haptic feedback
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
35
lib/core/haptic/haptic_service.dart
Normal file
35
lib/core/haptic/haptic_service.dart
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user