From cdb1f0ae95541641a8b4304ea970d7849235e6cb Mon Sep 17 00:00:00 2001
From: hiddify-com <114227601+hiddify-com@users.noreply.github.com>
Date: Thu, 19 Oct 2023 22:12:05 +0200
Subject: [PATCH 02/15] inlang: update translations
---
assets/translations/strings_en.i18n.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json
index ddf1dbca..e548a8eb 100644
--- a/assets/translations/strings_en.i18n.json
+++ b/assets/translations/strings_en.i18n.json
@@ -46,7 +46,7 @@
"remainingDuration": "${duration} Days Remaining",
"remainingTrafficSemanticLabel": "${consumed} of ${total} traffic consumed.",
"expired": "Expired",
- "noTraffic": "No more traffic"
+ "noTraffic": "Out of Quota"
},
"sortBy": {
"lastUpdate": "Recently updated",
From 7a332023ed736436ee2a9fee6e032100beb0230f Mon Sep 17 00:00:00 2001
From: Hiddify <114227601+hiddify-com@users.noreply.github.com>
Date: Thu, 19 Oct 2023 22:24:20 +0200
Subject: [PATCH 03/15] Update LICENSE.md
---
LICENSE.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/LICENSE.md b/LICENSE.md
index fd7de532..cac21c22 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -2,6 +2,9 @@
# Attribution-NonCommercial-ShareAlike 4.0 International
## Summary:
+- The forks of the app are not allowed to be listed on F-Droid or other app stores under the original name or original design.
+- Any forks should be published open-source under the same license.
+- You need prior consent to publish a fork or use any part of this code in an application published in Apple Store.
- You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
From e75f39a9afb149b1ce3357ad6e3342d043e5890e Mon Sep 17 00:00:00 2001
From: problematicconsumer
Date: Fri, 20 Oct 2023 19:10:40 +0330
Subject: [PATCH 04/15] Add rules
---
lib/data/repository/config_options_store.dart | 29 ++++++++++++++-
lib/domain/singbox/config_options.dart | 8 +++--
lib/domain/singbox/rules.dart | 35 +++++++++++++++++++
.../widgets/advanced_setting_tiles.dart | 2 ++
lib/services/singbox/ffi_singbox_service.dart | 2 +-
libcore | 2 +-
6 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/lib/data/repository/config_options_store.dart b/lib/data/repository/config_options_store.dart
index afc10987..e846d46c 100644
--- a/lib/data/repository/config_options_store.dart
+++ b/lib/data/repository/config_options_store.dart
@@ -1,6 +1,6 @@
// ignore_for_file: avoid_manual_providers_as_generated_provider_dependency
import 'package:hiddify/core/prefs/prefs.dart';
-import 'package:hiddify/domain/singbox/config_options.dart';
+import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/utils/pref_notifier.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -67,6 +67,32 @@ final enableTunStore = PrefNotifier.provider("enable-tun", _default.enableTun);
final setSystemProxyStore =
PrefNotifier.provider("set-system-proxy", _default.setSystemProxy);
+// HACK temporary
+@riverpod
+List rules(RulesRef ref) => switch (ref.watch(regionNotifierProvider)) {
+ Region.ir => [
+ const Rule(
+ id: "id",
+ name: "name",
+ enabled: true,
+ domains: "domain:.ir",
+ ip: "geoip:ir",
+ outbound: RuleOutbound.bypass,
+ ),
+ ],
+ Region.cn => [
+ const Rule(
+ id: "id",
+ name: "name",
+ enabled: true,
+ domains: "domain:.cn,geosite:cn",
+ ip: "geoip:cn",
+ outbound: RuleOutbound.bypass,
+ ),
+ ],
+ _ => [],
+ };
+
@riverpod
ConfigOptions configOptions(ConfigOptionsRef ref) => ConfigOptions(
executeConfigAsIs:
@@ -88,4 +114,5 @@ ConfigOptions configOptions(ConfigOptionsRef ref) => ConfigOptions(
clashApiPort: ref.watch(clashApiPortStore),
enableTun: ref.watch(enableTunStore),
setSystemProxy: ref.watch(setSystemProxyStore),
+ rules: ref.watch(rulesProvider),
);
diff --git a/lib/domain/singbox/config_options.dart b/lib/domain/singbox/config_options.dart
index 1890d8a9..bfae62f4 100644
--- a/lib/domain/singbox/config_options.dart
+++ b/lib/domain/singbox/config_options.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/prefs/prefs.dart';
+import 'package:hiddify/domain/singbox/rules.dart';
import 'package:hiddify/utils/platform_utils.dart';
part 'config_options.freezed.dart';
@@ -19,13 +20,13 @@ class ConfigOptions with _$ConfigOptions {
@Default(IPv6Mode.disable) IPv6Mode ipv6Mode,
@Default("tcp://8.8.8.8") String remoteDnsAddress,
@Default(DomainStrategy.auto) DomainStrategy remoteDnsDomainStrategy,
- @Default("8.8.8.8") String directDnsAddress,
+ @Default("local") String directDnsAddress,
@Default(DomainStrategy.auto) DomainStrategy directDnsDomainStrategy,
@Default(2334) int mixedPort,
@Default(6450) int localDnsPort,
@Default(TunImplementation.mixed) TunImplementation tunImplementation,
@Default(9000) int mtu,
- @Default("https://www.gstatic.com/generate_204") String connectionTestUrl,
+ @Default("http://cp.cloudflare.com/") String connectionTestUrl,
@IntervalConverter()
@Default(Duration(minutes: 10))
Duration urlTestInterval,
@@ -33,6 +34,9 @@ class ConfigOptions with _$ConfigOptions {
@Default(6756) int clashApiPort,
@Default(false) bool enableTun,
@Default(true) bool setSystemProxy,
+ @Default(false) bool bypassLan,
+ @Default(false) bool enableFakeDns,
+ List? rules,
}) = _ConfigOptions;
static ConfigOptions initial = ConfigOptions(
diff --git a/lib/domain/singbox/rules.dart b/lib/domain/singbox/rules.dart
index f30f024f..80db6ee7 100644
--- a/lib/domain/singbox/rules.dart
+++ b/lib/domain/singbox/rules.dart
@@ -1,5 +1,40 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/prefs/locale_prefs.dart';
+part 'rules.freezed.dart';
+part 'rules.g.dart';
+
+@freezed
+class Rule with _$Rule {
+ @JsonSerializable(fieldRename: FieldRename.kebab)
+ const factory Rule({
+ required String id,
+ required String name,
+ @Default(false) bool enabled,
+ String? domains,
+ String? ip,
+ String? port,
+ String? protocol,
+ @Default(RuleNetwork.tcpAndUdp) RuleNetwork network,
+ @Default(RuleOutbound.proxy) RuleOutbound outbound,
+ }) = _Rule;
+
+ factory Rule.fromJson(Map json) => _$RuleFromJson(json);
+}
+
+enum RuleOutbound { proxy, bypass, block }
+
+@JsonEnum(valueField: 'key')
+enum RuleNetwork {
+ tcpAndUdp(""),
+ tcp("tcp"),
+ udp("udp");
+
+ const RuleNetwork(this.key);
+
+ final String? key;
+}
+
enum PerAppProxyMode {
off,
include,
diff --git a/lib/features/settings/widgets/advanced_setting_tiles.dart b/lib/features/settings/widgets/advanced_setting_tiles.dart
index 82b94bdb..64274c21 100644
--- a/lib/features/settings/widgets/advanced_setting_tiles.dart
+++ b/lib/features/settings/widgets/advanced_setting_tiles.dart
@@ -6,6 +6,7 @@ import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/prefs/prefs.dart';
import 'package:hiddify/core/router/routes/routes.dart';
import 'package:hiddify/domain/singbox/singbox.dart';
+import 'package:hiddify/features/common/common.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class AdvancedSettingTiles extends HookConsumerWidget {
@@ -20,6 +21,7 @@ class AdvancedSettingTiles extends HookConsumerWidget {
return Column(
children: [
+ const RegionPrefTile(),
ListTile(
title: Text(t.settings.config.pageTitle),
leading: const Icon(Icons.edit_document),
diff --git a/lib/services/singbox/ffi_singbox_service.dart b/lib/services/singbox/ffi_singbox_service.dart
index e2f75d9c..47dc4e65 100644
--- a/lib/services/singbox/ffi_singbox_service.dart
+++ b/lib/services/singbox/ffi_singbox_service.dart
@@ -8,7 +8,7 @@ import 'package:combine/combine.dart';
import 'package:ffi/ffi.dart';
import 'package:fpdart/fpdart.dart';
import 'package:hiddify/domain/connectivity/connectivity.dart';
-import 'package:hiddify/domain/singbox/config_options.dart';
+import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/gen/singbox_generated_bindings.dart';
import 'package:hiddify/services/singbox/shared.dart';
import 'package:hiddify/services/singbox/singbox_service.dart';
diff --git a/libcore b/libcore
index d410fe1c..0480a5d3 160000
--- a/libcore
+++ b/libcore
@@ -1 +1 @@
-Subproject commit d410fe1c4b0d90f545716737d53e0002be9504cd
+Subproject commit 0480a5d3ec0571b7a0662625679a277219c51d0f
From f89c4c21c1f2b03419d4e1ee4198e96e3f64835f Mon Sep 17 00:00:00 2001
From: lymanjre <125398461+lymanjre@users.noreply.github.com>
Date: Fri, 20 Oct 2023 23:50:45 +0330
Subject: [PATCH 05/15] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index c4dc0dfd..5afee5ef 100644
--- a/README.md
+++ b/README.md
@@ -80,8 +80,8 @@ You can easily contribute to this project by using the following links to improv
Android
-
-
+
+
From 886b860e68daee8ecb32e1239bb231a45267525d Mon Sep 17 00:00:00 2001
From: solokot
Date: Sat, 21 Oct 2023 14:20:07 +0300
Subject: [PATCH 06/15] Russian translation: fix some mistakes
---
assets/translations/strings_ru.i18n.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json
index d798d217..77aa313d 100644
--- a/assets/translations/strings_ru.i18n.json
+++ b/assets/translations/strings_ru.i18n.json
@@ -30,8 +30,8 @@
"stats": {
"traffic": "Скорость",
"trafficTotal": "Трафик",
- "uplink": "Входящий канал",
- "downlink": "Исходящий канал"
+ "uplink": "Исходящий канал",
+ "downlink": "Входящий канал"
}
},
"profile": {
@@ -198,7 +198,7 @@
"pageTitle": "О программе",
"version": "Версия",
"sourceCode": "Исходный код",
- "telegramChannel": "Telegram канал",
+ "telegramChannel": "Telegram-канал",
"checkForUpdate": "Проверка обновления",
"privacyPolicy": "Политика конфиденциальности",
"termsAndConditions": "Условия и положения"
@@ -255,6 +255,6 @@
"play": {
"title": "Hiddify Next (Preview)",
"short_description": "Автовыбор, SSH, VLESS, Vmess, Trojan, Reality, Sing-Box, Clash, Xray, Shadowsocks",
- "full_description": "Основная цель HiddifyNext — предоставить безопасный, удобный и эффективный клиент туннелирования. Он позволяет направлять весь трафик или трафик выбранного приложения на выбранный вами удалённый сервер, используя разрешение VPN–сервиса.\n\nПримечание: мы не предоставляем серверы, пользователи должны обеспечивать конфиденциальность своих действий в Интернете, используя собственный сервер или доверенные серверы.\n \nПоддерживаемые серверы:\n— Обычная ссылка на подписку V2ray/Xray\n— Ссылка на подписку Clash\n— Ссылка на подписку на Sing–Box\n\nВ чём уникальные особенности?\n — Удобство\n — Оптимизация и скорость\n — Автоматический выбор минимальной задержки\n — Отображение информации об использовании\n — Простой импорт ссылок одним щелчком мыши\n — Бесплатно и без рекламы\n — Простое переключение ссылок\n — …и много больше\n\nПоддержка:\n• Все протоколы, поддерживаемые Sing-Box\n• VLESS + xtls reality, vision\n• VMESS\n• Trojan\n• ShoadowSocks\n• Reality\n• V2ray\n• Hystria2\n• TUIC\n• SSH\n• ShadowTLS\n\n\nИсходный код доступен по адресу https://github.com/hiddify/Hiddify-Next.\nЯдро приложения основано на открытом исходном коде Sing–Box.\n\nОписание разрешений:\n— СЛУЖБА VPN: поскольку целью данного приложения является предоставление безопасного, удобного и эффективного клиента туннелирования, это разрешение необходимо, чтобы иметь возможность направлять трафик через туннель на удалённый сервер.\n— ЗАПРОС ВСЕХ ПАКЕТОВ: это разрешение позволяет включать или исключать определённые приложения для туннелирования.\n— ИНФОРМИРОВАНИЕ О ЗАВЕРШЕНИИ ЗАГРУЗКИ: это разрешение можно включить или отключить в настройках приложения, чтобы (де)активировать запуск приложения при загрузке устройства.\n- ПОСТОЯННОЕ УВЕДОМЛЕНИЕ: это разрешение необходимо, поскольку используется приоритетная служба для обеспечения непрерывной работы службы VPN.\n— Приложение не содержит рекламы. Сбор аналитики и данных о сбоях происходят только с явного согласия пользователя при первом использовании приложения."
+ "full_description": "Основная цель HiddifyNext — предоставить безопасный, удобный и эффективный клиент туннелирования. Он позволяет направлять весь трафик или трафик выбранного приложения на выбранный вами удалённый сервер, используя разрешение VPN–сервиса.\n\nПримечание: мы не предоставляем серверы, пользователи должны обеспечивать конфиденциальность своих действий в Интернете, используя собственный сервер или доверенные серверы.\n \nПоддерживаемые серверы:\n— Обычная ссылка на подписку V2ray/Xray\n— Ссылка на подписку Clash\n— Ссылка на подписку на Sing–Box\n\nВ чём уникальные особенности?\n — Удобство\n — Оптимизация и скорость\n — Автоматический выбор минимальной задержки\n — Отображение информации об использовании\n — Простой импорт ссылок одним щелчком мыши\n — Бесплатно и без рекламы\n — Простое переключение ссылок\n — …и много больше\n\nПоддержка:\n• Все протоколы, поддерживаемые Sing-Box\n• VLESS + xtls reality, vision\n• VMESS\n• Trojan\n• ShoadowSocks\n• Reality\n• V2ray\n• Hystria2\n• TUIC\n• SSH\n• ShadowTLS\n\n\nИсходный код доступен по адресу https://github.com/hiddify/Hiddify-Next.\nЯдро приложения основано на открытом исходном коде Sing–Box.\n\nОписание разрешений:\n— СЛУЖБА VPN: поскольку целью данного приложения является предоставление безопасного, удобного и эффективного клиента туннелирования, это разрешение необходимо, чтобы иметь возможность направлять трафик через туннель на удалённый сервер.\n— ЗАПРОС ВСЕХ ПАКЕТОВ: это разрешение позволяет включать или исключать определённые приложения для туннелирования.\n— ИНФОРМИРОВАНИЕ О ЗАВЕРШЕНИИ ЗАГРУЗКИ: это разрешение можно включить или отключить в настройках приложения, чтобы (де)активировать запуск приложения при загрузке устройства.\n— ПОСТОЯННОЕ УВЕДОМЛЕНИЕ: это разрешение необходимо, поскольку используется приоритетная служба для обеспечения непрерывной работы службы VPN.\n— Приложение не содержит рекламы. Сбор аналитики и данных о сбоях происходят только с явного согласия пользователя при первом использовании приложения."
}
}
From a8e75dfb28517487dd634d4fe25f0a27adcb21a4 Mon Sep 17 00:00:00 2001
From: lymanjre <125398461+lymanjre@users.noreply.github.com>
Date: Sat, 21 Oct 2023 17:23:38 +0330
Subject: [PATCH 07/15] Update README.md
---
README.md | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 5afee5ef..e3ea3826 100644
--- a/README.md
+++ b/README.md
@@ -25,14 +25,6 @@
The app is developed using [Flutter](https://flutter.dev) and [Go](https://go.dev). For more information you can read through our [Contribution Guidelines](https://github.com/hiddify/hiddify-next/blob/main/CONTRIBUTING.md) for development.
-## Improve Translations
-You can easily contribute to this project by using the following links to improve the translations:
- - [English](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en)
-- [Persian](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=fa)
-- [Russian](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=ru)
-- [Chinese](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=zh)
-
-
## 🚀 Main features
@@ -108,6 +100,15 @@ You can easily contribute to this project by using the following links to improv
## Installation and tutorials
Please find tutorial information on the [wiki page](https://github.com/hiddify/hiddify-next/wiki).
+## Improve Translations
+You can easily contribute to this project by using the following links to improve the translations:
+ - [English](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en)
+- [Persian](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=fa)
+- [Russian](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=ru)
+- [Chinese](https://inlang.com/editor/github.com/hiddify/hiddify-next?lang=en&lang=zh)
+
+
+
## Acknowledgements
- [Sing-box](https://github.com/SagerNet/sing-box)
From c9d75d73bc11a06c85dc7a45204a945e2a057973 Mon Sep 17 00:00:00 2001
From: lymanjre <125398461+lymanjre@users.noreply.github.com>
Date: Sat, 21 Oct 2023 17:27:00 +0330
Subject: [PATCH 08/15] Update README.md
---
README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index e3ea3826..fca6f2a7 100644
--- a/README.md
+++ b/README.md
@@ -13,11 +13,6 @@
-
-
-
-
-
## What is Hiddify-Next?
@@ -25,6 +20,11 @@
The app is developed using [Flutter](https://flutter.dev) and [Go](https://go.dev). For more information you can read through our [Contribution Guidelines](https://github.com/hiddify/hiddify-next/blob/main/CONTRIBUTING.md) for development.
+
+
+
+
+
## 🚀 Main features
From 1bfc8f0d688d5aafcac0b475780a179f40559d8d Mon Sep 17 00:00:00 2001
From: lymanjre <125398461+lymanjre@users.noreply.github.com>
Date: Sat, 21 Oct 2023 17:49:50 +0330
Subject: [PATCH 09/15] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index fca6f2a7..743713a3 100644
--- a/README.md
+++ b/README.md
@@ -74,7 +74,7 @@ The app is developed using [Flutter](https://flutter.dev) and [Go](https://go.de
-
+
From 7b23bb94eda2b82c03e13982168f351034a536ed Mon Sep 17 00:00:00 2001
From: lymanjre <125398461+lymanjre@users.noreply.github.com>
Date: Sat, 21 Oct 2023 17:53:05 +0330
Subject: [PATCH 10/15] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 743713a3..934a8192 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,7 @@ The app is developed using [Flutter](https://flutter.dev) and [Go](https://go.de
Linux
-
+
From 3e054df31abebb45404295b6a168bb17af367b04 Mon Sep 17 00:00:00 2001
From: problematicconsumer
Date: Sat, 21 Oct 2023 20:11:53 +0330
Subject: [PATCH 11/15] Change theme prefs
---
assets/translations/strings_en.i18n.json | 6 +--
assets/translations/strings_fa.i18n.json | 6 +--
assets/translations/strings_ru.i18n.json | 6 +--
assets/translations/strings_zh.i18n.json | 6 +--
lib/core/app/app_view.dart | 2 +-
lib/core/core_providers.dart | 1 -
lib/core/prefs/app_theme.dart | 30 +++++++++--
lib/core/prefs/theme_prefs.dart | 24 ++-------
.../widgets/general_setting_tiles.dart | 44 ++++++++--------
.../widgets/theme_mode_switch_button.dart | 51 -------------------
10 files changed, 67 insertions(+), 109 deletions(-)
delete mode 100644 lib/features/settings/widgets/theme_mode_switch_button.dart
diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json
index e548a8eb..1b6157d8 100644
--- a/assets/translations/strings_en.i18n.json
+++ b/assets/translations/strings_en.i18n.json
@@ -129,11 +129,11 @@
"themeModes": {
"system": "Follow system theme",
"dark": "Dark mode",
- "light": "Light mode"
+ "light": "Light mode",
+ "black": "Black mode"
},
"enableAnalytics": "Enable Analytics",
"enableAnalyticsMsg": "Give permission to collect analytics and send crash reports to improve the app",
- "trueBlack": "Pure Black",
"autoStart": "Start on Boot",
"silentStart": "Silent Start",
"openWorkingDir": "Open Working Directory",
@@ -257,4 +257,4 @@
"short_description": "Auto, SSH, VLESS, Vmess, Trojan, Reality, Sing-Box, Clash, Xray, Shadowsocks",
"full_description": "The key goal of HiddifyNext is to provide a secure, user-friendly and efficient tunneling client. It enables you to route all traffic or selected app traffic to a remote server of your choose, utilizing VPN-Service permission.\n\nNote: We do not provide any server; users are required to ensure their online activities stay private by using use their own self-hosted server or trusted servers. \n \nWe support servers with:\n- Normal V2ray/Xray Subscription Link\n- Clash Subscription Link\n- Sing-Box Subscription Link\n\nWhat is our unique features?\n - User Friendly\n - Optimized and Fast\n - Automatically select LowestPing \n - Show user usage information\n - Easily import sublink by one click using deeplinking \n - Free and No ADS\n - Easily switch user sublinks\n - more and more\n\nSupport:\n- All Protocols supported by Sing-Box \n- VLESS + xtls reality, vision\n- VMESS\n- Trojan\n- ShoadowSocks\n- Reality\n- V2ray\n- Hystria2\n- TUIC\n- SSH\n- ShadowTLS\n\n\nThe source code exist in https://github.com/hiddify/Hiddify-Next\nThe application core is based on open-source sing-box.\n\nPermission Description:\n- VPN Service: As the goal of this application is to provide a secure, user-friendly and efficient tunneling client, we need this permission to be able to route the traffic via tunnel to the remote server. \n- QUERY ALL PACKAGES: This permission is used to allow users to include or exclude specific applications for tunneling.\n- RECEIVE BOOT COMPLETED: This permission can be enabled or disabled from app settings to activate this application upon device boot.\n- POST NOTIFICATIONS: This permission is essential as we employ a foreground service to ensure the continuous operation of the VPN service.\n- This application is free from advertisements. The analytics and crash data only occurs with the explicit consent of the user in the first use of application."
}
-}
+}
\ No newline at end of file
diff --git a/assets/translations/strings_fa.i18n.json b/assets/translations/strings_fa.i18n.json
index 9fe3206c..d52f50ba 100644
--- a/assets/translations/strings_fa.i18n.json
+++ b/assets/translations/strings_fa.i18n.json
@@ -129,11 +129,11 @@
"themeModes": {
"system": "پیروی از تم دستگاه",
"dark": "تم تیره",
- "light": "تم روشن"
+ "light": "تم روشن",
+ "black": "تم سیاه"
},
"enableAnalytics": "فعالسازی آنالیتیکز",
"enableAnalyticsMsg": "ارائه دسترسی آنالیز و گزارش خطا برای بهبود عملکرد برنامه",
- "trueBlack": "کاملا سیاه",
"autoStart": "اجرا با روشن شدن سیستم",
"silentStart": "اجرای ساکت",
"openWorkingDir": "باز کردن دایرکتوری کاری",
@@ -257,4 +257,4 @@
"short_description": "Auto, SSH, VLESS, Vmess, Trojan, Reality, Sing-Box, Clash, Xray, Shadowsocks",
"full_description": "هدف اصلی HiddifyNext ارائه یک کلاینت تونل زنی ایمن، کاربرپسند و کارآمد است. این به شما امکان می دهد تا با استفاده از مجوز VPN-Service، تمام ترافیک یا ترافیک برنامه انتخابی را به یک سرور راه دور مورد نظر خود هدایت کنید.\n\nتوجه: ما هیچ سروری ارائه نمی دهیم. کاربران موظفند با استفاده از سرورهای خود میزبان یا سرورهای مورد اعتماد، فعالیتهای آنلاین خود را خصوصی نگه دارند.\n \nما از سرورهایی با موارد زیر پشتیبانی می کنیم:\n- لینک اشتراک V2ray/Xray معمولی\n- لینک اشتراک کلش\n- لینک اشتراک Sing-Box\n\nویژگی های منحصر به فرد ما چیست؟\n - کاربر پسند\n - بهینه و سریع\n - به طور خودکار LowestPing را انتخاب کنید\n - نمایش اطلاعات استفاده کاربر\n - به راحتی لینک فرعی را با یک کلیک با استفاده از دیپ لینک وارد کنید\n - رایگان و بدون تبلیغات\n - به راحتی پیوندهای فرعی کاربر را تغییر دهید\n - بیشتر و بیشتر\n\nحمایت کردن:\n- تمام پروتکل های پشتیبانی شده توسط Sing-Box\n- VLESS + xtls \n- VMESS\n- تروجان\n- ShoadowSocks\n- ریالیتی\n- V2ray\n- هیستریا 2\n- TUIC\n- SSH\n- ShadowTLS\n\n\nکد منبع در https://github.com/hiddify/Hiddify-Next وجود دارد\nهسته برنامه بر اساس sing-box منبع باز است.\n\nتوضیحات مجوز:\n- سرویس VPN: از آنجا که هدف این برنامه ارائه یک کلاینت تونل زنی ایمن، کاربر پسند و کارآمد است، ما به این مجوز نیاز داریم تا بتوانیم ترافیک را از طریق تونل به سرور راه دور هدایت کنیم.\n- QUERY ALL PACKAGES: این مجوز برای اجازه دادن به کاربران برای گنجاندن یا حذف برنامه های کاربردی خاص برای تونل زدن استفاده می شود.\n- دریافت بوت تکمیل شد: این مجوز را می توان از تنظیمات برنامه فعال یا غیرفعال کرد تا این برنامه پس از بوت شدن دستگاه فعال شود.\n- اعلان های ارسالی: این مجوز ضروری است زیرا ما از یک سرویس پیش زمینه برای اطمینان از عملکرد مداوم سرویس VPN استفاده می کنیم.\n- این برنامه بدون تبلیغات است. تجزیه و تحلیل و داده های اشکال فقط با رضایت صریح کاربر در اولین استفاده از برنامه اتفاق می افتد."
}
-}
+}
\ No newline at end of file
diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json
index 77aa313d..52782e8c 100644
--- a/assets/translations/strings_ru.i18n.json
+++ b/assets/translations/strings_ru.i18n.json
@@ -129,11 +129,11 @@
"themeModes": {
"system": "Системная тема",
"dark": "Тёмная тема",
- "light": "Светлая тема"
+ "light": "Светлая тема",
+ "black": "Черный режим"
},
"enableAnalytics": "Сбор аналитики",
"enableAnalyticsMsg": "Сбор аналитических данных и отправка отчётов о сбоях для улучшения приложения.",
- "trueBlack": "Чистый чёрный цвет",
"autoStart": "Запуск при загрузке",
"silentStart": "Тихий запуск",
"openWorkingDir": "Открыть рабочую папку",
@@ -257,4 +257,4 @@
"short_description": "Автовыбор, SSH, VLESS, Vmess, Trojan, Reality, Sing-Box, Clash, Xray, Shadowsocks",
"full_description": "Основная цель HiddifyNext — предоставить безопасный, удобный и эффективный клиент туннелирования. Он позволяет направлять весь трафик или трафик выбранного приложения на выбранный вами удалённый сервер, используя разрешение VPN–сервиса.\n\nПримечание: мы не предоставляем серверы, пользователи должны обеспечивать конфиденциальность своих действий в Интернете, используя собственный сервер или доверенные серверы.\n \nПоддерживаемые серверы:\n— Обычная ссылка на подписку V2ray/Xray\n— Ссылка на подписку Clash\n— Ссылка на подписку на Sing–Box\n\nВ чём уникальные особенности?\n — Удобство\n — Оптимизация и скорость\n — Автоматический выбор минимальной задержки\n — Отображение информации об использовании\n — Простой импорт ссылок одним щелчком мыши\n — Бесплатно и без рекламы\n — Простое переключение ссылок\n — …и много больше\n\nПоддержка:\n• Все протоколы, поддерживаемые Sing-Box\n• VLESS + xtls reality, vision\n• VMESS\n• Trojan\n• ShoadowSocks\n• Reality\n• V2ray\n• Hystria2\n• TUIC\n• SSH\n• ShadowTLS\n\n\nИсходный код доступен по адресу https://github.com/hiddify/Hiddify-Next.\nЯдро приложения основано на открытом исходном коде Sing–Box.\n\nОписание разрешений:\n— СЛУЖБА VPN: поскольку целью данного приложения является предоставление безопасного, удобного и эффективного клиента туннелирования, это разрешение необходимо, чтобы иметь возможность направлять трафик через туннель на удалённый сервер.\n— ЗАПРОС ВСЕХ ПАКЕТОВ: это разрешение позволяет включать или исключать определённые приложения для туннелирования.\n— ИНФОРМИРОВАНИЕ О ЗАВЕРШЕНИИ ЗАГРУЗКИ: это разрешение можно включить или отключить в настройках приложения, чтобы (де)активировать запуск приложения при загрузке устройства.\n— ПОСТОЯННОЕ УВЕДОМЛЕНИЕ: это разрешение необходимо, поскольку используется приоритетная служба для обеспечения непрерывной работы службы VPN.\n— Приложение не содержит рекламы. Сбор аналитики и данных о сбоях происходят только с явного согласия пользователя при первом использовании приложения."
}
-}
+}
\ No newline at end of file
diff --git a/assets/translations/strings_zh.i18n.json b/assets/translations/strings_zh.i18n.json
index d7610172..95971a12 100644
--- a/assets/translations/strings_zh.i18n.json
+++ b/assets/translations/strings_zh.i18n.json
@@ -129,11 +129,11 @@
"themeModes": {
"system": "遵循系统主题",
"dark": "深色模式",
- "light": "灯光模式"
+ "light": "灯光模式",
+ "black": "黑色模式"
},
"enableAnalytics": "启用分析",
"enableAnalyticsMsg": "授予收集分析并发送崩溃报告以改进应用程序的权限",
- "trueBlack": "纯黑",
"autoStart": "开机启动",
"silentStart": "无声启动",
"openWorkingDir": "打开工作目录",
@@ -257,4 +257,4 @@
"short_description": "自动,SSH, VLESS, Vmess, Trojan, Reality, Sing-Box, Clash, Xray, Shadowsocks",
"full_description": "HiddifyNext 的主要目标是提供安全、用户友好且高效的隧道客户端。它使您能够利用 VPN 服务权限将所有流量或选定的应用程序流量路由到您选择的远程服务器。\n\n注:我们不提供任何服务器;用户需要使用自己的自托管服务器或受信任的服务器来确保其在线活动的私密性。\n \n我们支持以下类型的服务器:\n- 普通V2ray/Xray订阅链接\n- Clash订阅链接\n- Sing-Box 订阅链接\n\n我们的独特特点是什么?\n\n-用户友好\n-优化和高速\n-自动选择最低延迟\n-显示用户使用信息\n-通过一键深度链接轻松导入子链接\n-免费且无广告\n-轻松切换用户子链接\n-等等\n\n支持:\n- Sing-Box 支持的所有协议\n- VLESS + xtls 现实、愿景\n- VMESS\n- Trojan\n- ShoadowSocks\n- Reality\n-V2ray\n- Hystria2\n- TUIC\n- SSH\n- ShadowTLS\n\n\n源代码位于https://github.com/hiddify/Hiddify-Next\n应用程序核心基于开源的Sing-Box。\n\n权限说明:\n\nVPN服务:由于此应用程序的目标是提供安全、用户友好和高效的隧道客户端,我们需要此权限以能够通过隧道将流量路由到远程服务器。\n查询所有包:此权限用于允许用户包括或排除特定应用程序以进行隧道传输。\n接收启动完成:此权限可以从应用程序设置中启用或禁用,以在设备启动时激活此应用程序。\n发送通知:此权限是必需的,因为我们使用前台服务来确保VPN服务的持续运行。\n此应用程序没有广告。分析和崩溃数据仅在用户在首次使用应用程序时明确同意的情况下发生。"
}
-}
+}
\ No newline at end of file
diff --git a/lib/core/app/app_view.dart b/lib/core/app/app_view.dart
index 69549dc6..35129467 100644
--- a/lib/core/app/app_view.dart
+++ b/lib/core/app/app_view.dart
@@ -33,7 +33,7 @@ class AppView extends HookConsumerWidget with PresLogger {
supportedLocales: AppLocaleUtils.supportedLocales,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
debugShowCheckedModeBanner: false,
- themeMode: theme.mode,
+ themeMode: theme.mode.flutterThemeMode,
theme: theme.light(),
darkTheme: theme.dark(),
title: Constants.appName,
diff --git a/lib/core/core_providers.dart b/lib/core/core_providers.dart
index 9cd598ff..35ce17e4 100644
--- a/lib/core/core_providers.dart
+++ b/lib/core/core_providers.dart
@@ -19,6 +19,5 @@ TranslationsEn translations(TranslationsRef ref) =>
@Riverpod(keepAlive: true)
AppTheme theme(ThemeRef ref) => AppTheme(
ref.watch(themeModeNotifierProvider),
- ref.watch(trueBlackThemeNotifierProvider),
ref.watch(localeNotifierProvider).preferredFontFamily,
);
diff --git a/lib/core/prefs/app_theme.dart b/lib/core/prefs/app_theme.dart
index 8e6c8601..786be4f5 100644
--- a/lib/core/prefs/app_theme.dart
+++ b/lib/core/prefs/app_theme.dart
@@ -1,16 +1,38 @@
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';
+import 'package:hiddify/core/prefs/locale_prefs.dart';
+
+enum AppThemeMode {
+ system,
+ light,
+ dark,
+ black;
+
+ String present(TranslationsEn t) => switch (this) {
+ system => t.settings.general.themeModes.system,
+ light => t.settings.general.themeModes.light,
+ dark => t.settings.general.themeModes.dark,
+ black => t.settings.general.themeModes.black,
+ };
+
+ ThemeMode get flutterThemeMode => switch (this) {
+ system => ThemeMode.system,
+ light => ThemeMode.light,
+ dark => ThemeMode.dark,
+ black => ThemeMode.dark,
+ };
+
+ bool get trueBlack => this == black;
+}
// mostly exact copy of flex color scheme 7.1's fabulous 12 theme
class AppTheme {
AppTheme(
this.mode,
- this.trueBlack,
this.fontFamily,
);
- final ThemeMode mode;
- final bool trueBlack;
+ final AppThemeMode mode;
final String fontFamily;
ThemeData light() {
@@ -81,7 +103,7 @@ class AppTheme {
useMaterial3: true,
swapLegacyOnMaterial3: true,
useMaterial3ErrorColors: true,
- darkIsTrueBlack: trueBlack,
+ darkIsTrueBlack: mode.trueBlack,
surfaceMode: FlexSurfaceMode.highScaffoldLowSurface,
// blendLevel: 1,
subThemesData: const FlexSubThemesData(
diff --git a/lib/core/prefs/theme_prefs.dart b/lib/core/prefs/theme_prefs.dart
index 8a0eca45..a9f21b3b 100644
--- a/lib/core/prefs/theme_prefs.dart
+++ b/lib/core/prefs/theme_prefs.dart
@@ -1,4 +1,4 @@
-import 'package:flutter/material.dart';
+import 'package:hiddify/core/prefs/app_theme.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/utils/pref_notifier.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -10,29 +10,15 @@ class ThemeModeNotifier extends _$ThemeModeNotifier {
late final _pref = Pref(
ref.watch(sharedPreferencesProvider),
"theme_mode",
- ThemeMode.system,
- mapFrom: ThemeMode.values.byName,
+ AppThemeMode.system,
+ mapFrom: AppThemeMode.values.byName,
mapTo: (value) => value.name,
);
@override
- ThemeMode build() => _pref.getValue();
+ AppThemeMode build() => _pref.getValue();
- Future update(ThemeMode value) {
- state = value;
- return _pref.update(value);
- }
-}
-
-@Riverpod(keepAlive: true)
-class TrueBlackThemeNotifier extends _$TrueBlackThemeNotifier {
- late final _pref =
- Pref(ref.watch(sharedPreferencesProvider), "true_black_theme", false);
-
- @override
- bool build() => _pref.getValue();
-
- Future update(bool value) {
+ Future update(AppThemeMode value) {
state = value;
return _pref.update(value);
}
diff --git a/lib/features/settings/widgets/general_setting_tiles.dart b/lib/features/settings/widgets/general_setting_tiles.dart
index f8b76249..a66cb81e 100644
--- a/lib/features/settings/widgets/general_setting_tiles.dart
+++ b/lib/features/settings/widgets/general_setting_tiles.dart
@@ -3,7 +3,6 @@ import 'package:go_router/go_router.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/prefs/prefs.dart';
import 'package:hiddify/features/common/common.dart';
-import 'package:hiddify/features/settings/widgets/theme_mode_switch_button.dart';
import 'package:hiddify/services/auto_start_service.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -44,31 +43,34 @@ class GeneralSettingTiles extends HookConsumerWidget {
),
ListTile(
title: Text(t.settings.general.themeMode),
- subtitle: Text(
- switch (theme.mode) {
- ThemeMode.system => t.settings.general.themeModes.system,
- ThemeMode.light => t.settings.general.themeModes.light,
- ThemeMode.dark => t.settings.general.themeModes.dark,
- },
- ),
- trailing: ThemeModeSwitch(
- themeMode: theme.mode,
- onChanged: ref.read(themeModeNotifierProvider.notifier).update,
- ),
+ subtitle: Text(theme.mode.present(t)),
leading: const Icon(Icons.light_mode),
onTap: () async {
- await ref.read(themeModeNotifierProvider.notifier).update(
- Theme.of(context).brightness == Brightness.light
- ? ThemeMode.dark
- : ThemeMode.light,
+ final selectedThemeMode = await showDialog(
+ context: context,
+ builder: (context) {
+ return SimpleDialog(
+ title: Text(t.settings.general.themeMode),
+ children: AppThemeMode.values
+ .map(
+ (e) => RadioListTile(
+ title: Text(e.present(t)),
+ value: e,
+ groupValue: theme.mode,
+ onChanged: (e) => context.pop(e),
+ ),
+ )
+ .toList(),
);
+ },
+ );
+ if (selectedThemeMode != null) {
+ await ref
+ .read(themeModeNotifierProvider.notifier)
+ .update(selectedThemeMode);
+ }
},
),
- SwitchListTile(
- title: Text(t.settings.general.trueBlack),
- value: theme.trueBlack,
- onChanged: ref.read(trueBlackThemeNotifierProvider.notifier).update,
- ),
if (PlatformUtils.isDesktop) ...[
SwitchListTile(
title: Text(t.settings.general.autoStart),
diff --git a/lib/features/settings/widgets/theme_mode_switch_button.dart b/lib/features/settings/widgets/theme_mode_switch_button.dart
deleted file mode 100644
index 580a633b..00000000
--- a/lib/features/settings/widgets/theme_mode_switch_button.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:hiddify/core/core_providers.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
-
-class ThemeModeSwitch extends HookConsumerWidget {
- const ThemeModeSwitch({
- super.key,
- required this.themeMode,
- required this.onChanged,
- });
- final ThemeMode themeMode;
- final ValueChanged onChanged;
-
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final t = ref.watch(translationsProvider);
-
- final List isSelected = [
- themeMode == ThemeMode.light,
- themeMode == ThemeMode.system,
- themeMode == ThemeMode.dark,
- ];
-
- return ToggleButtons(
- isSelected: isSelected,
- onPressed: (int newIndex) {
- if (newIndex == 0) {
- onChanged(ThemeMode.light);
- } else if (newIndex == 1) {
- onChanged(ThemeMode.system);
- } else {
- onChanged(ThemeMode.dark);
- }
- },
- children: [
- Icon(
- Icons.wb_sunny,
- semanticLabel: t.settings.general.themeModes.light,
- ),
- Icon(
- Icons.phone_iphone,
- semanticLabel: t.settings.general.themeModes.system,
- ),
- Icon(
- Icons.bedtime,
- semanticLabel: t.settings.general.themeModes.dark,
- ),
- ],
- );
- }
-}
From 87cf7348259b1bb6e3fa54224eee3dbe05f5de01 Mon Sep 17 00:00:00 2001
From: problematicconsumer
Date: Sat, 21 Oct 2023 20:28:37 +0330
Subject: [PATCH 12/15] Add russia region
---
assets/translations/strings_en.i18n.json | 1 +
assets/translations/strings_fa.i18n.json | 1 +
assets/translations/strings_ru.i18n.json | 1 +
assets/translations/strings_zh.i18n.json | 1 +
lib/data/repository/config_options_store.dart | 10 ++++++++++
lib/domain/singbox/rules.dart | 2 ++
6 files changed, 16 insertions(+)
diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json
index 1b6157d8..186966de 100644
--- a/assets/translations/strings_en.i18n.json
+++ b/assets/translations/strings_en.i18n.json
@@ -123,6 +123,7 @@
"regions": {
"ir": "Iran (ir)",
"cn": "China (cn)",
+ "ru": "Russia (ru)",
"other": "Other"
},
"themeMode": "Theme Mode",
diff --git a/assets/translations/strings_fa.i18n.json b/assets/translations/strings_fa.i18n.json
index d52f50ba..520be7ad 100644
--- a/assets/translations/strings_fa.i18n.json
+++ b/assets/translations/strings_fa.i18n.json
@@ -123,6 +123,7 @@
"regions": {
"ir": "ایران (ir)",
"cn": "چین (cn)",
+ "ru": "روسیه (ru)",
"other": "سایر"
},
"themeMode": "تم مود",
diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json
index 52782e8c..7bcda9c2 100644
--- a/assets/translations/strings_ru.i18n.json
+++ b/assets/translations/strings_ru.i18n.json
@@ -123,6 +123,7 @@
"regions": {
"ir": "Иран (ir)",
"cn": "Китай (cn)",
+ "ru": "Россия (ru)",
"other": "Другой"
},
"themeMode": "Оформление",
diff --git a/assets/translations/strings_zh.i18n.json b/assets/translations/strings_zh.i18n.json
index 95971a12..168f9da1 100644
--- a/assets/translations/strings_zh.i18n.json
+++ b/assets/translations/strings_zh.i18n.json
@@ -123,6 +123,7 @@
"regions": {
"ir": "伊朗 (ir)",
"cn": "中国 (cn)",
+ "ru": "俄罗斯 (ru)",
"other": "其他"
},
"themeMode": "主题模式",
diff --git a/lib/data/repository/config_options_store.dart b/lib/data/repository/config_options_store.dart
index e846d46c..fb7b9432 100644
--- a/lib/data/repository/config_options_store.dart
+++ b/lib/data/repository/config_options_store.dart
@@ -90,6 +90,16 @@ List rules(RulesRef ref) => switch (ref.watch(regionNotifierProvider)) {
outbound: RuleOutbound.bypass,
),
],
+ Region.ru => [
+ const Rule(
+ id: "id",
+ name: "name",
+ enabled: true,
+ domains: "domain:.ru",
+ ip: "geoip:ru",
+ outbound: RuleOutbound.bypass,
+ ),
+ ],
_ => [],
};
diff --git a/lib/domain/singbox/rules.dart b/lib/domain/singbox/rules.dart
index 80db6ee7..96c53c9e 100644
--- a/lib/domain/singbox/rules.dart
+++ b/lib/domain/singbox/rules.dart
@@ -61,11 +61,13 @@ enum PerAppProxyMode {
enum Region {
ir,
cn,
+ ru,
other;
String present(TranslationsEn t) => switch (this) {
ir => t.settings.general.regions.ir,
cn => t.settings.general.regions.cn,
+ ru => t.settings.general.regions.ru,
other => t.settings.general.regions.other,
};
}
From 88c7f8d2c7efd8ee413d6a294e29dd5ee1473a94 Mon Sep 17 00:00:00 2001
From: problematicconsumer
Date: Sat, 21 Oct 2023 21:49:26 +0330
Subject: [PATCH 13/15] Change changelog workflow
---
CHANGELOG.md | 22 +
Makefile | 3 +-
changelog.md | 1265 --------------------------------------------------
pubspec.yaml | 5 +
4 files changed, 28 insertions(+), 1267 deletions(-)
create mode 100644 CHANGELOG.md
delete mode 100644 changelog.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..fab9bd51
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## Unreleased
+
+### Added
+
+- Basic region based routing rules
+- Russian region
+
+### Changed
+
+- Theme preferences
+
+### Fixed
+
+- Localization mistakes in Russian from [solokot](https://github.com/solokot)
+- Localization mistakes in Russian from [Elshad Guseynov](https://github.com/lifeindarkside)
diff --git a/Makefile b/Makefile
index 445cc656..29f3f1f0 100644
--- a/Makefile
+++ b/Makefile
@@ -116,9 +116,8 @@ release: # Create a new tag for release.
echo "version: $${VERSION_STR}+$${BUILD_NUMBER}" && \
sed -i "s/version: .*/version: $${VERSION_STR}\+$${BUILD_NUMBER}/g" pubspec.yaml && \
git tag $${TAG} > /dev/null && \
- gitchangelog > changelog.md || { git tag -d $${TAG}; echo "Please run pip install git gitchangelog pystache mustache markdown"; exit 2; } && \
git tag -d $${TAG} > /dev/null && \
- git add pubspec.yaml changelog.md && \
+ git add pubspec.yaml CHANGELOG.md && \
make sync_translate && \
git add assets/translations/* && \
git commit -m "release: version $${TAG}" && \
diff --git a/changelog.md b/changelog.md
deleted file mode 100644
index 1ead2d96..00000000
--- a/changelog.md
+++ /dev/null
@@ -1,1265 +0,0 @@
-# Changelog
-
-
-## 0.9.2 (2023-10-15)
-
-#### Other
-
-* Fix ndk setup.
-
-* Fix android arm bug.
-
-
-
-## v0.9.1 (2023-10-15)
-
-#### Other
-
-* Update README_cn.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README_ru.md.
-
-* Update README_cn.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Delete docs/file.
-
-* Google play badge.
-
-* Delete docs/google-play-badge1.png.
-
-* Upload google play badge.
-
-* Create file.
-
-* Delete docs/google-play-badge.png.
-
-* Fix ci.
-
-* Change ndk setup.
-
-* Update dependencies.
-
-* Update README_ru.md.
-
-* Update README_cn.md.
-
-* Update README_ru.md.
-
-* Update README_ru.md.
-
-* Change desktop error handling.
-
-* Fix android bugs.
-
-* Update README.md.
-
-* Update README_cn.md.
-
-* Update README_ru.md.
-
-* Update README_ru.md.
-
-* Update README_cn.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Delete Russian_Flag.png.
-
-* Add Russian flag.
-
-* Delete docs/file.
-
-* Create README_ru.md.
-
-* Delete REAMME_ru.md.
-
-* Create REAMME_ru.md.
-
-* Update README_cn.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_cn.md.
-
-* Update README_cn.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update file.
-
-* Uplaod a badge for google play.
-
-* Delete google-play-badge.png.
-
-* Add files via upload.
-
-* Create file.
-
-* Delete docs/google-play-badge.png.
-
-* Delete google-play-badge.png.
-
-* Add files via upload.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Create Chinese README_cn.md.
-
-
-
-## v0.8.12 (2023-10-13)
-
-#### Fix
-
-* Typo.
-
-* Bug.
-
-* Release names.
-
-#### Other
-
-* Update readme.
-
-* Update core.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Merge pull request #56 from solokot/main.
- _Improvement of Russian translation_
-
-* Improvement of Russian translation.
- _Basically a replacement for machine automatic translation_
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Fix bugs.
-
-* Change android signing.
-
-* Update README.md.
-
-* Update readme.
-
-* Update contribution guide.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update release_message.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update release template.
-
-
-
-## v0.8.11 (2023-10-08)
-
-#### Changes
-
-* Remove auto release message.
-
-
-
-## v0.8.10 (2023-10-08)
-
-#### Fix
-
-* Release changelog.
-
-
-
-## v0.8.9 (2023-10-08)
-
-#### Fix
-
-* Missing libs.
-
-
-
-## v0.8.8 (2023-10-08)
-
-#### Fix
-
-* Release bug.
-
-
-
-## v0.8.7 (2023-10-08)
-
-#### Fix
-
-* Release message.
-
-
-
-## v0.8.6 (2023-10-08)
-
-#### Fix
-
-* Windows build.
-
-* Build issue.
-
-#### Other
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-* Update release_message.md.
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-* Update release_message.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Delete docs/note.
-
-* Add files via upload.
-
-* Create note.
-
-* Update contribute.md.
-
-* Update README.md.
-
-* Delete assets/images/google-play-badge.png.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update release_message.md.
-
-* Update release_message.md.
-
-* Update release_message.md.
-
-* Fix build.
-
-
-
-## v0.8.5 (2023-10-07)
-
-#### Fix
-
-* Bug.
-
-
-
-## v0.8.4 (2023-10-07)
-
-#### Fix
-
-* Translate.
-
-
-
-## v0.8.3 (2023-10-07)
-
-#### Other
-
-* Add release message and help.
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-* Fix bugs.
-
-* Update release_message.md.
-
-* Update release_message.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update release_message.md.
-
-* Update release_message.md.
-
-* Create release_message.md.
-
-* Add google play badge to assets.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Create contribute.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README_fa.md.
-
-* Add feature request template.
-
-* Fix issue template.
-
-* Add issue template.
-
-
-
-## v0.8.2 (2023-10-07)
-
-#### Fix
-
-* Hysteria2 and some links.
-
-#### Other
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Create README_fa.md.
-
-* Update README.md.
-
-* Update README.md.
-
-* Update README.md.
- _Add some features to the readme_
-
-* Add debug export to clipboard.
-
-
-
-## v0.8.1 (2023-10-06)
-
-#### New
-
-* Add chinese lang.
-
-#### Fix
-
-* Chinese translation.
-
-#### Other
-
-* Update core 0.5.1.
-
-* Fix floating number sub info header.
-
-* Add russian.
-
-* Add google play descriptions.
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-
-
-## v0.8.0 (2023-10-05)
-
-#### New
-
-* Add russian lang.
-
-#### Other
-
-* Add proxy tag sanitization.
-
-* Fix bugs.
-
-* Add ignore app update version.
-
-* Add new protocols to link parser.
-
-* Auto update translations on release.
-
-* Update translation.
-
-* Remove param in ru translation.
-
-
-
-## v0.7.2 (2023-10-04)
-
-#### Other
-
-* Fix bugs.
-
-
-
-## v0.7.1 (2023-10-03)
-
-#### Other
-
-* Fix log and analytics bugs.
-
-
-
-## v0.7.0 (2023-10-03)
-
-#### New
-
-* Add support of some exception panel with zero usage.
-
-#### Other
-
-* Fix translation bug.
-
-* Improve error handling and presentation.
-
-* Add retry for network ops.
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-* Add local profile.
-
-* Add auto translator.
-
-* Add auto translate.
-
-
-
-## v0.6.0 (2023-09-30)
-
-#### Other
-
-* Fix minor bugs.
-
-* Add scheduled profile update.
-
-* Update dependencies.
-
-* Refactor profile details page.
-
-
-
-## v0.5.11 (2023-09-22)
-
-#### Other
-
-* Fix android bundle abi.
-
-* Bump core version.
-
-
-
-## v0.5.10 (2023-09-22)
-
-#### Other
-
-* Fix minor bugs.
-
-* Fix profile update bug.
-
-
-
-## v0.5.9 (2023-09-22)
-
-#### Other
-
-* Add build number.
-
-
-
-## v0.5.8 (2023-09-22)
-
-#### New
-
-* Add crashlytics.
-
-* Add support for base64 sublink for header from content.
-
-* Add profile headers from comments in response! good for hosting in github and show information.
-
-* Automated version release.
-
-* Send release versions only to play market add pre-release version.
-
-#### Changes
-
-* Change invalid dns 235.5.5.5 to 8.8.8.8.
-
-#### Fix
-
-* Improve routing accessibility and logs.
-
-* Minor bugs.
-
-* Prefs persistence.
-
-* Crashlytics.
-
-* App update url.
-
-* Small profiles.
-
-* Makefile vars.
-
-* Adaptive icon.
-
-* Pre-release.
-
-* Typo in adaptive icon.
-
-* If .dev is exist in the version do not show update needed.
-
-* Keep the link as it is. fix the issue with &
-
-* Dependency issue.
-
-* Remove extra print.
-
-* Bug in get headers from body.
-
-* Bug ini ci to google play.
-
-* Tag version issue.
-
-* Ci bug.
-
-* Remove comments.
-
-* Bug.
-
-#### Other
-
-* Fix ci.
-
-* Fix false-positive error reports.
-
-* Change build setup.
-
-* Fix minor bugs.
-
-* Refactor app update.
-
-* Fix sentry dart plugin upload.
-
-* Fix ci debug symbols upload.
-
-* Add sentry provider observer.
-
-* Ci: add sentry debug info upload.
-
-* Update dependencies and general fixes.
-
-* Chore: bump agp version.
-
-* Ci: fix env.
-
-* Ci: add dsn env.
-
-* Feat: add region and terms to intro.
-
-* Update ci.yml.
-
-* Build: add sentry dsn.
-
-* Feat: add intro screen.
-
-* Feat: add sentry.
-
-* Ci: bump macos version.
-
-* Feat: update profile when adding preexisting url.
-
-* Publish draft even with error.
-
-* Update version of core.
-
-* Merge branch 'main' of hiddify-github:hiddify/hiddify-next.
-
-* Add firebase.
-
-* Update translation.
-
-* Refactor: version presentation.
-
-* Perf: improve header parser.
-
-* Feat: remove check for updates in market releases.
-
-* Better manage the market release.
-
-* Update.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Improve accessability.
-
-* Fix per-app proxy selection.
-
-* Add android per-app proxy.
-
-* Add basic flavors.
-
-* Update Makefile.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update Makefile.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update README.md.
-
-* Add accessability semantics.
-
-* Add support for fragment in the url.
-
-
-
-## v0.1.0 (2023-09-11)
-
-#### New
-
-* Add signing to android.
-
-* Add android universal build also.
-
-* Add change in network entitlements.
-
-* Change logo icon to next.
-
-* Add cache for speed up build process.
-
-* Add windows portable version.
-
-* Add libclash.
-
-* Add as draft release.
-
-* Make better ci and building applications.
-
-#### Changes
-
-* Change windows logo.
-
-* Change macos build to flutter_distributor.
-
-* Remove x86 builds since flutter does not support.
-
-* Add x64 to the name.
-
-* Update makefile.
-
-#### Fix
-
-* Space bugs in some panels.
-
-* Aab.
-
-* Aab build.
-
-* Universal sign.
-
-* KeystoreProperties.
-
-* Name issue.
-
-* Revert package name change.
-
-* Name.
-
-* Geosite download.
-
-* Windows portable bug.
-
-* Change name bug.
-
-* Setup exe files.
-
-* Libclash.so.
-
-* Linux AppImage.
-
-* Error.
-
-* Category in linux.
-
-* Add fuse for linux.
-
-* Icon.
-
-* Linux logo.
-
-* Android.
-
-* Makefile error.
-
-#### Other
-
-* Release v0.1.0.
-
-* Fix ci build.
-
-* Update ci.
-
-* Add core version.
-
-* Fix barrel file.
-
-* Change proxies lifecycle.
-
-* Add service restart.
-
-* Remove notification service.
-
-* Change android notification permission.
-
-* Add android service restart.
-
-* Change mark new profile active.
-
-* Handle unlimited.
-
-* Update upload download link stats.
-
-* Update Translations.
-
-* Remove // TODO add content disposition parsing.
-
-* Add content-disposition for profile title.
-
-* Update README.md.
-
-* Add hysteria2.
-
-* Fix android build connection.
-
-* Add android connection shortcut.
-
-* Add desktop autostart.
-
-* Add android boot receiver.
-
-* Add android proxy service.
-
-* Add android battery optimizations settings.
-
-* Change sharedpreferences to unify with android.
-
-* Add vclibs.
-
-* Update dependencies.
-
-* Add submodule.
-
-* Fix translation code gen.
-
-* Change prefs.
-
-* Change default config options.
-
-* Remove string casing.
-
-* Update ci.yml.
-
-* Remove caching.
-
-* Change core prefs to use code generation.
-
-* Fix custom lint.
-
-* Fix general issues.
-
-* Remove vclibs.
-
-* Update README.md.
-
-* Fix blank screen.
-
-* Add proxies sort.
-
-* Refactor preferences.
-
-* Update dependencies.
-
-* Add more config options to settings.
-
-* Add tun implementation option.
-
-* Add android power manager.
-
-* Add android quick tile.
-
-* Fix macos dependencies.
-
-* Fix mac build.
-
-* Fix build.
-
-* Change system tray icon.
-
-* Fix riverpod code generation.
-
-* Remove unnecessary config options.
-
-* Add accessability semantics.
-
-* Update dependencies.
-
-* Add config options.
-
-* Add pref utilities.
-
-* Add stats overview.
-
-* Update Translations.
-
-* Fix android outbounds view.
-
-* Remove unnecessary options.
-
-* Change proxies flow.
-
-* Add android command client support.
-
-* Update README.md.
-
-* Add status command receiver.
-
-* Add hiddify deeplink.
-
-* Add macos deeplink support.
-
-* Add singbox deeplink.
-
-* Change error prompts.
-
-* Fix url parser.
-
-* Remove unnecessary prefs.
-
-* Update dependencies.
-
-* Make AppImage zipped for preserving permission in linux.
-
-* Add user agent.
-
-* Fix uri launch.
-
-* Update ci flutter version.
-
-* Fix macos silent start.
-
-* Change proxies page.
-
-* Fix desktop connection error msg.
-
-* Add button tooltips.
-
-* Fix logging.
-
-* Create dependabot.yml.
-
-* Create CODE_OF_CONDUCT.md.
-
-* Fix aab.
-
-* Add aab file.
-
-* Change windows-portable name to HiddifyNext-portable.
-
-* Add debug mode.
-
-* Add misc settings ui.
-
-* Remote unnecessary logs.
-
-* Add misc preferences.
-
-* Add directory options.
-
-* Fix linux build.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Fix android builds.
-
-* Fix android splash screen.
-
-* Update icons.
-
-* Fix windows executable build.
-
-* Remove unnecessary build steps.
-
-* Remove build number from appbar.
-
-* Update readme.
-
-* Change desktop directories.
-
-* Remove desktop notifications.
-
-* Force same version code for all platforms.
-
-* Add more logs.
-
-* Add log timestamp.
-
-* Update icons.
-
-* Remove drawer branding.
-
-* Add download section in readme.
-
-* Fix name of universal apk.
-
-* Fix order.
-
-* Update readme.
-
-* Update logging.
-
-* Update geo assets url.
-
-* Change linux directories.
-
-* Update icon.
-
-* Update icon.
-
-* Update logo for all platforms.
-
-* Revert name in macos.
-
-* Temporary disable app sandbox.
-
-* Change name.
-
-* Update Release.entitlements to fix binding issue.
-
-* Merge pull request #5 from evstegneych/main.
- _add macos option_
-
-* Add macos option.
-
-* Update ci flutter version.
-
-* Update kotlin version.
-
-* Update other dependencies.
-
-* Update dependencies.
-
-* Update flutter version.
-
-* Update LICENSE.md.
-
-* Add build option for ios but not tested.
-
-* Return: build for all.
-
-* Fix build for macos.
-
-* Fix ci.
-
-* Migrate to singbox.
-
-* Fix routing.
-
-* Fix connection button text casing.
-
-* Add update checking.
-
-* Add separate page for clash overrides.
-
-* Add version number to appbar.
-
-* Add more icons.
-
-* Add sort limited profiles last.
-
-* Fix profile sort icon.
-
-* Fix profile traffic ratio.
-
-* Add profiles sort option.
-
-* Refactor profile addition flow.
-
-* Add extra profile metadata.
-
-* Fix linux deep link service.
-
-* Refactor profile tile.
-
-* Add locale based font.
-
-* Fix linux startup.
-
-* Update dependencies.
-
-* Add about page.
-
-* Fix linux notifications.
-
-* Build all.
-
-* Hard coding.
-
-* Add png.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update Makefile.
-
-* Update ci.yml.
-
-* Update Makefile.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Update Makefile.
-
-* Update ci.yml.
-
-* Update Makefile.
-
-* Fix makefile.
-
-* Fix actions.
-
-* Fix actions.
-
-* Fix actions.
-
-* Update build setup.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Create LICENSE.md.
-
-* Add core submodule.
-
-* Remove core libs.
-
-* Update Makefile.
-
-* Update Makefile.
-
-* Remove c install.
-
-* Update make.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Add Persian font.
-
-* Update dependencies.
-
-* Update to libclash.
-
-* Add cache.
-
-* Add: new action.
-
-* Add write permission.
-
-* Fix.
-
-* Modify.
-
-* Fix.
-
-* Update.
-
-* Fix android build.
-
-* Fix code gen bug.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Fix CI.
-
-* Fix CI.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Fix CI.
-
-* Update ci.yml.
-
-* Update ci.yml.
-
-* Add CI.
-
-* Add silent start for desktop.
-
-* Update readme.
-
-* Add headless mode to desktop.
-
-* Update dependencies.
-
-* Add distribution setup for windows.
-
-* Add Farsi(fa) language.
-
-* Merge branch 'main' of https://github.com/hiddify/hiddify-next.
-
-* Initial commit.
-
-* Initial.
-
-
-
diff --git a/pubspec.yaml b/pubspec.yaml
index 5016d264..e460c9b9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -170,3 +170,8 @@ sentry:
upload_sources: true
log_level: info
ignore_missing: true
+
+cider:
+ link_template:
+ tag: https://github.com/hiddify/hiddify-next/releases/tag/%tag%
+ diff: https://github.com/hiddify/hiddify-next/compare/%from%...%to%
From 49901695254666e2e2460597586d2da6b71fb8be Mon Sep 17 00:00:00 2001
From: problematicconsumer
Date: Mon, 23 Oct 2023 19:39:29 +0330
Subject: [PATCH 14/15] Change logging
---
CHANGELOG.md | 8 +-
.../kotlin/com/hiddify/hiddify/LogHandler.kt | 9 +-
.../com/hiddify/hiddify/MainActivity.kt | 28 +--
.../com/hiddify/hiddify/MethodHandler.kt | 60 +++--
assets/translations/strings_en.i18n.json | 6 +-
assets/translations/strings_fa.i18n.json | 6 +-
assets/translations/strings_ru.i18n.json | 6 +-
assets/translations/strings_zh.i18n.json | 6 +-
lib/data/repository/core_facade_impl.dart | 19 +-
lib/domain/singbox/box_log.dart | 62 +++++
lib/domain/singbox/config_options.dart | 8 +-
lib/domain/singbox/singbox.dart | 1 +
lib/domain/singbox/singbox_facade.dart | 4 +-
lib/features/common/common_controllers.dart | 5 -
lib/features/logs/notifier/logs_notifier.dart | 149 +++++++----
lib/features/logs/notifier/logs_state.dart | 6 +-
lib/features/logs/view/logs_page.dart | 233 ++++++++++--------
.../settings/view/config_options_page.dart | 6 +-
lib/services/singbox/ffi_singbox_service.dart | 59 +++--
.../singbox/mobile_singbox_service.dart | 17 +-
lib/services/singbox/singbox_service.dart | 4 +-
libcore | 2 +-
pubspec.lock | 2 +-
pubspec.yaml | 19 +-
24 files changed, 450 insertions(+), 275 deletions(-)
create mode 100644 lib/domain/singbox/box_log.dart
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fab9bd51..8d56e98b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,22 +1,20 @@
# Changelog
-
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
-
### Added
-
- Basic region based routing rules
- Russian region
+- Logs flow control
### Changed
-
- Theme preferences
+- Logs page
### Fixed
-
- Localization mistakes in Russian from [solokot](https://github.com/solokot)
- Localization mistakes in Russian from [Elshad Guseynov](https://github.com/lifeindarkside)
+- Logs filtering
diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/LogHandler.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/LogHandler.kt
index d1ae2e46..3fc91860 100644
--- a/android/app/src/main/kotlin/com/hiddify/hiddify/LogHandler.kt
+++ b/android/app/src/main/kotlin/com/hiddify/hiddify/LogHandler.kt
@@ -1,5 +1,6 @@
package com.hiddify.hiddify
+import android.util.Log
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.EventChannel
@@ -18,13 +19,15 @@ class LogHandler : FlutterPlugin {
logsChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
- MainActivity.instance.serviceLogs.observeForever {
- if (it == null) return@observeForever
- events?.success(it)
+ val activity = MainActivity.instance
+ events?.success(activity.logList)
+ activity.logCallback = {
+ events?.success(activity.logList)
}
}
override fun onCancel(arguments: Any?) {
+ MainActivity.instance.logCallback = null
}
})
}
diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt
index f2253b36..f605144c 100644
--- a/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt
@@ -39,7 +39,6 @@ class MainActivity : FlutterFragmentActivity(), ServiceConnection.Callback {
var logCallback: ((Boolean) -> Unit)? = null
val serviceStatus = MutableLiveData(Status.Stopped)
val serviceAlerts = MutableLiveData(null)
- val serviceLogs = MutableLiveData(null)
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
@@ -102,37 +101,18 @@ class MainActivity : FlutterFragmentActivity(), ServiceConnection.Callback {
serviceAlerts.postValue(ServiceEvent(Status.Stopped, type, message))
}
- private var paused = false
- override fun onPause() {
- super.onPause()
-
- paused = true
- }
-
- override fun onResume() {
- super.onResume()
-
- paused = false
- logCallback?.invoke(true)
- }
-
override fun onServiceWriteLog(message: String?) {
- if (paused) {
- if (logList.size > 300) {
- logList.removeFirst()
- }
+ if (logList.size > 300) {
+ logList.removeFirst()
}
logList.addLast(message)
- if (!paused) {
- logCallback?.invoke(false)
- serviceLogs.postValue(message)
- }
+ logCallback?.invoke(false)
}
override fun onServiceResetLogs(messages: MutableList) {
logList.clear()
logList.addAll(messages)
- if (!paused) logCallback?.invoke(true)
+ logCallback?.invoke(true)
}
override fun onDestroy() {
diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/MethodHandler.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/MethodHandler.kt
index 944c52f7..36e01b2a 100644
--- a/android/app/src/main/kotlin/com/hiddify/hiddify/MethodHandler.kt
+++ b/android/app/src/main/kotlin/com/hiddify/hiddify/MethodHandler.kt
@@ -29,6 +29,7 @@ class MethodHandler(private val scope: CoroutineScope) : FlutterPlugin,
Restart("restart"),
SelectOutbound("select_outbound"),
UrlTest("url_test"),
+ ClearLogs("clear_logs"),
}
}
@@ -63,38 +64,44 @@ class MethodHandler(private val scope: CoroutineScope) : FlutterPlugin,
}
Trigger.ChangeConfigOptions.method -> {
- result.runCatching {
- val args = call.arguments as String
- Settings.configOptions = args
- success(true)
+ scope.launch {
+ result.runCatching {
+ val args = call.arguments as String
+ Settings.configOptions = args
+ success(true)
+ }
}
}
Trigger.Start.method -> {
- result.runCatching {
- val args = call.arguments as Map<*, *>
- Settings.activeConfigPath = args["path"] as String? ?: ""
- val mainActivity = MainActivity.instance
- val started = mainActivity.serviceStatus.value == Status.Started
- if (started) {
- Log.w(TAG, "service is already running")
- return success(true)
+ scope.launch {
+ result.runCatching {
+ val args = call.arguments as Map<*, *>
+ Settings.activeConfigPath = args["path"] as String? ?: ""
+ val mainActivity = MainActivity.instance
+ val started = mainActivity.serviceStatus.value == Status.Started
+ if (started) {
+ Log.w(TAG, "service is already running")
+ return@launch success(true)
+ }
+ mainActivity.startService()
+ success(true)
}
- mainActivity.startService()
- success(true)
}
}
Trigger.Stop.method -> {
- result.runCatching {
- val mainActivity = MainActivity.instance
- val started = mainActivity.serviceStatus.value == Status.Started
- if (!started) {
- Log.w(TAG, "service is not running")
- return success(true)
+ scope.launch {
+ result.runCatching {
+ val mainActivity = MainActivity.instance
+ val started = mainActivity.serviceStatus.value == Status.Started
+ if (!started) {
+ Log.w(TAG, "service is not running")
+ return@launch success(true)
+ }
+ BoxService.stop()
+ success(true)
}
- BoxService.stop()
- success(true)
}
}
@@ -151,6 +158,15 @@ class MethodHandler(private val scope: CoroutineScope) : FlutterPlugin,
}
}
+ Trigger.ClearLogs.method -> {
+ scope.launch {
+ result.runCatching {
+ MainActivity.instance.onServiceResetLogs(mutableListOf())
+ success(true)
+ }
+ }
+ }
+
else -> result.notImplemented()
}
}
diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json
index 186966de..8a5e9056 100644
--- a/assets/translations/strings_en.i18n.json
+++ b/assets/translations/strings_en.i18n.json
@@ -106,11 +106,13 @@
},
"logs": {
"pageTitle": "Logs",
- "clearLogsButtonText": "Clear Logs",
"filterHint": "Filter",
"allLevelsFilter": "All",
"shareCoreLogs": "Share Core Logs",
- "shareAppLogs": "Share App logs"
+ "shareAppLogs": "Share App logs",
+ "pauseTooltip": "Pause",
+ "resumeTooltip": "Resume",
+ "clearTooltip": "Clear"
},
"settings": {
"pageTitle": "Settings",
diff --git a/assets/translations/strings_fa.i18n.json b/assets/translations/strings_fa.i18n.json
index 520be7ad..cebc0b0a 100644
--- a/assets/translations/strings_fa.i18n.json
+++ b/assets/translations/strings_fa.i18n.json
@@ -106,11 +106,13 @@
},
"logs": {
"pageTitle": "لاگها",
- "clearLogsButtonText": "پاکسازی",
"filterHint": "فیلتر",
"allLevelsFilter": "همه",
"shareCoreLogs": "اشتراکگذاری لاگ هسته",
- "shareAppLogs": "اشتراکگذاری لاگ برنامه"
+ "shareAppLogs": "اشتراکگذاری لاگ برنامه",
+ "pauseTooltip": "مکث",
+ "resumeTooltip": "از سرگیری",
+ "clearTooltip": "پاکسازی"
},
"settings": {
"pageTitle": "تنظیمات",
diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json
index 7bcda9c2..12259231 100644
--- a/assets/translations/strings_ru.i18n.json
+++ b/assets/translations/strings_ru.i18n.json
@@ -106,11 +106,13 @@
},
"logs": {
"pageTitle": "Журналы",
- "clearLogsButtonText": "Очистить журналы",
"filterHint": "Фильтр",
"allLevelsFilter": "Все",
"shareCoreLogs": "Поделиться журналами ядра",
- "shareAppLogs": "Поделиться журналами приложения"
+ "shareAppLogs": "Поделиться журналами приложения",
+ "pauseTooltip": "Пауза",
+ "resumeTooltip": "Резюме",
+ "clearTooltip": "Прозрачный"
},
"settings": {
"pageTitle": "Настройки",
diff --git a/assets/translations/strings_zh.i18n.json b/assets/translations/strings_zh.i18n.json
index 168f9da1..a1ec9bd4 100644
--- a/assets/translations/strings_zh.i18n.json
+++ b/assets/translations/strings_zh.i18n.json
@@ -106,11 +106,13 @@
},
"logs": {
"pageTitle": "日志",
- "clearLogsButtonText": "清除日志",
"filterHint": "筛选",
"allLevelsFilter": "全部",
"shareCoreLogs": "分享核心日志",
- "shareAppLogs": "分享日志"
+ "shareAppLogs": "分享日志",
+ "pauseTooltip": "暂停",
+ "resumeTooltip": "恢复",
+ "clearTooltip": "清除"
},
"settings": {
"pageTitle": "设置",
diff --git a/lib/data/repository/core_facade_impl.dart b/lib/data/repository/core_facade_impl.dart
index b344809f..fa89af87 100644
--- a/lib/data/repository/core_facade_impl.dart
+++ b/lib/data/repository/core_facade_impl.dart
@@ -179,10 +179,21 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
}
@override
- Stream> watchLogs() {
- return singbox
- .watchLogs(filesEditor.coreLogsPath)
- .handleExceptions(CoreServiceFailure.unexpected);
+ Stream>> watchLogs() {
+ return singbox.watchLogs(filesEditor.coreLogsPath).handleExceptions(
+ (error, stackTrace) {
+ loggy.warning("error watching logs", error, stackTrace);
+ return CoreServiceFailure.unexpected(error, stackTrace);
+ },
+ );
+ }
+
+ @override
+ TaskEither clearLogs() {
+ return exceptionHandler(
+ () => singbox.clearLogs().mapLeft(CoreServiceFailure.other).run(),
+ CoreServiceFailure.unexpected,
+ );
}
@override
diff --git a/lib/domain/singbox/box_log.dart b/lib/domain/singbox/box_log.dart
new file mode 100644
index 00000000..84ee25c1
--- /dev/null
+++ b/lib/domain/singbox/box_log.dart
@@ -0,0 +1,62 @@
+import 'package:dartx/dartx.dart';
+import 'package:flutter/material.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:tint/tint.dart';
+
+part 'box_log.freezed.dart';
+
+enum LogLevel {
+ trace,
+ debug,
+ info,
+ warn,
+ error,
+ fatal,
+ panic;
+
+ static List get choices => values.takeFirst(4);
+
+ Color? get color => switch (this) {
+ trace => Colors.lightBlueAccent,
+ debug => Colors.grey,
+ info => Colors.lightGreen,
+ warn => Colors.orange,
+ error => Colors.redAccent,
+ fatal => Colors.red,
+ panic => Colors.red,
+ };
+}
+
+@freezed
+class BoxLog with _$BoxLog {
+ const factory BoxLog({
+ LogLevel? level,
+ DateTime? time,
+ required String message,
+ }) = _BoxLog;
+
+ factory BoxLog.parse(String log) {
+ log = log.strip();
+ DateTime? time;
+ if (log.length > 25) {
+ time = DateTime.tryParse(log.substring(6, 25));
+ }
+ if (time != null) {
+ log = log.substring(26);
+ }
+ final level = LogLevel.values.firstOrNullWhere(
+ (e) {
+ if (log.startsWith(e.name.toUpperCase())) {
+ log = log.removePrefix(e.name.toUpperCase());
+ return true;
+ }
+ return false;
+ },
+ );
+ return BoxLog(
+ level: level,
+ time: time,
+ message: log.trim(),
+ );
+ }
+}
diff --git a/lib/domain/singbox/config_options.dart b/lib/domain/singbox/config_options.dart
index bfae62f4..4206a840 100644
--- a/lib/domain/singbox/config_options.dart
+++ b/lib/domain/singbox/config_options.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/prefs/prefs.dart';
+import 'package:hiddify/domain/singbox/box_log.dart';
import 'package:hiddify/domain/singbox/rules.dart';
import 'package:hiddify/utils/platform_utils.dart';
@@ -53,13 +54,6 @@ class ConfigOptions with _$ConfigOptions {
_$ConfigOptionsFromJson(json);
}
-enum LogLevel {
- warn,
- info,
- debug,
- trace,
-}
-
@JsonEnum(valueField: 'key')
enum IPv6Mode {
disable("ipv4_only"),
diff --git a/lib/domain/singbox/singbox.dart b/lib/domain/singbox/singbox.dart
index 39bb5774..ea665c8f 100644
--- a/lib/domain/singbox/singbox.dart
+++ b/lib/domain/singbox/singbox.dart
@@ -1,3 +1,4 @@
+export 'box_log.dart';
export 'config_options.dart';
export 'core_status.dart';
export 'outbounds.dart';
diff --git a/lib/domain/singbox/singbox_facade.dart b/lib/domain/singbox/singbox_facade.dart
index bcd40f80..6a8d9541 100644
--- a/lib/domain/singbox/singbox_facade.dart
+++ b/lib/domain/singbox/singbox_facade.dart
@@ -37,5 +37,7 @@ abstract interface class SingboxFacade {
Stream> watchCoreStatus();
- Stream> watchLogs();
+ Stream>> watchLogs();
+
+ TaskEither clearLogs();
}
diff --git a/lib/features/common/common_controllers.dart b/lib/features/common/common_controllers.dart
index 8cfbb413..db6e7e2c 100644
--- a/lib/features/common/common_controllers.dart
+++ b/lib/features/common/common_controllers.dart
@@ -2,7 +2,6 @@ import 'package:hiddify/core/prefs/general_prefs.dart';
import 'package:hiddify/features/common/app_update_notifier.dart';
import 'package:hiddify/features/common/connectivity/connectivity_controller.dart';
import 'package:hiddify/features/common/window/window_controller.dart';
-import 'package:hiddify/features/logs/notifier/notifier.dart';
import 'package:hiddify/features/profiles/notifier/notifier.dart';
import 'package:hiddify/features/system_tray/controller/system_tray_controller.dart';
import 'package:hiddify/services/service_providers.dart';
@@ -24,10 +23,6 @@ void commonControllers(CommonControllersRef ref) {
},
fireImmediately: true,
);
- ref.listen(
- logsNotifierProvider,
- (previous, next) {},
- );
ref.listen(
connectivityControllerProvider,
(previous, next) {},
diff --git a/lib/features/logs/notifier/logs_notifier.dart b/lib/features/logs/notifier/logs_notifier.dart
index 6c7cfd43..b089840d 100644
--- a/lib/features/logs/notifier/logs_notifier.dart
+++ b/lib/features/logs/notifier/logs_notifier.dart
@@ -1,66 +1,133 @@
import 'dart:async';
-import 'package:dartx/dartx.dart';
import 'package:hiddify/data/data_providers.dart';
-import 'package:hiddify/domain/clash/clash.dart';
+import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/features/logs/notifier/logs_state.dart';
+import 'package:hiddify/utils/riverpod_utils.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:rxdart/rxdart.dart';
part 'logs_notifier.g.dart';
-// TODO: rewrite
-@Riverpod(keepAlive: true)
+@riverpod
class LogsNotifier extends _$LogsNotifier with AppLogger {
- static const maxLength = 1000;
-
@override
- Stream build() {
- state = const AsyncData(LogsState());
- return ref.read(coreFacadeProvider).watchLogs().asyncMap(
- (event) async {
- _logs = [
- event.getOrElse((l) => throw l),
- ..._logs.takeFirst(maxLength - 1),
- ];
- return switch (state) {
- // ignore: unused_result
- AsyncData(:final value) => value.copyWith(logs: await _computeLogs()),
- _ => LogsState(logs: await _computeLogs()),
- };
+ LogsState build() {
+ ref.disposeDelay(const Duration(seconds: 20));
+ state = const LogsState();
+ ref.onDispose(
+ () {
+ loggy.debug("disposing");
+ _listener?.cancel();
+ _listener = null;
},
);
+ ref.onCancel(
+ () {
+ if (_listener?.isPaused != true) {
+ loggy.debug("pausing");
+ _listener?.pause();
+ }
+ },
+ );
+ ref.onResume(
+ () {
+ if (!state.paused && (_listener?.isPaused ?? false)) {
+ loggy.debug("resuming");
+ _listener?.resume();
+ }
+ },
+ );
+
+ _addListeners();
+ return const LogsState();
}
- var _logs = [];
+ StreamSubscription? _listener;
+
+ Future _addListeners() async {
+ loggy.debug("adding listeners");
+ await _listener?.cancel();
+ _listener = ref
+ .read(coreFacadeProvider)
+ .watchLogs()
+ .throttle(
+ (_) => Stream.value(_listener?.isPaused ?? false),
+ leading: false,
+ trailing: true,
+ )
+ .throttleTime(
+ const Duration(milliseconds: 250),
+ leading: false,
+ trailing: true,
+ )
+ .asyncMap(
+ (event) async {
+ await event.fold(
+ (f) {
+ _logs = [];
+ state = state.copyWith(logs: AsyncError(f, StackTrace.current));
+ },
+ (a) async {
+ _logs = a.reversed;
+ state = state.copyWith(logs: AsyncData(await _computeLogs()));
+ },
+ );
+ },
+ ).listen((event) {});
+ }
+
+ Iterable _logs = [];
final _debouncer = CallbackDebouncer(const Duration(milliseconds: 200));
LogLevel? _levelFilter;
String _filter = "";
- Future> _computeLogs() async {
- if (_levelFilter == null && _filter.isEmpty) return _logs;
- return _logs.where((e) {
- return _filter.isEmpty || e.contains(_filter);
+ Future> _computeLogs() async {
+ final logs = _logs.map(BoxLog.parse);
+ if (_levelFilter == null && _filter.isEmpty) return logs.toList();
+ return logs.where((e) {
+ return (_filter.isEmpty || e.message.contains(_filter)) &&
+ (_levelFilter == null ||
+ e.level == null ||
+ e.level!.index >= _levelFilter!.index);
}).toList();
}
- void clear() {
- if (state case AsyncData(:final value)) {
- state = AsyncData(value.copyWith(logs: [])).copyWithPrevious(state);
- }
+ void pause() {
+ loggy.debug("pausing");
+ _listener?.pause();
+ state = state.copyWith(paused: true);
+ }
+
+ void resume() {
+ loggy.debug("resuming");
+ _listener?.resume();
+ state = state.copyWith(paused: false);
+ }
+
+ Future clear() async {
+ loggy.debug("clearing");
+ await ref.read(coreFacadeProvider).clearLogs().match(
+ (l) {
+ loggy.warning("error clearing logs", l);
+ },
+ (_) {
+ _logs = [];
+ state = state.copyWith(logs: const AsyncData([]));
+ },
+ ).run();
}
void filterMessage(String? filter) {
_filter = filter ?? '';
_debouncer(
() async {
- if (state case AsyncData(:final value)) {
- state = AsyncData(
- value.copyWith(
- filter: _filter,
- logs: await _computeLogs(),
- ),
- ).copyWithPrevious(state);
+ if (state.logs case AsyncData()) {
+ state = state.copyWith(
+ filter: _filter,
+ logs: AsyncData(await _computeLogs()),
+ );
}
},
);
@@ -68,13 +135,11 @@ class LogsNotifier extends _$LogsNotifier with AppLogger {
Future filterLevel(LogLevel? level) async {
_levelFilter = level;
- if (state case AsyncData(:final value)) {
- state = AsyncData(
- value.copyWith(
- levelFilter: _levelFilter,
- logs: await _computeLogs(),
- ),
- ).copyWithPrevious(state);
+ if (state.logs case AsyncData()) {
+ state = state.copyWith(
+ levelFilter: _levelFilter,
+ logs: AsyncData(await _computeLogs()),
+ );
}
}
}
diff --git a/lib/features/logs/notifier/logs_state.dart b/lib/features/logs/notifier/logs_state.dart
index ba34a075..4318870a 100644
--- a/lib/features/logs/notifier/logs_state.dart
+++ b/lib/features/logs/notifier/logs_state.dart
@@ -1,5 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart';
-import 'package:hiddify/domain/clash/clash.dart';
+import 'package:hiddify/domain/singbox/singbox.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'logs_state.freezed.dart';
@@ -8,7 +9,8 @@ class LogsState with _$LogsState {
const LogsState._();
const factory LogsState({
- @Default([]) List logs,
+ @Default(AsyncLoading()) AsyncValue> logs,
+ @Default(false) bool paused,
@Default("") String filter,
LogLevel? levelFilter,
}) = _LogsState;
diff --git a/lib/features/logs/view/logs_page.dart b/lib/features/logs/view/logs_page.dart
index af2e7954..7c5d093c 100644
--- a/lib/features/logs/view/logs_page.dart
+++ b/lib/features/logs/view/logs_page.dart
@@ -1,31 +1,31 @@
-import 'package:dartx/dartx.dart';
+
import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fpdart/fpdart.dart';
import 'package:gap/gap.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/prefs/prefs.dart';
-import 'package:hiddify/domain/clash/clash.dart';
import 'package:hiddify/domain/failures.dart';
-import 'package:hiddify/features/common/common.dart';
+import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/features/logs/notifier/notifier.dart';
import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:tint/tint.dart';
-
class LogsPage extends HookConsumerWidget with PresLogger {
const LogsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final t = ref.watch(translationsProvider);
- final asyncState = ref.watch(logsNotifierProvider);
+ final state = ref.watch(logsNotifierProvider);
final notifier = ref.watch(logsNotifierProvider.notifier);
final debug = ref.watch(debugModeNotifierProvider);
final filesEditor = ref.watch(filesEditorServiceProvider);
+ final filterController = useTextEditingController(text: state.filter);
+
final List popupButtons = debug || PlatformUtils.isDesktop
? [
PopupMenuItem(
@@ -49,115 +49,146 @@ class LogsPage extends HookConsumerWidget with PresLogger {
]
: [];
- switch (asyncState) {
- case AsyncData(value: final state):
- return Scaffold(
- appBar: AppBar(
- // TODO: fix height
- toolbarHeight: 90,
- title: Text(t.logs.pageTitle),
- actions: [
- if (popupButtons.isNotEmpty)
- PopupMenuButton(
- itemBuilder: (context) {
- return popupButtons;
- },
- ),
- ],
- bottom: PreferredSize(
- preferredSize: const Size.fromHeight(36),
- child: Padding(
- padding:
- const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
- child: Row(
- children: [
- Flexible(
- child: TextFormField(
- onChanged: notifier.filterMessage,
- decoration: InputDecoration(
- isDense: true,
- hintText: t.logs.filterHint,
- ),
- ),
+ return Scaffold(
+ appBar: AppBar(
+ // TODO: fix height
+ toolbarHeight: 90,
+ title: Text(t.logs.pageTitle),
+ actions: [
+ if (state.paused)
+ IconButton(
+ onPressed: notifier.resume,
+ icon: const Icon(Icons.play_arrow),
+ tooltip: t.logs.resumeTooltip,
+ )
+ else
+ IconButton(
+ onPressed: notifier.pause,
+ icon: const Icon(Icons.pause),
+ tooltip: t.logs.pauseTooltip,
+ ),
+ IconButton(
+ onPressed: notifier.clear,
+ icon: const Icon(Icons.clear_all),
+ tooltip: t.logs.clearTooltip,
+ ),
+ if (popupButtons.isNotEmpty)
+ PopupMenuButton(
+ itemBuilder: (context) {
+ return popupButtons;
+ },
+ ),
+ ],
+ bottom: PreferredSize(
+ preferredSize: const Size.fromHeight(36),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ child: Row(
+ children: [
+ Flexible(
+ child: TextFormField(
+ controller: filterController,
+ onChanged: notifier.filterMessage,
+ decoration: InputDecoration(
+ isDense: true,
+ hintText: t.logs.filterHint,
),
- const Gap(16),
- DropdownButton