Merge branch 'main' of hiddify-github:hiddify/hiddify-next

This commit is contained in:
Hiddify
2023-10-06 09:02:37 +02:00
19 changed files with 103 additions and 40 deletions

View File

@@ -1,7 +1,31 @@
# Changelog # Changelog
## 0.7.2 (2023-10-04) ## 0.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 #### Other

View File

@@ -1 +1 @@
core.version=0.4.1 core.version=0.5.0

View File

@@ -137,7 +137,7 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
}).toList(); }).toList();
}).handleExceptions( }).handleExceptions(
(error, stackTrace) { (error, stackTrace) {
loggy.warning("error watching outbounds", error, stackTrace); loggy.error("error watching outbounds", error, stackTrace);
return CoreServiceFailure.unexpected(error, stackTrace); return CoreServiceFailure.unexpected(error, stackTrace);
}, },
); );

View File

@@ -40,7 +40,7 @@ class ProfilesRepositoryImpl
Stream<Either<ProfileFailure, Profile?>> watchActiveProfile() { Stream<Either<ProfileFailure, Profile?>> watchActiveProfile() {
return profilesDao.watchActiveProfile().handleExceptions( return profilesDao.watchActiveProfile().handleExceptions(
(error, stackTrace) { (error, stackTrace) {
loggy.warning("error watching active profile", error, stackTrace); loggy.error("error watching active profile", error, stackTrace);
return ProfileUnexpectedFailure(error, stackTrace); return ProfileUnexpectedFailure(error, stackTrace);
}, },
); );

View File

@@ -21,6 +21,8 @@ class OutboundGroup with _$OutboundGroup {
@freezed @freezed
class OutboundGroupItem with _$OutboundGroupItem { class OutboundGroupItem with _$OutboundGroupItem {
const OutboundGroupItem._();
@JsonSerializable(fieldRename: FieldRename.kebab) @JsonSerializable(fieldRename: FieldRename.kebab)
const factory OutboundGroupItem({ const factory OutboundGroupItem({
required String tag, required String tag,
@@ -28,6 +30,9 @@ class OutboundGroupItem with _$OutboundGroupItem {
required int urlTestDelay, required int urlTestDelay,
}) = _OutboundGroupItem; }) = _OutboundGroupItem;
String get sanitizedTag =>
tag.replaceFirst(RegExp(r"\§[^]*"), "").trimRight();
factory OutboundGroupItem.fromJson(Map<String, dynamic> json) => factory OutboundGroupItem.fromJson(Map<String, dynamic> json) =>
_$OutboundGroupItemFromJson(json); _$OutboundGroupItemFromJson(json);
} }

View File

@@ -4,6 +4,7 @@ enum ProxyType {
dns("DNS"), dns("DNS"),
socks("SOCKS"), socks("SOCKS"),
http("HTTP"), http("HTTP"),
shadowsocks("Shadowsocks"),
vmess("VMess"), vmess("VMess"),
trojan("Trojan"), trojan("Trojan"),
naive("Naive"), naive("Naive"),

View File

@@ -24,7 +24,8 @@ class AboutPage extends HookConsumerWidget {
(_, next) async { (_, next) async {
if (!context.mounted) return; if (!context.mounted) return;
switch (next) { switch (next) {
case AppUpdateStateAvailable(:final versionInfo): case AppUpdateStateAvailable(:final versionInfo) ||
AppUpdateStateIgnored(:final versionInfo):
return NewVersionDialog( return NewVersionDialog(
appInfo.presentVersion, appInfo.presentVersion,
versionInfo, versionInfo,
@@ -108,15 +109,16 @@ class AboutPage extends HookConsumerWidget {
.check(); .check();
}, },
), ),
ListTile( if (PlatformUtils.isDesktop)
title: Text(t.settings.general.openWorkingDir), ListTile(
trailing: const Icon(Icons.arrow_outward_outlined), title: Text(t.settings.general.openWorkingDir),
onTap: () async { trailing: const Icon(Icons.arrow_outward_outlined),
final path = onTap: () async {
ref.read(filesEditorServiceProvider).workingDir.uri; final path =
await UriUtils.tryLaunch(path); ref.read(filesEditorServiceProvider).workingDir.uri;
}, await UriUtils.tryLaunch(path);
), },
),
], ],
), ),
), ),

View File

@@ -6,6 +6,7 @@ import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/domain/app/app.dart'; import 'package:hiddify/domain/app/app.dart';
import 'package:hiddify/features/common/new_version_dialog.dart'; import 'package:hiddify/features/common/new_version_dialog.dart';
import 'package:hiddify/services/service_providers.dart'; import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/utils/pref_notifier.dart';
import 'package:hiddify/utils/utils.dart'; import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -20,6 +21,8 @@ class AppUpdateState with _$AppUpdateState {
const factory AppUpdateState.error(AppFailure error) = AppUpdateStateError; const factory AppUpdateState.error(AppFailure error) = AppUpdateStateError;
const factory AppUpdateState.available(RemoteVersionInfo versionInfo) = const factory AppUpdateState.available(RemoteVersionInfo versionInfo) =
AppUpdateStateAvailable; AppUpdateStateAvailable;
const factory AppUpdateState.ignored(RemoteVersionInfo versionInfo) =
AppUpdateStateIgnored;
const factory AppUpdateState.notAvailable() = AppUpdateStateNotAvailable; const factory AppUpdateState.notAvailable() = AppUpdateStateNotAvailable;
} }
@@ -31,6 +34,12 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
return const AppUpdateState.initial(); return const AppUpdateState.initial();
} }
Pref<String?, dynamic> get _ignoreReleasePref => Pref(
ref.read(sharedPreferencesProvider),
'ignored_release_version',
null,
);
Future<AppUpdateState> check() async { Future<AppUpdateState> check() async {
loggy.debug("checking for update"); loggy.debug("checking for update");
state = const AppUpdateState.checking(); state = const AppUpdateState.checking();
@@ -54,7 +63,10 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
return state = AppUpdateState.error(err); return state = AppUpdateState.error(err);
}, },
(remote) { (remote) {
if (remote.version.compareTo(currentVersion) > 0) { if (remote.version == _ignoreReleasePref.getValue()) {
loggy.debug("ignored release [${remote.version}]");
return state = AppUpdateStateIgnored(remote);
} else if (remote.version.compareTo(currentVersion) > 0) {
loggy.debug("new version available: $remote"); loggy.debug("new version available: $remote");
return state = AppUpdateState.available(remote); return state = AppUpdateState.available(remote);
} }
@@ -66,6 +78,12 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
).run(); ).run();
} }
Future<void> ignoreRelease(RemoteVersionInfo versionInfo) async {
loggy.debug("ignoring release [${versionInfo.version}]");
await _ignoreReleasePref.update(versionInfo.version);
state = AppUpdateStateIgnored(versionInfo);
}
Future<void> _schedule() async { Future<void> _schedule() async {
loggy.debug("scheduling app update checker"); loggy.debug("scheduling app update checker");
return ref.read(cronServiceProvider).schedule( return ref.read(cronServiceProvider).schedule(

View File

@@ -3,6 +3,7 @@ import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hiddify/core/core_providers.dart'; import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/domain/app/app.dart'; import 'package:hiddify/domain/app/app.dart';
import 'package:hiddify/features/common/app_update_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';
@@ -11,7 +12,6 @@ class NewVersionDialog extends HookConsumerWidget with PresLogger {
NewVersionDialog( NewVersionDialog(
this.currentVersion, this.currentVersion,
this.newVersion, { this.newVersion, {
// super.key,
this.canIgnore = true, this.canIgnore = true,
}) : super(key: _dialogKey); }) : super(key: _dialogKey);
@@ -79,9 +79,11 @@ class NewVersionDialog extends HookConsumerWidget with PresLogger {
actions: [ actions: [
if (canIgnore) if (canIgnore)
TextButton( TextButton(
onPressed: () { onPressed: () async {
// TODO add prefs for ignoring version await ref
context.pop(); .read(appUpdateNotifierProvider.notifier)
.ignoreRelease(newVersion);
if (context.mounted) context.pop();
}, },
child: Text(t.appUpdate.ignoreBtnTxt), child: Text(t.appUpdate.ignoreBtnTxt),
), ),

View File

@@ -73,7 +73,7 @@ class IntroPage extends HookConsumerWidget with PresLogger {
try { try {
await Sentry.close(); await Sentry.close();
} catch (error, stackTrace) { } catch (error, stackTrace) {
loggy.warning( loggy.error(
"could not disable analytics", "could not disable analytics",
error, error,
stackTrace, stackTrace,

View File

@@ -123,7 +123,7 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger {
loggy.debug("testing group: [$groupTag]"); loggy.debug("testing group: [$groupTag]");
if (state case AsyncData()) { if (state case AsyncData()) {
await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((err) { await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((err) {
loggy.warning("error testing group", err); loggy.error("error testing group", err);
throw err; throw err;
}).run(); }).run();
} }

View File

@@ -21,7 +21,7 @@ class ProxyTile extends HookConsumerWidget {
return ListTile( return ListTile(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
title: Text( title: Text(
proxy.tag, proxy.sanitizedTag,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
leading: Padding( leading: Padding(

View File

@@ -26,7 +26,7 @@ Future<List<InstalledPackageInfo>> installedPackagesInfo(
.watch(platformSettingsProvider) .watch(platformSettingsProvider)
.getInstalledPackages() .getInstalledPackages()
.getOrElse((err) { .getOrElse((err) {
_logger.warning("error getting installed packages", err); _logger.error("error getting installed packages", err);
throw err; throw err;
}).run(); }).run();
} }

View File

@@ -191,7 +191,7 @@ class FFISingboxService
_logger.debug("stopping status command client"); _logger.debug("stopping status command client");
final err = _box.stopCommandClient(1).cast<Utf8>().toDartString(); final err = _box.stopCommandClient(1).cast<Utf8>().toDartString();
if (err.isNotEmpty) { if (err.isNotEmpty) {
_logger.warning("error stopping status client"); _logger.error("error stopping status client");
} }
receiver.close(); receiver.close();
_statusStream = null; _statusStream = null;
@@ -200,12 +200,12 @@ class FFISingboxService
(event) { (event) {
if (event case String _) { if (event case String _) {
if (event.startsWith('error:')) { if (event.startsWith('error:')) {
loggy.warning("[status client] error received: $event"); loggy.error("[status client] error received: $event");
throw event.replaceFirst('error:', ""); throw event.replaceFirst('error:', "");
} }
return event; return event;
} }
loggy.warning("[status client] unexpected type, msg: $event"); loggy.error("[status client] unexpected type, msg: $event");
throw "invalid type"; throw "invalid type";
}, },
); );
@@ -215,7 +215,7 @@ class FFISingboxService
.cast<Utf8>() .cast<Utf8>()
.toDartString(); .toDartString();
if (err.isNotEmpty) { if (err.isNotEmpty) {
loggy.warning("error starting status command: $err"); loggy.error("error starting status command: $err");
throw err; throw err;
} }
@@ -231,7 +231,7 @@ class FFISingboxService
_logger.debug("stopping group command client"); _logger.debug("stopping group command client");
final err = _box.stopCommandClient(4).cast<Utf8>().toDartString(); final err = _box.stopCommandClient(4).cast<Utf8>().toDartString();
if (err.isNotEmpty) { if (err.isNotEmpty) {
_logger.warning("error stopping group client"); _logger.error("error stopping group client");
} }
receiver.close(); receiver.close();
_groupsStream = null; _groupsStream = null;
@@ -240,12 +240,12 @@ class FFISingboxService
(event) { (event) {
if (event case String _) { if (event case String _) {
if (event.startsWith('error:')) { if (event.startsWith('error:')) {
loggy.warning("[group client] error received: $event"); loggy.error("[group client] error received: $event");
throw event.replaceFirst('error:', ""); throw event.replaceFirst('error:', "");
} }
return event; return event;
} }
loggy.warning("[group client] unexpected type, msg: $event"); loggy.error("[group client] unexpected type, msg: $event");
throw "invalid type"; throw "invalid type";
}, },
); );
@@ -255,7 +255,7 @@ class FFISingboxService
.cast<Utf8>() .cast<Utf8>()
.toDartString(); .toDartString();
if (err.isNotEmpty) { if (err.isNotEmpty) {
loggy.warning("error starting group command: $err"); loggy.error("error starting group command: $err");
throw err; throw err;
} }

View File

@@ -120,7 +120,7 @@ class MobileSingboxService
if (event case String _) { if (event case String _) {
return event; return event;
} }
loggy.warning("[group client] unexpected type, msg: $event"); loggy.error("[group client] unexpected type, msg: $event");
throw "invalid type"; throw "invalid type";
}, },
); );

View File

@@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:hiddify/domain/clash/clash.dart'; import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/utils/validators.dart'; import 'package:hiddify/utils/validators.dart';
typedef ProfileLink = ({String url, String name}); typedef ProfileLink = ({String url, String name});
@@ -9,7 +9,15 @@ typedef ProfileLink = ({String url, String name});
abstract class LinkParser { abstract class LinkParser {
// protocols schemas // protocols schemas
static const protocols = {'clash', 'clashmeta', 'sing-box', 'hiddify'}; static const protocols = {'clash', 'clashmeta', 'sing-box', 'hiddify'};
static const rawProtocols = {'vmess', 'vless', 'trojan', 'ss', 'tuic'}; static const rawProtocols = {
'ss',
'vmess',
'vless',
'trojan',
'tuic',
'hysteria2',
'ssh',
};
static ProfileLink? parse(String link) { static ProfileLink? parse(String link) {
return simple(link) ?? deep(link); return simple(link) ?? deep(link);
@@ -32,10 +40,13 @@ abstract class LinkParser {
final fragment = final fragment =
uri.hasFragment ? Uri.decodeComponent(uri.fragment) : null; uri.hasFragment ? Uri.decodeComponent(uri.fragment) : null;
final name = switch (uri.scheme) { final name = switch (uri.scheme) {
'ss' => fragment ?? ProxyType.shadowSocks.label, 'ss' => fragment ?? ProxyType.shadowsocks.label,
'vless' => fragment ?? ProxyType.vless.label,
'tuic' => fragment ?? ProxyType.tuic.label,
'vmess' => ProxyType.vmess.label, 'vmess' => ProxyType.vmess.label,
'vless' => fragment ?? ProxyType.vless.label,
'trojan' => fragment ?? ProxyType.trojan.label,
'tuic' => fragment ?? ProxyType.tuic.label,
'hy2' || 'hysteria2' => fragment ?? ProxyType.hysteria.label,
'ssh' => fragment ?? ProxyType.ssh.label,
_ => null, _ => null,
}; };
if (name != null) { if (name != null) {

View File

@@ -7,7 +7,7 @@ class SentryLoggyIntegration extends LoggyPrinter
implements Integration<SentryOptions> { implements Integration<SentryOptions> {
SentryLoggyIntegration({ SentryLoggyIntegration({
LogLevel minBreadcrumbLevel = LogLevel.info, LogLevel minBreadcrumbLevel = LogLevel.info,
LogLevel minEventLevel = LogLevel.warning, LogLevel minEventLevel = LogLevel.error,
}) : _minBreadcrumbLevel = minBreadcrumbLevel, }) : _minBreadcrumbLevel = minBreadcrumbLevel,
_minEventLevel = minEventLevel; _minEventLevel = minEventLevel;

Submodule libcore updated: 75e342b6ba...dced5a30d0

View File

@@ -1,7 +1,7 @@
name: hiddify name: hiddify
description: A Proxy Frontend. description: A Proxy Frontend.
publish_to: "none" publish_to: "none"
version: 0.7.2+702 version: 0.8.0+800
environment: environment:
sdk: ">=3.0.5 <4.0.0" sdk: ">=3.0.5 <4.0.0"