Change ip refresh
This commit is contained in:
@@ -125,6 +125,8 @@
|
|||||||
"emptyProxiesMsg": "No proxies available",
|
"emptyProxiesMsg": "No proxies available",
|
||||||
"delayTestTooltip": "Test Delay",
|
"delayTestTooltip": "Test Delay",
|
||||||
"sortTooltip": "Sort Proxies",
|
"sortTooltip": "Sort Proxies",
|
||||||
|
"checkIp": "Check IP",
|
||||||
|
"unknownIp": "Unknown IP",
|
||||||
"sortOptions": {
|
"sortOptions": {
|
||||||
"unsorted": "Default",
|
"unsorted": "Default",
|
||||||
"name": "Alphabetically",
|
"name": "Alphabetically",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:hiddify/core/widget/animated_visibility.dart';
|
|||||||
import 'package:hiddify/core/widget/shimmer_skeleton.dart';
|
import 'package:hiddify/core/widget/shimmer_skeleton.dart';
|
||||||
import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart';
|
import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart';
|
||||||
import 'package:hiddify/features/proxy/active/ip_widget.dart';
|
import 'package:hiddify/features/proxy/active/ip_widget.dart';
|
||||||
|
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||||
import 'package:hiddify/features/stats/notifier/stats_notifier.dart';
|
import 'package:hiddify/features/stats/notifier/stats_notifier.dart';
|
||||||
import 'package:hiddify/utils/utils.dart';
|
import 'package:hiddify/utils/utils.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@@ -56,12 +57,27 @@ class ActiveProxyFooter extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
AsyncError(error: final UnknownIp _) => Row(
|
||||||
|
children: [
|
||||||
|
const Icon(FluentIcons.arrow_sync_20_regular),
|
||||||
|
const Gap(8),
|
||||||
|
UnknownIPText(
|
||||||
|
text: t.proxies.checkIp,
|
||||||
|
onTap: () async {
|
||||||
|
ref
|
||||||
|
.read(ipInfoNotifierProvider.notifier)
|
||||||
|
.refresh();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
AsyncError() => Row(
|
AsyncError() => Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(FluentIcons.error_circle_20_regular),
|
const Icon(FluentIcons.error_circle_20_regular),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
IPText.unknown(
|
UnknownIPText(
|
||||||
onLongPress: () async {
|
text: t.proxies.unknownIp,
|
||||||
|
onTap: () async {
|
||||||
ref
|
ref
|
||||||
.read(ipInfoNotifierProvider.notifier)
|
.read(ipInfoNotifierProvider.notifier)
|
||||||
.refresh();
|
.refresh();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:hiddify/core/haptic/haptic_service.dart';
|
import 'package:hiddify/core/haptic/haptic_service.dart';
|
||||||
import 'package:hiddify/core/preferences/general_preferences.dart';
|
import 'package:hiddify/core/preferences/general_preferences.dart';
|
||||||
@@ -19,21 +21,32 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
|||||||
Future<IpInfo> build() async {
|
Future<IpInfo> build() async {
|
||||||
ref.disposeDelay(const Duration(seconds: 20));
|
ref.disposeDelay(const Duration(seconds: 20));
|
||||||
final cancelToken = CancelToken();
|
final cancelToken = CancelToken();
|
||||||
|
Timer? timer;
|
||||||
ref.onDispose(() {
|
ref.onDispose(() {
|
||||||
loggy.debug("disposing");
|
loggy.debug("disposing");
|
||||||
cancelToken.cancel();
|
cancelToken.cancel();
|
||||||
|
timer?.cancel();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ref.listen(
|
||||||
|
serviceRunningProvider,
|
||||||
|
(_, next) => _idle = false,
|
||||||
|
);
|
||||||
|
|
||||||
final autoCheck = ref.watch(autoCheckIpProvider);
|
final autoCheck = ref.watch(autoCheckIpProvider);
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||||
if (!_userRequestedFetch && !serviceRunning) {
|
// loggy.debug(
|
||||||
|
// "idle? [$_idle], forced? [$_forceCheck], connected? [$serviceRunning]",
|
||||||
|
// );
|
||||||
|
if (!_forceCheck && !serviceRunning) {
|
||||||
throw const ServiceNotRunning();
|
throw const ServiceNotRunning();
|
||||||
} else if (!_userRequestedFetch && serviceRunning && !autoCheck) {
|
} else if ((_idle && !_forceCheck) ||
|
||||||
|
(!_forceCheck && serviceRunning && !autoCheck)) {
|
||||||
throw const UnknownIp();
|
throw const UnknownIp();
|
||||||
}
|
}
|
||||||
|
|
||||||
_userRequestedFetch = false;
|
_forceCheck = false;
|
||||||
return ref
|
final info = await ref
|
||||||
.watch(proxyRepositoryProvider)
|
.watch(proxyRepositoryProvider)
|
||||||
.getCurrentIpInfo(cancelToken)
|
.getCurrentIpInfo(cancelToken)
|
||||||
.getOrElse(
|
.getOrElse(
|
||||||
@@ -42,15 +55,28 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
|||||||
throw err;
|
throw err;
|
||||||
},
|
},
|
||||||
).run();
|
).run();
|
||||||
|
|
||||||
|
timer = Timer(
|
||||||
|
const Duration(seconds: 10),
|
||||||
|
() {
|
||||||
|
loggy.debug("entering idle mode");
|
||||||
|
_idle = true;
|
||||||
|
ref.invalidateSelf();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _userRequestedFetch = false;
|
bool _idle = false;
|
||||||
|
bool _forceCheck = false;
|
||||||
|
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
if (state is AsyncLoading) return;
|
if (state.isLoading) return;
|
||||||
loggy.debug("refreshing");
|
loggy.debug("refreshing");
|
||||||
|
state = const AsyncLoading();
|
||||||
await ref.read(hapticServiceProvider.notifier).lightImpact();
|
await ref.read(hapticServiceProvider.notifier).lightImpact();
|
||||||
_userRequestedFetch = true;
|
_forceCheck = true;
|
||||||
ref.invalidateSelf();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:hiddify/core/localization/translations.dart';
|
|||||||
import 'package:hiddify/core/widget/shimmer_skeleton.dart';
|
import 'package:hiddify/core/widget/shimmer_skeleton.dart';
|
||||||
import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart';
|
import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart';
|
||||||
import 'package:hiddify/features/proxy/active/ip_widget.dart';
|
import 'package:hiddify/features/proxy/active/ip_widget.dart';
|
||||||
|
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
class ActiveProxySideBarCard extends HookConsumerWidget {
|
class ActiveProxySideBarCard extends HookConsumerWidget {
|
||||||
@@ -84,10 +85,21 @@ class ActiveProxySideBarCard extends HookConsumerWidget {
|
|||||||
const Icon(FluentIcons.question_circle_20_regular),
|
const Icon(FluentIcons.question_circle_20_regular),
|
||||||
const ShimmerSkeleton(widthFactor: .85, height: 14),
|
const ShimmerSkeleton(widthFactor: .85, height: 14),
|
||||||
),
|
),
|
||||||
|
AsyncError(error: final UnknownIp _) => buildProp(
|
||||||
|
const Icon(FluentIcons.arrow_sync_20_regular),
|
||||||
|
UnknownIPText(
|
||||||
|
text: t.proxies.checkIp,
|
||||||
|
onTap: () async {
|
||||||
|
ref.read(ipInfoNotifierProvider.notifier).refresh();
|
||||||
|
},
|
||||||
|
constrained: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
_ => buildProp(
|
_ => buildProp(
|
||||||
const Icon(FluentIcons.error_circle_20_regular),
|
const Icon(FluentIcons.error_circle_20_regular),
|
||||||
IPText.unknown(
|
UnknownIPText(
|
||||||
onLongPress: () async {
|
text: t.proxies.unknownIp,
|
||||||
|
onTap: () async {
|
||||||
ref.read(ipInfoNotifierProvider.notifier).refresh();
|
ref.read(ipInfoNotifierProvider.notifier).refresh();
|
||||||
},
|
},
|
||||||
constrained: true,
|
constrained: true,
|
||||||
|
|||||||
@@ -12,20 +12,14 @@ final _showIp = StateProvider.autoDispose((ref) {
|
|||||||
|
|
||||||
class IPText extends HookConsumerWidget {
|
class IPText extends HookConsumerWidget {
|
||||||
const IPText({
|
const IPText({
|
||||||
required String this.ip,
|
required this.ip,
|
||||||
required VoidCallback this.onLongPress,
|
required this.onLongPress,
|
||||||
this.constrained = false,
|
this.constrained = false,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
const IPText.unknown({
|
final String ip;
|
||||||
this.onLongPress,
|
final VoidCallback onLongPress;
|
||||||
this.constrained = false,
|
|
||||||
super.key,
|
|
||||||
}) : ip = null;
|
|
||||||
|
|
||||||
final String? ip;
|
|
||||||
final VoidCallback? onLongPress;
|
|
||||||
final bool constrained;
|
final bool constrained;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -38,46 +32,73 @@ class IPText extends HookConsumerWidget {
|
|||||||
return Semantics(
|
return Semantics(
|
||||||
label: t.proxies.ipInfoSemantics.address,
|
label: t.proxies.ipInfoSemantics.address,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: ip == null
|
onTap: () {
|
||||||
? null
|
ref.read(_showIp.notifier).state = !isVisible;
|
||||||
: () {
|
},
|
||||||
ref.read(_showIp.notifier).state = !isVisible;
|
|
||||||
},
|
|
||||||
onLongPress: onLongPress,
|
onLongPress: onLongPress,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
child: switch (ip) {
|
child: AnimatedCrossFade(
|
||||||
final ip? => AnimatedCrossFade(
|
firstChild: Text(
|
||||||
firstChild: Text(
|
ip,
|
||||||
ip,
|
style: ipStyle,
|
||||||
style: ipStyle,
|
textDirection: TextDirection.ltr,
|
||||||
textDirection: TextDirection.ltr,
|
overflow: TextOverflow.ellipsis,
|
||||||
overflow: TextOverflow.ellipsis,
|
),
|
||||||
),
|
secondChild: Padding(
|
||||||
secondChild: Padding(
|
padding: constrained
|
||||||
padding: constrained
|
? EdgeInsets.zero
|
||||||
? EdgeInsets.zero
|
: const EdgeInsetsDirectional.only(end: 48),
|
||||||
: const EdgeInsetsDirectional.only(end: 48),
|
child: Text(
|
||||||
child: Text(
|
obscureIp(ip),
|
||||||
obscureIp(ip),
|
semanticsLabel: t.general.hidden,
|
||||||
semanticsLabel: t.general.hidden,
|
style: ipStyle,
|
||||||
style: ipStyle,
|
textDirection: TextDirection.ltr,
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
crossFadeState: isVisible
|
|
||||||
? CrossFadeState.showFirst
|
|
||||||
: CrossFadeState.showSecond,
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
),
|
|
||||||
_ => Text(
|
|
||||||
t.general.unknown,
|
|
||||||
style: constrained ? textTheme.bodySmall : ipStyle,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
},
|
),
|
||||||
|
crossFadeState: isVisible
|
||||||
|
? CrossFadeState.showFirst
|
||||||
|
: CrossFadeState.showSecond,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnknownIPText extends HookConsumerWidget {
|
||||||
|
const UnknownIPText({
|
||||||
|
required this.text,
|
||||||
|
required this.onTap,
|
||||||
|
this.constrained = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String text;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final bool constrained;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final t = ref.watch(translationsProvider);
|
||||||
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
final style = constrained ? textTheme.bodySmall : textTheme.labelMedium;
|
||||||
|
|
||||||
|
return Semantics(
|
||||||
|
label: t.proxies.ipInfoSemantics.address,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: style,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user