diff --git a/lib/features/home/widget/connection_button.dart b/lib/features/home/widget/connection_button.dart index e0cda02b..8a8bfa2b 100644 --- a/lib/features/home/widget/connection_button.dart +++ b/lib/features/home/widget/connection_button.dart @@ -11,6 +11,7 @@ import 'package:hiddify/features/connection/model/connection_status.dart'; import 'package:hiddify/features/connection/notifier/connection_notifier.dart'; import 'package:hiddify/features/connection/widget/experimental_feature_notice.dart'; import 'package:hiddify/features/profile/notifier/active_profile_notifier.dart'; +import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart'; import 'package:hiddify/gen/assets.gen.dart'; import 'package:hiddify/utils/alerts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -23,8 +24,10 @@ class ConnectionButton extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final t = ref.watch(translationsProvider); final connectionStatus = ref.watch(connectionNotifierProvider); - final requiresReconnect = - ref.watch(configOptionNotifierProvider).valueOrNull; + final activeProxy = ref.watch(activeProxyNotifierProvider); + final delay = activeProxy.valueOrNull?.urlTestDelay ?? 0; + + final requiresReconnect = ref.watch(configOptionNotifierProvider).valueOrNull; final today = DateTime.now(); ref.listen( @@ -33,10 +36,8 @@ class ConnectionButton extends HookConsumerWidget { if (next case AsyncError(:final error)) { CustomAlertDialog.fromErr(t.presentError(error)).show(context); } - if (next - case AsyncData(value: Disconnected(:final connectionFailure?))) { - CustomAlertDialog.fromErr(t.presentError(connectionFailure)) - .show(context); + if (next case AsyncData(value: Disconnected(:final connectionFailure?))) { + CustomAlertDialog.fromErr(t.presentError(connectionFailure)).show(context); } }, ); @@ -47,8 +48,7 @@ class ConnectionButton extends HookConsumerWidget { final hasExperimental = ref.read(ConfigOptions.hasExperimentalFeatures); final canShowNotice = !ref.read(disableExperimentalFeatureNoticeProvider); if (hasExperimental && canShowNotice && context.mounted) { - return await const ExperimentalFeatureNoticeDialog().show(context) ?? - false; + return await const ExperimentalFeatureNoticeDialog().show(context) ?? false; } return true; } @@ -57,52 +57,40 @@ class ConnectionButton extends HookConsumerWidget { onTap: switch (connectionStatus) { AsyncData(value: Disconnected()) || AsyncError() => () async { if (await showExperimentalNotice()) { - return await ref - .read(connectionNotifierProvider.notifier) - .toggleConnection(); + return await ref.read(connectionNotifierProvider.notifier).toggleConnection(); } }, AsyncData(value: Connected()) => () async { if (requiresReconnect == true && await showExperimentalNotice()) { - return await ref - .read(connectionNotifierProvider.notifier) - .reconnect(await ref.read(activeProfileProvider.future)); + return await ref.read(connectionNotifierProvider.notifier).reconnect(await ref.read(activeProfileProvider.future)); } - return await ref - .read(connectionNotifierProvider.notifier) - .toggleConnection(); + return await ref.read(connectionNotifierProvider.notifier).toggleConnection(); }, _ => () {}, }, enabled: switch (connectionStatus) { - AsyncData(value: Connected()) || - AsyncData(value: Disconnected()) || - AsyncError() => - true, + AsyncData(value: Connected()) || AsyncData(value: Disconnected()) || AsyncError() => true, _ => false, }, label: switch (connectionStatus) { - AsyncData(value: Connected()) when requiresReconnect == true => - t.connection.reconnect, + AsyncData(value: Connected()) when requiresReconnect == true => t.connection.reconnect, + AsyncData(value: Connected()) when delay <= 0 || delay >= 65000 => t.connection.connecting, AsyncData(value: final status) => status.present(t), _ => "", }, buttonColor: switch (connectionStatus) { - AsyncData(value: Connected()) when requiresReconnect == true => - Colors.teal, + AsyncData(value: Connected()) when requiresReconnect == true => Colors.teal, + AsyncData(value: Connected()) when delay <= 0 || delay >= 65000 => Color.fromARGB(255, 185, 176, 103), AsyncData(value: Connected()) => buttonTheme.connectedColor!, AsyncData(value: _) => buttonTheme.idleColor!, _ => Colors.red, }, image: switch (connectionStatus) { - AsyncData(value: Connected()) when requiresReconnect == true => - Assets.images.disconnectNorouz, + AsyncData(value: Connected()) when requiresReconnect == true => Assets.images.disconnectNorouz, AsyncData(value: Connected()) => Assets.images.connectNorouz, AsyncData(value: _) => Assets.images.disconnectNorouz, _ => Assets.images.disconnectNorouz, - AsyncData(value: Disconnected()) || - AsyncError() => - Assets.images.disconnectNorouz, + AsyncData(value: Disconnected()) || AsyncError() => Assets.images.disconnectNorouz, AsyncData(value: Connected()) => Assets.images.connectNorouz, _ => Assets.images.disconnectNorouz, }, @@ -177,9 +165,7 @@ class _ConnectionButton extends StatelessWidget { ), ), ).animate(target: enabled ? 0 : 1).blurXY(end: 1), - ) - .animate(target: enabled ? 0 : 1) - .scaleXY(end: .88, curve: Curves.easeIn), + ).animate(target: enabled ? 0 : 1).scaleXY(end: .88, curve: Curves.easeIn), ), const Gap(16), ExcludeSemantics( diff --git a/lib/features/home/widget/home_page.dart b/lib/features/home/widget/home_page.dart index cf16bddb..fda9a46e 100644 --- a/lib/features/home/widget/home_page.dart +++ b/lib/features/home/widget/home_page.dart @@ -12,6 +12,7 @@ import 'package:hiddify/features/profile/notifier/active_profile_notifier.dart'; import 'package:hiddify/features/profile/widget/profile_tile.dart'; import 'package:hiddify/features/proxy/active/active_proxy_delay_indicator.dart'; import 'package:hiddify/features/proxy/active/active_proxy_footer.dart'; +import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart'; import 'package:hiddify/utils/utils.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:sliver_tools/sliver_tools.dart'; @@ -76,20 +77,17 @@ class HomePage extends HookConsumerWidget { ], ), ), - if (MediaQuery.sizeOf(context).width < 840) - const ActiveProxyFooter(), + if (MediaQuery.sizeOf(context).width < 840) const ActiveProxyFooter(), ], ), ), ], ), AsyncData() => switch (hasAnyProfile) { - AsyncData(value: true) => - const EmptyActiveProfileHomeBody(), + AsyncData(value: true) => const EmptyActiveProfileHomeBody(), _ => const EmptyProfilesHomeBody(), }, - AsyncError(:final error) => - SliverErrorBodyPlaceholder(t.presentShortError(error)), + AsyncError(:final error) => SliverErrorBodyPlaceholder(t.presentShortError(error)), _ => const SliverToBoxAdapter(), }, ], diff --git a/lib/features/proxy/active/active_proxy_delay_indicator.dart b/lib/features/proxy/active/active_proxy_delay_indicator.dart index ff8cde35..db070750 100644 --- a/lib/features/proxy/active/active_proxy_delay_indicator.dart +++ b/lib/features/proxy/active/active_proxy_delay_indicator.dart @@ -1,11 +1,16 @@ +import 'dart:io'; + import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/core/widget/animated_visibility.dart'; import 'package:hiddify/core/widget/shimmer_skeleton.dart'; +import 'package:hiddify/features/connection/model/connection_status.dart'; import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart'; +import 'package:hiddify/features/system_tray/notifier/system_tray_notifier.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:tray_manager/tray_manager.dart'; class ActiveProxyDelayIndicator extends HookConsumerWidget { const ActiveProxyDelayIndicator({super.key}); @@ -24,17 +29,15 @@ class ActiveProxyDelayIndicator extends HookConsumerWidget { case AsyncData(value: final proxy): final delay = proxy.urlTestDelay; final timeout = delay > 65000; + return Center( child: InkWell( onTap: () async { - await ref - .read(activeProxyNotifierProvider.notifier) - .urlTest(proxy.tag); + await ref.read(activeProxyNotifierProvider.notifier).urlTest(proxy.tag); }, borderRadius: BorderRadius.circular(24), child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -42,9 +45,7 @@ class ActiveProxyDelayIndicator extends HookConsumerWidget { const Gap(8), if (delay > 0) Text.rich( - semanticsLabel: timeout - ? t.proxies.delaySemantics.timeout - : t.proxies.delaySemantics.result(delay: delay), + semanticsLabel: timeout ? t.proxies.delaySemantics.timeout : t.proxies.delaySemantics.result(delay: delay), TextSpan( children: [ if (timeout) @@ -58,8 +59,7 @@ class ActiveProxyDelayIndicator extends HookConsumerWidget { else ...[ TextSpan( text: delay.toString(), - style: theme.textTheme.titleMedium - ?.copyWith(fontWeight: FontWeight.bold), + style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), const TextSpan(text: " ms"), ], diff --git a/lib/features/proxy/active/active_proxy_notifier.dart b/lib/features/proxy/active/active_proxy_notifier.dart index 3fa1e635..06536c40 100644 --- a/lib/features/proxy/active/active_proxy_notifier.dart +++ b/lib/features/proxy/active/active_proxy_notifier.dart @@ -78,11 +78,11 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger { } } -@riverpod +@Riverpod(keepAlive: true) class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger { @override Stream build() async* { - ref.disposeDelay(const Duration(seconds: 20)); + // ref.disposeDelay(const Duration(seconds: 20)); final serviceRunning = await ref.watch(serviceRunningProvider.future); if (!serviceRunning) {