diff --git a/lib/core/model/constants.dart b/lib/core/model/constants.dart index eee07964..0697ca10 100644 --- a/lib/core/model/constants.dart +++ b/lib/core/model/constants.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:hiddify/utils/utils.dart'; abstract class Constants { static const appName = "Hiddify"; @@ -56,21 +57,49 @@ abstract class IntroConst { static const termsAndConditionsKey = 'terms-and-conditions'; static const githubKey = 'github'; static const licenseKey = 'license'; - static const url = {IntroConst.termsAndConditionsKey: Constants.termsAndConditionsUrl, IntroConst.githubKey: Constants.githubUrl, IntroConst.licenseKey: Constants.licenseUrl}; + static const url = { + IntroConst.termsAndConditionsKey: Constants.termsAndConditionsUrl, + IntroConst.githubKey: Constants.githubUrl, + IntroConst.licenseKey: Constants.licenseUrl, + }; } abstract class WarpConst { - static const warpAccountId = 'warp-account-id'; - static const warpAccessToken = "warp-access-token"; static const warpConsentGiven = "warp-consent-given"; static const warpTermsOfServiceKey = 'warp-terms-of-service'; static const warpPrivacyPolicyKey = 'warp-privacy-policy'; - static const url = {WarpConst.warpTermsOfServiceKey: Constants.cfWarpTermsOfService, WarpConst.warpPrivacyPolicyKey: Constants.cfWarpPrivacyPolicy}; + static const url = { + WarpConst.warpTermsOfServiceKey: Constants.cfWarpTermsOfService, + WarpConst.warpPrivacyPolicyKey: Constants.cfWarpPrivacyPolicy, + }; } abstract class KeyboardConst { - static final allArrows = {LogicalKeyboardKey.arrowUp, LogicalKeyboardKey.arrowDown, LogicalKeyboardKey.arrowLeft, LogicalKeyboardKey.arrowRight}; + static final allArrows = { + LogicalKeyboardKey.arrowUp, + LogicalKeyboardKey.arrowDown, + LogicalKeyboardKey.arrowLeft, + LogicalKeyboardKey.arrowRight, + }; static final horizontalArrows = {LogicalKeyboardKey.arrowLeft, LogicalKeyboardKey.arrowRight}; static final verticalArrows = {LogicalKeyboardKey.arrowUp, LogicalKeyboardKey.arrowDown}; static final select = {LogicalKeyboardKey.select, LogicalKeyboardKey.enter, LogicalKeyboardKey.tab}; } + +abstract class ChainConst { + static IconData iconByPlatform() { + if (PlatformUtils.isAndroid) return Icons.phone_android; + if (PlatformUtils.isIOS) return Icons.phone_iphone; + if (PlatformUtils.isWeb) return Icons.web; + // Desktops + return Icons.laptop; + } + + static Color finalIpColor(ThemeData theme) => + theme.brightness == Brightness.dark ? const Color(0xFF99AD7A) : const Color.fromARGB(255, 87, 136, 13); + static const warpColor = Color(0xFFF6821F); + static const psiphonColor = Color(0xFFD52027); + static const profileColor = Color(0xFF3282B8); + + static const finalIpDuration = Duration(milliseconds: 500); +} diff --git a/lib/hiddifycore/hiddify_core_service.dart b/lib/hiddifycore/hiddify_core_service.dart index e48068bd..b32533d3 100644 --- a/lib/hiddifycore/hiddify_core_service.dart +++ b/lib/hiddifycore/hiddify_core_service.dart @@ -407,30 +407,30 @@ class HiddifyCoreService with InfraLogger { }); } - TaskEither generateWarpConfig({ - required String licenseKey, - required String previousAccountId, - required String previousAccessToken, - }) { - return TaskEither(() async { - loggy.debug("generating warp config"); - final warpConfig = await core.fgClient.generateWarpConfig( - GenerateWarpConfigRequest( - licenseKey: licenseKey, - accountId: previousAccountId, - accessToken: previousAccessToken, - ), - ); - // if (warpConfig.code != ResponseCode.OK) return left("${warpConfig.code} ${warpConfig.message}"); - final WarpResponse warp = ( - log: warpConfig.log, - accountId: warpConfig.account.accountId, - accessToken: warpConfig.account.accessToken, - wireguardConfig: jsonEncode(warpConfig.config.toProto3Json()), - ); - return right(warp); - }); - } + // TaskEither generateWarpConfig({ + // required String licenseKey, + // required String previousAccountId, + // required String previousAccessToken, + // }) { + // return TaskEither(() async { + // loggy.debug("generating warp config"); + // final warpConfig = await core.fgClient.generateWarpConfig( + // GenerateWarpConfigRequest( + // licenseKey: licenseKey, + // accountId: previousAccountId, + // accessToken: previousAccessToken, + // ), + // ); + // // if (warpConfig.code != ResponseCode.OK) return left("${warpConfig.code} ${warpConfig.message}"); + // final WarpResponse warp = ( + // log: warpConfig.log, + // accountId: warpConfig.account.accountId, + // accessToken: warpConfig.account.accessToken, + // wireguardConfig: jsonEncode(warpConfig.config.toProto3Json()), + // ); + // return right(warp); + // }); + // } Stream watchStatus() async* { await startListeningStatus("bg", core.bgClient); diff --git a/lib/singbox/model/singbox_config_enum.dart b/lib/singbox/model/singbox_config_enum.dart index 7b4f09ac..bd964f8c 100644 --- a/lib/singbox/model/singbox_config_enum.dart +++ b/lib/singbox/model/singbox_config_enum.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/localization/translations.dart'; +import 'package:hiddify/core/model/constants.dart'; import 'package:hiddify/utils/platform_utils.dart'; @JsonEnum(valueField: 'key') @@ -119,24 +121,147 @@ enum TunImplementation { }; } -enum MuxProtocol { h2mux, smux, yamux } - @JsonEnum(valueField: 'key') -enum WarpDetourMode { - proxyOverWarp("proxy_over_warp"), - warpOverProxy("warp_over_proxy"); +enum ChainStatus { + off('off'), + extraSecurity('extra_security'), + unblocker('unblocker'); - const WarpDetourMode(this.key); + const ChainStatus(this.key); final String key; - String present(TranslationsEn t) => switch (this) { - proxyOverWarp => t.pages.settings.warp.detourModes.proxyOverWarp, - warpOverProxy => t.pages.settings.warp.detourModes.warpOverProxy, + bool isOff() => this == off; + bool isUnblocker() => this == unblocker; + bool isExtraSecurity() => this == extraSecurity; +} + +@JsonEnum(valueField: 'key') +enum ChainMode { + psiphon('psiphon'), + warp('warp'), + profile('profile'); + + const ChainMode(this.key); + + final String key; + + String present(Translations t) => switch (this) { + psiphon => t.common.psiphon, + warp => t.common.warp, + profile => t.common.profile, }; - String presentExplain(TranslationsEn t) => switch (this) { - proxyOverWarp => t.pages.settings.warp.detourModes.proxyOverWarpExplain, - warpOverProxy => t.pages.settings.warp.detourModes.warpOverProxyExplain, + IconData icon() => switch (this) { + psiphon => Icons.local_parking, + warp => Icons.cloud, + profile => Icons.link, + }; + + Color color() => switch (this) { + psiphon => ChainConst.psiphonColor, + warp => ChainConst.warpColor, + profile => ChainConst.profileColor, + }; + + bool isPsiphon() => this == psiphon; + bool isWarp() => this == warp; + bool isProfile() => this == profile; +} + +@JsonEnum(valueField: 'key') +enum PsiphonRegion { + auto('AUTO'), + austria('AT'), + australia('AU'), + belgium('BE'), + bulgaria('BG'), + canada('CA'), + switzerland('CH'), + czechRepublic('CZ'), + germany('DE'), + denmark('DK'), + estonia('EE'), + spain('ES'), + finland('FI'), + france('FR'), + unitedKingdom('GB'), + croatia('HR'), + hungary('HU'), + ireland('IE'), + india('IN'), + italy('IT'), + japan('JP'), + latvia('LV'), + netherlands('NL'), + norway('NO'), + poland('PL'), + portugal('PT'), + romania('RO'), + serbia('RS'), + sweden('SE'), + singapore('SG'), + slovakia('SK'), + unitedStates('US'); + + const PsiphonRegion(this.key); + + final String key; + + String present(Translations t) => switch (this) { + auto => t.pages.settings.chain.psiphon.regions.auto, + austria => t.pages.settings.chain.psiphon.regions.at, + australia => t.pages.settings.chain.psiphon.regions.au, + belgium => t.pages.settings.chain.psiphon.regions.be, + bulgaria => t.pages.settings.chain.psiphon.regions.bg, + canada => t.pages.settings.chain.psiphon.regions.ca, + switzerland => t.pages.settings.chain.psiphon.regions.ch, + czechRepublic => t.pages.settings.chain.psiphon.regions.cz, + germany => t.pages.settings.chain.psiphon.regions.de, + denmark => t.pages.settings.chain.psiphon.regions.dk, + estonia => t.pages.settings.chain.psiphon.regions.ee, + spain => t.pages.settings.chain.psiphon.regions.es, + finland => t.pages.settings.chain.psiphon.regions.fi, + france => t.pages.settings.chain.psiphon.regions.fr, + unitedKingdom => t.pages.settings.chain.psiphon.regions.gb, + croatia => t.pages.settings.chain.psiphon.regions.hr, + hungary => t.pages.settings.chain.psiphon.regions.hu, + ireland => t.pages.settings.chain.psiphon.regions.ie, + india => t.pages.settings.chain.psiphon.regions.kIn, + italy => t.pages.settings.chain.psiphon.regions.it, + japan => t.pages.settings.chain.psiphon.regions.jp, + latvia => t.pages.settings.chain.psiphon.regions.lv, + netherlands => t.pages.settings.chain.psiphon.regions.nl, + norway => t.pages.settings.chain.psiphon.regions.no, + poland => t.pages.settings.chain.psiphon.regions.pl, + portugal => t.pages.settings.chain.psiphon.regions.pt, + romania => t.pages.settings.chain.psiphon.regions.ro, + serbia => t.pages.settings.chain.psiphon.regions.rs, + sweden => t.pages.settings.chain.psiphon.regions.se, + singapore => t.pages.settings.chain.psiphon.regions.sg, + slovakia => t.pages.settings.chain.psiphon.regions.sk, + unitedStates => t.pages.settings.chain.psiphon.regions.us, }; } + +enum MuxProtocol { h2mux, smux, yamux } + +// @JsonEnum(valueField: 'key') +// enum WarpDetourMode { +// proxyOverWarp("proxy_over_warp"), +// warpOverProxy("warp_over_proxy"); + +// const WarpDetourMode(this.key); + +// final String key; + +// String present(TranslationsEn t) => switch (this) { +// proxyOverWarp => t.pages.settings.warp.detourModes.proxyOverWarp, +// warpOverProxy => t.pages.settings.warp.detourModes.warpOverProxy, +// }; + +// String presentExplain(TranslationsEn t) => switch (this) { +// proxyOverWarp => t.pages.settings.warp.detourModes.proxyOverWarpExplain, +// warpOverProxy => t.pages.settings.warp.detourModes.warpOverProxyExplain, +// }; +// } diff --git a/lib/singbox/model/singbox_config_option.dart b/lib/singbox/model/singbox_config_option.dart index ba3abc2d..29524d80 100644 --- a/lib/singbox/model/singbox_config_option.dart +++ b/lib/singbox/model/singbox_config_option.dart @@ -50,8 +50,9 @@ class SingboxConfigOption with _$SingboxConfigOption { required List rules, // required SingboxMuxOption mux, required SingboxTlsTricks tlsTricks, - required SingboxWarpOption warp, - required SingboxWarpOption warp2, + required ChainStatus chainStatus, + required SingboxExtraSecurityOption extraSecurity, + required SingboxUnblockerOption unblocker, }) = _SingboxConfigOption; String format() { @@ -63,24 +64,90 @@ class SingboxConfigOption with _$SingboxConfigOption { } @freezed -class SingboxWarpOption with _$SingboxWarpOption { +class SingboxExtraSecurityOption with _$SingboxExtraSecurityOption { @JsonSerializable(fieldRename: FieldRename.kebab) - const factory SingboxWarpOption({ - required bool enable, - required WarpDetourMode mode, - required String wireguardConfig, + const factory SingboxExtraSecurityOption({ + required ChainMode mode, + required SingboxExtraSecurityWarpOption warp, + required SingboxExtraSecurityPsiphonOption psiphon, + required SingboxExtraSecurityProfileOption profile, + }) = _SingboxExtraSecurityOption; + + factory SingboxExtraSecurityOption.fromJson(Map json) => _$SingboxExtraSecurityOptionFromJson(json); +} + +@freezed +class SingboxUnblockerOption with _$SingboxUnblockerOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxUnblockerOption({ + required ChainMode mode, + required SingboxUnblockerWarpOption warp, + required SingboxUnblockerPsiphonOption psiphon, + required SingboxUnblockerProfileOption profile, + }) = _SingboxUnblockerOption; + + factory SingboxUnblockerOption.fromJson(Map json) => _$SingboxUnblockerOptionFromJson(json); +} + +@freezed +class SingboxExtraSecurityWarpOption with _$SingboxExtraSecurityWarpOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxExtraSecurityWarpOption({required String licenseKey}) = _SingboxExtraSecurityWarpOption; + + factory SingboxExtraSecurityWarpOption.fromJson(Map json) => + _$SingboxExtraSecurityWarpOptionFromJson(json); +} + +@freezed +class SingboxUnblockerWarpOption with _$SingboxUnblockerWarpOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxUnblockerWarpOption({ required String licenseKey, - required String accountId, - required String accessToken, required String cleanIp, required int cleanPort, @OptionalRangeJsonConverter() required OptionalRange noise, @OptionalRangeJsonConverter() required OptionalRange noiseSize, @OptionalRangeJsonConverter() required OptionalRange noiseDelay, - @OptionalRangeJsonConverter() required String noiseMode, - }) = _SingboxWarpOption; + required String noiseMode, + }) = _SingboxUnblockerWarpOption; - factory SingboxWarpOption.fromJson(Map json) => _$SingboxWarpOptionFromJson(json); + factory SingboxUnblockerWarpOption.fromJson(Map json) => _$SingboxUnblockerWarpOptionFromJson(json); +} + +@freezed +class SingboxExtraSecurityPsiphonOption with _$SingboxExtraSecurityPsiphonOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxExtraSecurityPsiphonOption({required PsiphonRegion region}) = _SingboxExtraSecurityPsiphonOption; + + factory SingboxExtraSecurityPsiphonOption.fromJson(Map json) => + _$SingboxExtraSecurityPsiphonOptionFromJson(json); +} + +@freezed +class SingboxUnblockerPsiphonOption with _$SingboxUnblockerPsiphonOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxUnblockerPsiphonOption({required PsiphonRegion region}) = _SingboxUnblockerPsiphonOption; + + factory SingboxUnblockerPsiphonOption.fromJson(Map json) => + _$SingboxUnblockerPsiphonOptionFromJson(json); +} + +@freezed +class SingboxExtraSecurityProfileOption with _$SingboxExtraSecurityProfileOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxExtraSecurityProfileOption({required String? id}) = _SingboxExtraSecurityProfileOption; + + factory SingboxExtraSecurityProfileOption.fromJson(Map json) => + _$SingboxExtraSecurityProfileOptionFromJson(json); +} + +@freezed +class SingboxUnblockerProfileOption with _$SingboxUnblockerProfileOption { + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxUnblockerProfileOption({required String? id}) = _SingboxUnblockerProfileOption; + + factory SingboxUnblockerProfileOption.fromJson(Map json) => + _$SingboxUnblockerProfileOptionFromJson(json); } // @freezed