├── assets ├── core │ └── .gitkeep ├── fonts │ ├── Emoji.ttf │ └── Shabnam.ttf └── images │ ├── tray_icon.ico │ ├── tray_icon.png │ ├── connect_norouz.PNG │ ├── convert_icon.sh │ ├── source │ ├── hiddify.ico │ ├── ic_notify.png │ ├── tray_icon.png │ ├── ic_launcher_border.png │ ├── tray_icon_connected.png │ └── tray_icon_disconnected.png │ ├── tray_icon_dark.ico │ ├── tray_icon_dark.png │ ├── disconnect_norouz.PNG │ ├── tray_icon_connected.ico │ ├── tray_icon_connected.png │ ├── tray_icon_disconnected.ico │ └── tray_icon_disconnected.png ├── ios ├── Frameworks │ └── .gitkeep ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset.zip │ │ ├── AppIcon.appiconset │ │ │ ├── app-icon-1024.png │ │ │ ├── ipad │ │ │ │ ├── app-icon-20.png │ │ │ │ ├── app-icon-29.png │ │ │ │ ├── app-icon-40.png │ │ │ │ ├── app-icon-76.png │ │ │ │ ├── app-icon-1024.png │ │ │ │ ├── app-icon-20@2x.png │ │ │ │ ├── app-icon-29@2x.png │ │ │ │ ├── app-icon-40@2x.png │ │ │ │ ├── app-icon-76@2x.png │ │ │ │ └── app-icon-83.5@2x.png │ │ │ ├── iphone │ │ │ │ ├── app-icon-1024.png │ │ │ │ ├── app-icon-29.png │ │ │ │ ├── app-icon-20@2x.png │ │ │ │ ├── app-icon-20@3x.png │ │ │ │ ├── app-icon-29@2x.png │ │ │ │ ├── app-icon-29@3x.png │ │ │ │ ├── app-icon-40@2x.png │ │ │ │ ├── app-icon-40@3x.png │ │ │ │ ├── app-icon-60@2x.png │ │ │ │ └── app-icon-60@3x.png │ │ │ ├── tvOS │ │ │ │ ├── app-icon-back-400.png │ │ │ │ ├── app-icon-back-400@2x.png │ │ │ │ ├── app-icon-front-400.png │ │ │ │ ├── app-icon-middle-400.png │ │ │ │ ├── app-icon-back-1280x768.png │ │ │ │ ├── app-icon-front-400@2x.png │ │ │ │ ├── app-icon-middle-400@2x.png │ │ │ │ ├── app-icon-front-1280x768.png │ │ │ │ └── app-icon-middle-1280x768.png │ │ │ └── Contents.json │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── LaunchBackground.imageset │ │ │ ├── background.png │ │ │ └── Contents.json │ ├── Extensions │ │ └── Bundle+Properties.swift │ ├── VPN │ │ └── VPNConfig.swift │ ├── Runner.entitlements │ ├── Handlers │ │ └── FileMethodHandler.swift │ └── PrivacyInfo.xcprivacy ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Base.xcconfig ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── RunnerTests │ └── RunnerTests.swift ├── Shared │ ├── Outbound.swift │ └── FilePath.swift ├── HiddifyPacketTunnel │ ├── Info.plist │ ├── HiddifyPacketTunnel.entitlements │ ├── PrivacyInfo.xcprivacy │ ├── PacketTunnelProvider.swift │ └── SingBox │ │ └── Extension+RunBlocking.swift ├── .stignore ├── .gitignore ├── Local Packages │ └── Package.swift ├── packaging │ └── ios │ │ └── make_config.yaml └── exportOptions.plist ├── android ├── app │ ├── libs │ │ └── .gitkeep │ └── src │ │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── ic_banner_background.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── background.png │ │ │ │ ├── launch_background.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-v21 │ │ │ │ ├── background.png │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── splash.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_banner.png │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── drawable-hdpi │ │ │ │ └── ic_stat_logo.png │ │ │ ├── drawable-mdpi │ │ │ │ └── ic_stat_logo.png │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_banner.xml │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── xml │ │ │ │ └── shortcuts.xml │ │ │ ├── values-v31 │ │ │ │ └── styles.xml │ │ │ ├── values-night-v31 │ │ │ │ └── styles.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ ├── ic_launcher-playstore.png │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── hiddify │ │ │ │ └── hiddify │ │ │ │ ├── constant │ │ │ │ ├── ServiceMode.kt │ │ │ │ ├── Status.kt │ │ │ │ ├── PerAppProxyMode.kt │ │ │ │ ├── Alert.kt │ │ │ │ ├── Action.kt │ │ │ │ └── SettingsKey.kt │ │ │ │ ├── ktx │ │ │ │ ├── Continuations.kt │ │ │ │ └── Wrappers.kt │ │ │ │ ├── bg │ │ │ │ ├── ProxyService.kt │ │ │ │ ├── BootReceiver.kt │ │ │ │ └── AppChangeReceiver.kt │ │ │ │ ├── utils │ │ │ │ └── OutboundMapper.kt │ │ │ │ └── LogHandler.kt │ │ └── aidl │ │ │ └── com │ │ │ └── hiddify │ │ │ └── hiddify │ │ │ ├── IService.aidl │ │ │ └── IServiceCallback.aidl │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── gradle.properties ├── .stignore ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── devtools_options.yaml ├── linux ├── .gitignore ├── .stignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── my_application.h └── packaging │ ├── rpm │ └── make_config.yaml │ ├── deb │ └── make_config.yaml │ └── appimage │ ├── make_config.yaml │ └── AppRun ├── dependencies.properties ├── lib ├── features │ ├── panel │ │ └── xboard │ │ │ ├── viewmodels │ │ │ ├── account_balance_viewmodel.dart │ │ │ ├── dialog_viewmodel │ │ │ │ ├── purchase_details_viewmodel_provider.dart │ │ │ │ └── payment_methods_viewmodel_provider.dart │ │ │ ├── purchase_viewmodel.dart │ │ │ └── reset_subscription_viewmodel.dart │ │ │ ├── models │ │ │ ├── invite_code_model.dart │ │ │ └── purchase_detail_model.dart │ │ │ ├── services │ │ │ ├── http_service │ │ │ │ ├── balance.service.dart │ │ │ │ ├── plan_service.dart │ │ │ │ └── payment_service.dart │ │ │ ├── auth_provider.dart │ │ │ └── future_provider.dart │ │ │ ├── utils │ │ │ ├── storage │ │ │ │ └── token_storage.dart │ │ │ └── price_widget.dart │ │ │ └── views │ │ │ └── components │ │ │ └── user_info │ │ │ └── reset_subscription_button.dart │ ├── settings │ │ ├── widgets │ │ │ ├── widgets.dart │ │ │ └── sections_widgets.dart │ │ ├── data │ │ │ └── settings_data_providers.dart │ │ ├── model │ │ │ └── settings_failure.dart │ │ └── overview │ │ │ └── settings_overview_page.dart │ ├── log │ │ ├── model │ │ │ ├── log_entity.dart │ │ │ ├── log_level.dart │ │ │ └── log_failure.dart │ │ ├── data │ │ │ ├── log_path_resolver.dart │ │ │ ├── log_data_providers.dart │ │ │ └── log_parser.dart │ │ └── overview │ │ │ └── logs_overview_state.dart │ ├── per_app_proxy │ │ ├── data │ │ │ └── per_app_proxy_data_providers.dart │ │ ├── model │ │ │ ├── installed_package_info.dart │ │ │ └── per_app_proxy_mode.dart │ │ └── overview │ │ │ └── per_app_proxy_notifier.dart │ ├── stats │ │ ├── data │ │ │ ├── stats_data_providers.dart │ │ │ └── stats_repository.dart │ │ ├── model │ │ │ ├── stats_entity.dart │ │ │ └── stats_failure.dart │ │ └── notifier │ │ │ └── stats_notifier.dart │ ├── profile │ │ ├── data │ │ │ └── profile_path_resolver.dart │ │ ├── model │ │ │ └── profile_sort_enum.dart │ │ ├── details │ │ │ └── profile_details_state.dart │ │ └── notifier │ │ │ └── active_profile_notifier.dart │ ├── app_update │ │ ├── data │ │ │ └── app_update_data_providers.dart │ │ ├── model │ │ │ ├── remote_version_entity.dart │ │ │ └── app_update_failure.dart │ │ └── notifier │ │ │ └── app_update_state.dart │ ├── proxy │ │ ├── data │ │ │ └── proxy_data_providers.dart │ │ └── model │ │ │ └── proxy_entity.dart │ ├── config_option │ │ ├── data │ │ │ └── config_option_data_providers.dart │ │ └── model │ │ │ └── config_option_failure.dart │ ├── geo_asset │ │ ├── model │ │ │ └── geo_asset_entity.dart │ │ ├── data │ │ │ ├── geo_asset_data_mapper.dart │ │ │ └── geo_asset_path_resolver.dart │ │ └── notifier │ │ │ └── geo_asset_notifier.dart │ ├── common │ │ └── confirmation_dialogs.dart │ ├── connection │ │ └── data │ │ │ └── connection_data_providers.dart │ └── auto_start │ │ └── notifier │ │ └── auto_start_notifier.dart ├── core │ ├── router │ │ └── router.dart │ ├── model │ │ ├── directories.dart │ │ ├── environment.dart │ │ ├── region.dart │ │ ├── constants.dart │ │ └── app_info_entity.dart │ ├── database │ │ ├── database_provider.dart │ │ ├── converters │ │ │ └── duration_converter.dart │ │ └── connection │ │ │ └── database_connection.dart │ ├── utils │ │ ├── ffi_utils.dart │ │ ├── json_converters.dart │ │ ├── throttler.dart │ │ └── ip_utils.dart │ ├── widget │ │ ├── spaced_list_widget.dart │ │ ├── adaptive_icon.dart │ │ ├── skeleton_widget.dart │ │ ├── shimmer_skeleton.dart │ │ ├── animated_visibility.dart │ │ └── tip_card.dart │ ├── preferences │ │ ├── actions_at_closing.dart │ │ └── preferences_provider.dart │ ├── localization │ │ ├── translations.dart │ │ ├── locale_extensions.dart │ │ └── locale_preferences.dart │ ├── logger │ │ └── logger.dart │ ├── theme │ │ ├── app_theme_mode.dart │ │ ├── theme_preferences.dart │ │ ├── theme_extensions.dart │ │ └── app_theme.dart │ ├── http_client │ │ └── http_client_provider.dart │ ├── analytics │ │ └── analytics_filter.dart │ ├── app_info │ │ └── app_info_provider.dart │ └── haptic │ │ └── haptic_service.dart ├── utils │ ├── platform_utils.dart │ ├── date_time_formatter.dart │ ├── riverpod_utils.dart │ ├── utils.dart │ ├── callback_debouncer.dart │ ├── number_formatters.dart │ ├── mutation_state.dart │ ├── text_utils.dart │ ├── custom_loggers.dart │ ├── bottom_sheet_page.dart │ ├── sentry_utils.dart │ ├── validators.dart │ └── sentry_riverpod_observer.dart ├── singbox │ ├── service │ │ └── singbox_service_provider.dart │ ├── generated │ │ └── core.pbenum.dart │ └── model │ │ ├── singbox_stats.dart │ │ ├── warp_account.dart │ │ ├── singbox_rule.dart │ │ └── singbox_proxy_type.dart ├── main_prod.dart └── main.dart ├── web ├── icon.png └── manifest.json ├── macos ├── .stignore ├── packaging │ ├── pkg │ │ └── make_config.yaml │ └── dmg │ │ └── make_config.yaml ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app-icon-1024.png │ │ │ ├── app-icon-128.png │ │ │ ├── app-icon-16.png │ │ │ ├── app-icon-256.png │ │ │ ├── app-icon-32.png │ │ │ ├── app-icon-512.png │ │ │ ├── app-icon-128@2x.png │ │ │ ├── app-icon-16@2x.png │ │ │ ├── app-icon-256@2x.png │ │ │ ├── app-icon-32@2x.png │ │ │ └── app-icon-512@2x.png │ ├── MainFlutterWindow.swift │ ├── Release.entitlements │ └── DebugProfile.entitlements ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ └── Flutter-Release.xcconfig ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── RunnerTests │ └── RunnerTests.swift ├── project.inlang ├── project_id └── settings.json ├── snap └── gui │ ├── app_icon.png │ └── app_icon.desktop ├── .gitmodules ├── docs └── google-play-badge.png ├── windows ├── runner │ ├── resources │ │ └── app_icon.ico │ ├── resource.h │ ├── utils.h │ ├── runner.exe.manifest │ └── flutter_window.h ├── .stignore ├── .gitignore ├── flutter │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake └── packaging │ ├── exe │ └── make_config.yaml │ └── msix │ └── make_config.yaml ├── .github ├── help │ ├── mac-windows │ │ ├── Tutorial_For_HiddifyNext.url │ │ ├── آموزش هیدیفای‌نکست فارسی.url │ │ └── آموزش هیدیفای‌نکست فارسی.url │ └── linux │ │ ├── Tutorial_For_HiddifyNext_Linux.desktop │ │ ├── آموزش هیدیفای‌نکست فارسی لینوکس.desktop │ │ └── آموزش هیدیفای‌نکست فارسی لینوکس.desktop ├── ISSUE_TEMPLATE │ ├── config.yml │ └── feature_request.yaml ├── workflows │ ├── winget.yml │ ├── release.yml │ ├── add_signed_microsft.yml │ └── ci.yml └── dependabot.yml ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── .release_notes.tpl ├── analysis_options.yaml ├── .stignore ├── .gitchangelog.rc ├── distribute_options.yaml ├── test └── core │ ├── database │ └── generated_migrations │ │ └── schema.dart │ └── utils │ └── ip_utils_test.dart ├── test.configs ├── warp └── warp2 ├── .gitignore └── scripts └── package_windows.ps1 /assets/core/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Frameworks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/app/libs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | extensions: 2 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/.stignore: -------------------------------------------------------------------------------- 1 | /flutter/ephemeral 2 | -------------------------------------------------------------------------------- /dependencies.properties: -------------------------------------------------------------------------------- 1 | core.version=3.1.8 -------------------------------------------------------------------------------- /lib/features/panel/xboard/viewmodels/account_balance_viewmodel.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/core/router/router.dart: -------------------------------------------------------------------------------- 1 | export 'app_router.dart'; 2 | export 'routes.dart'; 3 | -------------------------------------------------------------------------------- /web/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/web/icon.png -------------------------------------------------------------------------------- /macos/.stignore: -------------------------------------------------------------------------------- 1 | **/Flutter/ephemeral/ 2 | **/Pods/ 3 | 4 | **/dgph 5 | **/xcuserdata/ 6 | -------------------------------------------------------------------------------- /project.inlang/project_id: -------------------------------------------------------------------------------- 1 | 33134c0ff949ed5f9d94c105afe0750868db4328feb5f504f9c62db06940f891 -------------------------------------------------------------------------------- /assets/fonts/Emoji.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/fonts/Emoji.ttf -------------------------------------------------------------------------------- /snap/gui/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/snap/gui/app_icon.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libcore"] 2 | path = libcore 3 | url = https://github.com/hiddify/hiddify-next-core 4 | -------------------------------------------------------------------------------- /assets/fonts/Shabnam.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/fonts/Shabnam.ttf -------------------------------------------------------------------------------- /macos/packaging/pkg/make_config.yaml: -------------------------------------------------------------------------------- 1 | install-path: /Applications 2 | #sign-identity: 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/tray_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon.ico -------------------------------------------------------------------------------- /assets/images/tray_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon.png -------------------------------------------------------------------------------- /docs/google-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/docs/google-play-badge.png -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /assets/images/connect_norouz.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/connect_norouz.PNG -------------------------------------------------------------------------------- /assets/images/convert_icon.sh: -------------------------------------------------------------------------------- 1 | in=$1 2 | convert -define icon:auto-resize=128,64,48,32,16 -gravity center $in.png $in.ico 3 | -------------------------------------------------------------------------------- /assets/images/source/hiddify.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/hiddify.ico -------------------------------------------------------------------------------- /assets/images/tray_icon_dark.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_dark.ico -------------------------------------------------------------------------------- /assets/images/tray_icon_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_dark.png -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /assets/images/disconnect_norouz.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/disconnect_norouz.PNG -------------------------------------------------------------------------------- /assets/images/source/ic_notify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/ic_notify.png -------------------------------------------------------------------------------- /assets/images/source/tray_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/tray_icon.png -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /assets/images/tray_icon_connected.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_connected.ico -------------------------------------------------------------------------------- /assets/images/tray_icon_connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_connected.png -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4048m -Dfile.encoding=UTF-8 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/images/tray_icon_disconnected.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_disconnected.ico -------------------------------------------------------------------------------- /assets/images/tray_icon_disconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/tray_icon_disconnected.png -------------------------------------------------------------------------------- /windows/.stignore: -------------------------------------------------------------------------------- 1 | /flutter/ephemeral/ 2 | 3 | *.suo 4 | *.user 5 | *.userosscache 6 | *.sln.docstates 7 | 8 | /x64/ 9 | /x86/ 10 | -------------------------------------------------------------------------------- /assets/images/source/ic_launcher_border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/ic_launcher_border.png -------------------------------------------------------------------------------- /assets/images/source/tray_icon_connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/tray_icon_connected.png -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /assets/images/source/tray_icon_disconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/assets/images/source/tray_icon_disconnected.png -------------------------------------------------------------------------------- /.github/help/mac-windows/Tutorial_For_HiddifyNext.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://github.com/hiddify/hiddify-next/wiki/How-to-install-HiddifyNext-app 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_banner.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset.zip -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_stat_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/drawable-hdpi/ic_stat_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_stat_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/drawable-mdpi/ic_stat_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /lib/core/model/directories.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | typedef Directories = ({ 4 | Directory baseDir, 5 | Directory workingDir, 6 | Directory tempDir 7 | }); 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | 4 | #include "Base.xcconfig" 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | 4 | #include "Base.xcconfig" 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_banner_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F0F3FA 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F0F3FA 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-512.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-128@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-16@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-256@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-32@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app-icon-512@2x.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions & Help 4 | url: https://t.me/hiddify_board 5 | about: Ask a question about Hiddify 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29.png -------------------------------------------------------------------------------- /lib/utils/platform_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | abstract class PlatformUtils { 4 | static bool get isDesktop => 5 | Platform.isLinux || Platform.isWindows || Platform.isMacOS; 6 | } 7 | -------------------------------------------------------------------------------- /android/.stignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | .gradle 3 | captures/ 4 | gradlew 5 | gradlew.bat 6 | local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | key.properties 10 | **.keystore 11 | **.jks -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/ServiceMode.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | object ServiceMode { 4 | const val NORMAL = "proxy" 5 | const val VPN = "vpn" 6 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/Status.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | enum class Status { 4 | Stopped, 5 | Starting, 6 | Started, 7 | Stopping, 8 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/ipad/app-icon-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/iphone/app-icon-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-400.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-400@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-400@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-400.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-400.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": ".github/**", 5 | "options": { 6 | "singleQuote": true 7 | } 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-1280x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-back-1280x768.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-400@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-400@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-400@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-400@2x.png -------------------------------------------------------------------------------- /lib/utils/date_time_formatter.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | extension DateTimeFormatter on DateTime { 4 | String format() { 5 | return DateFormat.yMMMd().add_Hm().format(this); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-1280x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-front-1280x768.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-1280x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/V2hiddify/HiddifyWithPanels/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/tvOS/app-icon-middle-1280x768.png -------------------------------------------------------------------------------- /snap/gui/app_icon.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Flutter Linux App 3 | Comment=Flutter Linux launcher icon 4 | Exec=app_icon 5 | Icon=app_icon.png 6 | Terminal=false 7 | Type=Application 8 | Categories=Entertainment; 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macos/packaging/dmg/make_config.yaml: -------------------------------------------------------------------------------- 1 | title: Hiddify 2 | contents: 3 | - x: 448 4 | y: 344 5 | type: link 6 | path: "/Applications" 7 | - x: 192 8 | y: 344 9 | type: file 10 | path: Hiddify.app 11 | -------------------------------------------------------------------------------- /lib/features/settings/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'advanced_setting_tiles.dart'; 2 | export 'general_setting_tiles.dart'; 3 | export 'platform_settings_tiles.dart'; 4 | export 'sections_widgets.dart'; 5 | export 'settings_input_dialog.dart'; 6 | -------------------------------------------------------------------------------- /ios/Base.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Base.xcconfig 3 | // Runner 4 | // 5 | // Created by GFWFighter on 7/24/1402 AP. 6 | // 7 | 8 | BASE_BUNDLE_IDENTIFIER=app.hiddify.com 9 | SERVICE_IDENTIFIER=com.hiddify.app 10 | DEVELOPMENT_TEAM=3JFTY5BP58 11 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/PerAppProxyMode.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | object PerAppProxyMode { 4 | const val OFF = "off" 5 | const val INCLUDE = "include" 6 | const val EXCLUDE = "exclude" 7 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dart-code.dart-code", 4 | "dart-code.flutter", 5 | "github.vscode-github-actions", 6 | "golang.go", 7 | "redhat.vscode-yaml", 8 | "codeium.codeium", 9 | "kangping.protobuf" 10 | ] 11 | } -------------------------------------------------------------------------------- /.github/help/linux/Tutorial_For_HiddifyNext_Linux.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Icon=text-html 4 | Name[en_US]=Tutorial_For_HiddifyNext_Linux 5 | Name=Tutorial_For_HiddifyNext_Linux 6 | Type=Link 7 | URL=https://github.com/hiddify/hiddify-next/wiki/How-to-install-HiddifyNext-app 8 | -------------------------------------------------------------------------------- /.github/help/mac-windows/آموزش هیدیفای‌نکست فارسی.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA 3 | -------------------------------------------------------------------------------- /.github/help/mac-windows/آموزش هیدیفای‌نکست فارسی.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # HiddifyWithPanels 3 | 4 | > **⚠️ 项目已归档 | Project Archived** 5 | > 6 | > 由于 Hiddify 官方维护停滞,本项目决定归档。 7 | > 8 | > **新项目地址**: [Xboard-Mihomo](https://github.com/hakimi-x/Xboard-Mihomo) 9 | > 10 | > 新项目基于 Flclash(Clash Meta 内核),已完全开源,将由作者 [Hakimi X](https://github.com/hakimi-x) 维护,欢迎使用! 11 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/Alert.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | enum class Alert { 4 | RequestVPNPermission, 5 | RequestNotificationPermission, 6 | EmptyConfiguration, 7 | StartCommandServer, 8 | CreateService, 9 | StartService 10 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/core/database/database_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/database/app_database.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | 4 | part 'database_provider.g.dart'; 5 | 6 | @Riverpod(keepAlive: true) 7 | AppDatabase appDatabase(AppDatabaseRef ref) => AppDatabase.connect(); 8 | -------------------------------------------------------------------------------- /android/app/src/main/aidl/com/hiddify/hiddify/IService.aidl: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify; 2 | 3 | import com.hiddify.hiddify.IServiceCallback; 4 | 5 | interface IService { 6 | int getStatus(); 7 | void registerCallback(in IServiceCallback callback); 8 | oneway void unregisterCallback(in IServiceCallback callback); 9 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/Action.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | object Action { 4 | const val SERVICE = "com.hiddify.app.SERVICE" 5 | const val SERVICE_CLOSE = "com.hiddify.app.SERVICE_CLOSE" 6 | const val SERVICE_RELOAD = "com.hiddify.app.sfa.SERVICE_RELOAD" 7 | } -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Stop 4 | Toggle 5 | Service starting… 6 | Service started 7 | -------------------------------------------------------------------------------- /android/app/src/main/aidl/com/hiddify/hiddify/IServiceCallback.aidl: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify; 2 | 3 | interface IServiceCallback { 4 | void onServiceStatusChanged(int status); 5 | void onServiceAlert(int type, String message); 6 | void onServiceWriteLog(String message); 7 | void onServiceResetLogs(in List messages); 8 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.release_notes.tpl: -------------------------------------------------------------------------------- 1 | {{#general_title}} 2 | # {{{title}}} 3 | 4 | 5 | {{/general_title}} 6 | {{#versions}} 7 | ## {{{label}}} 8 | 9 | {{#sections}} 10 | #### {{{label}}} 11 | 12 | {{#commits}} 13 | * {{{subject}}} 14 | {{#body}} 15 | _{{{body}}}_ 16 | {{/body}} 17 | 18 | {{/commits}} 19 | {{/sections}} 20 | 21 | 22 | {{/versions}} -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "app-icon-1024.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | # distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip 4 | distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-7.6.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /lib/core/utils/ffi_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi'; 2 | 3 | import 'package:ffi/ffi.dart'; 4 | 5 | R withMemory( 6 | int size, 7 | R Function(Pointer memory) action, 8 | ) { 9 | final memory = calloc(size); 10 | try { 11 | return action(memory.cast()); 12 | } finally { 13 | calloc.free(memory); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/singbox/service/singbox_service_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/singbox/service/singbox_service.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | 4 | part 'singbox_service_provider.g.dart'; 5 | 6 | @Riverpod(keepAlive: true) 7 | SingboxService singboxService(SingboxServiceRef ref) { 8 | return SingboxService(); 9 | } 10 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/core/widget/spaced_list_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | extension SpacedWidgets on List { 4 | List spaceBy({double? width, double? height}) => [ 5 | for (int i = 0; i < length; i++) ...[ 6 | if (i > 0) SizedBox(width: width, height: height), 7 | this[i], 8 | ], 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /lib/core/database/converters/duration_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:drift/drift.dart'; 2 | 3 | class DurationTypeConverter extends TypeConverter { 4 | @override 5 | Duration fromSql(int fromDb) { 6 | return Duration(seconds: fromDb); 7 | } 8 | 9 | @override 10 | int toSql(Duration value) { 11 | return value.inSeconds; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/models/invite_code_model.dart: -------------------------------------------------------------------------------- 1 | class InviteCode { 2 | final String code; 3 | 4 | InviteCode({ 5 | required this.code, 6 | }); 7 | 8 | // 从 JSON 创建 InviteCode 实例 9 | factory InviteCode.fromJson(Map json) { 10 | return InviteCode( 11 | code: json['code'] as String? ?? '', // 使用空字符串作为默认值 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /lib/core/utils/json_converters.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | class IntervalInSecondsConverter implements JsonConverter { 4 | const IntervalInSecondsConverter(); 5 | 6 | @override 7 | Duration fromJson(int json) => Duration(seconds: json); 8 | 9 | @override 10 | int toJson(Duration object) => object.inSeconds; 11 | } 12 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | 15 | /app/libs/* 16 | !/app/libs/.gitkeep -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/features/settings/data/settings_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/settings/data/settings_repository.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | 4 | part 'settings_data_providers.g.dart'; 5 | 6 | @Riverpod(keepAlive: true) 7 | SettingsRepository settingsRepository(SettingsRepositoryRef ref) { 8 | return SettingsRepositoryImpl(); 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/features/log/model/log_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/features/log/model/log_level.dart'; 3 | 4 | part 'log_entity.freezed.dart'; 5 | 6 | @freezed 7 | class LogEntity with _$LogEntity { 8 | const factory LogEntity({ 9 | LogLevel? level, 10 | DateTime? time, 11 | required String message, 12 | }) = _LogEntity; 13 | } 14 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/features/per_app_proxy/data/per_app_proxy_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/per_app_proxy/data/per_app_proxy_repository.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | 4 | part 'per_app_proxy_data_providers.g.dart'; 5 | 6 | @Riverpod(keepAlive: true) 7 | PerAppProxyRepository perAppProxyRepository(PerAppProxyRepositoryRef ref) { 8 | return PerAppProxyRepositoryImpl(); 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/core/utils/throttler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class Throttler { 4 | Throttler(this.throttleFor); 5 | 6 | final Duration throttleFor; 7 | DateTime? _lastCall; 8 | 9 | void call(VoidCallback callback) { 10 | if (_lastCall == null || 11 | DateTime.now().difference(_lastCall!) > throttleFor) { 12 | callback(); 13 | _lastCall = DateTime.now(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/help/linux/آموزش هیدیفای‌نکست فارسی لینوکس.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Icon=text-html 4 | Name[en_US]=آموزش هیدیفای‌نکست فارسی لینوکس 5 | Name=آموزش هیدیفای‌نکست فارسی لینوکس 6 | Type=Link 7 | URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA 8 | -------------------------------------------------------------------------------- /lib/core/preferences/actions_at_closing.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/gen/translations.g.dart'; 2 | 3 | enum ActionsAtClosing { 4 | ask, 5 | hide, 6 | exit; 7 | 8 | String present(TranslationsEn t) => switch (this) { 9 | ask => t.settings.general.actionsAtClosing.askEachTime, 10 | hide => t.settings.general.actionsAtClosing.hide, 11 | exit => t.settings.general.actionsAtClosing.exit, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /.github/help/linux/آموزش هیدیفای‌نکست فارسی لینوکس.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Icon=text-html 4 | Name[en_US]=آموزش هیدیفای‌نکست فارسی لینوکس 5 | Name=آموزش هیدیفای‌نکست فارسی لینوکس 6 | Type=Link 7 | URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA 8 | -------------------------------------------------------------------------------- /lib/singbox/generated/core.pbenum.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated code. Do not modify. 3 | // source: core.proto 4 | // 5 | // @dart = 2.12 6 | 7 | // ignore_for_file: annotate_overrides, camel_case_types, comment_references 8 | // ignore_for_file: constant_identifier_names, library_prefixes 9 | // ignore_for_file: non_constant_identifier_names, prefer_final_fields 10 | // ignore_for_file: unnecessary_import, unnecessary_this, unused_import 11 | 12 | -------------------------------------------------------------------------------- /ios/Runner/Extensions/Bundle+Properties.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bundle+Properties.swift 3 | // Runner 4 | // 5 | // Created by Hiddify on 12/26/23. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Bundle { 11 | var serviceIdentifier: String { 12 | (infoDictionary?["SERVICE_IDENTIFIER"] as? String)! 13 | } 14 | 15 | var baseBundleIdentifier: String { 16 | (infoDictionary?["BASE_BUNDLE_IDENTIFIER"] as? String)! 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/Shared/Outbound.swift: -------------------------------------------------------------------------------- 1 | public struct SBItem: Codable { 2 | let tag: String 3 | let type: String 4 | let urlTestDelay: Int 5 | 6 | enum CodingKeys: String, CodingKey { 7 | case tag 8 | case type 9 | case urlTestDelay = "url-test-delay" 10 | } 11 | } 12 | 13 | public struct SBGroup: Codable { 14 | let tag: String 15 | let type: String 16 | let selected: String 17 | let items: [SBItem] 18 | } 19 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/core/localization/translations.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/localization/locale_preferences.dart'; 2 | import 'package:hiddify/gen/translations.g.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | 5 | export 'package:hiddify/gen/translations.g.dart'; 6 | 7 | part 'translations.g.dart'; 8 | 9 | @Riverpod(keepAlive: true) 10 | TranslationsEn translations(TranslationsRef ref) => 11 | ref.watch(localePreferencesProvider).build(); 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request a new feature 3 | title: '[FR] ' 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | # Only English 9 | - type: textarea 10 | attributes: 11 | label: Feature description 12 | description: Please provide a clear and concise description of what you want to happen and what problem will this solve. 13 | validations: 14 | required: true 15 | -------------------------------------------------------------------------------- /lib/features/log/data/log_path_resolver.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as p; 4 | 5 | class LogPathResolver { 6 | const LogPathResolver(this._workingDir); 7 | 8 | final Directory _workingDir; 9 | 10 | Directory get directory => _workingDir; 11 | 12 | File coreFile() { 13 | return File(p.join(directory.path, "box.log")); 14 | } 15 | 16 | File appFile() { 17 | return File(p.join(directory.path, "app.log")); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/stats/data/stats_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/stats/data/stats_repository.dart'; 2 | import 'package:hiddify/singbox/service/singbox_service_provider.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | 5 | part 'stats_data_providers.g.dart'; 6 | 7 | @Riverpod(keepAlive: true) 8 | StatsRepository statsRepository(StatsRepositoryRef ref) { 9 | return StatsRepositoryImpl(singbox: ref.watch(singboxServiceProvider)); 10 | } 11 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hiddify", 3 | "short_name": "Hiddify", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "Hiddify", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icon.png", 14 | "sizes": "512x512", 15 | "type": "image/png" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lint/strict.yaml 2 | 3 | analyzer: 4 | plugins: 5 | - custom_lint 6 | exclude: 7 | - "libcore/**" 8 | - "**.g.dart" 9 | - "lib/gen/**" 10 | errors: 11 | invalid_annotation_target: ignore 12 | 13 | linter: 14 | rules: 15 | sort_pub_dependencies: false 16 | sort_unnamed_constructors_first: false 17 | avoid_classes_with_only_static_members: false 18 | 19 | custom_lint: 20 | rules: 21 | # Enable one rule 22 | - provider_parameters -------------------------------------------------------------------------------- /lib/features/profile/data/profile_path_resolver.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as p; 4 | 5 | class ProfilePathResolver { 6 | const ProfilePathResolver(this._workingDir); 7 | 8 | final Directory _workingDir; 9 | 10 | Directory get directory => Directory(p.join(_workingDir.path, "configs")); 11 | 12 | File file(String fileName) { 13 | return File(p.join(directory.path, "$fileName.json")); 14 | } 15 | 16 | File tempFile(String fileName) => file("$fileName.tmp"); 17 | } 18 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/packaging/exe/make_config.yaml: -------------------------------------------------------------------------------- 1 | app_id: 6L903538-42B1-4596-G479-BJ779F21A65D 2 | publisher: Hiddify 3 | publisher_url: https://github.com/hiddify/hiddify-next 4 | display_name: Hiddify 5 | executable_name: Hiddify.exe 6 | output_base_file_name: Hiddify.exe 7 | create_desktop_icon: true 8 | install_dir_name: "{autopf64}\\Hiddify" 9 | setup_icon_file: ..\..\windows\runner\resources\app_icon.ico 10 | locales: 11 | - ar 12 | - en 13 | - fa 14 | - ru 15 | - pt 16 | - tr 17 | script_template: inno_setup.sas 18 | -------------------------------------------------------------------------------- /lib/core/database/connection/database_connection.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:drift/drift.dart'; 4 | import 'package:drift/native.dart'; 5 | import 'package:hiddify/core/directories/directories_provider.dart'; 6 | import 'package:path/path.dart' as p; 7 | 8 | LazyDatabase openConnection() { 9 | return LazyDatabase(() async { 10 | final dbDir = await AppDirectories.getDatabaseDirectory(); 11 | final file = File(p.join(dbDir.path, 'db.sqlite')); 12 | return NativeDatabase(file); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/winget.yml: -------------------------------------------------------------------------------- 1 | name: Publish to WinGet 2 | on: 3 | release: 4 | types: [released] 5 | 6 | env: 7 | IDENTIFIER: ${{ endsWith(github.event.release.tag_name, 'dev') && 'Hiddify.Next.Beta' || 'Hiddify.Next' }} 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: vedantmgoyal9/winget-releaser@2 14 | with: 15 | identifier: ${{ env.IDENTIFIER }} 16 | version: ${{ github.event.release.tag_name }} 17 | token: ${{ secrets.WINGET_TOKEN }} 18 | -------------------------------------------------------------------------------- /.stignore: -------------------------------------------------------------------------------- 1 | #include /.stignore 2 | #include /android/.stignore 3 | #include /ios/.stignore 4 | #include /linux/.stignore 5 | #include /windows/.stignore 6 | #include /macos/.stignore 7 | 8 | .git 9 | 10 | .DS_Store 11 | .idea 12 | .dart_tool 13 | 14 | .flutter-plugins 15 | .flutter-plugins-dependencies 16 | 17 | .packages 18 | .pub-cache 19 | .pub 20 | build 21 | 22 | *.log 23 | *.iml 24 | *.ipr 25 | *.iws 26 | 27 | **/ios/Flutter/.last_build_id 28 | 29 | /android/app/debug 30 | /android/app/profile 31 | /android/app/release 32 | -------------------------------------------------------------------------------- /lib/features/app_update/data/app_update_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/http_client/http_client_provider.dart'; 2 | import 'package:hiddify/features/app_update/data/app_update_repository.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | 5 | part 'app_update_data_providers.g.dart'; 6 | 7 | @Riverpod(keepAlive: true) 8 | AppUpdateRepository appUpdateRepository( 9 | AppUpdateRepositoryRef ref, 10 | ) { 11 | return AppUpdateRepositoryImpl(httpClient: ref.watch(httpClientProvider)); 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/ktx/Continuations.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.ktx 2 | 3 | import kotlin.coroutines.Continuation 4 | 5 | 6 | fun Continuation.tryResume(value: T) { 7 | try { 8 | resumeWith(Result.success(value)) 9 | } catch (ignored: IllegalStateException) { 10 | } 11 | } 12 | 13 | fun Continuation.tryResumeWithException(exception: Throwable) { 14 | try { 15 | resumeWith(Result.failure(exception)) 16 | } catch (ignored: IllegalStateException) { 17 | } 18 | } -------------------------------------------------------------------------------- /lib/utils/riverpod_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | 5 | extension RefLifeCycle on AutoDisposeRef { 6 | void disposeDelay(Duration duration) { 7 | final link = keepAlive(); 8 | Timer? timer; 9 | 10 | onCancel(() { 11 | timer?.cancel(); 12 | timer = Timer(duration, link.close); 13 | }); 14 | 15 | onDispose(() { 16 | timer?.cancel(); 17 | }); 18 | 19 | onResume(() { 20 | timer?.cancel(); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitchangelog.rc: -------------------------------------------------------------------------------- 1 | #output_engine = mustache("markdown") 2 | output_engine = mustache(".release_notes.tpl") 3 | 4 | 5 | tag_filter_regexp = r'^v?[0-9]+\.[0-9]+(\.[0-9]+)?$' 6 | 7 | ignore_regexps = [ 8 | r'@minor', r'!minor', 9 | r'@cosmetic', r'!cosmetic', 10 | r'@refactor', r'!refactor', 11 | r'@wip', r'!wip', 12 | r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[p|P]kg:', 13 | r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[d|D]ev:', 14 | r'^(.{3,3}\s*:)?\s*[fF]irst commit.?\s*$', 15 | r'^$', ## ignore commits with empty messages 16 | r'release: *', 17 | ] -------------------------------------------------------------------------------- /ios/Runner/VPN/VPNConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VPNConfig.swift 3 | // Runner 4 | // 5 | // Created by GFWFighter on 10/24/23. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | 11 | class VPNConfig: ObservableObject { 12 | static let shared = VPNConfig() 13 | 14 | @Stored(key: "VPN.ActiveConfigPath") 15 | var activeConfigPath: String = "" 16 | 17 | @Stored(key: "VPN.ConfigOptions") 18 | var configOptions: String = "" 19 | 20 | @Stored(key: "VPN.DisableMemoryLimit") 21 | var disableMemoryLimit: Bool = false 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/utils/ip_utils.dart: -------------------------------------------------------------------------------- 1 | const String fallbackObscuredAddress = "*.*.*.*"; 2 | 3 | String obscureIp(String ip) { 4 | try { 5 | if (ip.contains(".")) { 6 | final splits = ip.split("."); 7 | return "${splits.first}.*.*.${splits.last}"; 8 | } else if (ip.contains(":")) { 9 | final splits = ip.split(":"); 10 | return [ 11 | splits.first, 12 | ...splits.sublist(1).map((part) => "*" * part.length), 13 | ].join(":"); 14 | } 15 | // ignore: empty_catches 16 | } catch (e) {} 17 | return fallbackObscuredAddress; 18 | } 19 | -------------------------------------------------------------------------------- /linux/packaging/rpm/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: Hiddify 2 | url: https://github.com/hiddify/hiddify-next/ 3 | license: Other 4 | 5 | packager: hiddify 6 | packagerEmail: linux@hiddify.com 7 | 8 | priority: optional 9 | section: x11 10 | installed_size: 6604 11 | essential: false 12 | icon: ./assets/images/source/ic_launcher_border.png 13 | 14 | keywords: 15 | - Hiddify 16 | - Proxy 17 | - VPN 18 | - V2ray 19 | - Nekoray 20 | - Xray 21 | - Psiphon 22 | - OpenVPN 23 | 24 | generic_name: Hiddify 25 | 26 | group: Applications/Internet 27 | 28 | startup_notify: true 29 | -------------------------------------------------------------------------------- /ios/HiddifyPacketTunnel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BASE_BUNDLE_IDENTIFIER 6 | $(BASE_BUNDLE_IDENTIFIER) 7 | NSExtension 8 | 9 | NSExtensionPointIdentifier 10 | com.apple.networkextension.packet-tunnel 11 | NSExtensionPrincipalClass 12 | $(PRODUCT_MODULE_NAME).PacketTunnelProvider 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | export 'alerts.dart'; 2 | export 'async_mutation.dart'; 3 | export 'bottom_sheet_page.dart'; 4 | export 'callback_debouncer.dart'; 5 | export 'custom_loggers.dart'; 6 | export 'custom_text_form_field.dart'; 7 | export 'date_time_formatter.dart'; 8 | export 'link_parsers.dart'; 9 | export 'mutation_state.dart'; 10 | export 'number_formatters.dart'; 11 | export 'placeholders.dart'; 12 | export 'platform_utils.dart'; 13 | export 'sentry_riverpod_observer.dart'; 14 | export 'sentry_utils.dart'; 15 | export 'text_utils.dart'; 16 | export 'uri_utils.dart'; 17 | export 'validators.dart'; 18 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/services/http_service/balance.service.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:hiddify/features/panel/xboard/services/http_service/http_service.dart'; 3 | 4 | class BalanceService { 5 | final HttpService _httpService = HttpService(); 6 | // 划转佣金到余额的方法 7 | Future transferCommission( 8 | String accessToken, 9 | int transferAmount, 10 | ) async { 11 | await _httpService.postRequest( 12 | '/api/v1/user/transfer', 13 | {'transfer_amount': transferAmount}, 14 | headers: {'Authorization': accessToken}, // 需要用户的认证令牌 15 | ); 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gitsubmodule" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | open-pull-requests-limit: 5 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/core/model/environment.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartx/dartx.dart'; 2 | 3 | enum Environment { 4 | prod, 5 | dev; 6 | 7 | static const sentryDSN = String.fromEnvironment("sentry_dsn"); 8 | } 9 | 10 | enum Release { 11 | general("general"), 12 | googlePlay("google-play"); 13 | 14 | const Release(this.key); 15 | 16 | final String key; 17 | 18 | bool get allowCustomUpdateChecker => this == general; 19 | 20 | static Release read() => 21 | Release.values.firstOrNullWhere( 22 | (e) => e.key == const String.fromEnvironment("release"), 23 | ) ?? 24 | Release.general; 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/models/purchase_detail_model.dart: -------------------------------------------------------------------------------- 1 | class PurchaseDetailPlan { 2 | final String name; 3 | final double? monthPrice; 4 | final double? quarterPrice; 5 | final double? halfYearPrice; 6 | final double? yearPrice; 7 | final double? twoYearPrice; 8 | final double? threeYearPrice; 9 | final double? onetimePrice; 10 | 11 | PurchaseDetailPlan({ 12 | required this.name, 13 | this.monthPrice, 14 | this.quarterPrice, 15 | this.halfYearPrice, 16 | this.yearPrice, 17 | this.twoYearPrice, 18 | this.threeYearPrice, 19 | this.onetimePrice, 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/proxy/data/proxy_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/http_client/http_client_provider.dart'; 2 | import 'package:hiddify/features/proxy/data/proxy_repository.dart'; 3 | import 'package:hiddify/singbox/service/singbox_service_provider.dart'; 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'proxy_data_providers.g.dart'; 7 | 8 | @Riverpod(keepAlive: true) 9 | ProxyRepository proxyRepository(ProxyRepositoryRef ref) { 10 | return ProxyRepositoryImpl( 11 | singbox: ref.watch(singboxServiceProvider), 12 | client: ref.watch(httpClientProvider), 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/stats/model/stats_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'stats_entity.freezed.dart'; 4 | 5 | @freezed 6 | class StatsEntity with _$StatsEntity { 7 | const StatsEntity._(); 8 | 9 | const factory StatsEntity({ 10 | required int uplink, 11 | required int downlink, 12 | required int uplinkTotal, 13 | required int downlinkTotal, 14 | }) = _StatsEntity; 15 | 16 | factory StatsEntity.empty() => const StatsEntity( 17 | uplink: 0, 18 | downlink: 0, 19 | uplinkTotal: 0, 20 | downlinkTotal: 0, 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/shortcuts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - 'v[0-9]+.[0-9]+.[0-9]+' 6 | - 'v[0-9]+.[0-9]+.[0-9]+.*' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | build-release: 14 | uses: ./.github/workflows/build.yml 15 | secrets: inherit 16 | permissions: write-all 17 | with: 18 | upload-artifact: true 19 | tag-name: "${{ github.ref_name }}" 20 | channel: "${{ github.ref_type == 'tag' && endsWith(github.ref_name, 'dev') && 'dev' || github.ref_type != 'tag' && 'dev' || 'prod' }}" 21 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/bg/ProxyService.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.bg 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | 6 | class ProxyService : Service(), PlatformInterfaceWrapper { 7 | 8 | private val service = BoxService(this, this) 9 | 10 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = 11 | service.onStartCommand(intent, flags, startId) 12 | 13 | override fun onBind(intent: Intent) = service.onBind(intent) 14 | override fun onDestroy() = service.onDestroy() 15 | 16 | override fun writeLog(message: String) = service.writeLog(message) 17 | } -------------------------------------------------------------------------------- /distribute_options.yaml: -------------------------------------------------------------------------------- 1 | output: dist/ 2 | releases: 3 | - name: prod 4 | jobs: 5 | - name: release-windows-exe 6 | package: 7 | platform: windows 8 | target: exe 9 | 10 | - name: release-android-apk 11 | package: 12 | platform: android 13 | target: apk 14 | build_args: 15 | target-platform: android-arm,android-arm64,android-x64 16 | 17 | - name: release-android-bundle 18 | package: 19 | platform: android 20 | target: aab 21 | build_args: 22 | target-platform: android-arm,android-arm64,android-x64 23 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/ktx/Wrappers.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.ktx 2 | 3 | import android.net.IpPrefix 4 | import android.os.Build 5 | import androidx.annotation.RequiresApi 6 | import io.nekohasekai.libbox.RoutePrefix 7 | import io.nekohasekai.libbox.StringIterator 8 | import java.net.InetAddress 9 | 10 | fun StringIterator.toList(): List { 11 | return mutableListOf().apply { 12 | while (hasNext()) { 13 | add(next()) 14 | } 15 | } 16 | } 17 | 18 | @RequiresApi(Build.VERSION_CODES.TIRAMISU) 19 | fun RoutePrefix.toIpPrefix() = IpPrefix(InetAddress.getByName(address()), prefix()) -------------------------------------------------------------------------------- /lib/main_prod.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:hiddify/bootstrap.dart'; 4 | import 'package:hiddify/core/model/environment.dart'; 5 | 6 | void main() async { 7 | final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); 8 | 9 | SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); 10 | SystemChrome.setSystemUIOverlayStyle( 11 | const SystemUiOverlayStyle( 12 | statusBarColor: Colors.transparent, 13 | systemNavigationBarColor: Colors.transparent, 14 | ), 15 | ); 16 | 17 | return lazyBootstrap(widgetsBinding, Environment.prod); 18 | } 19 | -------------------------------------------------------------------------------- /lib/utils/callback_debouncer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | class CallbackDebouncer { 6 | CallbackDebouncer(this._delay); 7 | 8 | final Duration _delay; 9 | Timer? _timer; 10 | 11 | /// Calls the given [callback] after the given duration has passed. 12 | void call(VoidCallback callback) { 13 | if (_delay == Duration.zero) { 14 | callback(); 15 | } else { 16 | _timer?.cancel(); 17 | _timer = Timer(_delay, callback); 18 | } 19 | } 20 | 21 | /// Stops any running timers and disposes this instance. 22 | void dispose() { 23 | _timer?.cancel(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/per_app_proxy/model/installed_package_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'installed_package_info.freezed.dart'; 4 | part 'installed_package_info.g.dart'; 5 | 6 | @freezed 7 | class InstalledPackageInfo with _$InstalledPackageInfo { 8 | @JsonSerializable(fieldRename: FieldRename.kebab) 9 | const factory InstalledPackageInfo({ 10 | required String packageName, 11 | required String name, 12 | required bool isSystemApp, 13 | }) = _InstalledPackageInfo; 14 | 15 | factory InstalledPackageInfo.fromJson(Map json) => 16 | _$InstalledPackageInfoFromJson(json); 17 | } 18 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /linux/packaging/deb/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: Hiddify 2 | package_name: hiddify 3 | maintainer: 4 | name: hiddify 5 | email: linux@hiddify.com 6 | 7 | priority: optional 8 | section: x11 9 | installed_size: 6604 10 | essential: false 11 | icon: ./assets/images/source/ic_launcher_border.png 12 | 13 | postinstall_scripts: 14 | - echo "Installed Hiddify" 15 | postuninstall_scripts: 16 | - echo "Surprised Why?" 17 | 18 | keywords: 19 | - Hiddify 20 | - Proxy 21 | - VPN 22 | - V2ray 23 | - Nekoray 24 | - Xray 25 | - Psiphon 26 | - OpenVPN 27 | 28 | generic_name: Hiddify 29 | 30 | categories: 31 | - Network 32 | 33 | startup_notify: true 34 | -------------------------------------------------------------------------------- /windows/packaging/msix/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: Hiddify 2 | publisher_display_name: Hiddify 3 | identity_name: Hiddify.HiddifyNext 4 | msix_version: 2.5.7.0 5 | logo_path: windows\runner\resources\app_icon.ico 6 | capabilities: internetClient, internetClientServer, privateNetworkClientServer 7 | languages: en-us, zh-cn, zh-tw, tr-tr,fa-ir,ru-ru,pt-br,es-es 8 | protocol_activation: hiddify 9 | execution_alias: hiddify 10 | certificate_path: windows\sign.pfx 11 | certificate_password: 12 | publisher: CN=8CB43675-F44B-4AA5-9372-E8727781BDC4 13 | install_certificate: "false" 14 | enable_at_startup: "true" 15 | startup_task: 16 | parameters: --autostart 17 | -------------------------------------------------------------------------------- /lib/core/model/region.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/localization/translations.dart'; 2 | 3 | enum Region { 4 | ir, 5 | cn, 6 | ru, 7 | af, 8 | id, 9 | tr, 10 | br, 11 | other; 12 | 13 | String present(TranslationsEn t) => switch (this) { 14 | ir => t.settings.general.regions.ir, 15 | cn => t.settings.general.regions.cn, 16 | ru => t.settings.general.regions.ru, 17 | tr => t.settings.general.regions.tr, 18 | af => t.settings.general.regions.af, 19 | id => t.settings.general.regions.id, 20 | br => t.settings.general.regions.br, 21 | other => t.settings.general.regions.other, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /lib/utils/number_formatters.dart: -------------------------------------------------------------------------------- 1 | import 'package:humanizer/humanizer.dart'; 2 | 3 | extension ByteFormatter on int { 4 | String size() => bytes().toString(); 5 | 6 | static final _sizeOfFormat = 7 | InformationSizeFormat(permissibleValueUnits: {InformationUnit.gibibyte}); 8 | 9 | String sizeGB() => _sizeOfFormat.format(bytes()); 10 | 11 | String sizeOf(int total) => 12 | "${_sizeOfFormat.format(bytes())} / ${_sizeOfFormat.format(total.bytes())}"; 13 | 14 | static final _rateFormat = 15 | InformationRateFormat(permissibleRateUnits: {RateUnit.second}); 16 | 17 | String speed() => _rateFormat.format(bytes().per(const Duration(seconds: 1))); 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dart.lineLength": 250, 3 | "[dart]": { 4 | "editor.defaultFormatter": "Dart-Code.dart-code", 5 | "editor.formatOnSave": true, 6 | "editor.formatOnType": true, 7 | "editor.tabSize": 2, 8 | "editor.rulers": [ 9 | 250 10 | ], 11 | "editor.detectIndentation": false, 12 | "editor.selectionHighlight": false, 13 | "editor.suggest.snippetsPreventQuickSuggestions": false, 14 | "editor.suggestSelection": "first", 15 | "editor.tabCompletion": "onlySnippets", 16 | "editor.wordBasedSuggestions": "off" 17 | }, 18 | 19 | "html.format.wrapLineLength": 250, 20 | 21 | } -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = Hiddify 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = app.hiddify.com 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 hiddify.com. All rights reserved. 15 | -------------------------------------------------------------------------------- /lib/features/config_option/data/config_option_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/preferences/preferences_provider.dart'; 2 | import 'package:hiddify/features/config_option/data/config_option_repository.dart'; 3 | 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'config_option_data_providers.g.dart'; 7 | 8 | @Riverpod(keepAlive: true) 9 | ConfigOptionRepository configOptionRepository( 10 | ConfigOptionRepositoryRef ref, 11 | ) { 12 | return ConfigOptionRepository( 13 | preferences: ref.watch(sharedPreferencesProvider).requireValue, 14 | getConfigOptions: () => ref.read(ConfigOptions.singboxConfigOptions.future), 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/mutation_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/model/failures.dart'; 3 | 4 | part 'mutation_state.freezed.dart'; 5 | 6 | // TODO: remove 7 | @freezed 8 | class MutationState with _$MutationState { 9 | const MutationState._(); 10 | 11 | const factory MutationState.initial() = MutationInitial; 12 | const factory MutationState.inProgress() = MutationInProgress; 13 | const factory MutationState.failure(Failure failure) = MutationFailure; 14 | const factory MutationState.success() = MutationSuccess; 15 | 16 | bool get isInProgress => this is MutationInProgress; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/services/auth_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:go_router/go_router.dart'; 3 | import 'package:hiddify/features/panel/xboard/utils/storage/token_storage.dart'; 4 | 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | 7 | final authProvider = StateProvider((ref) { 8 | // 初始为未登录状态 9 | return false; 10 | }); 11 | // 定义一个登出函数 12 | Future logout(BuildContext context, WidgetRef ref) async { 13 | // 清除存储的 token 14 | await deleteToken(); 15 | // 更新 authProvider 状态为未登录 16 | ref.read(authProvider.notifier).state = false; 17 | // 跳转到登录页面 18 | if (context.mounted) { 19 | context.go('/'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/utils/storage/token_storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | Future storeToken(String token) async { 5 | final prefs = await SharedPreferences.getInstance(); 6 | await prefs.setString('auth_token', token); 7 | if (kDebugMode) { 8 | print('Token stored: $token'); 9 | } 10 | } 11 | 12 | Future getToken() async { 13 | final prefs = await SharedPreferences.getInstance(); 14 | return prefs.getString('auth_token'); 15 | } 16 | 17 | Future deleteToken() async { 18 | final prefs = await SharedPreferences.getInstance(); 19 | await prefs.remove('auth_token'); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/settings/widgets/sections_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SettingsSection extends StatelessWidget { 4 | const SettingsSection(this.title, {super.key}); 5 | 6 | final String title; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return ListTile( 11 | title: Text(title), 12 | titleTextStyle: Theme.of(context).textTheme.titleSmall, 13 | dense: true, 14 | ); 15 | } 16 | } 17 | 18 | class SettingsDivider extends StatelessWidget { 19 | const SettingsDivider({super.key}); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return const Divider(indent: 16, endIndent: 16); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/singbox/model/singbox_stats.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'singbox_stats.freezed.dart'; 4 | part 'singbox_stats.g.dart'; 5 | 6 | @freezed 7 | class SingboxStats with _$SingboxStats { 8 | const SingboxStats._(); 9 | 10 | @JsonSerializable(fieldRename: FieldRename.kebab) 11 | const factory SingboxStats({ 12 | required int connectionsIn, 13 | required int connectionsOut, 14 | required int uplink, 15 | required int downlink, 16 | required int uplinkTotal, 17 | required int downlinkTotal, 18 | }) = _SingboxStats; 19 | 20 | factory SingboxStats.fromJson(Map json) => 21 | _$SingboxStatsFromJson(json); 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/log/overview/logs_overview_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/features/log/model/log_entity.dart'; 3 | import 'package:hiddify/features/log/model/log_level.dart'; 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'logs_overview_state.freezed.dart'; 7 | 8 | @freezed 9 | class LogsOverviewState with _$LogsOverviewState { 10 | const LogsOverviewState._(); 11 | 12 | const factory LogsOverviewState({ 13 | @Default(AsyncLoading()) AsyncValue> logs, 14 | @Default(false) bool paused, 15 | @Default("") String filter, 16 | LogLevel? levelFilter, 17 | }) = _LogsOverviewState; 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/profile/model/profile_sort_enum.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluentui_system_icons/fluentui_system_icons.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hiddify/core/localization/translations.dart'; 4 | 5 | enum ProfilesSort { 6 | lastUpdate, 7 | name; 8 | 9 | String present(TranslationsEn t) { 10 | return switch (this) { 11 | lastUpdate => t.profile.sortBy.lastUpdate, 12 | name => t.profile.sortBy.name, 13 | }; 14 | } 15 | 16 | IconData get icon => switch (this) { 17 | lastUpdate => FluentIcons.history_24_regular, 18 | name => FluentIcons.text_sort_ascending_24_regular, 19 | }; 20 | } 21 | 22 | enum SortMode { ascending, descending } 23 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:hiddify/bootstrap.dart'; 4 | // 导入环境配置文件 5 | import 'package:hiddify/core/model/environment.dart'; 6 | 7 | // 应用程序的主入口函数 8 | void main() async { 9 | // 确保Flutter的Widgets绑定已初始化 10 | final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); 11 | 12 | SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); 13 | SystemChrome.setSystemUIOverlayStyle( 14 | const SystemUiOverlayStyle( 15 | statusBarColor: Colors.transparent, 16 | systemNavigationBarColor: Colors.transparent, 17 | ), 18 | ); 19 | 20 | return lazyBootstrap(widgetsBinding, Environment.dev); 21 | } 22 | -------------------------------------------------------------------------------- /ios/.stignore: -------------------------------------------------------------------------------- 1 | /**/dgph 2 | /*.mode1v3 3 | /*.mode2v3 4 | /*.moved-aside 5 | /*.pbxuser 6 | /*.perspectivev3 7 | /**/*sync/ 8 | /.sconsign.dblite 9 | /.tags* 10 | /**/.vagrant/ 11 | /**/DerivedData/ 12 | /Icon? 13 | /**/Pods/ 14 | /**/.symlinks/ 15 | /profile 16 | /xcuserdata 17 | /**/.generated/ 18 | /Flutter/App.framework 19 | /Flutter/Flutter.framework 20 | /Flutter/Flutter.podspec 21 | /Flutter/Generated.xcconfig 22 | /Flutter/ephemeral/ 23 | /Flutter/app.flx 24 | /Flutter/app.zip 25 | /Flutter/flutter_assets/ 26 | /Flutter/flutter_export_environment.sh 27 | /ServiceDefinitions.json 28 | /Runner/GeneratedPluginRegistrant.* 29 | 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/HiddifyPacketTunnel/HiddifyPacketTunnel.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.security.app-sandbox 10 | 11 | com.apple.security.application-groups 12 | 13 | group.$(BASE_BUNDLE_IDENTIFIER) 14 | 15 | com.apple.security.network.client 16 | 17 | com.apple.security.network.server 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import window_manager 4 | 5 | class MainFlutterWindow: NSWindow { 6 | override func awakeFromNib() { 7 | let flutterViewController = FlutterViewController() 8 | let windowFrame = self.frame 9 | self.contentViewController = flutterViewController 10 | self.setFrame(windowFrame, display: true) 11 | 12 | RegisterGeneratedPlugins(registry: flutterViewController) 13 | 14 | super.awakeFromNib() 15 | } 16 | 17 | // window manager hidden at launch 18 | override public func order(_ place: NSWindow.OrderingMode, relativeTo otherWin: Int) { 19 | super.order(place, relativeTo: otherWin) 20 | hiddenWindowAtLaunch() 21 | } 22 | } -------------------------------------------------------------------------------- /ios/Local Packages/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.4 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Hiddify Packages", 8 | platforms: [ 9 | // Minimum platform version 10 | .iOS(.v13) 11 | ], 12 | products: [ 13 | .library( 14 | name: "Libcore", 15 | targets: ["Libcore"]), 16 | ], 17 | dependencies: [ 18 | // No dependencies 19 | ], 20 | targets: [ 21 | .binaryTarget( 22 | name: "Libcore", 23 | path: "../Frameworks/Libcore.xcframework" 24 | ) 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/viewmodels/dialog_viewmodel/purchase_details_viewmodel_provider.dart: -------------------------------------------------------------------------------- 1 | // purchase_details_view_model_provider.dart 2 | 3 | import 'package:hiddify/features/panel/xboard/viewmodels/dialog_viewmodel/purchase_details_viewmodel.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | 6 | 7 | class PurchaseDetailsViewModelParams { 8 | final int planId; 9 | 10 | PurchaseDetailsViewModelParams({ 11 | required this.planId, 12 | }); 13 | } 14 | 15 | final purchaseDetailsViewModelProvider = ChangeNotifierProvider.autoDispose 16 | .family( 17 | (ref, params) => PurchaseDetailsViewModel( 18 | planId: params.planId, 19 | ), 20 | ); 21 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/services/http_service/plan_service.dart: -------------------------------------------------------------------------------- 1 | // services/plan_service.dart 2 | import 'package:hiddify/features/panel/xboard/models/plan_model.dart'; 3 | import 'package:hiddify/features/panel/xboard/services/http_service/http_service.dart'; 4 | 5 | 6 | class PlanService { 7 | final HttpService _httpService = HttpService(); 8 | 9 | Future> fetchPlanData(String accessToken) async { 10 | final result = await _httpService.getRequest( 11 | "/api/v1/user/plan/fetch", 12 | headers: {'Authorization': accessToken}, 13 | ); 14 | return (result["data"] as List) 15 | .cast>() 16 | .map((json) => Plan.fromJson(json)) 17 | .toList(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/singbox/model/warp_account.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | typedef WarpResponse = ({ 4 | String log, 5 | String accountId, 6 | String accessToken, 7 | String wireguardConfig, 8 | }); 9 | 10 | WarpResponse warpFromJson(dynamic json) { 11 | if (json 12 | case { 13 | "account-id": final String newAccountId, 14 | "access-token": final String newAccessToken, 15 | "log": final String log, 16 | "config": final Map wireguardConfig, 17 | }) { 18 | return ( 19 | log: log, 20 | accountId: newAccountId, 21 | accessToken: newAccessToken, 22 | wireguardConfig: jsonEncode(wireguardConfig), 23 | ); 24 | } 25 | throw Exception("invalid response"); 26 | } 27 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.networking.networkextension 8 | 9 | packet-tunnel-provider 10 | 11 | com.apple.security.app-sandbox 12 | 13 | com.apple.security.application-groups 14 | 15 | group.$(BASE_BUNDLE_IDENTIFIER) 16 | 17 | com.apple.security.network.client 18 | 19 | com.apple.security.network.server 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /.github/workflows/add_signed_microsft.yml: -------------------------------------------------------------------------------- 1 | name: Upload store MSIX to release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | release: 8 | types: [released] # Run the action when a GitHub release is published 9 | 10 | schedule: 11 | - cron: '0 */6 * * *' # Run the action every 6 hours 12 | 13 | workflow_dispatch: # Manually run the action 14 | 15 | jobs: 16 | upload-store-msix-to-release: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Upload store MSIX to release 21 | uses: hiddify/Upload-Microsoft-Store-MSIX-Package-to-GitHub-Release@develop 22 | with: 23 | store-id: 9pdfnl3qv2s5 24 | token: ${{ secrets.GITHUB_TOKEN }} 25 | asset-name-pattern: Hiddify-Windows-Setup-x64 # Optional -------------------------------------------------------------------------------- /lib/utils/text_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart' as intl; 3 | 4 | extension TextAlignX on BuildContext { 5 | bool get isRtl => Directionality.of(this) == TextDirection.rtl; 6 | 7 | TextAlign get textAlign { 8 | if (isRtl) { 9 | return TextAlign.right; 10 | } else { 11 | return TextAlign.left; 12 | } 13 | } 14 | } 15 | 16 | extension StringX on String { 17 | TextDirection get textDirection { 18 | return intl.Bidi.detectRtlDirectionality(this) ? TextDirection.rtl : TextDirection.ltr; 19 | } 20 | } 21 | 22 | extension TextEditingControllerX on TextEditingController { 23 | TextDirection? get textDirection { 24 | if (text.isEmpty) return null; 25 | return text.textDirection; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/app_update/model/remote_version_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/model/environment.dart'; 3 | 4 | part 'remote_version_entity.freezed.dart'; 5 | 6 | @Freezed() 7 | class RemoteVersionEntity with _$RemoteVersionEntity { 8 | const RemoteVersionEntity._(); 9 | 10 | const factory RemoteVersionEntity({ 11 | required String version, 12 | required String buildNumber, 13 | required String releaseTag, 14 | required bool preRelease, 15 | required String url, 16 | required DateTime publishedAt, 17 | required Environment flavor, 18 | }) = _RemoteVersionEntity; 19 | 20 | String get presentVersion => 21 | flavor == Environment.prod ? version : "$version ${flavor.name}"; 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/logger/logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:loggy/loggy.dart'; 3 | 4 | class Logger { 5 | static final app = Loggy("app"); 6 | static final bootstrap = Loggy("bootstrap"); 7 | 8 | static void logFlutterError(FlutterErrorDetails details) { 9 | if (details.silent) { 10 | return; 11 | } 12 | 13 | final description = details.exceptionAsString(); 14 | 15 | app.error( 16 | 'Flutter Error: $description', 17 | details.exception, 18 | details.stack, 19 | ); 20 | } 21 | 22 | static bool logPlatformDispatcherError(Object error, StackTrace stackTrace) { 23 | app.error( 24 | 'PlatformDispatcherError: $error', 25 | error, 26 | stackTrace, 27 | ); 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/log/model/log_level.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | import 'package:dartx/dartx.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | part 'log_level.mapper.dart'; 6 | 7 | @MappableEnum() 8 | enum LogLevel { 9 | trace, 10 | debug, 11 | info, 12 | warn, 13 | error, 14 | fatal, 15 | panic; 16 | 17 | /// [LogLevel] selectable by user as preference 18 | static List get choices => values.takeFirst(4); 19 | 20 | Color? get color => switch (this) { 21 | trace => Colors.lightBlueAccent, 22 | debug => Colors.grey, 23 | info => Colors.lightGreen, 24 | warn => Colors.orange, 25 | error => Colors.redAccent, 26 | fatal => Colors.red, 27 | panic => Colors.red, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/core/theme/app_theme_mode.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | 4 | enum AppThemeMode { 5 | system, 6 | light, 7 | dark, 8 | black; 9 | 10 | String present(TranslationsEn t) => switch (this) { 11 | system => t.settings.general.themeModes.system, 12 | light => t.settings.general.themeModes.light, 13 | dark => t.settings.general.themeModes.dark, 14 | black => t.settings.general.themeModes.black, 15 | }; 16 | 17 | ThemeMode get flutterThemeMode => switch (this) { 18 | system => ThemeMode.system, 19 | light => ThemeMode.light, 20 | dark => ThemeMode.dark, 21 | black => ThemeMode.dark, 22 | }; 23 | 24 | bool get trueBlack => this == black; 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/log/model/log_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/core/model/failures.dart'; 4 | 5 | part 'log_failure.freezed.dart'; 6 | 7 | @freezed 8 | sealed class LogFailure with _$LogFailure, Failure { 9 | const LogFailure._(); 10 | 11 | @With() 12 | const factory LogFailure.unexpected([ 13 | Object? error, 14 | StackTrace? stackTrace, 15 | ]) = LogUnexpectedFailure; 16 | 17 | @override 18 | ({String type, String? message}) present(TranslationsEn t) { 19 | return switch (this) { 20 | LogUnexpectedFailure() => ( 21 | type: t.failure.unexpected, 22 | message: null, 23 | ), 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/core/database/generated_migrations/schema.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE, DO NOT EDIT BY HAND. 2 | // ignore_for_file: type=lint 3 | //@dart=2.12 4 | import 'package:drift/drift.dart'; 5 | import 'package:drift/internal/migrations.dart'; 6 | import 'schema_v1.dart' as v1; 7 | import 'schema_v2.dart' as v2; 8 | import 'schema_v3.dart' as v3; 9 | 10 | class GeneratedHelper implements SchemaInstantiationHelper { 11 | @override 12 | GeneratedDatabase databaseForVersion(QueryExecutor db, int version) { 13 | switch (version) { 14 | case 1: 15 | return v1.DatabaseAtV1(db); 16 | case 2: 17 | return v2.DatabaseAtV2(db); 18 | case 3: 19 | return v3.DatabaseAtV3(db); 20 | default: 21 | throw MissingSchemaException(version, const {1, 2, 3}); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ios/HiddifyPacketTunnel/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategorySystemBootTime 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | 35F9.1 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /lib/features/stats/model/stats_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/core/model/failures.dart'; 4 | 5 | part 'stats_failure.freezed.dart'; 6 | 7 | @freezed 8 | sealed class StatsFailure with _$StatsFailure, Failure { 9 | const StatsFailure._(); 10 | 11 | @With() 12 | const factory StatsFailure.unexpected([ 13 | Object? error, 14 | StackTrace? stackTrace, 15 | ]) = StatsUnexpectedFailure; 16 | 17 | @override 18 | ({String type, String? message}) present(TranslationsEn t) { 19 | return switch (this) { 20 | StatsUnexpectedFailure() => ( 21 | type: t.failure.unexpected, 22 | message: null, 23 | ), 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/geo_asset/model/geo_asset_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'geo_asset_entity.freezed.dart'; 4 | 5 | enum GeoAssetType { geoip, geosite } 6 | 7 | typedef GeoAssetWithFileSize = (GeoAssetEntity geoAsset, int? size); 8 | 9 | @freezed 10 | class GeoAssetEntity with _$GeoAssetEntity { 11 | const GeoAssetEntity._(); 12 | 13 | const factory GeoAssetEntity({ 14 | required String id, 15 | required String name, 16 | required GeoAssetType type, 17 | required bool active, 18 | required String providerName, 19 | String? version, 20 | DateTime? lastCheck, 21 | }) = _GeoAssetEntity; 22 | 23 | String get fileName => name; 24 | 25 | String get repositoryUrl => 26 | "https://api.github.com/repos/$providerName/releases/latest"; 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | paths-ignore: 5 | - '**.md' 6 | - 'docs/**' 7 | - '.vscode/' 8 | - 'appcast.xml' 9 | push: 10 | branches: 11 | - main 12 | - dev 13 | - android-fix-action-bug 14 | paths-ignore: 15 | - '**.md' 16 | - 'docs/**' 17 | - '.vscode/' 18 | - 'appcast.xml' 19 | 20 | concurrency: 21 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 22 | cancel-in-progress: true 23 | 24 | jobs: 25 | run: 26 | uses: ./.github/workflows/build.yml 27 | secrets: inherit 28 | permissions: write-all 29 | if: "${{!contains(github.event.head_commit.message, 'release: version')}}" 30 | with: 31 | upload-artifact: ${{ github.event_name == 'push' }} 32 | 33 | -------------------------------------------------------------------------------- /lib/utils/custom_loggers.dart: -------------------------------------------------------------------------------- 1 | import 'package:loggy/loggy.dart'; 2 | 3 | /// application layer logger 4 | /// 5 | /// used in notifiers and controllers 6 | mixin AppLogger implements LoggyType { 7 | @override 8 | Loggy get loggy => Loggy('$runtimeType'); 9 | } 10 | 11 | /// presentation layer logger 12 | /// 13 | /// used in widgets and ui 14 | mixin PresLogger implements LoggyType { 15 | @override 16 | Loggy get loggy => Loggy('$runtimeType'); 17 | } 18 | 19 | /// data layer logger 20 | /// 21 | /// used in Repositories, DAOs, Services 22 | mixin InfraLogger implements LoggyType { 23 | @override 24 | Loggy get loggy => Loggy('$runtimeType'); 25 | } 26 | 27 | abstract class LoggerMixin { 28 | LoggerMixin(this.loggy); 29 | 30 | final Loggy loggy; 31 | } 32 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.4.2" apply false 22 | id "org.jetbrains.kotlin.android" version "1.8.21" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /lib/features/settings/model/settings_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/core/model/failures.dart'; 4 | 5 | part 'settings_failure.freezed.dart'; 6 | 7 | @freezed 8 | sealed class SettingsFailure with _$SettingsFailure, Failure { 9 | const SettingsFailure._(); 10 | 11 | @With() 12 | const factory SettingsFailure.unexpected([ 13 | Object? error, 14 | StackTrace? stackTrace, 15 | ]) = SettingsUnexpectedFailure; 16 | 17 | @override 18 | ({String type, String? message}) present(TranslationsEn t) { 19 | return switch (this) { 20 | SettingsUnexpectedFailure() => ( 21 | type: t.failure.unexpected, 22 | message: null, 23 | ), 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/core/widget/adaptive_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluentui_system_icons/fluentui_system_icons.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AdaptiveIcon { 5 | AdaptiveIcon(BuildContext context) : platform = Theme.of(context).platform; 6 | 7 | final TargetPlatform platform; 8 | 9 | IconData get more => switch (platform) { 10 | TargetPlatform.iOS || 11 | TargetPlatform.macOS => 12 | FluentIcons.more_horizontal_24_regular, 13 | _ => FluentIcons.more_vertical_24_regular, 14 | }; 15 | 16 | IconData get share => switch (platform) { 17 | TargetPlatform.android => FluentIcons.share_android_24_regular, 18 | TargetPlatform.iOS || 19 | TargetPlatform.macOS => 20 | FluentIcons.share_ios_24_regular, 21 | _ => FluentIcons.share_24_regular, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/app_update/model/app_update_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/core/model/failures.dart'; 4 | 5 | part 'app_update_failure.freezed.dart'; 6 | 7 | @freezed 8 | sealed class AppUpdateFailure with _$AppUpdateFailure, Failure { 9 | const AppUpdateFailure._(); 10 | 11 | @With() 12 | const factory AppUpdateFailure.unexpected([ 13 | Object? error, 14 | StackTrace? stackTrace, 15 | ]) = AppUpdateUnexpectedFailure; 16 | 17 | @override 18 | ({String type, String? message}) present(TranslationsEn t) { 19 | return switch (this) { 20 | AppUpdateUnexpectedFailure() => ( 21 | type: t.failure.unexpected, 22 | message: null, 23 | ), 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/per_app_proxy/model/per_app_proxy_mode.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/localization/translations.dart'; 2 | 3 | enum PerAppProxyMode { 4 | off, 5 | include, 6 | exclude; 7 | 8 | bool get enabled => this != off; 9 | 10 | ({String title, String message}) present(TranslationsEn t) => switch (this) { 11 | off => ( 12 | title: t.settings.network.perAppProxyModes.off, 13 | message: t.settings.network.perAppProxyModes.offMsg, 14 | ), 15 | include => ( 16 | title: t.settings.network.perAppProxyModes.include, 17 | message: t.settings.network.perAppProxyModes.includeMsg, 18 | ), 19 | exclude => ( 20 | title: t.settings.network.perAppProxyModes.exclude, 21 | message: t.settings.network.perAppProxyModes.excludeMsg, 22 | ), 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /lib/core/http_client/http_client_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:hiddify/core/app_info/app_info_provider.dart'; 3 | import 'package:hiddify/core/http_client/dio_http_client.dart'; 4 | import 'package:hiddify/features/config_option/data/config_option_repository.dart'; 5 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 6 | 7 | part 'http_client_provider.g.dart'; 8 | 9 | @Riverpod(keepAlive: true) 10 | DioHttpClient httpClient(HttpClientRef ref) { 11 | final client = DioHttpClient( 12 | timeout: const Duration(seconds: 15), 13 | userAgent: ref.watch(appInfoProvider).requireValue.userAgent, 14 | debug: kDebugMode, 15 | ); 16 | 17 | ref.listen( 18 | ConfigOptions.mixedPort, 19 | (_, next) async { 20 | client.setProxyPort(next); 21 | }, 22 | fireImmediately: true, 23 | ); 24 | return client; 25 | } 26 | -------------------------------------------------------------------------------- /lib/core/localization/locale_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:hiddify/gen/fonts.gen.dart'; 4 | import 'package:hiddify/gen/translations.g.dart'; 5 | 6 | extension AppLocaleX on AppLocale { 7 | String get preferredFontFamily => this == AppLocale.fa ? FontFamily.shabnam : (!Platform.isWindows ? "" : FontFamily.emoji); 8 | 9 | String get localeName => switch (flutterLocale.toString()) { 10 | "en" => "English", 11 | "fa" => "فارسی", 12 | "ar" => "العربية", 13 | "ckb-KUR" => "کوردی سۆرانی", 14 | "ru" => "Русский", 15 | "zh" || "zh_CN" => "中文 (中国)", 16 | "zh_TW" => "中文 (台湾)", 17 | "tr" => "Türkçe", 18 | "es" => "Spanish", 19 | "id" => "Indonesian", 20 | "hi" => "हिन्दी", 21 | "pt_BR" => "Portuguese (Brazil)", 22 | "fr" => "Français", 23 | _ => "Unknown", 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /lib/utils/bottom_sheet_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomSheetPage extends Page { 4 | const BottomSheetPage({ 5 | super.key, 6 | super.name, 7 | required this.builder, 8 | this.fixed = false, 9 | }); 10 | 11 | final Widget Function(ScrollController? controller) builder; 12 | final bool fixed; 13 | 14 | @override 15 | Route createRoute(BuildContext context) { 16 | return ModalBottomSheetRoute( 17 | settings: this, 18 | isScrollControlled: true, 19 | useSafeArea: true, 20 | showDragHandle: true, 21 | builder: (_) { 22 | if (!fixed) { 23 | return DraggableScrollableSheet( 24 | expand: false, 25 | builder: (_, scrollController) => builder(scrollController), 26 | ); 27 | } 28 | return builder(null); 29 | }, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 15.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/packaging/ios/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: Hiddify 2 | 3 | icon: ..\..\assets\images\windows.ico 4 | 5 | keywords: 6 | - Hiddify 7 | - Proxy 8 | - VPN 9 | - V2ray 10 | - Nekoray 11 | - Xray 12 | - Psiphon 13 | - OpenVPN 14 | 15 | generic_name: Hiddify 16 | 17 | actions: 18 | - name: Start 19 | label: start 20 | arguments: 21 | - --start 22 | - name: Stop 23 | label: stop 24 | arguments: 25 | - --stop 26 | 27 | categories: 28 | - Internet 29 | 30 | startup_notify: true 31 | 32 | # You can specify the shared libraries that you want to bundle with your app 33 | # 34 | # flutter_distributor automatically detects the shared libraries that your app 35 | # depends on, but you can also specify them manually here. 36 | # 37 | # The following example shows how to bundle the libcurl library with your app. 38 | # 39 | # include: 40 | # - libcurl.so.4 41 | include: [] 42 | 43 | -------------------------------------------------------------------------------- /lib/core/theme/theme_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/preferences/preferences_provider.dart'; 2 | import 'package:hiddify/core/theme/app_theme_mode.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | 5 | part 'theme_preferences.g.dart'; 6 | 7 | @Riverpod(keepAlive: true) 8 | class ThemePreferences extends _$ThemePreferences { 9 | @override 10 | AppThemeMode build() { 11 | final persisted = ref 12 | .watch(sharedPreferencesProvider) 13 | .requireValue 14 | .getString("theme_mode"); 15 | if (persisted == null) return AppThemeMode.system; 16 | return AppThemeMode.values.byName(persisted); 17 | } 18 | 19 | Future changeThemeMode(AppThemeMode value) async { 20 | state = value; 21 | await ref 22 | .read(sharedPreferencesProvider) 23 | .requireValue 24 | .setString("theme_mode", value.name); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/profile/details/profile_details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/features/profile/model/profile_entity.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | 5 | part 'profile_details_state.freezed.dart'; 6 | 7 | @freezed 8 | class ProfileDetailsState with _$ProfileDetailsState { 9 | const ProfileDetailsState._(); 10 | 11 | const factory ProfileDetailsState({ 12 | required ProfileEntity profile, 13 | @Default(false) bool isEditing, 14 | @Default(false) bool showErrorMessages, 15 | AsyncValue? save, 16 | AsyncValue? update, 17 | AsyncValue? delete, 18 | @Default("") String configContent, 19 | @Default(false) bool configContentChanged, 20 | }) = _ProfileDetailsState; 21 | 22 | bool get isBusy => save is AsyncLoading || delete is AsyncLoading || update is AsyncLoading; 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/services/http_service/payment_service.dart: -------------------------------------------------------------------------------- 1 | // services/payment_service.dart 2 | import 'package:hiddify/features/panel/xboard/services/http_service/http_service.dart'; 3 | 4 | class PaymentService { 5 | final HttpService _httpService = HttpService(); 6 | 7 | Future> submitOrder( 8 | String tradeNo, String method, String accessToken,) async { 9 | return await _httpService.postRequest( 10 | "/api/v1/user/order/checkout", 11 | {"trade_no": tradeNo, "method": method}, 12 | headers: {'Authorization': accessToken}, 13 | ); 14 | } 15 | 16 | Future> getPaymentMethods(String accessToken) async { 17 | final response = await _httpService.getRequest( 18 | "/api/v1/user/order/getPaymentMethod", 19 | headers: {'Authorization': accessToken}, 20 | ); 21 | return (response['data'] as List).cast(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/geo_asset/data/geo_asset_data_mapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:drift/drift.dart'; 2 | import 'package:hiddify/core/database/app_database.dart'; 3 | import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart'; 4 | 5 | extension GeoAssetEntityMapper on GeoAssetEntity { 6 | GeoAssetEntriesCompanion toEntry() { 7 | return GeoAssetEntriesCompanion.insert( 8 | id: id, 9 | type: type, 10 | active: active, 11 | name: name, 12 | providerName: providerName, 13 | version: Value(version), 14 | lastCheck: Value(lastCheck), 15 | ); 16 | } 17 | } 18 | 19 | extension GeoAssetEntryMapper on GeoAssetEntry { 20 | GeoAssetEntity toEntity() { 21 | return GeoAssetEntity( 22 | id: id, 23 | name: name, 24 | type: type, 25 | active: active, 26 | providerName: providerName, 27 | version: version, 28 | lastCheck: lastCheck, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /linux/packaging/appimage/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: Hiddify 2 | 3 | icon: ./assets/images/source/ic_launcher_border.png 4 | 5 | keywords: 6 | - Hiddify 7 | - Proxy 8 | - VPN 9 | - V2ray 10 | - Nekoray 11 | - Xray 12 | - Psiphon 13 | - OpenVPN 14 | 15 | generic_name: Hiddify 16 | 17 | actions: 18 | - name: Start 19 | label: start 20 | arguments: 21 | - --start 22 | - name: Stop 23 | label: stop 24 | arguments: 25 | - --stop 26 | 27 | categories: 28 | - Network 29 | 30 | startup_notify: true 31 | 32 | app_run_file: AppRun 33 | 34 | # You can specify the shared libraries that you want to bundle with your app 35 | # 36 | # flutter_distributor automatically detects the shared libraries that your app 37 | # depends on, but you can also specify them manually here. 38 | # 39 | # The following example shows how to bundle the libcurl library with your app. 40 | # 41 | # include: 42 | # - libcurl.so.4 43 | include: [] 44 | -------------------------------------------------------------------------------- /ios/exportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | destination 6 | export 7 | manageAppVersionAndBuildNumber 8 | 9 | method 10 | app-store 11 | provisioningProfiles 12 | 13 | app.hiddify.com 14 | dist.apple.app.hiddify.com 15 | app.hiddify.com.SingBoxPacketTunnel 16 | dist.apple.app.hiddify.com.singboxpackettunnel 17 | 18 | signingCertificate 19 | E2217AF6F3AD11BA09F9FD95E025D7E637F8B081 20 | signingStyle 21 | manual 22 | stripSwiftSymbols 23 | 24 | teamID 25 | 3JFTY5BP58 26 | uploadSymbols 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/singbox/model/singbox_rule.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'singbox_rule.freezed.dart'; 4 | part 'singbox_rule.g.dart'; 5 | 6 | @freezed 7 | class SingboxRule with _$SingboxRule { 8 | const SingboxRule._(); 9 | 10 | @JsonSerializable(fieldRename: FieldRename.kebab) 11 | const factory SingboxRule({ 12 | String? ruleSetUrl, 13 | String? domains, 14 | String? ip, 15 | String? port, 16 | String? protocol, 17 | @Default(RuleNetwork.tcpAndUdp) RuleNetwork network, 18 | @Default(RuleOutbound.proxy) RuleOutbound outbound, 19 | }) = _SingboxRule; 20 | 21 | factory SingboxRule.fromJson(Map json) => _$SingboxRuleFromJson(json); 22 | } 23 | 24 | enum RuleOutbound { proxy, bypass, block } 25 | 26 | @JsonEnum(valueField: 'key') 27 | enum RuleNetwork { 28 | tcpAndUdp(""), 29 | tcp("tcp"), 30 | udp("udp"); 31 | 32 | const RuleNetwork(this.key); 33 | 34 | final String? key; 35 | } 36 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/bg/BootReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.bg 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import com.hiddify.hiddify.Settings 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.GlobalScope 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.withContext 11 | 12 | class BootReceiver : BroadcastReceiver() { 13 | 14 | override fun onReceive(context: Context, intent: Intent) { 15 | when (intent.action) { 16 | Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED -> { 17 | } 18 | 19 | else -> return 20 | } 21 | GlobalScope.launch(Dispatchers.IO) { 22 | if (Settings.startedByUser) { 23 | withContext(Dispatchers.Main) { 24 | BoxService.start() 25 | } 26 | } 27 | } 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /lib/features/log/data/log_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/directories/directories_provider.dart'; 2 | import 'package:hiddify/features/log/data/log_path_resolver.dart'; 3 | import 'package:hiddify/features/log/data/log_repository.dart'; 4 | import 'package:hiddify/singbox/service/singbox_service_provider.dart'; 5 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 6 | 7 | part 'log_data_providers.g.dart'; 8 | 9 | @Riverpod(keepAlive: true) 10 | Future logRepository(LogRepositoryRef ref) async { 11 | final repo = LogRepositoryImpl( 12 | singbox: ref.watch(singboxServiceProvider), 13 | logPathResolver: ref.watch(logPathResolverProvider), 14 | ); 15 | await repo.init().getOrElse((l) => throw l).run(); 16 | return repo; 17 | } 18 | 19 | @Riverpod(keepAlive: true) 20 | LogPathResolver logPathResolver(LogPathResolverRef ref) { 21 | return LogPathResolver( 22 | ref.watch(appDirectoriesProvider).requireValue.workingDir, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /lib/core/model/constants.dart: -------------------------------------------------------------------------------- 1 | abstract class Constants { 2 | static const appName = "Hiddify"; 3 | static const githubUrl = "https://github.com/hiddify/hiddify-next"; 4 | static const githubReleasesApiUrl = 5 | "https://api.github.com/repos/hiddify/hiddify-next/releases"; 6 | static const githubLatestReleaseUrl = 7 | "https://github.com/hiddify/hiddify-next/releases/latest"; 8 | static const appCastUrl = 9 | "https://raw.githubusercontent.com/hiddify/hiddify-next/main/appcast.xml"; 10 | static const telegramChannelUrl = "https://t.me/hiddify"; 11 | static const privacyPolicyUrl = "https://hiddify.com/privacy-policy/"; 12 | static const termsAndConditionsUrl = "https://hiddify.com/terms/"; 13 | static const cfWarpPrivacyPolicy = 14 | "https://www.cloudflare.com/application/privacypolicy/"; 15 | static const cfWarpTermsOfService = 16 | "https://www.cloudflare.com/application/terms/"; 17 | } 18 | 19 | const kAnimationDuration = Duration(milliseconds: 250); 20 | -------------------------------------------------------------------------------- /lib/features/app_update/notifier/app_update_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/features/app_update/model/app_update_failure.dart'; 3 | import 'package:hiddify/features/app_update/model/remote_version_entity.dart'; 4 | 5 | part 'app_update_state.freezed.dart'; 6 | 7 | @freezed 8 | class AppUpdateState with _$AppUpdateState { 9 | const factory AppUpdateState.initial() = AppUpdateStateInitial; 10 | const factory AppUpdateState.disabled() = AppUpdateStateDisabled; 11 | const factory AppUpdateState.checking() = AppUpdateStateChecking; 12 | const factory AppUpdateState.error(AppUpdateFailure error) = 13 | AppUpdateStateError; 14 | const factory AppUpdateState.available(RemoteVersionEntity versionInfo) = 15 | AppUpdateStateAvailable; 16 | const factory AppUpdateState.ignored(RemoteVersionEntity versionInfo) = 17 | AppUpdateStateIgnored; 18 | const factory AppUpdateState.notAvailable() = AppUpdateStateNotAvailable; 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/geo_asset/data/geo_asset_path_resolver.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as p; 4 | 5 | class GeoAssetPathResolver { 6 | const GeoAssetPathResolver(this._workingDir); 7 | 8 | final Directory _workingDir; 9 | 10 | Directory get directory => Directory(p.join(_workingDir.path, "geo-assets")); 11 | 12 | File file(String providerName, String fileName) { 13 | final prefix = providerName.replaceAll("/", "-").toLowerCase().trim(); 14 | return File( 15 | p.join( 16 | directory.path, 17 | "$prefix${prefix.isEmpty ? "" : "-"}$fileName", 18 | ), 19 | ); 20 | } 21 | 22 | /// geoasset's path relative to working directory 23 | String relativePath(String providerName, String fileName) { 24 | final fullPath = file(providerName, fileName).path; 25 | return p.relative(fullPath, from: _workingDir.path); 26 | } 27 | 28 | String resolvePath(String path) { 29 | return p.absolute(_workingDir.path, path); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/log/data/log_parser.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: parameter_assignments 2 | 3 | import 'package:dartx/dartx.dart'; 4 | import 'package:hiddify/features/log/model/log_entity.dart'; 5 | import 'package:hiddify/features/log/model/log_level.dart'; 6 | import 'package:tint/tint.dart'; 7 | 8 | abstract class LogParser { 9 | static LogEntity parseSingbox(String log) { 10 | log = log.strip(); 11 | DateTime? time; 12 | if (log.length > 25) { 13 | time = DateTime.tryParse(log.substring(6, 25)); 14 | } 15 | if (time != null) { 16 | log = log.substring(26); 17 | } 18 | final level = LogLevel.values.firstOrNullWhere( 19 | (e) { 20 | if (log.startsWith(e.name.toUpperCase())) { 21 | log = log.removePrefix(e.name.toUpperCase()); 22 | return true; 23 | } 24 | return false; 25 | }, 26 | ); 27 | return LogEntity( 28 | level: level, 29 | time: time, 30 | message: log.trim(), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/core/utils/ip_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:hiddify/core/utils/ip_utils.dart'; 3 | 4 | void main() { 5 | group( 6 | "obscureIp", 7 | () { 8 | test( 9 | "Should obscure parts of ipv4", 10 | () { 11 | const ipv4 = "1.1.1.1"; 12 | final obscured = obscureIp(ipv4); 13 | expect(obscured, "1.*.*.1"); 14 | }, 15 | ); 16 | 17 | test( 18 | "Should obscure parts of full ipv6", 19 | () { 20 | const ipv6 = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"; 21 | final obscured = obscureIp(ipv6); 22 | expect(obscured, "FEDC:****:****:****:****:****:****:****"); 23 | }, 24 | ); 25 | 26 | test( 27 | "Should obscure parts of ipv6", 28 | () { 29 | const ipv6 = "::1"; 30 | final obscured = obscureIp(ipv6); 31 | expect(obscured, "::*"); 32 | }, 33 | ); 34 | }, 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/viewmodels/dialog_viewmodel/payment_methods_viewmodel_provider.dart: -------------------------------------------------------------------------------- 1 | // payment_methods_view_model_provider.dart 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:hiddify/features/panel/xboard/viewmodels/dialog_viewmodel/payment_methods_viewmodel.dart'; 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | 7 | 8 | class PaymentMethodsViewModelParams { 9 | final String tradeNo; 10 | final double totalAmount; 11 | final VoidCallback onPaymentSuccess; 12 | 13 | PaymentMethodsViewModelParams({ 14 | required this.tradeNo, 15 | required this.totalAmount, 16 | required this.onPaymentSuccess, 17 | }); 18 | } 19 | 20 | final paymentMethodsViewModelProvider = ChangeNotifierProvider.autoDispose 21 | .family( 22 | (ref, params) => PaymentMethodsViewModel( 23 | tradeNo: params.tradeNo, 24 | totalAmount: params.totalAmount, 25 | onPaymentSuccess: params.onPaymentSuccess, 26 | ), 27 | ); 28 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | dynamic_color 7 | screen_retriever 8 | sentry_flutter 9 | sqlite3_flutter_libs 10 | tray_manager 11 | url_launcher_linux 12 | window_manager 13 | ) 14 | 15 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 16 | ) 17 | 18 | set(PLUGIN_BUNDLED_LIBRARIES) 19 | 20 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 22 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 25 | endforeach(plugin) 26 | 27 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 28 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 29 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 30 | endforeach(ffi_plugin) 31 | -------------------------------------------------------------------------------- /test.configs/warp: -------------------------------------------------------------------------------- 1 | //profile-title: base64:8J+UpSBXQVJQIPCflKU= 2 | //profile-update-interval: 24 3 | //subscription-userinfo: upload=0; download=0; total=10737418240000000; expire=2546249531 4 | //support-url: https://t.me/hiddify 5 | //profile-web-page-url: https://hiddify.com 6 | 7 | warp://p1@188.114.97.170:894?ifp=40-80&ifps=40-100&ifpd=4-8&ifpm=m4#m4&&detour=warp://p2@188.114.97.170:894#warp in warp 8 | warp://p1@auto?ifpm=m4#LocalIP&&detour=warp://p2@auto#WarpInWarp✅ 9 | #warp://p1@ip1?ifp=1-3#WarpInWarp✅&&detour=warp://p2@ip2ifp=1-3#Warp 🇮🇷 IP 10 | 11 | #warp://auto?ifp=10-20&ifps=40-100&ifpd=10-20#Warp_10-20_40-100_10-20 12 | #warp://auto?ifp=10-20&ifps=40-100&ifpd=30-200#Warp_10-20_40-100_30-50 13 | #warp://auto?ifp=10-20&ifps=40-100&ifpd=300-500#Warp_10-20_40-100_300-500 14 | 15 | 16 | #warp://auto?ifp=5-10&ifps=40-100&ifpd=10-20#Warp_5-10_40-100_10-20 17 | #warp://auto?ifp=5-10&ifps=40-100&ifpd=30-50#Warp_5-10_40-100_30-50 18 | #warp://auto?ifp=5-10&ifps=40-100&ifpd=300-500#Warp_5-10_40-100_300-500 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/features/common/confirmation_dialogs.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:go_router/go_router.dart'; 3 | 4 | Future showConfirmationDialog( 5 | BuildContext context, { 6 | required String title, 7 | required String message, 8 | IconData? icon, 9 | }) async { 10 | return showDialog( 11 | context: context, 12 | builder: (context) { 13 | final localizations = MaterialLocalizations.of(context); 14 | return AlertDialog( 15 | icon: icon != null ? Icon(icon) : null, 16 | title: Text(title), 17 | content: Text(message), 18 | actions: [ 19 | TextButton( 20 | onPressed: () => context.pop(true), 21 | child: Text(localizations.okButtonLabel), 22 | ), 23 | TextButton( 24 | onPressed: () => context.pop(false), 25 | child: Text(localizations.cancelButtonLabel), 26 | ), 27 | ], 28 | ); 29 | }, 30 | ).then((value) => value ?? false); 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/views/components/user_info/reset_subscription_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/features/panel/xboard/services/subscription.dart'; 4 | 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | 7 | class ResetSubscriptionButton extends ConsumerWidget { 8 | const ResetSubscriptionButton({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context, WidgetRef ref) { 12 | final t = ref.watch(translationsProvider); 13 | 14 | return Center( 15 | child: ElevatedButton.icon( 16 | onPressed: () => Subscription.resetSubscription(context, ref), 17 | icon: const Icon(Icons.refresh), 18 | label: Text(t.userInfo.resetSubscription), 19 | style: ElevatedButton.styleFrom( 20 | padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), 21 | backgroundColor: Colors.blue, 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/stats/notifier/stats_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/connection/notifier/connection_notifier.dart'; 2 | import 'package:hiddify/features/stats/data/stats_data_providers.dart'; 3 | import 'package:hiddify/features/stats/model/stats_entity.dart'; 4 | import 'package:hiddify/utils/custom_loggers.dart'; 5 | import 'package:hiddify/utils/riverpod_utils.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'stats_notifier.g.dart'; 9 | 10 | @riverpod 11 | class StatsNotifier extends _$StatsNotifier with AppLogger { 12 | @override 13 | Stream build() async* { 14 | ref.disposeDelay(const Duration(seconds: 10)); 15 | final serviceRunning = await ref.watch(serviceRunningProvider.future); 16 | if (serviceRunning) { 17 | yield* ref 18 | .watch(statsRepositoryProvider) 19 | .watchStats() 20 | .map((event) => event.getOrElse((_) => StatsEntity.empty())); 21 | } else { 22 | yield* Stream.value(StatsEntity.empty()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | dynamic_color 7 | protocol_handler_windows 8 | screen_retriever 9 | sentry_flutter 10 | share_plus 11 | sqlite3_flutter_libs 12 | tray_manager 13 | url_launcher_windows 14 | vclibs 15 | window_manager 16 | ) 17 | 18 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 19 | ) 20 | 21 | set(PLUGIN_BUNDLED_LIBRARIES) 22 | 23 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 25 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 28 | endforeach(plugin) 29 | 30 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 31 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 32 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 33 | endforeach(ffi_plugin) 34 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /lib/utils/sentry_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:hiddify/core/model/failures.dart'; 5 | import 'package:hiddify/features/proxy/model/proxy_failure.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | import 'package:sentry_flutter/sentry_flutter.dart'; 8 | 9 | FutureOr sentryBeforeSend(SentryEvent event, {Hint? hint}) { 10 | if (canSendEvent(event.throwable)) return event; 11 | return null; 12 | } 13 | 14 | bool canSendEvent(dynamic throwable) { 15 | return switch (throwable) { 16 | UnexpectedFailure(:final error) => canSendEvent(error), 17 | DioException _ => false, 18 | SocketException _ => false, 19 | UnknownIp _ => false, 20 | HttpException _ => false, 21 | HandshakeException _ => false, 22 | ExpectedFailure _ => false, 23 | ExpectedMeasuredFailure _ => false, 24 | _ => true, 25 | }; 26 | } 27 | 28 | bool canLogEvent(dynamic throwable) => switch (throwable) { 29 | ExpectedMeasuredFailure _ => true, 30 | _ => canSendEvent(throwable), 31 | }; 32 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/constant/SettingsKey.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.constant 2 | 3 | object SettingsKey { 4 | private const val KEY_PREFIX = "flutter." 5 | 6 | const val SERVICE_MODE = "${KEY_PREFIX}service-mode" 7 | const val ACTIVE_CONFIG_PATH = "${KEY_PREFIX}active_config_path" 8 | const val ACTIVE_PROFILE_NAME = "${KEY_PREFIX}active_profile_name" 9 | 10 | const val PER_APP_PROXY_MODE = "${KEY_PREFIX}per_app_proxy_mode" 11 | const val PER_APP_PROXY_INCLUDE_LIST = "${KEY_PREFIX}per_app_proxy_include_list" 12 | const val PER_APP_PROXY_EXCLUDE_LIST = "${KEY_PREFIX}per_app_proxy_exclude_list" 13 | 14 | const val DEBUG_MODE = "${KEY_PREFIX}debug_mode" 15 | const val DISABLE_MEMORY_LIMIT = "${KEY_PREFIX}disable_memory_limit" 16 | const val DYNAMIC_NOTIFICATION = "${KEY_PREFIX}dynamic_notification" 17 | const val SYSTEM_PROXY_ENABLED = "${KEY_PREFIX}system_proxy_enabled" 18 | 19 | // cache 20 | 21 | const val STARTED_BY_USER = "${KEY_PREFIX}started_by_user" 22 | const val CONFIG_OPTIONS = "config_options_json" 23 | 24 | } -------------------------------------------------------------------------------- /lib/core/analytics/analytics_filter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:hiddify/core/model/failures.dart'; 5 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 6 | import 'package:sentry_flutter/sentry_flutter.dart'; 7 | 8 | FutureOr sentryBeforeSend(SentryEvent event, {Hint? hint}) { 9 | if (!canSendEvent(event.throwable)) return null; 10 | return event.copyWith( 11 | user: SentryUser(email: "", username: "", ipAddress: "0.0.0.0"), 12 | ); 13 | } 14 | 15 | bool canSendEvent(dynamic throwable) { 16 | return switch (throwable) { 17 | UnexpectedFailure(:final error) => canSendEvent(error), 18 | DioException _ => false, 19 | SocketException _ => false, 20 | HttpException _ => false, 21 | HandshakeException _ => false, 22 | ExpectedFailure _ => false, 23 | ExpectedMeasuredFailure _ => false, 24 | _ => true, 25 | }; 26 | } 27 | 28 | bool canLogEvent(dynamic throwable) => switch (throwable) { 29 | ExpectedMeasuredFailure _ => true, 30 | _ => canSendEvent(throwable), 31 | }; 32 | -------------------------------------------------------------------------------- /lib/core/model/app_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/model/environment.dart'; 3 | 4 | part 'app_info_entity.freezed.dart'; 5 | 6 | @freezed 7 | class AppInfoEntity with _$AppInfoEntity { 8 | const AppInfoEntity._(); 9 | 10 | const factory AppInfoEntity({ 11 | required String name, 12 | required String version, 13 | required String buildNumber, 14 | required Release release, 15 | required String operatingSystem, 16 | required String operatingSystemVersion, 17 | required Environment environment, 18 | }) = _AppInfoEntity; 19 | 20 | String get userAgent => 21 | "HiddifyNext/$version ($operatingSystem) like ClashMeta v2ray sing-box"; 22 | 23 | String get presentVersion => environment == Environment.prod 24 | ? version 25 | : "$version ${environment.name}"; 26 | 27 | /// formats app info for sharing 28 | String format() => ''' 29 | $name v$version ($buildNumber) [${environment.name}] 30 | ${release.name} release 31 | $operatingSystem [$operatingSystemVersion]'''; 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/viewmodels/purchase_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/features/panel/xboard/models/plan_model.dart'; 3 | import 'package:hiddify/features/panel/xboard/services/purchase_service.dart'; 4 | 5 | class PurchaseViewModel extends ChangeNotifier { 6 | final PurchaseService _purchaseService; 7 | List _plans = []; 8 | String? _errorMessage; 9 | bool _isLoading = false; 10 | 11 | List get plans => _plans; 12 | String? get errorMessage => _errorMessage; 13 | bool get isLoading => _isLoading; 14 | 15 | PurchaseViewModel({required PurchaseService purchaseService}) 16 | : _purchaseService = purchaseService; 17 | 18 | // 每次调用时都重新加载数据 19 | Future fetchPlans() async { 20 | _isLoading = true; 21 | _errorMessage = null; 22 | notifyListeners(); 23 | 24 | try { 25 | _plans = await _purchaseService.fetchPlanData(); 26 | } catch (e) { 27 | _errorMessage = e.toString(); 28 | } finally { 29 | _isLoading = false; 30 | notifyListeners(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/profile/notifier/active_profile_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/profile/data/profile_data_providers.dart'; 2 | import 'package:hiddify/features/profile/model/profile_entity.dart'; 3 | import 'package:hiddify/utils/utils.dart'; 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'active_profile_notifier.g.dart'; 7 | 8 | @Riverpod(keepAlive: true) 9 | class ActiveProfile extends _$ActiveProfile with AppLogger { 10 | @override 11 | Stream build() { 12 | loggy.debug("watching active profile"); 13 | return ref 14 | .watch(profileRepositoryProvider) 15 | .requireValue 16 | .watchActiveProfile() 17 | .map((event) => event.getOrElse((l) => throw l)); 18 | } 19 | } 20 | 21 | // TODO: move to specific feature 22 | @Riverpod(keepAlive: true) 23 | Stream hasAnyProfile( 24 | HasAnyProfileRef ref, 25 | ) { 26 | return ref 27 | .watch(profileRepositoryProvider) 28 | .requireValue 29 | .watchHasAnyProfile() 30 | .map((event) => event.getOrElse((l) => throw l)); 31 | } 32 | -------------------------------------------------------------------------------- /lib/core/widget/skeleton_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Skeleton extends StatelessWidget { 4 | const Skeleton({ 5 | this.width, 6 | this.height, 7 | this.widthFactor, 8 | this.heightFactor, 9 | this.shape = BoxShape.rectangle, 10 | this.alignment = AlignmentDirectional.center, 11 | }); 12 | 13 | final double? width; 14 | final double? height; 15 | final double? widthFactor; 16 | final double? heightFactor; 17 | final BoxShape shape; 18 | final AlignmentGeometry alignment; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | final theme = Theme.of(context); 23 | 24 | return FractionallySizedBox( 25 | widthFactor: widthFactor, 26 | heightFactor: heightFactor, 27 | alignment: alignment, 28 | child: Container( 29 | width: width, 30 | height: height, 31 | decoration: BoxDecoration( 32 | borderRadius: BorderRadius.circular(8), 33 | shape: shape, 34 | color: theme.hintColor.withOpacity(.16), 35 | ), 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/core/app_info/app_info_provider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:hiddify/core/model/app_info_entity.dart'; 4 | import 'package:hiddify/core/model/environment.dart'; 5 | import 'package:package_info_plus/package_info_plus.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'app_info_provider.g.dart'; 9 | 10 | @Riverpod(keepAlive: true) 11 | Environment environment(EnvironmentRef ref) => 12 | throw Exception("override environmentProvider"); 13 | 14 | @Riverpod(keepAlive: true) 15 | class AppInfo extends _$AppInfo { 16 | @override 17 | Future build() async { 18 | final packageInfo = await PackageInfo.fromPlatform(); 19 | final environment = ref.watch(environmentProvider); 20 | return AppInfoEntity( 21 | name: packageInfo.appName, 22 | version: packageInfo.version, 23 | buildNumber: packageInfo.buildNumber, 24 | release: Release.read(), 25 | operatingSystem: Platform.operatingSystem, 26 | operatingSystemVersion: Platform.operatingSystemVersion, 27 | environment: environment, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/config_option/model/config_option_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/core/localization/translations.dart'; 3 | import 'package:hiddify/core/model/failures.dart'; 4 | 5 | part 'config_option_failure.freezed.dart'; 6 | 7 | @freezed 8 | sealed class ConfigOptionFailure with _$ConfigOptionFailure, Failure { 9 | const ConfigOptionFailure._(); 10 | 11 | @With() 12 | const factory ConfigOptionFailure.unexpected([ 13 | Object? error, 14 | StackTrace? stackTrace, 15 | ]) = ConfigOptionUnexpectedFailure; 16 | 17 | @With() 18 | const factory ConfigOptionFailure.missingWarp() = MissingWarpConfigFailure; 19 | 20 | @override 21 | ({String type, String? message}) present(TranslationsEn t) { 22 | return switch (this) { 23 | ConfigOptionUnexpectedFailure() => ( 24 | type: t.failure.unexpected, 25 | message: null, 26 | ), 27 | MissingWarpConfigFailure() => ( 28 | type: t.config.missingWarpConfig, 29 | message: null, 30 | ), 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /project.inlang/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://inlang.com/schema/project-settings", 3 | "sourceLanguageTag": "en", 4 | "languageTags": [ 5 | "en", 6 | "ar", 7 | "ckb-KUR", 8 | "es", 9 | "fa", 10 | "fr", 11 | "id", 12 | "pt-BR", 13 | "ru", 14 | "tr", 15 | "zh-CN", 16 | "zh-TW", 17 | "hi" 18 | ], 19 | "modules": [ 20 | "https://cdn.jsdelivr.net/npm/@inlang/plugin-i18next@4/dist/index.js", 21 | "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@1/dist/index.js", 22 | "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@1/dist/index.js", 23 | "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@1/dist/index.js", 24 | "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@1/dist/index.js", 25 | "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@latest/dist/index.js" 26 | ], 27 | "plugin.inlang.i18next": { 28 | "pathPattern": "./assets/translations/strings_{languageTag}.i18n.json", 29 | "variableReferencePattern": [ 30 | "@:" 31 | ] 32 | } 33 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | .github/help 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # generated files 36 | **/*.g.dart 37 | **/*.freezed.dart 38 | **/*.mapper.dart 39 | **/*.gen.dart 40 | **/*.dll 41 | **/*.dylib 42 | **/*.xcframework 43 | /dist/ 44 | 45 | /assets/core/* 46 | !/assets/core/.gitkeep 47 | 48 | # Symbolication related 49 | app.*.symbols 50 | 51 | # Obfuscation related 52 | app.*.map.json 53 | 54 | # Android Studio will place build artifacts here 55 | /android/app/debug 56 | /android/app/profile 57 | /android/app/release 58 | 59 | 60 | /data -------------------------------------------------------------------------------- /lib/features/connection/data/connection_data_providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/directories/directories_provider.dart'; 2 | import 'package:hiddify/features/config_option/data/config_option_data_providers.dart'; 3 | import 'package:hiddify/features/connection/data/connection_platform_source.dart'; 4 | import 'package:hiddify/features/connection/data/connection_repository.dart'; 5 | 6 | import 'package:hiddify/features/profile/data/profile_data_providers.dart'; 7 | import 'package:hiddify/singbox/service/singbox_service_provider.dart'; 8 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 9 | 10 | part 'connection_data_providers.g.dart'; 11 | 12 | @Riverpod(keepAlive: true) 13 | ConnectionRepository connectionRepository( 14 | ConnectionRepositoryRef ref, 15 | ) { 16 | return ConnectionRepositoryImpl( 17 | directories: ref.watch(appDirectoriesProvider).requireValue, 18 | configOptionRepository: ref.watch(configOptionRepositoryProvider), 19 | singbox: ref.watch(singboxServiceProvider), 20 | platformSource: ConnectionPlatformSourceImpl(), 21 | profilePathResolver: ref.watch(profilePathResolverProvider), 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /lib/core/widget/shimmer_skeleton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_animate/flutter_animate.dart'; 3 | import 'package:hiddify/core/widget/skeleton_widget.dart'; 4 | 5 | class ShimmerSkeleton extends StatelessWidget { 6 | const ShimmerSkeleton({ 7 | this.width, 8 | this.height, 9 | this.widthFactor, 10 | this.heightFactor, 11 | this.color, 12 | this.duration = const Duration(seconds: 1), 13 | super.key, 14 | }); 15 | 16 | final double? width; 17 | final double? height; 18 | final double? widthFactor; 19 | final double? heightFactor; 20 | final Color? color; 21 | final Duration duration; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Skeleton( 26 | width: width, 27 | height: height, 28 | widthFactor: widthFactor, 29 | heightFactor: heightFactor, 30 | ) 31 | .animate( 32 | onPlay: (controller) => controller.loop(), 33 | ) 34 | .shimmer( 35 | duration: duration, 36 | angle: 45, 37 | color: color ?? Theme.of(context).colorScheme.secondary, 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/core/widget/animated_visibility.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class AnimatedVisibility extends StatelessWidget { 4 | const AnimatedVisibility({ 5 | super.key, 6 | required this.visible, 7 | this.axis = Axis.horizontal, 8 | this.padding = EdgeInsets.zero, 9 | required this.child, 10 | }); 11 | 12 | final bool visible; 13 | final Axis axis; 14 | final EdgeInsets padding; 15 | final Widget child; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | final replacement = axis == Axis.vertical 20 | ? const SizedBox(width: double.infinity) 21 | : const SizedBox.shrink(); 22 | 23 | return AnimatedSwitcher( 24 | duration: const Duration(milliseconds: 200), 25 | transitionBuilder: (child, animation) => SizeTransition( 26 | sizeFactor: animation, 27 | child: FadeTransition(opacity: animation, child: child), 28 | ), 29 | child: visible 30 | ? AnimatedPadding( 31 | padding: padding, 32 | duration: const Duration(milliseconds: 200), 33 | child: child, 34 | ) 35 | : replacement, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/core/widget/tip_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluentui_system_icons/fluentui_system_icons.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TipCard extends StatelessWidget { 5 | const TipCard({required this.message, super.key}); 6 | 7 | final String message; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Card( 12 | margin: const EdgeInsets.symmetric( 13 | horizontal: 12, 14 | vertical: 4, 15 | ), 16 | child: Row( 17 | children: [ 18 | const Padding( 19 | padding: EdgeInsets.all(8.0), 20 | child: Icon(FluentIcons.lightbulb_24_regular), 21 | ), 22 | Expanded( 23 | child: Column( 24 | crossAxisAlignment: CrossAxisAlignment.stretch, 25 | children: [ 26 | Padding( 27 | padding: const EdgeInsets.symmetric( 28 | horizontal: 8, 29 | vertical: 8, 30 | ), 31 | child: Text(message), 32 | ), 33 | ], 34 | ), 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/features/stats/data/stats_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:hiddify/core/utils/exception_handler.dart'; 3 | import 'package:hiddify/features/stats/model/stats_entity.dart'; 4 | import 'package:hiddify/features/stats/model/stats_failure.dart'; 5 | import 'package:hiddify/singbox/service/singbox_service.dart'; 6 | import 'package:hiddify/utils/custom_loggers.dart'; 7 | 8 | abstract interface class StatsRepository { 9 | Stream> watchStats(); 10 | } 11 | 12 | class StatsRepositoryImpl 13 | with ExceptionHandler, InfraLogger 14 | implements StatsRepository { 15 | StatsRepositoryImpl({required this.singbox}); 16 | 17 | final SingboxService singbox; 18 | 19 | @override 20 | Stream> watchStats() { 21 | return singbox 22 | .watchStats() 23 | .map( 24 | (event) => StatsEntity( 25 | uplink: event.uplink, 26 | downlink: event.downlink, 27 | uplinkTotal: event.uplinkTotal, 28 | downlinkTotal: event.downlinkTotal, 29 | ), 30 | ) 31 | .handleExceptions(StatsUnexpectedFailure.new); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ios/HiddifyPacketTunnel/PacketTunnelProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketTunnelProvider.swift 3 | // SingBoxPacketTunnel 4 | // 5 | // Created by GFWFighter on 7/24/1402 AP. 6 | // 7 | 8 | import NetworkExtension 9 | 10 | class PacketTunnelProvider: ExtensionProvider { 11 | 12 | private var upload: Int64 = 0 13 | private var download: Int64 = 0 14 | // private var trafficLock: NSLock = NSLock() 15 | 16 | // var trafficReader: TrafficReader! 17 | 18 | override func startTunnel(options: [String : NSObject]?) async throws { 19 | try await super.startTunnel(options: options) 20 | /*trafficReader = TrafficReader { [unowned self] traffic in 21 | trafficLock.lock() 22 | upload += traffic.up 23 | download += traffic.down 24 | trafficLock.unlock() 25 | }*/ 26 | } 27 | 28 | override func handleAppMessage(_ messageData: Data) async -> Data? { 29 | let message = String(data: messageData, encoding: .utf8) 30 | switch message { 31 | case "stats": 32 | return "\(upload),\(download)".data(using: .utf8)! 33 | default: 34 | return nil 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/viewmodels/reset_subscription_viewmodel.dart: -------------------------------------------------------------------------------- 1 | // viewmodels/reset_subscription_viewmodel.dart 2 | import 'package:flutter/material.dart'; 3 | import 'package:hiddify/features/panel/xboard/services/subscription.dart'; 4 | 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | 7 | class ResetSubscriptionViewModel extends ChangeNotifier { 8 | bool _isLoading = false; 9 | bool get isLoading => _isLoading; 10 | ResetSubscriptionViewModel(); 11 | 12 | Future resetSubscription(BuildContext context, WidgetRef ref) async { 13 | _isLoading = true; 14 | notifyListeners(); 15 | 16 | try { 17 | await Subscription.resetSubscription(context, ref); 18 | // ignore: use_build_context_synchronously 19 | ScaffoldMessenger.of(context).showSnackBar( 20 | const SnackBar(content: Text('Subscription reset successfully')), 21 | ); 22 | } catch (e) { 23 | // ignore: use_build_context_synchronously 24 | ScaffoldMessenger.of(context).showSnackBar( 25 | SnackBar(content: Text('Error resetting subscription: $e')), 26 | ); 27 | } finally { 28 | _isLoading = false; 29 | notifyListeners(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ios/HiddifyPacketTunnel/SingBox/Extension+RunBlocking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+RunBlocking.swift 3 | // SingBoxPacketTunnel 4 | // 5 | // Created by GFWFighter on 7/25/1402 AP. 6 | // 7 | 8 | import Foundation 9 | import Libcore 10 | import NetworkExtension 11 | 12 | func runBlocking(_ block: @escaping () async -> T) -> T { 13 | let semaphore = DispatchSemaphore(value: 0) 14 | let box = resultBox() 15 | Task.detached { 16 | let value = await block() 17 | box.result0 = value 18 | semaphore.signal() 19 | } 20 | semaphore.wait() 21 | return box.result0 22 | } 23 | 24 | func runBlocking(_ tBlock: @escaping () async throws -> T) throws -> T { 25 | let semaphore = DispatchSemaphore(value: 0) 26 | let box = resultBox() 27 | Task.detached { 28 | do { 29 | let value = try await tBlock() 30 | box.result = .success(value) 31 | } catch { 32 | box.result = .failure(error) 33 | } 34 | semaphore.signal() 35 | } 36 | semaphore.wait() 37 | return try box.result.get() 38 | } 39 | 40 | private class resultBox { 41 | var result: Result! 42 | var result0: T! 43 | } 44 | -------------------------------------------------------------------------------- /lib/features/proxy/model/proxy_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hiddify/singbox/model/singbox_proxy_type.dart'; 3 | 4 | part 'proxy_entity.freezed.dart'; 5 | 6 | @freezed 7 | class ProxyGroupEntity with _$ProxyGroupEntity { 8 | const ProxyGroupEntity._(); 9 | 10 | const factory ProxyGroupEntity({ 11 | required String tag, 12 | required ProxyType type, 13 | required String selected, 14 | @Default([]) List items, 15 | }) = _ProxyGroupEntity; 16 | 17 | String get name => _sanitizedTag(tag); 18 | } 19 | 20 | @freezed 21 | class ProxyItemEntity with _$ProxyItemEntity { 22 | const ProxyItemEntity._(); 23 | 24 | const factory ProxyItemEntity({ 25 | required String tag, 26 | required ProxyType type, 27 | required int urlTestDelay, 28 | String? selectedTag, 29 | }) = _ProxyItemEntity; 30 | 31 | String get name => _sanitizedTag(tag); 32 | String? get selectedName => 33 | selectedTag == null ? null : _sanitizedTag(selectedTag!); 34 | bool get isVisible => !tag.contains("§hide§"); 35 | } 36 | 37 | String _sanitizedTag(String tag) => 38 | tag.replaceFirst(RegExp(r"\§[^]*"), "").trimRight(); 39 | -------------------------------------------------------------------------------- /test.configs/warp2: -------------------------------------------------------------------------------- 1 | //profile-title: base64:8J+UpSBXQVJQIPCflKU= 2 | //profile-update-interval: 24 3 | //subscription-userinfo: upload=0; download=0; total=10737418240000000; expire=2546249531 4 | //support-url: https://t.me/hiddify 5 | //profile-web-page-url: https://hiddify.com 6 | 7 | #attention! do not use p1 and p2 in more than two configs otherwise confilicts may occure 8 | #ifpm is about mode we have currently 6 modes. 9 | 10 | warp://p1@auto/?ifp=1-3&ifpm=m1#m1 11 | warp://p2@auto/?ifp=1-3&ifpm=m2#m2 12 | warp://p1@auto/?ifp=1-3&ifpm=m3#m3 13 | warp://p2@auto/?ifp=1-3&ifpm=m4#m4 14 | 15 | warp://p1@auto/?ifp=1-3&ifpm=m5#m5 16 | warp://p2@auto/?ifp=1-3&ifpm=m6#m6 17 | 18 | #For g and h mode, you can use hex bytes between each _, with each part ranging from 00 to FF. You can also select more hex bytes to randomly choose between them. 19 | #In the next line, this means that the fake packet uses 0x30 as the first byte in the noise. 20 | warp://p2@auto/?ifp=1-3&ifpm=h_30#h_30 21 | #In the following line, g indicates that the fake packet randomly uses one of the values 0x10, 0x20, or 0x30 as the initial byte in the noise after the WireGuard reserved key. This should not be effective. 22 | warp://p1@auto/?ifp=1-3&ifpm=g_10_20_30#g_10_20_30 23 | -------------------------------------------------------------------------------- /ios/Runner/Handlers/FileMethodHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileMethodHandler.swift 3 | // Runner 4 | // 5 | // Created by GFWFighter on 10/24/23. 6 | // 7 | 8 | import Foundation 9 | 10 | public class FileMethodHandler: NSObject, FlutterPlugin { 11 | 12 | public static let name = "\(Bundle.main.serviceIdentifier)/files.method" 13 | 14 | public static func register(with registrar: FlutterPluginRegistrar) { 15 | let channel = FlutterMethodChannel(name: Self.name, binaryMessenger: registrar.messenger()) 16 | let instance = FileMethodHandler() 17 | registrar.addMethodCallDelegate(instance, channel: channel) 18 | instance.channel = channel 19 | } 20 | 21 | private var channel: FlutterMethodChannel? 22 | 23 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 24 | switch call.method { 25 | case "get_paths": 26 | result([ 27 | "working": FilePath.workingDirectory.path, 28 | "temp": FilePath.cacheDirectory.path, 29 | "base": FilePath.sharedDirectory.path 30 | ]) 31 | default: 32 | result(FlutterMethodNotImplemented) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ios/Shared/FilePath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilePath.swift 3 | // SingBoxPacketTunnel 4 | // 5 | // Created by GFWFighter on 7/25/1402 AP. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum FilePath { 11 | public static let packageName = { 12 | Bundle.main.infoDictionary?["BASE_BUNDLE_IDENTIFIER"] as? String ?? "unknown" 13 | }() 14 | } 15 | 16 | public extension FilePath { 17 | static let groupName = "group.\(packageName)" 18 | 19 | private static let defaultSharedDirectory: URL! = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: FilePath.groupName) 20 | 21 | static let sharedDirectory = defaultSharedDirectory! 22 | 23 | static let cacheDirectory = sharedDirectory 24 | .appendingPathComponent("Library", isDirectory: true) 25 | .appendingPathComponent("Caches", isDirectory: true) 26 | 27 | static let workingDirectory = cacheDirectory.appendingPathComponent("Working", isDirectory: true) 28 | } 29 | 30 | public extension URL { 31 | var fileName: String { 32 | var path = relativePath 33 | if let index = path.lastIndex(of: "/") { 34 | path = String(path[path.index(index, offsetBy: 1)...]) 35 | } 36 | return path 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/core/preferences/preferences_provider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:loggy/loggy.dart'; 4 | import 'package:path/path.dart' as p; 5 | import 'package:path_provider/path_provider.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | import 'package:shared_preferences/shared_preferences.dart'; 8 | 9 | part 'preferences_provider.g.dart'; 10 | 11 | @Riverpod(keepAlive: true) 12 | Future sharedPreferences(SharedPreferencesRef ref) async { 13 | final logger = Loggy("preferences"); 14 | SharedPreferences? sharedPreferences; 15 | 16 | logger.debug("initializing preferences"); 17 | try { 18 | sharedPreferences = await SharedPreferences.getInstance(); 19 | } catch (e) { 20 | logger.error("error initializing preferences", e); 21 | if (!Platform.isWindows && !Platform.isLinux) { 22 | rethrow; 23 | } 24 | // https://github.com/flutter/flutter/issues/89211 25 | final directory = await getApplicationSupportDirectory(); 26 | final file = File(p.join(directory.path, 'shared_preferences.json')); 27 | if (file.existsSync()) { 28 | file.deleteSync(); 29 | } 30 | } 31 | 32 | return sharedPreferences ??= await SharedPreferences.getInstance(); 33 | } 34 | -------------------------------------------------------------------------------- /linux/packaging/appimage/AppRun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | export LD_LIBRARY_PATH=usr/lib 5 | 6 | # Usage info 7 | show_help() { 8 | cat << EOF 9 | Usage: ${0##*/} ... 10 | start Hiddify or HiddifyCli, when no parameter is given, Hiddify is executed. 11 | -v show version 12 | EOF 13 | } 14 | show_version() { 15 | printf "Hiddify version " 16 | jq .version <./data/flutter_assets/version.json 17 | } 18 | # Initialize variables: 19 | service=0 #declare -i service 20 | OPTIND=1 21 | 22 | # Resetting OPTIND is necessary if getopts was used previously in the script. 23 | # It is a good idea to make OPTIND local if you process options in a function. 24 | 25 | # if no arg is provided, execute hiddify app 26 | if [[ $# == 0 ]];then 27 | exec ./hiddify 28 | else 29 | 30 | # processing arguments 31 | 32 | case $1 in 33 | HiddifyCli) 34 | exec ./HiddifyCli ${@:3} 35 | exit 0 36 | ;; 37 | h) 38 | show_help 39 | exit 0 40 | ;; 41 | v) show_version 42 | exit 0 43 | ;; 44 | *) 45 | show_help >&2 46 | exit 1 47 | ;; 48 | esac 49 | 50 | 51 | 52 | fi 53 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.network.client 6 | 7 | 9 | com.apple.security.app-sandbox 10 | 11 | com.apple.security.cs.allow-jit 12 | 13 | com.apple.security.network.server 14 | 15 | 17 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/core/localization/locale_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/core/preferences/preferences_provider.dart'; 2 | import 'package:hiddify/gen/translations.g.dart'; 3 | import 'package:hiddify/utils/custom_loggers.dart'; 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'locale_preferences.g.dart'; 7 | 8 | @Riverpod(keepAlive: true) 9 | class LocalePreferences extends _$LocalePreferences with AppLogger { 10 | @override 11 | AppLocale build() { 12 | final persisted = 13 | ref.watch(sharedPreferencesProvider).requireValue.getString("locale"); 14 | if (persisted == null) return AppLocaleUtils.findDeviceLocale(); 15 | // keep backward compatibility with chinese after changing zh to zh_CN 16 | if (persisted == "zh") { 17 | return AppLocale.zhCn; 18 | } 19 | try { 20 | return AppLocale.values.byName(persisted); 21 | } catch (e) { 22 | loggy.error("error setting locale: [$persisted]", e); 23 | return AppLocale.en; 24 | } 25 | } 26 | 27 | Future changeLocale(AppLocale value) async { 28 | state = value; 29 | await ref 30 | .read(sharedPreferencesProvider) 31 | .requireValue 32 | .setString("locale", value.name); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.network.client 6 | 7 | 9 | com.apple.security.app-sandbox 10 | 11 | com.apple.security.cs.allow-jit 12 | 13 | com.apple.security.network.server 14 | 15 | 17 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/core/haptic/haptic_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:hiddify/core/preferences/preferences_provider.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | part 'haptic_service.g.dart'; 7 | 8 | @Riverpod(keepAlive: true) 9 | class HapticService extends _$HapticService { 10 | @override 11 | bool build() { 12 | return _preferences.getBool(hapticFeedbackPrefKey) ?? true; 13 | } 14 | 15 | static const String hapticFeedbackPrefKey = "haptic_feedback"; 16 | SharedPreferences get _preferences => 17 | ref.read(sharedPreferencesProvider).requireValue; 18 | 19 | Future updatePreference(bool value) async { 20 | state = value; 21 | await _preferences.setBool(hapticFeedbackPrefKey, value); 22 | } 23 | 24 | Future lightImpact() async { 25 | if (state) { 26 | await HapticFeedback.lightImpact(); 27 | } 28 | } 29 | 30 | Future mediumImpact() async { 31 | if (state) { 32 | await HapticFeedback.mediumImpact(); 33 | } 34 | } 35 | 36 | Future heavyImpact() async { 37 | if (state) { 38 | await HapticFeedback.heavyImpact(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/core/theme/theme_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ConnectionButtonTheme extends ThemeExtension { 4 | const ConnectionButtonTheme({ 5 | this.idleColor, 6 | this.connectedColor, 7 | }); 8 | 9 | final Color? idleColor; 10 | final Color? connectedColor; 11 | 12 | static const ConnectionButtonTheme light = ConnectionButtonTheme( 13 | idleColor: Color(0xFF4a4d8b), 14 | connectedColor: Color(0xFF44a334), 15 | ); 16 | 17 | @override 18 | ThemeExtension copyWith({ 19 | Color? idleColor, 20 | Color? connectedColor, 21 | }) => 22 | ConnectionButtonTheme( 23 | idleColor: idleColor ?? this.idleColor, 24 | connectedColor: connectedColor ?? this.connectedColor, 25 | ); 26 | 27 | @override 28 | ThemeExtension lerp( 29 | covariant ThemeExtension? other, 30 | double t, 31 | ) { 32 | if (other is! ConnectionButtonTheme) { 33 | return this; 34 | } 35 | return ConnectionButtonTheme( 36 | idleColor: Color.lerp(idleColor, other.idleColor, t), 37 | connectedColor: Color.lerp(connectedColor, other.connectedColor, t), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/package_windows.ps1: -------------------------------------------------------------------------------- 1 | New-Item -ItemType Directory -Force -Name "dist\tmp" 2 | New-Item -ItemType Directory -Force -Name "out" 3 | 4 | # windows setup 5 | # Get-ChildItem -Recurse -File -Path "dist" -Filter "*windows-setup.exe" | Copy-Item -Destination "dist\tmp\hiddify-next-setup.exe" -ErrorAction SilentlyContinue 6 | # Compress-Archive -Force -Path "dist\tmp\hiddify-next-setup.exe",".github\help\mac-windows\*.url" -DestinationPath "out\hiddify-windows-x64-setup.zip" 7 | Get-ChildItem -Recurse -File -Path "dist" -Filter "*windows-setup.exe" | Copy-Item -Destination "out\Hiddify-Windows-Setup-x64.exe" -ErrorAction SilentlyContinue 8 | Get-ChildItem -Recurse -File -Path "dist" -Filter "*windows.msix" | Copy-Item -Destination "out\Hiddify-Windows-Setup-x64.msix" -ErrorAction SilentlyContinue 9 | 10 | 11 | # windows portable 12 | xcopy "build\windows\x64\runner\Release" "dist\tmp\hiddify-next" /E/H/C/I/Y 13 | xcopy ".github\help\mac-windows\*.url" "dist\tmp\hiddify-next" /E/H/C/I/Y 14 | Compress-Archive -Force -Path "dist\tmp\hiddify-next" -DestinationPath "out\Hiddify-Windows-Portable-x64.zip" -ErrorAction SilentlyContinue 15 | 16 | Remove-Item -Path "$HOME\.pub-cache\git\cache\flutter_circle_flags*" -Force -Recurse -ErrorAction SilentlyContinue 17 | 18 | echo "Done" -------------------------------------------------------------------------------- /lib/features/geo_asset/notifier/geo_asset_notifier.dart: -------------------------------------------------------------------------------- 1 | // import 'package:fpdart/fpdart.dart'; 2 | // import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart'; 3 | // import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart'; 4 | // import 'package:hiddify/utils/custom_loggers.dart'; 5 | // import 'package:hiddify/utils/riverpod_utils.dart'; 6 | // import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | // part 'geo_asset_notifier.g.dart'; 9 | 10 | // @riverpod 11 | // class FetchGeoAsset extends _$FetchGeoAsset with AppLogger { 12 | // @override 13 | // Future build(String id) async { 14 | // ref.disposeDelay(const Duration(seconds: 10)); 15 | // return null; 16 | // } 17 | 18 | // Future fetch(GeoAssetEntity geoAsset) async { 19 | // state = const AsyncLoading(); 20 | // state = await AsyncValue.guard( 21 | // () => ref 22 | // .read(geoAssetRepositoryProvider) 23 | // .requireValue 24 | // .update(geoAsset) 25 | // .getOrElse( 26 | // (failure) { 27 | // loggy.warning("error updating geo asset $failure", failure); 28 | // throw failure; 29 | // }, 30 | // ).run(), 31 | // ); 32 | // } 33 | // } 34 | -------------------------------------------------------------------------------- /lib/features/per_app_proxy/overview/per_app_proxy_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/features/per_app_proxy/data/per_app_proxy_data_providers.dart'; 3 | import 'package:hiddify/features/per_app_proxy/model/installed_package_info.dart'; 4 | import 'package:hiddify/utils/riverpod_utils.dart'; 5 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 6 | 7 | part 'per_app_proxy_notifier.g.dart'; 8 | 9 | @riverpod 10 | Future> installedPackagesInfo( 11 | InstalledPackagesInfoRef ref, 12 | ) async { 13 | return ref 14 | .watch(perAppProxyRepositoryProvider) 15 | .getInstalledPackages() 16 | .getOrElse((err) { 17 | // _logger.error("error getting installed packages", err); 18 | throw err; 19 | }).run(); 20 | } 21 | 22 | @riverpod 23 | Future packageIcon( 24 | PackageIconRef ref, 25 | String packageName, 26 | ) async { 27 | ref.disposeDelay(const Duration(seconds: 10)); 28 | final bytes = await ref 29 | .watch(perAppProxyRepositoryProvider) 30 | .getPackageIcon(packageName) 31 | .getOrElse((err) { 32 | // _logger.warning("error getting package icon", err); 33 | throw err; 34 | }).run(); 35 | return MemoryImage(bytes); 36 | } 37 | -------------------------------------------------------------------------------- /lib/utils/validators.dart: -------------------------------------------------------------------------------- 1 | /// https://gist.github.com/dperini/729294 2 | final _urlRegex = RegExp( 3 | // r"^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$", 4 | r'^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?#?.*$', 5 | ); 6 | 7 | /// https://stackoverflow.com/a/12968117 8 | final _portRegex = RegExp( 9 | r"^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$", 10 | ); 11 | 12 | /// https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url/3809435#3809435 13 | bool isUrl(String input) { 14 | return _urlRegex.hasMatch(input.trim().toLowerCase()); 15 | } 16 | 17 | bool isPort(String input) { 18 | return _portRegex.hasMatch(input); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/services/future_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:hiddify/features/panel/xboard/models/invite_code_model.dart'; 2 | import 'package:hiddify/features/panel/xboard/models/user_info_model.dart'; 3 | import 'package:hiddify/features/panel/xboard/services/http_service/invite_code_service.dart'; 4 | import 'package:hiddify/features/panel/xboard/services/http_service/user_service.dart'; 5 | 6 | 7 | 8 | 9 | import 'package:hiddify/features/panel/xboard/utils/storage/token_storage.dart'; 10 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 11 | 12 | 13 | // 创建一个 FutureProvider 来管理邀请码列表 14 | final inviteCodesProvider = FutureProvider>((ref) async { 15 | final accessToken = await getToken(); // 从存储中获取 accessToken 16 | if (accessToken == null) { 17 | throw Exception('No access token found.'); 18 | } 19 | return InviteCodeService().fetchInviteCodes(accessToken); 20 | }); 21 | 22 | // 定义 userInfoProvider 23 | final userTokenInfoProvider = FutureProvider((ref) async { 24 | // 获取存储的访问令牌 25 | final accessToken = await getToken(); 26 | 27 | // 如果令牌为空,返回空值 28 | if (accessToken == null) { 29 | return null; 30 | } 31 | 32 | // 调用 AuthService 获取用户信息 33 | return await UserService().fetchUserInfo(accessToken); 34 | }); 35 | -------------------------------------------------------------------------------- /lib/singbox/model/singbox_proxy_type.dart: -------------------------------------------------------------------------------- 1 | enum ProxyType { 2 | direct("Direct"), 3 | block("Block"), 4 | dns("DNS"), 5 | socks("SOCKS"), 6 | http("HTTP"), 7 | shadowsocks("Shadowsocks"), 8 | vmess("VMess"), 9 | trojan("Trojan"), 10 | naive("Naive"), 11 | wireguard("WireGuard"), 12 | hysteria("Hysteria"), 13 | tor("Tor"), 14 | ssh("SSH"), 15 | shadowtls("ShadowTLS"), 16 | shadowsocksr("ShadowsocksR"), 17 | vless("VLESS"), 18 | tuic("TUIC"), 19 | hysteria2("Hysteria2"), 20 | 21 | selector("Selector"), 22 | urltest("URLTest"), 23 | warp("Warp"), 24 | 25 | xvless("xVLESS"), 26 | xvmess("xVMess"), 27 | xtrojan("xTrojan"), 28 | xfreedom("xFragment"), 29 | xshadowsocks("xShadowsocks"), 30 | xsocks("xSocks"), 31 | invalid("Invalid"), 32 | unknown("Unknown"); 33 | 34 | const ProxyType(this.label); 35 | 36 | final String label; 37 | 38 | String get key => name; 39 | 40 | static List groupValues = [selector, urltest]; 41 | 42 | bool get isGroup => ProxyType.groupValues.contains(this); 43 | static final Map _keyMap = Map.fromEntries(ProxyType.values.map((e) => MapEntry(e.key, e))); 44 | static ProxyType fromJson(dynamic type) => _keyMap[(type as String?)?.toLowerCase()] ?? ProxyType.unknown; 45 | } 46 | -------------------------------------------------------------------------------- /ios/Runner/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryDiskSpace 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | E174.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyAccessedAPIType 33 | NSPrivacyAccessedAPICategoryUserDefaults 34 | NSPrivacyAccessedAPITypeReasons 35 | 36 | 1C8F.1 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/features/auto_start/notifier/auto_start_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:hiddify/core/app_info/app_info_provider.dart'; 4 | import 'package:hiddify/utils/utils.dart'; 5 | import 'package:launch_at_startup/launch_at_startup.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'auto_start_notifier.g.dart'; 9 | 10 | @Riverpod(keepAlive: true) 11 | class AutoStartNotifier extends _$AutoStartNotifier with InfraLogger { 12 | @override 13 | Future build() async { 14 | if (!PlatformUtils.isDesktop) return false; 15 | 16 | final appInfo = ref.watch(appInfoProvider).requireValue; 17 | launchAtStartup.setup( 18 | appName: appInfo.name, 19 | appPath: Platform.resolvedExecutable, 20 | ); 21 | final isEnabled = await launchAtStartup.isEnabled(); 22 | loggy.info("auto start is [${isEnabled ? "Enabled" : "Disabled"}]"); 23 | return isEnabled; 24 | } 25 | 26 | Future enable() async { 27 | loggy.debug("enabling auto start"); 28 | await launchAtStartup.enable(); 29 | state = const AsyncValue.data(true); 30 | } 31 | 32 | Future disable() async { 33 | loggy.debug("disabling auto start"); 34 | await launchAtStartup.disable(); 35 | state = const AsyncValue.data(false); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/settings/overview/settings_overview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gap/gap.dart'; 3 | import 'package:hiddify/core/localization/translations.dart'; 4 | import 'package:hiddify/features/common/nested_app_bar.dart'; 5 | import 'package:hiddify/features/settings/widgets/widgets.dart'; 6 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 7 | 8 | class SettingsOverviewPage extends HookConsumerWidget { 9 | const SettingsOverviewPage({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context, WidgetRef ref) { 13 | final t = ref.watch(translationsProvider); 14 | 15 | return Scaffold( 16 | body: CustomScrollView( 17 | slivers: [ 18 | NestedAppBar( 19 | title: Text(t.settings.pageTitle), 20 | ), 21 | SliverList.list( 22 | children: [ 23 | SettingsSection(t.settings.general.sectionTitle), 24 | const GeneralSettingTiles(), 25 | const PlatformSettingsTiles(), 26 | const SettingsDivider(), 27 | SettingsSection(t.settings.advanced.sectionTitle), 28 | const AdvancedSettingTiles(), 29 | const Gap(16), 30 | ], 31 | ), 32 | ], 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/utils/OutboundMapper.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.utils 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import io.nekohasekai.libbox.OutboundGroup 5 | import io.nekohasekai.libbox.OutboundGroupItem 6 | 7 | data class ParsedOutboundGroup( 8 | @SerializedName("tag") val tag: String, 9 | @SerializedName("type") val type: String, 10 | @SerializedName("selected") val selected: String, 11 | @SerializedName("items") val items: List 12 | ) { 13 | companion object { 14 | fun fromOutbound(group: OutboundGroup): ParsedOutboundGroup { 15 | val outboundItems = group.items 16 | val items = mutableListOf() 17 | while (outboundItems.hasNext()) { 18 | items.add(ParsedOutboundGroupItem(outboundItems.next())) 19 | } 20 | return ParsedOutboundGroup(group.tag, group.type, group.selected, items) 21 | } 22 | } 23 | } 24 | 25 | data class ParsedOutboundGroupItem( 26 | @SerializedName("tag") val tag: String, 27 | @SerializedName("type") val type: String, 28 | @SerializedName("url-test-delay") val urlTestDelay: Int, 29 | ) { 30 | constructor(item: OutboundGroupItem) : this(item.tag, item.type, item.urlTestDelay) 31 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /lib/features/panel/xboard/utils/price_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/features/panel/xboard/models/plan_model.dart'; 3 | 4 | 5 | class PriceWidget extends StatelessWidget { 6 | final Plan plan; 7 | final String priceLabel; 8 | final String currency; 9 | 10 | PriceWidget( 11 | {required this.plan, required this.priceLabel, required this.currency, required TextStyle style}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | final double? cheapestPrice = _findCheapestPrice(plan); 16 | 17 | return Text( 18 | '$priceLabel ${cheapestPrice != null ? cheapestPrice.toStringAsFixed(2) : 'N/A'} $currency', 19 | style: const TextStyle( 20 | fontSize: 16, 21 | fontWeight: FontWeight.bold, 22 | color: Colors.red, 23 | ), 24 | ); 25 | } 26 | 27 | double? _findCheapestPrice(Plan plan) { 28 | final prices = [ 29 | plan.monthPrice, 30 | plan.quarterPrice, 31 | plan.halfYearPrice, 32 | plan.yearPrice, 33 | plan.twoYearPrice, 34 | plan.threeYearPrice, 35 | plan.onetimePrice 36 | ].where((price) => price != null).toList(); 37 | 38 | if (prices.isNotEmpty) { 39 | return prices.reduce((a, b) => a! < b! ? a : b); 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /lib/utils/sentry_riverpod_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:sentry_flutter/sentry_flutter.dart'; 3 | 4 | class SentryRiverpodObserver extends ProviderObserver { 5 | void addBreadcrumb(String message, {Map? data}) { 6 | Sentry.addBreadcrumb( 7 | Breadcrumb( 8 | category: "Provider", 9 | message: message, 10 | data: data, 11 | ), 12 | ); 13 | } 14 | 15 | @override 16 | void didAddProvider( 17 | ProviderBase provider, 18 | Object? value, 19 | ProviderContainer container, 20 | ) { 21 | super.didAddProvider(provider, value, container); 22 | addBreadcrumb( 23 | 'Provider [${provider.name ?? provider.runtimeType}] was ADDED', 24 | data: value != null ? {"initial-value": value} : null, 25 | ); 26 | } 27 | 28 | @override 29 | void didUpdateProvider( 30 | ProviderBase provider, 31 | Object? previousValue, 32 | Object? newValue, 33 | ProviderContainer container, 34 | ) { 35 | super.didUpdateProvider(provider, previousValue, newValue, container); 36 | addBreadcrumb( 37 | 'Provider [${provider.name ?? provider.runtimeType}] was UPDATED', 38 | data: { 39 | "new-value": newValue, 40 | "old-value": previousValue, 41 | }, 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /lib/core/theme/app_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hiddify/core/theme/app_theme_mode.dart'; 3 | import 'package:hiddify/core/theme/theme_extensions.dart'; 4 | 5 | class AppTheme { 6 | AppTheme(this.mode, this.fontFamily); 7 | final AppThemeMode mode; 8 | final String fontFamily; 9 | 10 | ThemeData lightTheme(ColorScheme? lightColorScheme) { 11 | final ColorScheme scheme = lightColorScheme ?? 12 | ColorScheme.fromSeed(seedColor: const Color(0xFF293CA0)); 13 | return ThemeData( 14 | useMaterial3: true, 15 | colorScheme: scheme, 16 | fontFamily: fontFamily, 17 | extensions: const >{ 18 | ConnectionButtonTheme.light, 19 | }, 20 | ); 21 | } 22 | 23 | ThemeData darkTheme(ColorScheme? darkColorScheme) { 24 | final ColorScheme scheme = darkColorScheme ?? 25 | ColorScheme.fromSeed( 26 | seedColor: const Color(0xFF293CA0), 27 | brightness: Brightness.dark, 28 | ); 29 | return ThemeData( 30 | useMaterial3: true, 31 | colorScheme: scheme, 32 | scaffoldBackgroundColor: 33 | mode.trueBlack ? Colors.black : scheme.background, 34 | fontFamily: fontFamily, 35 | extensions: const >{ 36 | ConnectionButtonTheme.light, 37 | }, 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/bg/AppChangeReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify.bg 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import com.hiddify.hiddify.Settings 7 | 8 | class AppChangeReceiver : BroadcastReceiver() { 9 | 10 | companion object { 11 | private const val TAG = "A/AppChangeReceiver" 12 | } 13 | 14 | override fun onReceive(context: Context, intent: Intent) { 15 | checkUpdate(context, intent) 16 | } 17 | 18 | private fun checkUpdate(context: Context, intent: Intent) { 19 | // if (!Settings.perAppProxyEnabled) { 20 | // return 21 | // } 22 | // val perAppProxyUpdateOnChange = Settings.perAppProxyUpdateOnChange 23 | // if (perAppProxyUpdateOnChange == Settings.PER_APP_PROXY_DISABLED) { 24 | // return 25 | // } 26 | // val packageName = intent.dataString?.substringAfter("package:") 27 | // if (packageName.isNullOrBlank()) { 28 | // return 29 | // } 30 | // if ((perAppProxyUpdateOnChange == Settings.PER_APP_PROXY_INCLUDE)) { 31 | // Settings.perAppProxyList = Settings.perAppProxyList + packageName 32 | // } else { 33 | // Settings.perAppProxyList = Settings.perAppProxyList - packageName 34 | // } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiddify/hiddify/LogHandler.kt: -------------------------------------------------------------------------------- 1 | package com.hiddify.hiddify 2 | 3 | import android.util.Log 4 | import io.flutter.embedding.engine.plugins.FlutterPlugin 5 | import io.flutter.plugin.common.EventChannel 6 | 7 | 8 | class LogHandler : FlutterPlugin { 9 | 10 | companion object { 11 | const val TAG = "A/LogHandler" 12 | const val SERVICE_LOGS = "com.hiddify.app/service.logs" 13 | } 14 | 15 | private lateinit var logsChannel: EventChannel 16 | 17 | override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 18 | logsChannel = EventChannel(flutterPluginBinding.binaryMessenger, SERVICE_LOGS) 19 | 20 | logsChannel.setStreamHandler(object : EventChannel.StreamHandler { 21 | override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { 22 | val activity = MainActivity.instance 23 | events?.success(activity.logList) 24 | activity.logCallback = { 25 | events?.success(activity.logList) 26 | } 27 | } 28 | 29 | override fun onCancel(arguments: Any?) { 30 | MainActivity.instance.logCallback = null 31 | } 32 | }) 33 | } 34 | 35 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 36 | } 37 | } --------------------------------------------------------------------------------