Compare commits
2 Commits
v0.8.98
...
v0.8.94-pre.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 4df745ad2d | |||
| 6697ac5666 |
@@ -0,0 +1,28 @@
|
||||
# Agent Configuration Model
|
||||
|
||||
Use the smallest durable surface that matches the job.
|
||||
|
||||
## Surfaces
|
||||
|
||||
- `AGENTS.md`: auto-loaded repository entry point. Keep it small and reserve it for always-on rules, routing, and high-priority expectations.
|
||||
- `.agents/*.md`: human- and agent-readable reference docs linked from `AGENTS.md`. Use these for detailed project context, commands, architecture, and conventions.
|
||||
- `.agents/skills/*/SKILL.md`: repo-scoped Codex skills. Use these for repeatable workflows that should be discoverable by name and description.
|
||||
- `.codex/config.toml`: trusted project Codex settings such as MCP, hooks, sandbox, approval, or model defaults.
|
||||
- `.codex/rules/*.rules`: command permission rules for running commands outside the sandbox. Do not mix these with coding conventions in `.agents/rules.md`.
|
||||
- `.codex/hooks.json` or `.codex/config.toml` hooks: lifecycle automation such as prompt checks, command validation, or final verification gates.
|
||||
|
||||
## Placement Rules
|
||||
|
||||
- Put stable team conventions in `AGENTS.md` only when every task must see them without opening another file.
|
||||
- Put detailed explanations in `.agents/*.md` and link them from `AGENTS.md`.
|
||||
- Put reusable task workflows in `.agents/skills/<skill-name>/SKILL.md`.
|
||||
- Put mechanical enforcement in linters, tests, hooks, or `.codex/rules`; do not rely on prose when tooling can enforce the rule.
|
||||
- Keep user-specific preferences out of the repository. They belong in user-level Codex configuration or user-level skills.
|
||||
|
||||
## Skill Authoring Rules
|
||||
|
||||
- Use lowercase hyphenated names.
|
||||
- Start descriptions with `Use when...`.
|
||||
- Describe trigger conditions in the description, not the workflow.
|
||||
- Keep `SKILL.md` lean; link to `.agents/*.md` for large reference material.
|
||||
- Add scripts only when deterministic behavior is needed repeatedly.
|
||||
@@ -0,0 +1,156 @@
|
||||
# Architecture
|
||||
|
||||
## Core Integration
|
||||
|
||||
The Go proxy core in `core/` operates in two modes.
|
||||
|
||||
Android lib mode:
|
||||
|
||||
- Go core is compiled as a C shared library, `libclash.so`, through `go build -buildmode=c-shared` with CGO.
|
||||
- Flutter calls it via FFI through the `service` plugin.
|
||||
- Dart-side implementation: `lib/core/lib.dart` (`CoreLib`).
|
||||
|
||||
Desktop core mode:
|
||||
|
||||
- Go core runs as a separate process with `CGO_ENABLED=0`.
|
||||
- Flutter communicates via JSON over socket, using a Unix socket on macOS/Linux and TCP on Windows.
|
||||
- Dart-side implementation: `lib/core/service.dart` (`CoreService`).
|
||||
|
||||
`lib/core/controller.dart` (`CoreController`) selects the implementation based on platform. `lib/core/interface.dart` defines the shared `CoreHandlerInterface`.
|
||||
|
||||
Key Go core files:
|
||||
|
||||
- `core/hub.go`: handler functions.
|
||||
- `core/action.go`: dispatch.
|
||||
- `core/lib.go`: CGO exports.
|
||||
- `core/server.go`: socket server.
|
||||
|
||||
## State Management
|
||||
|
||||
Provider files in `lib/providers/`:
|
||||
|
||||
- `app.dart`: runtime/UI state, logs, traffic, delays, loading, navigation.
|
||||
- `config.dart`: persistent config providers, app settings, theme, VPN, proxy style.
|
||||
- `state.dart`: derived/computed providers, navigation, proxy, tray, color scheme.
|
||||
- `action.dart`: business logic notifiers, setup, backup, core lifecycle, proxy selection.
|
||||
- `database.dart`: Drift database provider wrappers.
|
||||
|
||||
`globalState` in `lib/state.dart` is a singleton holding app lifecycle, timers, theme, and start/stop state. Providers are generated into `lib/providers/generated/`.
|
||||
|
||||
## Database
|
||||
|
||||
The app uses Drift/SQLite in `lib/database/`. Current schema version is 2.
|
||||
|
||||
Tables:
|
||||
|
||||
- `Profiles`
|
||||
- `Scripts`
|
||||
- `Rules`
|
||||
- `ProfileRuleLinks` (`profile_rule_mapping`)
|
||||
- `ProxyGroups`
|
||||
- `IconRecords` (`icon_records`)
|
||||
|
||||
Rule scenes distinguish global added rules, profile added rules, profile custom rules, and disabled links. Rule and proxy-group ordering use fractional indexing.
|
||||
|
||||
Generated Drift output lives in `lib/database/generated/database.g.dart`. After schema changes, run code generation and add or update focused database tests under `test/database/` when converter or migration behavior changes.
|
||||
|
||||
## Manager Stack
|
||||
|
||||
Managers are nested `InheritedWidget`/`StatefulWidget` components in `lib/application.dart`:
|
||||
|
||||
```text
|
||||
AppEnvManager > StatusManager > ThemeManager
|
||||
> [Desktop: WindowManager > TrayManager > HotKeyManager > ProxyManager]
|
||||
> ConnectivityManager > CoreManager > AppStateManager
|
||||
> [Mobile: AndroidManager > VpnManager | Desktop: WindowHeaderContainer]
|
||||
```
|
||||
|
||||
Each manager in `lib/manager/` handles a specific platform concern. Desktop-only managers are conditionally inserted.
|
||||
|
||||
## Core Controller and Actions
|
||||
|
||||
`lib/core/controller.dart` (`CoreController`) is a singleton facade over `CoreHandlerInterface`. Public methods delegate to the platform-specific interface, either Android FFI or desktop socket. It has an `@visibleForTesting` constructor and `resetInstance()` for test injection.
|
||||
|
||||
Business logic lives in Riverpod notifier classes in `lib/providers/action.dart`:
|
||||
|
||||
- `CommonAction`: update check and common UI operations.
|
||||
- `SetupAction`: config setup and TUN management.
|
||||
- `BackupAction`: backup/restore with WebDAV sync.
|
||||
- `CoreAction`: core lifecycle, init, connect, restart, shutdown.
|
||||
- `SystemAction`: system integration, tray, exit, brightness.
|
||||
- `StoreAction`: profile storage operations.
|
||||
- `ThemeAction`: theme state updates.
|
||||
- `ProxiesAction`: group management and proxy selection.
|
||||
- `ProfilesAction`: profile CRUD, auto-update, import.
|
||||
|
||||
## Platform Managers
|
||||
|
||||
Desktop:
|
||||
|
||||
- `WindowManager`
|
||||
- `TrayManager`
|
||||
- `HotKeyManager`
|
||||
- `ProxyManager`
|
||||
|
||||
Mobile:
|
||||
|
||||
- `AndroidManager`
|
||||
- `TileManager`
|
||||
- `VpnManager`
|
||||
|
||||
Shared:
|
||||
|
||||
- `ConnectivityManager`
|
||||
- `CoreManager`
|
||||
- `AppStateManager`
|
||||
- `StatusManager`
|
||||
- `ThemeManager`
|
||||
|
||||
## Build System
|
||||
|
||||
`setup.dart` is the release build orchestrator:
|
||||
|
||||
1. On Windows, pre-builds Go core via `dart run build_tool windows` and reads `core_sha256.json`.
|
||||
2. Writes `env.json` (`APP_ENV`).
|
||||
3. Passes SHA256 as `--dart-define=CORE_SHA256=$val`, embedded at compile time for Windows.
|
||||
4. Activates `flutter_distributor` for packaging.
|
||||
|
||||
Go core building is handled by `build_tool`, a standalone Dart CLI in `plugins/setup/buildkit/build_tool/`.
|
||||
|
||||
Platform build hooks inside `flutter build` trigger `build_tool` automatically:
|
||||
|
||||
- macOS: podspec script phase, `build_pod.sh`, `build_tool macos`.
|
||||
- Linux: CMake include, `buildkit/cmake/buildkit.cmake`, `build_tool linux`.
|
||||
- Windows: CMake include, `buildkit/cmake/buildkit.cmake`, `build_tool windows`. Debug passes `--dev` via `CMAKE_BUILD_TYPE`.
|
||||
- Android: Gradle include, `buildkit/gradle/plugin.gradle`, `build_tool android`.
|
||||
|
||||
Windows helper auth:
|
||||
|
||||
- Release: Core SHA256 is embedded in both the Flutter app and the Rust helper. The app pings the helper and verifies the token matches.
|
||||
- Debug: The Rust helper skips token verification when built in debug mode, so `flutter run` works without the SHA256 flow.
|
||||
|
||||
`plugins/setup/` is an FFI plugin that exists only as a build harness. It carries no Dart API, only platform build hooks that trigger Go compilation. Windows builds also compile a Rust helper in `services/helper/` through `RustBuilder`.
|
||||
|
||||
Build configuration defaults live in `build_tool/lib/src/options.dart` and can be overridden via `build_config.yaml`.
|
||||
|
||||
Architecture detection is automatic. The `--description` flag passed to `flutter_distributor` adds arch suffixes to artifact names, such as `FlClash-0.8.93-macos-arm64.dmg`.
|
||||
|
||||
## Local Plugins
|
||||
|
||||
- `setup`: build harness FFI plugin.
|
||||
- `proxy`: system proxy configuration.
|
||||
- `rust_api`: Flutter Rust Bridge FFI plugin.
|
||||
- `tray_manager`: system tray fork/customization.
|
||||
- `wifi_ssid`: Wi-Fi SSID detection.
|
||||
- `window_ext`: window extensions.
|
||||
- `flutter_distributor`: app packaging/distribution.
|
||||
|
||||
## Rust Helper Service
|
||||
|
||||
`services/helper/` is a Windows-only privileged helper for starting the core as admin and managing TUN. It is built with:
|
||||
|
||||
```bash
|
||||
cargo build --release --features windows-service
|
||||
```
|
||||
|
||||
It uses token-based auth with the Flutter app.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Commands
|
||||
|
||||
## Building
|
||||
|
||||
Update submodules first. The ClashMeta Go core lives in `core/Clash.Meta/`.
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Full package build, including Go core, Flutter, and packaging, runs through `setup.dart`:
|
||||
|
||||
```bash
|
||||
dart setup.dart macos
|
||||
dart setup.dart linux
|
||||
dart setup.dart windows
|
||||
dart setup.dart android
|
||||
```
|
||||
|
||||
Build only the Go core and skip Flutter packaging:
|
||||
|
||||
```bash
|
||||
bash plugins/setup/buildkit/run_build_tool.sh macos
|
||||
bash plugins/setup/buildkit/run_build_tool.sh linux
|
||||
bash plugins/setup/buildkit/run_build_tool.sh windows
|
||||
bash plugins/setup/buildkit/run_build_tool.sh android
|
||||
```
|
||||
|
||||
## Flutter Development
|
||||
|
||||
The project is pinned with FVM.
|
||||
|
||||
```bash
|
||||
fvm flutter pub get
|
||||
fvm flutter run
|
||||
fvm flutter test
|
||||
```
|
||||
|
||||
Plain Flutter also works when the global SDK matches project constraints:
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
flutter run
|
||||
flutter test
|
||||
```
|
||||
|
||||
Use `flutter test`, not `dart test`, because models pull in Flutter types.
|
||||
|
||||
## Code Generation
|
||||
|
||||
Run code generation after modifying models, providers, or database schema:
|
||||
|
||||
```bash
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
dart run build_runner watch
|
||||
```
|
||||
|
||||
Code generation covers:
|
||||
|
||||
- Riverpod providers through `riverpod_generator`.
|
||||
- Models through `freezed` and `json_serializable`.
|
||||
- Database tables through `drift_dev`.
|
||||
|
||||
Generated output paths, configured in `build.yaml`:
|
||||
|
||||
- `lib/models/generated/*.g.dart`, `*.freezed.dart`.
|
||||
- `lib/providers/generated/*.g.dart`.
|
||||
- `lib/database/generated/*.g.dart`.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests use `package:test/test.dart` for pure Dart logic and `flutter_test` for provider and widget tests. `mocktail` is the mocking framework.
|
||||
|
||||
```bash
|
||||
flutter test test/models/
|
||||
flutter test test/core/
|
||||
flutter test test/providers/
|
||||
flutter test test/common/
|
||||
flutter test test/database/
|
||||
flutter test test/widgets/
|
||||
flutter test test/setup_test.dart
|
||||
flutter test plugins/proxy/test/proxy_test.dart
|
||||
```
|
||||
|
||||
Root `flutter test` only discovers the root package's `test/` directory by default. Include bundled plugin Dart tests by passing paths explicitly, or run `flutter test` from that plugin package directory. Native plugin tests under platform folders are not run by `flutter test`.
|
||||
|
||||
## Verify
|
||||
|
||||
CI runs these in order:
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
flutter analyze --no-fatal-infos
|
||||
flutter test --reporter expanded
|
||||
```
|
||||
|
||||
Run `flutter analyze` locally before committing when practical.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Project Context
|
||||
|
||||
FlClash is a multi-platform proxy client based on ClashMeta (mihomo), built with Flutter. It supports Android, Windows, macOS, and Linux, using a Material You design with Surfboard-like UI.
|
||||
|
||||
## Version Notes
|
||||
|
||||
- `.fvmrc` pins Flutter 3.35.7 for local development.
|
||||
- CI uses Flutter 3.41.9. These may diverge; trust CI as the source of truth for release builds.
|
||||
- Dart SDK constraint: `>=3.8.0 <4.0.0`.
|
||||
|
||||
## Build Dependencies
|
||||
|
||||
Linux:
|
||||
|
||||
```bash
|
||||
sudo apt-get install libayatana-appindicator3-dev libkeybinder-3.0-dev
|
||||
```
|
||||
|
||||
Windows:
|
||||
|
||||
- GCC and Inno Setup.
|
||||
- `ANDROID_NDK` env var for Android builds.
|
||||
|
||||
macOS:
|
||||
|
||||
```bash
|
||||
npm install -g appdmg
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
# Rules
|
||||
|
||||
These are repository coding and testing conventions. Codex command permission rules belong in `.codex/rules/*.rules`; see `.agents/agent-config.md` before adding those.
|
||||
|
||||
## Dart and Flutter Style
|
||||
|
||||
`analysis_options.yaml` enforces these non-default rules:
|
||||
|
||||
- `prefer_single_quotes: true`: always use single quotes.
|
||||
- `require_trailing_commas: true`: use trailing commas in multi-line argument lists.
|
||||
- `sort_child_properties_last: true`: `child:` must be the last named parameter.
|
||||
- `avoid_print: true`: do not use `print()` calls.
|
||||
- `prefer_const_constructors: true` and `prefer_const_declarations: true`.
|
||||
- `prefer_final_locals: true` and `prefer_final_in_for_each: true`.
|
||||
- `always_declare_return_types: true`.
|
||||
|
||||
Generated directories are excluded from analysis:
|
||||
|
||||
- `build/**`
|
||||
- `lib/l10n/intl/**`
|
||||
- `lib/**/generated/**`
|
||||
- `plugins/**`
|
||||
|
||||
## Testing Rules
|
||||
|
||||
Use `CoreController.test(mock)` to inject a mocked `CoreHandlerInterface`. Call `CoreController.resetInstance()` in `tearDown` to clean up the singleton between tests.
|
||||
|
||||
Register fallback values for freezed params used with `any()` matchers.
|
||||
|
||||
Use `ProviderContainer` directly for simple Riverpod provider tests. The generated Riverpod `update()` method takes a callback:
|
||||
|
||||
```dart
|
||||
notifier.update((state) => newValue);
|
||||
```
|
||||
|
||||
When testing freezed models with nested objects, always round-trip through `jsonEncode` and `jsonDecode`. Direct `fromJson(toJson())` fails for nested freezed types because `toJson()` stores child objects directly instead of maps.
|
||||
|
||||
## Generated Code
|
||||
|
||||
Do not manually edit generated files under:
|
||||
|
||||
- `lib/models/generated/`
|
||||
- `lib/providers/generated/`
|
||||
- `lib/database/generated/`
|
||||
- `lib/l10n/intl/`
|
||||
|
||||
After schema, model, or provider changes, run build generation and include focused tests when behavior changes.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Agent Skills
|
||||
|
||||
Repo-scoped Codex skills live under `.agents/skills/*/SKILL.md`. Codex can discover these by skill `name` and `description`, then load the full instructions only when a task matches.
|
||||
|
||||
## Available Repo Skills
|
||||
|
||||
- `localization`: hardcoded UI text scans, ARB updates, locale generation, and localization verification.
|
||||
- `provider-tests`: Riverpod provider, notifier, and state-management tests.
|
||||
- `ui-work`: Flutter UI, widgets, Material You styling, navigation surfaces, and user-facing interactions.
|
||||
- `core-platform`: core integration, platform managers, Go core communication, desktop/mobile behavior, and Windows helper flow.
|
||||
|
||||
## Authoring Notes
|
||||
|
||||
- Add new repeatable workflows as `.agents/skills/<skill-name>/SKILL.md`.
|
||||
- Keep skill descriptions trigger-focused and start them with `Use when...`.
|
||||
- Keep long reference material in `.agents/*.md`; skills should link to it instead of duplicating it.
|
||||
- Put command permission rules in `.codex/rules/*.rules`, not in this file.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: core-platform
|
||||
description: Use when changing FlClash core integration, platform managers, Go core communication, desktop/mobile platform behavior, or Windows helper flow.
|
||||
---
|
||||
|
||||
# Core And Platform
|
||||
|
||||
## When To Use
|
||||
|
||||
Use this for changes touching `lib/core/`, `lib/manager/`, `core/`, `services/helper/`, build hooks, system proxy, tray, VPN, TUN, or platform-specific desktop/mobile behavior.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Identify which boundary owns the behavior:
|
||||
- Android lib mode: `lib/core/lib.dart`.
|
||||
- Desktop process/socket mode: `lib/core/service.dart`.
|
||||
- Shared facade: `lib/core/controller.dart` and `lib/core/interface.dart`.
|
||||
- Platform lifecycle: `lib/manager/`.
|
||||
2. Route feature code through `CoreController` and `CoreHandlerInterface`; avoid direct calls to platform implementations outside their boundary.
|
||||
3. Keep desktop and mobile paths explicit.
|
||||
4. For action-layer behavior, inspect `lib/providers/action.dart` and relevant generated providers.
|
||||
5. Add or update shared Dart tests for logic that can be isolated.
|
||||
6. Manually verify native behavior when automated coverage is not practical.
|
||||
|
||||
## Reference Files
|
||||
|
||||
Read `.agents/architecture.md` for the current core modes, manager stack, build hooks, local plugins, and Windows helper notes.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Debug Windows helper auth differs from release token verification.
|
||||
- `plugins/setup/` is a build harness, not a Dart API plugin.
|
||||
- Build hooks can trigger Go or Rust compilation indirectly through Flutter platform builds.
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: localization
|
||||
description: Use when changing FlClash UI text, scanning for hardcoded Chinese strings, updating ARB localization, or fixing generated locale output in this repository.
|
||||
---
|
||||
|
||||
# Localization
|
||||
|
||||
## When To Use
|
||||
|
||||
Use this for localization work inside `/Users/Shared/follow/FlClash`, especially hardcoded UI text in `lib/`, ARB updates, missing translations, or generated `lib/l10n/` output that does not match source ARB values.
|
||||
|
||||
Do not use this for README translation sync or manual edits to generated localization Dart.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Confirm `pubspec.yaml` still uses `flutter_intl`, source ARBs under `arb/`, and generated output under `lib/l10n/`.
|
||||
2. Scan user-facing Dart text before opening many files:
|
||||
|
||||
```bash
|
||||
rg -n "[\\p{Han}]" lib -g '!lib/l10n/intl/**' -g '!lib/**/generated/**'
|
||||
```
|
||||
|
||||
3. Inspect the smallest relevant call sites and nearby ARB keys.
|
||||
4. Add or update every source ARB:
|
||||
- `arb/intl_en.arb`
|
||||
- `arb/intl_zh_CN.arb`
|
||||
- `arb/intl_ja.arb`
|
||||
- `arb/intl_ru.arb`
|
||||
5. Replace inline strings with existing project accessors:
|
||||
- Widgets with `BuildContext`: `context.appLocalizations.key` from `common.dart`.
|
||||
- Controllers/providers/non-widget code: `currentAppLocalizations.key` from `app_localizations.dart`.
|
||||
6. Regenerate:
|
||||
|
||||
```bash
|
||||
dart run intl_utils:generate
|
||||
```
|
||||
|
||||
7. Verify changed Dart files with `flutter analyze` when practical.
|
||||
8. Re-run the Han-text scan for targeted strings.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- If ja/ru still show English, fix ja/ru source ARB values and regenerate. Do not edit generated Dart.
|
||||
- Ignore `lib/l10n/intl/**` and `lib/**/generated/**` during text scans.
|
||||
- If generator or analyzer hits local cache permission friction, rerun serially before treating it as a code issue.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
name: provider-tests
|
||||
description: Use when adding or updating FlClash Riverpod provider tests, notifier tests, or state-management tests in this repository.
|
||||
---
|
||||
|
||||
# Provider Tests
|
||||
|
||||
## When To Use
|
||||
|
||||
Use this for tests under `test/providers/` or any change that validates Riverpod providers, generated notifiers, app state defaults, or provider interactions.
|
||||
|
||||
For broader test expansion, pair this with `.agents/rules.md` and `.agents/commands.md`.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Read the provider under test and its generated public API before writing assertions.
|
||||
2. Use `ProviderContainer` directly when no widget tree is needed.
|
||||
3. Dispose containers in teardown or with `addTearDown(container.dispose)`.
|
||||
4. Prefer generated notifier APIs over implementation details. Generated `update()` takes a callback:
|
||||
|
||||
```dart
|
||||
notifier.update((state) => newValue);
|
||||
```
|
||||
|
||||
5. Mock external dependencies with `mocktail`; register fallback values for freezed params used with `any()`.
|
||||
6. Keep tests focused on behavior: defaults, state transitions, persistence boundaries, and side effects.
|
||||
7. Run the narrowest relevant test first:
|
||||
|
||||
```bash
|
||||
flutter test test/providers/
|
||||
```
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Do not use `dart test`; FlClash models and provider tests may depend on Flutter types.
|
||||
- Re-check source defaults before asserting them; provider defaults can drift.
|
||||
- If async provider timing matters, wait on provider futures or state changes instead of fixed sleeps.
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: ui-work
|
||||
description: Use when changing FlClash Flutter UI, widgets, screens, Material You styling, navigation surfaces, or user-facing interactions.
|
||||
---
|
||||
|
||||
# UI Work
|
||||
|
||||
## When To Use
|
||||
|
||||
Use this for user-facing Flutter UI changes in `lib/`, including widgets, screens, navigation surfaces, settings rows, dialogs, and interaction behavior.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Locate existing nearby widgets and reuse their patterns before adding new abstractions.
|
||||
2. Follow current Material You and Surfboard-like visual conventions.
|
||||
3. Use existing providers, notifiers, and helpers where possible.
|
||||
4. Keep `child:` last in widget constructors.
|
||||
5. Prefer `const` constructors and final locals.
|
||||
6. Localize user-facing text through ARB; use `localization` when text changes are non-trivial.
|
||||
7. Add focused widget tests when behavior changes, especially for rendering states, taps, scrolling, and empty/error states.
|
||||
8. Run targeted verification:
|
||||
|
||||
```bash
|
||||
flutter analyze
|
||||
flutter test test/widgets/
|
||||
```
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Do not introduce a new visual system for one screen.
|
||||
- Do not manually edit generated localization or provider files.
|
||||
- Avoid broad layout rewrites unless the requested change requires them.
|
||||
@@ -1,93 +0,0 @@
|
||||
Scan `lib/` for hardcoded Chinese strings and internationalize them following the project's ARB conventions.
|
||||
|
||||
## Instructions
|
||||
|
||||
You are performing i18n extraction for a Flutter project that uses the Flutter Intl plugin with ARB files.
|
||||
|
||||
### Project localization context
|
||||
|
||||
- **ARB files**: `arb/intl_en.arb`, `arb/intl_zh_CN.arb`, `arb/intl_ja.arb`, `arb/intl_ru.arb`
|
||||
- **Key conventions**: camelCase, flat keys (no nesting, no `@` metadata), semantic naming
|
||||
- Short labels: `rule`, `global`, `direct`, `edit`, `confirm`
|
||||
- Descriptive suffix `Desc`: `themeDesc`, `tunDesc`, `logsDesc`
|
||||
- Validation suffix: `profileNameNullValidationDesc`
|
||||
- **Generated code**: `lib/l10n/l10n.dart` (DO NOT edit generated files)
|
||||
- **Access patterns**:
|
||||
- In widgets with BuildContext: `context.appLocalizations.key` (import `common.dart`)
|
||||
- In controllers/providers/non-widget code: `currentAppLocalizations.key` (import `app_localizations.dart`)
|
||||
|
||||
### Step 1: Find hardcoded Chinese strings
|
||||
|
||||
Use Grep to search `lib/` for Chinese characters. The regex pattern for Chinese characters is `[\x{4e00}-\x{9fff}]`.
|
||||
|
||||
Important filters:
|
||||
- **Exclude** `lib/l10n/` (generated localization files)
|
||||
- **Exclude** lines that already use `appLocalizations` or `currentAppLocalizations`
|
||||
- **Exclude** false positives that are NOT Chinese text:
|
||||
- Arrow symbols: `↑` `↓` `←` `→` (Unicode arrows, not CJK)
|
||||
- Middle dot: `·` (U+00B7, not CJK)
|
||||
- Command symbol: `⌘` (U+2318, not CJK)
|
||||
- Other CJK punctuation that is used as UI symbols, not translatable text
|
||||
|
||||
For each match, read the surrounding context (5-10 lines) to understand:
|
||||
- What the string represents (label, error message, tooltip, dialog text, etc.)
|
||||
- Whether it's inside a widget (has `BuildContext` available) or non-widget code
|
||||
- Whether it appears in a `Text()`, `TextSpan()`, `title:`, `label:`, or other text position
|
||||
|
||||
### Step 2: Generate ARB keys
|
||||
|
||||
For each hardcoded Chinese string:
|
||||
|
||||
1. **Choose a key name** following project conventions:
|
||||
- Use the Chinese meaning to derive an English camelCase key
|
||||
- Keep it concise: `createConfig` not `createAConfigurationForTheProfile`
|
||||
- Use `Desc` suffix for descriptive/explanatory text
|
||||
- Use existing similar keys as reference (check `arb/intl_en.arb` for patterns)
|
||||
|
||||
2. **Determine the English translation** (the value for `intl_en.arb`)
|
||||
|
||||
3. **Determine the Chinese translation** (the value for `intl_zh_CN.arb`) — this is the original hardcoded string
|
||||
|
||||
4. **For ja and ru**: use the English translation as a placeholder (translators will fill these in later)
|
||||
|
||||
### Step 3: Update ARB files
|
||||
|
||||
For each new key, add it to all 4 ARB files. Read each ARB file first to find the right insertion point (alphabetical order is not required, but appending near the end is clean).
|
||||
|
||||
Format: add a new line like `"keyName": "value",` before the closing `}`.
|
||||
|
||||
### Step 4: Replace hardcoded strings in Dart files
|
||||
|
||||
Replace each hardcoded Chinese string with the appropriate localization call:
|
||||
|
||||
- If inside a widget BuildContext: `context.appLocalizations.keyName`
|
||||
- If in controller/provider code: `currentAppLocalizations.keyName`
|
||||
|
||||
Ensure the correct import exists:
|
||||
- For `context.appLocalizations`: the file should import `common.dart` (check if it already does)
|
||||
- For `currentAppLocalizations`: the file should import `app_localizations.dart` (check if it already does)
|
||||
|
||||
If the file uses string interpolation (e.g., `'创建 $name 配置'`), convert to the ARB parameterized format:
|
||||
- In ARB: `"keyName": "Create $name config"`
|
||||
- In Dart: `currentAppLocalizations.keyName(name)`
|
||||
|
||||
### Step 5: Report changes
|
||||
|
||||
After all modifications, output a summary:
|
||||
1. List each file modified and what changed
|
||||
2. List each new ARB key added with its translations
|
||||
3. Remind the user to run code generation if needed:
|
||||
```
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
or trigger Flutter Intl regeneration in their IDE.
|
||||
|
||||
### Important notes
|
||||
|
||||
- Only extract strings that are user-facing UI text. Do NOT extract:
|
||||
- Comments (lines starting with `//`)
|
||||
- Log messages (unless they appear in the UI)
|
||||
- Variable names or identifiers
|
||||
- String literals used as keys/identifiers (not displayed to users)
|
||||
- If a Chinese string is split across multiple lines or concatenations, merge them into a single ARB entry
|
||||
- If a string contains dynamic content (variables, URLs), use ARB parameter syntax `$variableName`
|
||||
@@ -0,0 +1,5 @@
|
||||
# CodeGraph data files — local to each machine, not for committing.
|
||||
# Ignore everything in .codegraph/ except this file itself, so transient
|
||||
# files (the database, daemon.pid, sockets, logs) never show up in git.
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"codegraph": {
|
||||
"type": "stdio",
|
||||
"command": "codegraph",
|
||||
"args": [
|
||||
"serve",
|
||||
"--mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
cask "flclash" do
|
||||
version "VERSION"
|
||||
|
||||
on_macos do
|
||||
arch arm: "arm64", intel: "amd64"
|
||||
|
||||
sha256 arm: "ARM_SHA256",
|
||||
intel: "AMD_SHA256"
|
||||
|
||||
url "https://github.com/chen08209/FlClash/releases/download/v#{version}/FlClash-#{version}-macos-#{arch}.dmg"
|
||||
end
|
||||
|
||||
name "FlClash"
|
||||
desc "Multi-platform proxy client based on ClashMeta"
|
||||
homepage "https://github.com/chen08209/FlClash"
|
||||
|
||||
livecheck do
|
||||
url :url
|
||||
strategy :github_latest
|
||||
end
|
||||
|
||||
depends_on :macos
|
||||
|
||||
app "FlClash.app"
|
||||
|
||||
postflight do
|
||||
system_command "xattr",
|
||||
args: ["-rd", "com.apple.quarantine", "#{appdir}/FlClash.app"]
|
||||
end
|
||||
|
||||
uninstall quit: "com.follow.clash"
|
||||
|
||||
zap trash: [
|
||||
"~/Library/Application Support/com.follow.clash",
|
||||
"~/Library/Caches/com.follow.clash",
|
||||
"~/Library/Preferences/com.follow.clash.plist",
|
||||
"~/Library/Saved Application State/com.follow.clash.savedState",
|
||||
]
|
||||
end
|
||||
@@ -42,7 +42,7 @@
|
||||
<td>
|
||||
<a href="https://github.com/chen08209/FlClash/releases/download/vVERSION/FlClash-VERSION-linux-amd64.AppImage"><img src="https://img.shields.io/badge/AppImage-x64-f84e29.svg?logo=linux"> </a><br>
|
||||
<a href="https://github.com/chen08209/FlClash/releases/download/vVERSION/FlClash-VERSION-linux-amd64.deb"><img src="https://img.shields.io/badge/DebPackage-x64-FF9966.svg?logo=debian"> </a><br>
|
||||
<a href="https://github.com/chen08209/FlClash/releases/download/vVERSION/FlClash-VERSION-linux-amd64.deb"><img src="https://img.shields.io/badge/RpmPackage-x64-F1B42F.svg?logo=redhat"> </a>
|
||||
<a href="https://github.com/chen08209/FlClash/releases/download/vVERSION/FlClash-VERSION-linux-amd64.rpm"><img src="https://img.shields.io/badge/RpmPackage-x64-F1B42F.svg?logo=redhat"> </a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
- 'v*'
|
||||
env:
|
||||
IS_STABLE: ${{ !contains(github.ref, '-') }}
|
||||
FLUTTER_VERSION: '3.44.4'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -21,7 +22,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
flutter-version: 3.41.9
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -63,6 +64,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup rust
|
||||
if: startsWith(matrix.os, 'windows-11-arm')
|
||||
shell: pwsh
|
||||
run: |
|
||||
Invoke-WebRequest -Uri "https://win.rustup.rs/aarch64" -OutFile rustup-init.exe
|
||||
.\rustup-init.exe -y --default-toolchain stable
|
||||
@@ -79,14 +81,16 @@ jobs:
|
||||
run: |
|
||||
echo "${{ secrets.KEYSTORE }}" | base64 --decode > android/app/keystore.jks
|
||||
echo "${{ secrets.SERVICE_JSON }}" | base64 --decode > android/app/google-services.json
|
||||
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/local.properties
|
||||
echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> android/local.properties
|
||||
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/local.properties
|
||||
{
|
||||
echo "keyAlias=${{ secrets.KEY_ALIAS }}"
|
||||
echo "storePassword=${{ secrets.STORE_PASSWORD }}"
|
||||
echo "keyPassword=${{ secrets.KEY_PASSWORD }}"
|
||||
} >> android/local.properties
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24.0'
|
||||
go-version: '1.26.4'
|
||||
cache-dependency-path: |
|
||||
core/go.sum
|
||||
|
||||
@@ -95,20 +99,18 @@ jobs:
|
||||
run: git config --global core.longpaths true
|
||||
|
||||
- name: Setup Flutter
|
||||
if: ${{ !(startsWith(matrix.os, 'windows-11-arm') || startsWith(matrix.os, 'ubuntu-24.04-arm')) }}
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
flutter-version: 3.41.9
|
||||
cache: true
|
||||
- name: Setup Flutter With Other
|
||||
if: startsWith(matrix.os, 'windows-11-arm') || startsWith(matrix.os, 'ubuntu-24.04-arm')
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: master
|
||||
flutter-version: 3.44.0-0.1.pre
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Setup Xcode
|
||||
if: startsWith(matrix.platform,'macos')
|
||||
run: |
|
||||
sudo xcode-select -s /Applications/Xcode_26.3.app || sudo xcode-select -s /Applications/Xcode_26.2.app
|
||||
xcodebuild -version
|
||||
|
||||
- name: Setup NDK
|
||||
if: startsWith(matrix.platform,'android')
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -133,23 +135,25 @@ jobs:
|
||||
overwrite: true
|
||||
|
||||
changelog:
|
||||
if: ${{ !contains(github.ref, '-') }}
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ build ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/heads/main
|
||||
- name: Generate
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
run: |
|
||||
last_ver=$(grep -m1 '^## ' CHANGELOG.md 2>/dev/null | sed 's/^## //')
|
||||
|
||||
tags=($(git tag --merged HEAD --sort=-creatordate))
|
||||
mapfile -t tags < <(git tag --merged HEAD --sort=-creatordate)
|
||||
|
||||
temp="NEW_CHANGELOG.md" > "$temp"
|
||||
temp="NEW_CHANGELOG.md"
|
||||
: > "$temp"
|
||||
|
||||
for i in "${!tags[@]}"; do
|
||||
curr="${tags[i]}"
|
||||
@@ -167,7 +171,6 @@ jobs:
|
||||
mv "$temp" CHANGELOG.md
|
||||
|
||||
- name: Commit
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
run: |
|
||||
git add CHANGELOG.md
|
||||
if ! git diff --cached --quiet; then
|
||||
@@ -175,8 +178,7 @@ jobs:
|
||||
git config --local user.email "chen08209@gmail.com"
|
||||
git config --local user.name "chen08209"
|
||||
git commit -m "Update changelog"
|
||||
git push
|
||||
if [ $? -eq 0 ]; then
|
||||
if git push; then
|
||||
echo "Push succeeded"
|
||||
else
|
||||
echo "Push failed"
|
||||
@@ -188,7 +190,8 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
upload:
|
||||
permissions: write-all
|
||||
permissions:
|
||||
contents: write
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
@@ -214,13 +217,14 @@ jobs:
|
||||
|
||||
- name: Generate release.md
|
||||
run: |
|
||||
tags=($(git tag --merged HEAD --sort=-creatordate))
|
||||
mapfile -t tags < <(git tag --merged HEAD --sort=-creatordate)
|
||||
preTag=$(curl -s "https://api.github.com/repos/chen08209/FlClash/releases/latest" | \
|
||||
sed -nE 's/.*"tag_name": "([^"]+)".*/\1/p')
|
||||
|
||||
[ -z "$preTag" ] && preTag=""
|
||||
|
||||
out="release.md" > "$out"
|
||||
out="release.md"
|
||||
: > "$out"
|
||||
|
||||
for i in "${!tags[@]}"; do
|
||||
curr="${tags[i]}"
|
||||
@@ -251,7 +255,7 @@ jobs:
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
run: |
|
||||
cd ./dist
|
||||
sha256sum * > SHA256SUMS
|
||||
sha256sum ./* > SHA256SUMS
|
||||
|
||||
- name: Release
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
@@ -260,6 +264,35 @@ jobs:
|
||||
files: ./dist/*
|
||||
body_path: './release.md'
|
||||
|
||||
- name: Create Homebrew Cask Source Dir
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
run: |
|
||||
version=$(echo "${{ github.ref_name }}" | sed 's/^v//')
|
||||
arm_sha=$(sha256sum "./dist/FlClash-${version}-macos-arm64.dmg" | awk '{print $1}')
|
||||
amd_sha=$(sha256sum "./dist/FlClash-${version}-macos-amd64.dmg" | awk '{print $1}')
|
||||
|
||||
mkdir -p ./brew/Casks
|
||||
sed \
|
||||
-e "s|VERSION|$version|g" \
|
||||
-e "s|ARM_SHA256|$arm_sha|g" \
|
||||
-e "s|AMD_SHA256|$amd_sha|g" \
|
||||
./.github/homebrew_cask_template.rb > ./brew/Casks/flclash.rb
|
||||
|
||||
- name: Push to Homebrew tap
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
uses: cpina/github-action-push-to-another-repository@v1.7.2
|
||||
env:
|
||||
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
|
||||
with:
|
||||
source-directory: ./brew/
|
||||
destination-github-username: chen08209
|
||||
destination-repository-name: homebrew-tap
|
||||
user-name: 'chen08029'
|
||||
user-email: 'chen08209@gmail.com'
|
||||
target-branch: main
|
||||
commit-message: Update Homebrew cask from ${{ github.ref_name }}
|
||||
target-directory: /
|
||||
|
||||
- name: Create Fdroid Source Dir
|
||||
if: ${{ env.IS_STABLE == 'true' }}
|
||||
run: |
|
||||
@@ -276,8 +309,8 @@ jobs:
|
||||
source-directory: ./tmp/
|
||||
destination-github-username: chen08209
|
||||
destination-repository-name: FlClash-fdroid-repo
|
||||
user-name: 'github-actions[bot]'
|
||||
user-email: 'github-actions[bot]@users.noreply.github.com'
|
||||
user-name: 'chen08029'
|
||||
user-email: 'chen08209@gmail.com'
|
||||
target-branch: main
|
||||
commit-message: Update from ${{ github.ref_name }}
|
||||
target-directory: /tmp/
|
||||
|
||||
@@ -2,13 +2,3 @@
|
||||
path = core/Clash.Meta
|
||||
url = git@github.com:chen08209/Clash.Meta.git
|
||||
branch = FlClash
|
||||
[submodule "plugins/flutter_distributor"]
|
||||
path = plugins/flutter_distributor
|
||||
url = git@github.com:chen08209/flutter_distributor.git
|
||||
branch = FlClash
|
||||
[submodule "plugins/tray_manager"]
|
||||
path = plugins/tray_manager
|
||||
url = git@github.com:chen08209/tray_manager.git
|
||||
branch = main
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"codegraph": {
|
||||
"type": "stdio",
|
||||
"command": "codegraph",
|
||||
"args": [
|
||||
"serve",
|
||||
"--mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: dart-format
|
||||
name: dart format
|
||||
entry: dart format
|
||||
language: system
|
||||
files: \.dart$
|
||||
- id: flutter-analyze
|
||||
name: flutter analyze
|
||||
entry: flutter analyze --no-fatal-infos
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: \.dart$
|
||||
- id: flutter-test
|
||||
name: flutter test
|
||||
entry: flutter test --reporter expanded
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: \.dart$
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"lsp": {
|
||||
"gopls": {
|
||||
"binary": {
|
||||
"env": {
|
||||
"CGO_ENABLED": "0",
|
||||
// "GOOS": "android",
|
||||
// "GOARCH": "arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,233 +1,32 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance for AI coding agents working with code in this repository.
|
||||
This file is the entry point for AI coding agents working in this repository. Keep it small: detailed guidance lives under
|
||||
`.agents/`, and discoverable repo skills live under `.agents/skills/*/SKILL.md`.
|
||||
|
||||
## Project Overview
|
||||
## Start Here
|
||||
|
||||
FlClash is a multi-platform proxy client based on ClashMeta (mihomo), built with Flutter. Supports Android, Windows,
|
||||
macOS, and Linux. Material You design with Surfboard-like UI.
|
||||
Read these files before making changes:
|
||||
|
||||
## Common Development Commands
|
||||
- [.agents/project.md](.agents/project.md): project overview, versions, and build dependencies.
|
||||
- [.agents/commands.md](.agents/commands.md): build, development, code generation, and test commands.
|
||||
- [.agents/rules.md](.agents/rules.md): lint, testing, generated-code, and workflow rules.
|
||||
- [.agents/architecture.md](.agents/architecture.md): core integration, providers, database, managers, build system, and
|
||||
local plugins.
|
||||
- [.agents/agent-config.md](.agents/agent-config.md): how to choose between `AGENTS.md`, `.agents`, skills, Codex config,
|
||||
command rules, and hooks.
|
||||
- [.agents/skills.md](.agents/skills.md): index of repo-scoped skills in `.agents/skills/`.
|
||||
|
||||
### Building
|
||||
## Highest Priority Rules
|
||||
|
||||
```bash
|
||||
# Update submodules first (ClashMeta Go core lives in core/Clash.Meta/)
|
||||
git submodule update --init --recursive
|
||||
- Use `flutter test`, not `dart test`, because models pull in Flutter types.
|
||||
- Run code generation after modifying models, providers, or database schema.
|
||||
- Do not manually edit generated files.
|
||||
- Follow `analysis_options.yaml`, especially single quotes, trailing commas, `child:` last, no `print()`, const/final
|
||||
preferences, and declared return types.
|
||||
- For CI parity, verify with `flutter pub get`, `flutter analyze --no-fatal-infos`, and
|
||||
`flutter test --reporter expanded` when practical.
|
||||
|
||||
# Full package build (Go core + Flutter + packaging) via setup.dart
|
||||
dart setup.dart macos
|
||||
dart setup.dart linux
|
||||
dart setup.dart windows
|
||||
dart setup.dart android
|
||||
## Repo Skills
|
||||
|
||||
# Build only the Go core (skip Flutter packaging)
|
||||
bash plugins/setup/buildkit/run_build_tool.sh macos
|
||||
bash plugins/setup/buildkit/run_build_tool.sh linux
|
||||
bash plugins/setup/buildkit/run_build_tool.sh windows
|
||||
bash plugins/setup/buildkit/run_build_tool.sh android
|
||||
```
|
||||
|
||||
### Flutter Development
|
||||
|
||||
```bash
|
||||
# Project is pinned with FVM (.fvmrc currently uses Flutter 3.35.7)
|
||||
fvm flutter pub get
|
||||
fvm flutter run
|
||||
fvm flutter test
|
||||
|
||||
# Plain Flutter also works when your global SDK matches the project constraints
|
||||
flutter pub get
|
||||
flutter run # Run on connected device/desktop
|
||||
flutter test # Run all tests (use flutter test, not dart test — models pull in Flutter types)
|
||||
```
|
||||
|
||||
### Code Generation
|
||||
|
||||
Required after modifying models, providers, or database schema:
|
||||
|
||||
```bash
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
dart run build_runner watch # Continuous regeneration
|
||||
```
|
||||
|
||||
Code generation covers: Riverpod providers (`riverpod_generator`), models (`freezed`, `json_serializable`), and database
|
||||
tables (`drift_dev`).
|
||||
|
||||
### Testing
|
||||
|
||||
Tests use `package:test/test.dart` for pure Dart logic (common utils, models) and `flutter_test` for provider/widget tests.
|
||||
`mocktail` is the mocking framework.
|
||||
|
||||
```bash
|
||||
flutter test test/models/ # Model serialization & extension round-trip tests
|
||||
flutter test test/core/ # CoreController tests (mocked CoreHandlerInterface)
|
||||
flutter test test/providers/ # Riverpod provider tests (config & app state notifiers)
|
||||
flutter test test/common/ # Utility function tests (utils, string, iterable, fixed, etc.)
|
||||
flutter test test/database/ # Database type converter tests
|
||||
flutter test test/widgets/ # Widget-level rendering/interaction tests
|
||||
flutter test test/setup_test.dart
|
||||
flutter test plugins/proxy/test/proxy_test.dart # Dart tests for bundled plugin packages
|
||||
```
|
||||
|
||||
Root `flutter test` only discovers the root package's `test/` directory by default. Include bundled plugin Dart tests by
|
||||
passing their paths explicitly, or run `flutter test` from that plugin package directory. Native plugin tests under
|
||||
platform folders (for example Windows C++ tests) are not run by `flutter test`.
|
||||
|
||||
**Mocking `CoreHandlerInterface`:** Use `CoreController.test(mock)` to inject a mock interface. Call
|
||||
`CoreController.resetInstance()` in `tearDown` to clean up the singleton between tests. Remember to
|
||||
`registerFallbackValue()` for freezed params used with `any()` matchers.
|
||||
|
||||
**Provider tests:** Use `ProviderContainer` directly (no widget tree needed for simple notifiers). The Riverpod
|
||||
generated `update()` method takes a callback: `notifier.update((state) => newValue)`.
|
||||
|
||||
**Model round-trip tests:** Always go through `jsonEncode`/`jsonDecode` when testing freezed models with
|
||||
nested objects — `toJson()` stores child objects directly (not as maps), so direct `fromJson(toJson())`
|
||||
fails for nested freezed types.
|
||||
|
||||
### Build Dependencies
|
||||
|
||||
**Linux:** `sudo apt-get install libayatana-appindicator3-dev libkeybinder-3.0-dev`
|
||||
|
||||
**Windows:** GCC and Inno Setup. `ANDROID_NDK` env var for Android builds.
|
||||
|
||||
**macOS:** `npm install -g appdmg` for DMG creation.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Integration (Go ClashMeta <-> Flutter)
|
||||
|
||||
This is the most important architectural concept. The Go proxy core (`core/`) operates in two modes:
|
||||
|
||||
- **Android (lib mode):** Go core compiled as C shared library (`libclash.so`) via `go build -buildmode=c-shared` with
|
||||
CGO. Flutter calls it via FFI through the `service` plugin. Dart-side: `lib/core/lib.dart` (`CoreLib` class).
|
||||
|
||||
- **Desktop (core mode):** Go core runs as a separate process with `CGO_ENABLED=0`. Flutter communicates via
|
||||
JSON-over-socket (Unix socket on macOS/Linux, TCP on Windows). Dart-side: `lib/core/service.dart` (`CoreService`
|
||||
class).
|
||||
|
||||
`lib/core/controller.dart` (`CoreController`) selects the implementation based on platform. `lib/core/interface.dart`
|
||||
defines the shared `CoreHandlerInterface`.
|
||||
|
||||
Go core key files: `core/hub.go` (handler functions), `core/action.go` (dispatch), `core/lib.go` (CGO exports),
|
||||
`core/server.go` (socket server).
|
||||
|
||||
### State Management (Riverpod)
|
||||
|
||||
Provider files in `lib/providers/`:
|
||||
|
||||
- `app.dart` - Runtime/UI state (logs, traffic, delays, loading, navigation)
|
||||
- `config.dart` - Persistent config providers (app settings, theme, VPN, proxy style)
|
||||
- `state.dart` - Derived/computed providers (navigation, proxy, tray, color scheme)
|
||||
- `action.dart` - Business logic notifiers (setup, backup, core lifecycle, proxy selection)
|
||||
- `database.dart` - Drift database provider wrappers
|
||||
|
||||
`globalState` (`lib/state.dart`) is a singleton holding app lifecycle, timers, theme, and the start/stop state.
|
||||
Providers are generated into `lib/providers/generated/`.
|
||||
|
||||
### Database (Drift/SQLite)
|
||||
|
||||
Type-safe SQLite via Drift in `lib/database/`. Current schema version is 2. Tables are `Profiles`, `Scripts`, `Rules`,
|
||||
`ProfileRuleLinks` (`profile_rule_mapping`), `ProxyGroups`, and `IconRecords` (`icon_records`). Rule scenes distinguish
|
||||
global added rules, profile added rules, profile custom rules, and disabled links. Uses fractional indexing for rule and
|
||||
proxy-group ordering.
|
||||
|
||||
Generated Drift output lives in `lib/database/generated/database.g.dart`. After schema changes, run code generation and
|
||||
add/update focused database tests under `test/database/` when converter or migration behavior changes.
|
||||
|
||||
### Manager Stack (Widget Tree)
|
||||
|
||||
Managers are nested InheritedWidgets/StatefulWidgets in `lib/application.dart`:
|
||||
|
||||
```
|
||||
AppEnvManager > StatusManager > ThemeManager
|
||||
> [Desktop: WindowManager > TrayManager > HotKeyManager > ProxyManager]
|
||||
> ConnectivityManager > CoreManager > AppStateManager
|
||||
> [Mobile: AndroidManager > VpnManager | Desktop: WindowHeaderContainer]
|
||||
```
|
||||
|
||||
Each manager in `lib/manager/` handles a specific platform concern. Desktop-only managers are conditionally inserted.
|
||||
|
||||
### Core Controller + Actions
|
||||
|
||||
`lib/core/controller.dart` (`CoreController`) is a singleton facade over `CoreHandlerInterface`. All 25+ public methods
|
||||
delegate to the platform-specific interface (Android FFI or desktop socket). Has `@visibleForTesting` constructor and
|
||||
`resetInstance()` for test injection.
|
||||
|
||||
Business logic lives in Riverpod notifier classes in `lib/providers/action.dart` (~960 lines, should be split):
|
||||
|
||||
- `CommonAction` — update check, common UI operations
|
||||
- `SetupAction` — config setup, TUN management
|
||||
- `BackupAction` — backup/restore with WebDAV sync
|
||||
- `CoreAction` — core lifecycle (init, connect, restart, shutdown)
|
||||
- `SystemAction` — system integration (tray, exit, brightness)
|
||||
- `StoreAction` — profile storage operations
|
||||
- `ThemeAction` — theme state updates
|
||||
- `ProxiesAction` — group management, proxy selection
|
||||
- `ProfilesAction` — profile CRUD, auto-update, import
|
||||
|
||||
### Platform Managers (`lib/manager/`)
|
||||
|
||||
Desktop: `WindowManager`, `TrayManager`, `HotKeyManager`, `ProxyManager`
|
||||
Mobile: `AndroidManager`, `TileManager`, `VpnManager`
|
||||
Shared: `ConnectivityManager`, `CoreManager`, `AppStateManager`, `StatusManager`, `ThemeManager`
|
||||
|
||||
### Build System
|
||||
|
||||
`setup.dart` (project root) is the release build orchestrator:
|
||||
|
||||
1. On Windows, pre-builds Go core via `dart run build_tool windows` and reads `core_sha256.json`
|
||||
2. Writes `env.json` (APP_ENV)
|
||||
3. Passes SHA256 as `--dart-define=CORE_SHA256=$val` (compile-time embedded, secure; Windows only)
|
||||
4. Activates `flutter_distributor` for packaging
|
||||
|
||||
Go core building is handled by `build_tool`, a standalone Dart CLI in `plugins/setup/buildkit/build_tool/`.
|
||||
Platform build hooks inside `flutter build` trigger `build_tool` automatically:
|
||||
|
||||
- **macOS:** podspec script phase → `build_pod.sh` → `build_tool macos`
|
||||
- **Linux:** CMake include → `buildkit/cmake/buildkit.cmake` → `build_tool linux`
|
||||
- **Windows:** CMake include → `buildkit/cmake/buildkit.cmake` → `build_tool windows` (debug: `--dev` via `CMAKE_BUILD_TYPE`)
|
||||
- **Android:** Gradle include → `buildkit/gradle/plugin.gradle` → `build_tool android`
|
||||
|
||||
**Windows helper auth (release):** Core SHA256 is embedded in both the Flutter app (`--dart-define`) and the Rust
|
||||
helper (`TOKEN` env var during cargo build). The Dart app pings the helper and verifies the token matches.
|
||||
|
||||
**Windows helper auth (debug):** The Rust helper skips token verification when built in debug mode
|
||||
(`cfg!(debug_assertions)`), so `flutter run` works without any SHA256 dance.
|
||||
|
||||
`plugins/setup/` is an FFI plugin that exists solely as a build harness — it carries no Dart API, only platform build hooks
|
||||
(podspec, CMake, Gradle) that trigger Go compilation. Windows builds also compile a Rust helper (`services/helper/`) via
|
||||
`RustBuilder`.
|
||||
|
||||
Build configuration defaults live in `build_tool/lib/src/options.dart` and can be overridden via `build_config.yaml`
|
||||
in the project root.
|
||||
|
||||
Architecture detection is automatic (host arch via `uname -m` on Unix, `PROCESSOR_ARCHITECTURE` on Windows). The
|
||||
`--description` flag passed to flutter_distributor adds arch suffix to artifact names (e.g.,
|
||||
`FlClash-0.8.93-macos-arm64.dmg`).
|
||||
|
||||
### Local Plugins (`plugins/`)
|
||||
|
||||
- `setup` - Build harness FFI plugin (triggers Go/Rust compilation per platform)
|
||||
- `proxy` - System proxy configuration
|
||||
- `rust_api` - Flutter Rust Bridge FFI plugin (named pipe / local socket communication)
|
||||
- `tray_manager` - System tray (forked/custom)
|
||||
- `wifi_ssid` - Wi-Fi SSID detection
|
||||
- `window_ext` - Window extensions
|
||||
- `flutter_distributor` - App packaging/distribution
|
||||
|
||||
### Rust Helper Service (`services/helper/`)
|
||||
|
||||
Windows-only privileged helper for starting the core as admin and managing TUN. Built with
|
||||
`cargo build --release --features windows-service`. Token-based auth with Flutter app.
|
||||
|
||||
### Localization
|
||||
|
||||
ARB files in `arb/`. Generated via `flutter_intl` into `lib/l10n/`. Use `AppLocalizations.of(context)!` for strings.
|
||||
|
||||
**Supported locales:** `en`, `zh_CN`, `ja`, `ru`
|
||||
|
||||
**Access patterns:**
|
||||
|
||||
- In widgets with BuildContext: `context.appLocalizations.key` (import `common.dart`)
|
||||
- In controllers/providers/non-widget code: `currentAppLocalizations.key` (import `app_localizations.dart`)
|
||||
Use repo skills from `.agents/skills/` when a task matches their descriptions. Current skills cover localization,
|
||||
provider tests, UI work, and core/platform changes.
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
# CLAUDE.md - Claude Code instructions
|
||||
# CLAUDE.md
|
||||
|
||||
Please read AGENTS.md for all project guidelines and conventions.
|
||||
This file is the entry point for AI coding agents working in this repository. Keep it small: detailed guidance lives
|
||||
under
|
||||
`.agents/`, and discoverable repo skills live under `.agents/skills/*/SKILL.md`.
|
||||
|
||||
@AGENTS.md
|
||||
## Start Here
|
||||
|
||||
Read these files before making changes:
|
||||
|
||||
- [.agents/project.md](.agents/project.md): project overview, versions, and build dependencies.
|
||||
- [.agents/commands.md](.agents/commands.md): build, development, code generation, and test commands.
|
||||
- [.agents/rules.md](.agents/rules.md): lint, testing, generated-code, and workflow rules.
|
||||
- [.agents/architecture.md](.agents/architecture.md): core integration, providers, database, managers, build system, and
|
||||
local plugins.
|
||||
- [.agents/agent-config.md](.agents/agent-config.md): how to choose between `AGENTS.md`, `.agents`, skills, Codex
|
||||
config,
|
||||
command rules, and hooks.
|
||||
- [.agents/skills.md](.agents/skills.md): index of repo-scoped skills in `.agents/skills/`.
|
||||
|
||||
## Highest Priority Rules
|
||||
|
||||
- Use `flutter test`, not `dart test`, because models pull in Flutter types.
|
||||
- Run code generation after modifying models, providers, or database schema.
|
||||
- Do not manually edit generated files.
|
||||
- Follow `analysis_options.yaml`, especially single quotes, trailing commas, `child:` last, no `print()`, const/final
|
||||
preferences, and declared return types.
|
||||
- For CI parity, verify with `flutter pub get`, `flutter analyze --no-fatal-infos`, and
|
||||
`flutter test --reporter expanded` when practical.
|
||||
|
||||
## Repo Skills
|
||||
|
||||
Use repo skills from `.agents/skills/` when a task matches their descriptions. Current skills cover localization,
|
||||
provider tests, UI work, and core/platform changes.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
PLATFORM ?= macos
|
||||
BUILDKIT := plugins/setup/buildkit/run_build_tool.sh
|
||||
ARCH_ARG := $(if $(ARCH),--arch $(ARCH),)
|
||||
TARGET_PLATFORM_ARG := $(if $(TARGET_PLATFORM),--target-platform $(TARGET_PLATFORM),)
|
||||
|
||||
.PHONY: help submodules core core-macos core-linux core-windows core-android
|
||||
|
||||
help:
|
||||
@echo 'make core # build macOS core by default'
|
||||
@echo 'make core PLATFORM=linux ARCH=amd64'
|
||||
@echo 'make core-macos ARCH=arm64'
|
||||
@echo 'make core-android ARCH=arm64'
|
||||
@echo 'make core-android TARGET_PLATFORM=android-arm64'
|
||||
|
||||
submodules:
|
||||
git submodule update --init --recursive
|
||||
|
||||
core:
|
||||
bash $(BUILDKIT) $(PLATFORM) $(ARCH_ARG) $(TARGET_PLATFORM_ARG)
|
||||
|
||||
core-macos:
|
||||
$(MAKE) core PLATFORM=macos
|
||||
|
||||
core-linux:
|
||||
$(MAKE) core PLATFORM=linux
|
||||
|
||||
core-windows:
|
||||
$(MAKE) core PLATFORM=windows
|
||||
|
||||
core-android:
|
||||
$(MAKE) core PLATFORM=android
|
||||
@@ -61,6 +61,14 @@ Support the following actions
|
||||
|
||||
<a href="https://chen08209.github.io/FlClash-fdroid-repo/repo?fingerprint=789D6D32668712EF7672F9E58DEEB15FBD6DCEEC5AE7A4371EA72F2AAE8A12FD"><img alt="Get it on F-Droid" src="snapshots/get-it-on-fdroid.svg" width="200px"/></a> <a href="https://github.com/chen08209/FlClash/releases"><img alt="Get it on GitHub" src="snapshots/get-it-on-github.svg" width="200px"/></a>
|
||||
|
||||
### Homebrew
|
||||
|
||||
```bash
|
||||
brew tap chen08209/tap
|
||||
brew trust chen08209/tap
|
||||
brew install --cask flclash
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
1. Update submodules
|
||||
@@ -129,4 +137,4 @@ The easiest way to support developers is to click on the star (⭐) at the top o
|
||||
<a href="https://api.star-history.com/svg?repos=chen08209/FlClash&Date">
|
||||
<img alt="start" width=50% src="https://api.star-history.com/svg?repos=chen08209/FlClash&Date"/>
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@@ -61,6 +61,14 @@ on Mobile:
|
||||
|
||||
<a href="https://chen08209.github.io/FlClash-fdroid-repo/repo?fingerprint=789D6D32668712EF7672F9E58DEEB15FBD6DCEEC5AE7A4371EA72F2AAE8A12FD"><img alt="Get it on F-Droid" src="snapshots/get-it-on-fdroid.svg" width="200px"/></a> <a href="https://github.com/chen08209/FlClash/releases"><img alt="Get it on GitHub" src="snapshots/get-it-on-github.svg" width="200px"/></a>
|
||||
|
||||
### Homebrew
|
||||
|
||||
```bash
|
||||
brew tap chen08209/tap
|
||||
brew trust chen08209/tap
|
||||
brew install --cask flclash
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
1. 更新 submodules
|
||||
|
||||
@@ -3,14 +3,13 @@ import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
id("com.google.gms.google-services")
|
||||
id("com.google.firebase.crashlytics")
|
||||
}
|
||||
|
||||
val localPropertiesFile = rootProject.file("local.properties")
|
||||
val localProperties = Properties().apply {
|
||||
val localPropertiesFile = rootProject.file("local.properties")
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.inputStream().use { load(it) }
|
||||
}
|
||||
@@ -106,4 +105,4 @@ dependencies {
|
||||
implementation(platform(libs.firebase.bom))
|
||||
implementation(libs.firebase.crashlytics.ndk)
|
||||
implementation(libs.firebase.analytics)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,25 @@ subprojects {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||
}
|
||||
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
allprojects {
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
sourceCompatibility = JavaVersion.VERSION_17.toString()
|
||||
targetCompatibility = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
compilerOptions {
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.layout.buildDirectory)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -42,4 +41,4 @@ dependencies {
|
||||
implementation(platform(libs.firebase.bom))
|
||||
implementation(libs.firebase.crashlytics.ndk)
|
||||
implementation(libs.firebase.analytics)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||
android.builtInKotlin=false
|
||||
# This newDsl flag was added automatically by Flutter migrator
|
||||
android.newDsl=false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
#agp = "8.10.1"
|
||||
firebaseBom = "34.2.0"
|
||||
firebaseBom = "34.15.0"
|
||||
minSdk = "23"
|
||||
targetSdk = "36"
|
||||
compileSdk = "36"
|
||||
@@ -9,13 +9,12 @@ coreKtx = "1.17.0"
|
||||
annotationJvm = "1.9.1"
|
||||
coreSplashscreen = "1.0.1"
|
||||
gson = "2.13.1"
|
||||
kotlin = "2.2.10"
|
||||
kotlin = "2.2.20"
|
||||
smaliDexlib2 = "3.0.9"
|
||||
firebaseCrashlyticsKtx = "20.0.1"
|
||||
firebaseCommonKtx = "22.0.0"
|
||||
firebaseCrashlyticsKtx = "20.0.6"
|
||||
firebaseCommonKtx = "22.1.0"
|
||||
|
||||
[libraries]
|
||||
build-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
androidx-core = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
|
||||
annotation-jvm = { module = "androidx.annotation:annotation-jvm", version.ref = "annotationJvm" }
|
||||
core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
|
||||
@@ -25,4 +24,4 @@ firebase-crashlytics-ndk = { module = "com.google.firebase:firebase-crashlytics-
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
smali-dexlib2 = { module = "com.android.tools.smali:smali-dexlib2", version.ref = "smaliDexlib2" }
|
||||
firebase-crashlytics-ktx = { group = "com.google.firebase", name = "firebase-crashlytics-ktx", version.ref = "firebaseCrashlyticsKtx" }
|
||||
firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" }
|
||||
firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" }
|
||||
|
||||
@@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -45,4 +43,4 @@ dependencies {
|
||||
implementation(project(":common"))
|
||||
implementation(libs.gson)
|
||||
implementation(libs.androidx.core)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
package com.follow.clash.service.models
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class NotificationParams(
|
||||
val title: String = "FlClash",
|
||||
val stopText: String = "STOP",
|
||||
val onlyStatisticsProxy: Boolean = false,
|
||||
) : Parcelable
|
||||
) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
title = parcel.readString() ?: "FlClash",
|
||||
stopText = parcel.readString() ?: "STOP",
|
||||
onlyStatisticsProxy = parcel.readByte() != 0.toByte(),
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(title)
|
||||
parcel.writeString(stopText)
|
||||
parcel.writeByte(if (onlyStatisticsProxy) 1.toByte() else 0.toByte())
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<NotificationParams> {
|
||||
override fun createFromParcel(parcel: Parcel): NotificationParams {
|
||||
return NotificationParams(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<NotificationParams?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,45 @@
|
||||
package com.follow.clash.service.models
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.follow.clash.common.AccessControlMode
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.net.InetAddress
|
||||
|
||||
@Parcelize
|
||||
data class AccessControlProps(
|
||||
val enable: Boolean,
|
||||
val mode: AccessControlMode,
|
||||
val acceptList: List<String>,
|
||||
val rejectList: List<String>,
|
||||
) : Parcelable
|
||||
) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
enable = parcel.readByte() != 0.toByte(),
|
||||
mode = AccessControlMode.valueOf(parcel.readString() ?: AccessControlMode.ACCEPT_SELECTED.name),
|
||||
acceptList = parcel.createStringArrayList() ?: emptyList(),
|
||||
rejectList = parcel.createStringArrayList() ?: emptyList(),
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeByte(if (enable) 1.toByte() else 0.toByte())
|
||||
parcel.writeString(mode.name)
|
||||
parcel.writeStringList(acceptList)
|
||||
parcel.writeStringList(rejectList)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<AccessControlProps> {
|
||||
override fun createFromParcel(parcel: Parcel): AccessControlProps {
|
||||
return AccessControlProps(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<AccessControlProps?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class VpnOptions(
|
||||
val enable: Boolean,
|
||||
val port: Int,
|
||||
@@ -25,7 +51,59 @@ data class VpnOptions(
|
||||
val bypassDomain: List<String>,
|
||||
val stack: String,
|
||||
val routeAddress: List<String>,
|
||||
) : Parcelable
|
||||
) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
enable = parcel.readByte() != 0.toByte(),
|
||||
port = parcel.readInt(),
|
||||
ipv6 = parcel.readByte() != 0.toByte(),
|
||||
dnsHijacking = parcel.readByte() != 0.toByte(),
|
||||
accessControlProps = readAccessControlProps(parcel),
|
||||
allowBypass = parcel.readByte() != 0.toByte(),
|
||||
systemProxy = parcel.readByte() != 0.toByte(),
|
||||
bypassDomain = parcel.createStringArrayList() ?: emptyList(),
|
||||
stack = parcel.readString() ?: "",
|
||||
routeAddress = parcel.createStringArrayList() ?: emptyList(),
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeByte(if (enable) 1.toByte() else 0.toByte())
|
||||
parcel.writeInt(port)
|
||||
parcel.writeByte(if (ipv6) 1.toByte() else 0.toByte())
|
||||
parcel.writeByte(if (dnsHijacking) 1.toByte() else 0.toByte())
|
||||
parcel.writeParcelable(accessControlProps, flags)
|
||||
parcel.writeByte(if (allowBypass) 1.toByte() else 0.toByte())
|
||||
parcel.writeByte(if (systemProxy) 1.toByte() else 0.toByte())
|
||||
parcel.writeStringList(bypassDomain)
|
||||
parcel.writeString(stack)
|
||||
parcel.writeStringList(routeAddress)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<VpnOptions> {
|
||||
@Suppress("DEPRECATION")
|
||||
private fun readAccessControlProps(parcel: Parcel): AccessControlProps {
|
||||
return parcel.readParcelable<AccessControlProps>(
|
||||
AccessControlProps::class.java.classLoader,
|
||||
) ?: AccessControlProps(
|
||||
enable = false,
|
||||
mode = AccessControlMode.ACCEPT_SELECTED,
|
||||
acceptList = emptyList(),
|
||||
rejectList = emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun createFromParcel(parcel: Parcel): VpnOptions {
|
||||
return VpnOptions(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<VpnOptions?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class CIDR(val address: InetAddress, val prefixLength: Int)
|
||||
|
||||
@@ -80,4 +158,4 @@ fun String.toCIDR(): CIDR {
|
||||
}
|
||||
|
||||
return CIDR(address, prefixLength)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.12.2" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.2.10" apply false
|
||||
id("com.google.gms.google-services") version ("4.3.15") apply false
|
||||
id("com.google.firebase.crashlytics") version ("2.8.1") apply false
|
||||
id("com.android.application") version "9.0.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.4.0" apply false
|
||||
id("com.google.gms.google-services") version ("4.5.0") apply false
|
||||
id("com.google.firebase.crashlytics") version ("3.0.7") apply false
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"app": "App",
|
||||
"general": "General",
|
||||
"systemProxyDesc": "Attach HTTP proxy to VpnService",
|
||||
"userAgent": "User-Agent",
|
||||
"unifiedDelay": "Unified delay",
|
||||
"unifiedDelayDesc": "Remove extra delays such as handshaking",
|
||||
"tcpConcurrent": "TCP concurrent",
|
||||
@@ -537,5 +538,17 @@
|
||||
"editSsid": "Edit SSID",
|
||||
"authorized": "Authorized",
|
||||
"tapToAuthorize": "Tap to authorize",
|
||||
"suspended": "Suspended..."
|
||||
"suspended": "Suspended...",
|
||||
"geoOptions": "Geo Options",
|
||||
"geoAutoUpdate": "Auto Update",
|
||||
"geoAutoUpdateInterval": "Auto Update Interval",
|
||||
"geoAutoUpdateIntervalTip": "Auto update interval must be greater than 0",
|
||||
"hours": "hours",
|
||||
"hoursCount": "{count} hours",
|
||||
"geoResources": "Geo Resources",
|
||||
"geoUpdating": "Updating {name}...",
|
||||
"geoSkipped": "{name} skipped",
|
||||
"geoUpdated": "{name} updated",
|
||||
"secondsCount": "{count} seconds",
|
||||
"entriesCount": "{count} entries"
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"app": "アプリ",
|
||||
"general": "一般",
|
||||
"systemProxyDesc": "HTTPプロキシをVpnServiceに接続",
|
||||
"userAgent": "ユーザーエージェント",
|
||||
"unifiedDelay": "統一遅延",
|
||||
"unifiedDelayDesc": "ハンドシェイクなどの余分な遅延を削除",
|
||||
"tcpConcurrent": "TCP並列処理",
|
||||
@@ -537,5 +538,17 @@
|
||||
"editSsid": "SSIDを編集",
|
||||
"authorized": "許可済み",
|
||||
"tapToAuthorize": "タップして許可",
|
||||
"suspended": "一時停止中..."
|
||||
"suspended": "一時停止中...",
|
||||
"geoOptions": "Geoオプション",
|
||||
"geoAutoUpdate": "自動更新",
|
||||
"geoAutoUpdateInterval": "自動更新間隔",
|
||||
"geoAutoUpdateIntervalTip": "自動更新間隔は0より大きくなければなりません",
|
||||
"hours": "時間",
|
||||
"hoursCount": "{count} 時間",
|
||||
"geoResources": "Geoリソース",
|
||||
"geoUpdating": "{name}を更新中...",
|
||||
"geoSkipped": "{name} スキップ済み",
|
||||
"geoUpdated": "{name} 更新済み",
|
||||
"secondsCount": "{count} 秒",
|
||||
"entriesCount": "{count} エントリ"
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"app": "Приложение",
|
||||
"general": "Общие",
|
||||
"systemProxyDesc": "Прикрепить HTTP-прокси к VpnService",
|
||||
"userAgent": "User-Agent",
|
||||
"unifiedDelay": "Унифицированная задержка",
|
||||
"unifiedDelayDesc": "Убрать дополнительные задержки, такие как рукопожатие",
|
||||
"tcpConcurrent": "TCP параллелизм",
|
||||
@@ -537,5 +538,17 @@
|
||||
"editSsid": "Изменить SSID",
|
||||
"authorized": "Разрешено",
|
||||
"tapToAuthorize": "Нажмите, чтобы разрешить",
|
||||
"suspended": "Приостановлено..."
|
||||
"suspended": "Приостановлено...",
|
||||
"geoOptions": "Настройки Geo",
|
||||
"geoAutoUpdate": "Автообновление",
|
||||
"geoAutoUpdateInterval": "Интервал автообновления",
|
||||
"geoAutoUpdateIntervalTip": "Интервал автообновления должен быть больше 0",
|
||||
"hours": "часов",
|
||||
"hoursCount": "{count} часов",
|
||||
"geoResources": "Ресурсы Geo",
|
||||
"geoUpdating": "Обновление {name}...",
|
||||
"geoSkipped": "{name} пропущено",
|
||||
"geoUpdated": "{name} обновлено",
|
||||
"secondsCount": "{count} секунд",
|
||||
"entriesCount": "{count} записей"
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
"app": "应用",
|
||||
"general": "常规",
|
||||
"systemProxyDesc": "设置系统代理",
|
||||
"userAgent": "用户代理",
|
||||
"unifiedDelay": "统一延迟",
|
||||
"unifiedDelayDesc": "去除握手等额外延迟",
|
||||
"tcpConcurrent": "TCP并发",
|
||||
@@ -537,5 +538,17 @@
|
||||
"editSsid": "编辑SSID",
|
||||
"authorized": "已授权",
|
||||
"tapToAuthorize": "点击授权",
|
||||
"suspended": "挂起中..."
|
||||
"suspended": "挂起中...",
|
||||
"geoOptions": "Geo 选项",
|
||||
"geoAutoUpdate": "自动更新",
|
||||
"geoAutoUpdateInterval": "自动更新间隔",
|
||||
"geoAutoUpdateIntervalTip": "自动更新间隔必须大于0",
|
||||
"hours": "小时",
|
||||
"hoursCount": "{count} 小时",
|
||||
"geoResources": "Geo 资源",
|
||||
"geoUpdating": "正在更新 {name}...",
|
||||
"geoSkipped": "{name} 已跳过",
|
||||
"geoUpdated": "{name} 已更新",
|
||||
"secondsCount": "{count} 秒",
|
||||
"entriesCount": "{count} 个条目"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="108" height="108" viewBox="54 54 132 132" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>status_1</title>
|
||||
<defs>
|
||||
<filter id="glow-shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="0" dy="5" stdDeviation="5" flood-color="#0F172A" flood-opacity="0.12"/>
|
||||
</filter>
|
||||
<path id="shape-top"
|
||||
d="M60.65,89.6L154.18,35.6A18,18 107.59,0 1,178.77 42.19L178.77,42.19A18,18 107.59,0 1,172.18 66.78L78.65,120.78A18,18 106.67,0 1,54.06 114.19L54.06,114.19A18,18 106.67,0 1,60.65 89.6z"/>
|
||||
<path id="shape-mid"
|
||||
d="M84.65,131.17L131.42,104.17A18,18 107.83,0 1,156 110.76L156,110.76A18,18 107.83,0 1,149.42 135.35L102.65,162.35A18,18 106.67,0 1,78.06 155.76L78.06,155.76A18,18 106.67,0 1,84.65 131.17z"/>
|
||||
<path id="shape-bot"
|
||||
d="M108.65,172.74L108.65,172.74A18,18 116.03,0 1,133.24 179.33L133.24,179.33A18,18 116.03,0 1,126.65 203.92L126.65,203.92A18,18 116.03,0 1,102.06 197.33L102.06,197.33A18,18 116.03,0 1,108.65 172.74z"/>
|
||||
<mask id="cutout-mask">
|
||||
<rect x="0" y="0" width="240" height="240" fill="white"/>
|
||||
<g transform="translate(9.12, 9.12) scale(0.924, 0.924)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-mid" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-bot" fill="black" stroke="black" stroke-width="25"/>
|
||||
</g>
|
||||
</g>
|
||||
</mask>
|
||||
<linearGradient id="ring-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#B8C0CD"/>
|
||||
<stop offset="100%" stop-color="#D7DCE6"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="120" cy="120" r="56" fill="none" stroke="url(#ring-grad)" stroke-width="16" mask="url(#cutout-mask)"
|
||||
opacity="0.9"/>
|
||||
|
||||
|
||||
<g transform="translate(9.12, 9.12) scale(0.924, 0.924)" filter="url(#glow-shadow)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="#7E8798"/>
|
||||
<use href="#shape-mid" fill="#687386"/>
|
||||
<use href="#shape-bot" fill="#98A3B6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="108" height="108" viewBox="54 54 132 132" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>status_2</title>
|
||||
<defs>
|
||||
<filter id="glow-shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="0" dy="5" stdDeviation="5" flood-color="#0F172A" flood-opacity="0.12"/>
|
||||
</filter>
|
||||
<path id="shape-top" d="M60.65,89.6L154.18,35.6A18,18 107.59,0 1,178.77 42.19L178.77,42.19A18,18 107.59,0 1,172.18 66.78L78.65,120.78A18,18 106.67,0 1,54.06 114.19L54.06,114.19A18,18 106.67,0 1,60.65 89.6z"/>
|
||||
<path id="shape-mid" d="M84.65,131.17L131.42,104.17A18,18 107.83,0 1,156 110.76L156,110.76A18,18 107.83,0 1,149.42 135.35L102.65,162.35A18,18 106.67,0 1,78.06 155.76L78.06,155.76A18,18 106.67,0 1,84.65 131.17z"/>
|
||||
<path id="shape-bot" d="M108.65,172.74L108.65,172.74A18,18 116.03,0 1,133.24 179.33L133.24,179.33A18,18 116.03,0 1,126.65 203.92L126.65,203.92A18,18 116.03,0 1,102.06 197.33L102.06,197.33A18,18 116.03,0 1,108.65 172.74z"/>
|
||||
<mask id="cutout-mask">
|
||||
<rect x="0" y="0" width="240" height="240" fill="white"/>
|
||||
<g transform="translate(15.77, 15.77) scale(0.86856, 0.86856)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-mid" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-bot" fill="black" stroke="black" stroke-width="25"/>
|
||||
</g>
|
||||
</g>
|
||||
</mask>
|
||||
<linearGradient id="ring-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#72B7FF"/>
|
||||
<stop offset="100%" stop-color="#8066FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="120" cy="120" r="64" fill="none" stroke="url(#ring-grad)" stroke-width="4" opacity="0.55"/>
|
||||
<circle cx="120" cy="120" r="54" fill="none" stroke="url(#ring-grad)" stroke-width="12" mask="url(#cutout-mask)" opacity="1"/>
|
||||
|
||||
<g transform="translate(15.77, 15.77) scale(0.86856, 0.86856)" filter="url(#glow-shadow)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="#6666FB"/>
|
||||
<use href="#shape-mid" fill="#2F71C4"/>
|
||||
<use href="#shape-bot" fill="#53B7F2"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="108" height="108" viewBox="54 54 132 132" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>status_3</title>
|
||||
<defs>
|
||||
<filter id="glow-shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="0" dy="5" stdDeviation="5" flood-color="#0F172A" flood-opacity="0.12"/>
|
||||
</filter>
|
||||
<path id="shape-top"
|
||||
d="M60.65,89.6L154.18,35.6A18,18 107.59,0 1,178.77 42.19L178.77,42.19A18,18 107.59,0 1,172.18 66.78L78.65,120.78A18,18 106.67,0 1,54.06 114.19L54.06,114.19A18,18 106.67,0 1,60.65 89.6z"/>
|
||||
<path id="shape-mid"
|
||||
d="M84.65,131.17L131.42,104.17A18,18 107.83,0 1,156 110.76L156,110.76A18,18 107.83,0 1,149.42 135.35L102.65,162.35A18,18 106.67,0 1,78.06 155.76L78.06,155.76A18,18 106.67,0 1,84.65 131.17z"/>
|
||||
<path id="shape-bot"
|
||||
d="M108.65,172.74L108.65,172.74A18,18 116.03,0 1,133.24 179.33L133.24,179.33A18,18 116.03,0 1,126.65 203.92L126.65,203.92A18,18 116.03,0 1,102.06 197.33L102.06,197.33A18,18 116.03,0 1,108.65 172.74z"/>
|
||||
<mask id="cutout-mask">
|
||||
<rect x="0" y="0" width="240" height="240" fill="white"/>
|
||||
<g transform="translate(15.77, 15.77) scale(0.86856, 0.86856)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-mid" fill="black" stroke="black" stroke-width="25"/>
|
||||
<use href="#shape-bot" fill="black" stroke="black" stroke-width="25"/>
|
||||
</g>
|
||||
</g>
|
||||
</mask>
|
||||
<linearGradient id="ring-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#22D3EE"/>
|
||||
<stop offset="100%" stop-color="#7C5CFF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="120" cy="120" r="64" fill="none" stroke="#FFB02E" stroke-width="4" opacity="0.55"/>
|
||||
<circle cx="120" cy="120" r="54" fill="none" stroke="url(#ring-grad)" stroke-width="12" mask="url(#cutout-mask)"
|
||||
opacity="1"/>
|
||||
<circle cx="120" cy="120" r="42" fill="none" stroke="#FFD25F" stroke-width="3" opacity="0.78"/>
|
||||
<g transform="translate(15.77, 15.77) scale(0.86856, 0.86856)" filter="url(#glow-shadow)">
|
||||
<g transform="translate(45.96154, 43.846153) scale(0.63461536, 0.63461536)">
|
||||
<use href="#shape-top" fill="#7367FF"/>
|
||||
<use href="#shape-mid" fill="#1685D8"/>
|
||||
<use href="#shape-bot" fill="#12C8FF"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -129,19 +129,11 @@ func handleAction(action *Action, result ActionResult) {
|
||||
case getExternalProviderMethod:
|
||||
externalProviderName := action.Data.(string)
|
||||
result.success(handleGetExternalProvider(externalProviderName))
|
||||
return
|
||||
case updateGeoDataMethod:
|
||||
paramsString := action.Data.(string)
|
||||
var params = map[string]string{}
|
||||
err := json.Unmarshal([]byte(paramsString), ¶ms)
|
||||
if err != nil {
|
||||
result.success(err.Error())
|
||||
return
|
||||
}
|
||||
geoType := params["geo-type"]
|
||||
geoName := params["geo-name"]
|
||||
handleUpdateGeoData(geoType, geoName, func(value string) {
|
||||
result.success(value)
|
||||
})
|
||||
geoType := action.Data.(string)
|
||||
handleUpdateGeoData(geoType)
|
||||
result.success("")
|
||||
return
|
||||
case updateExternalProviderMethod:
|
||||
providerName := action.Data.(string)
|
||||
|
||||
@@ -6,6 +6,11 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/metacubex/mihomo/adapter"
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
"github.com/metacubex/mihomo/adapter/outboundgroup"
|
||||
@@ -13,6 +18,7 @@ import (
|
||||
"github.com/metacubex/mihomo/common/batch"
|
||||
"github.com/metacubex/mihomo/component/dialer"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
"github.com/metacubex/mihomo/component/updater"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/constant/features"
|
||||
@@ -24,10 +30,6 @@ import (
|
||||
"github.com/metacubex/mihomo/log"
|
||||
rp "github.com/metacubex/mihomo/rules/provider"
|
||||
"github.com/metacubex/mihomo/tunnel"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -234,7 +236,17 @@ func updateConfig(params *UpdateParams) {
|
||||
general.Tun.Stack = *params.Tun.Stack
|
||||
}
|
||||
|
||||
if params.GeoAutoUpdate != nil {
|
||||
updater.SetGeoAutoUpdate(*params.GeoAutoUpdate)
|
||||
}
|
||||
if params.GeoUpdateInterval != nil {
|
||||
updater.SetGeoUpdateInterval(*params.GeoUpdateInterval)
|
||||
}
|
||||
|
||||
updateListeners()
|
||||
if updater.GeoAutoUpdate() {
|
||||
updater.RegisterGeoUpdaterWithCancel()
|
||||
}
|
||||
}
|
||||
|
||||
func applyConfig(params *SetupParams) error {
|
||||
@@ -250,6 +262,9 @@ func applyConfig(params *SetupParams) error {
|
||||
hub.ApplyConfig(currentConfig)
|
||||
patchSelectGroup(params.SelectedMap)
|
||||
updateListeners()
|
||||
if updater.GeoAutoUpdate() {
|
||||
updater.RegisterGeoUpdaterWithCancel()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ type UpdateParams struct {
|
||||
ExternalController *string `json:"external-controller"`
|
||||
Interface *string `json:"interface-name"`
|
||||
UnifiedDelay *bool `json:"unified-delay"`
|
||||
GeoAutoUpdate *bool `json:"geo-auto-update"`
|
||||
GeoUpdateInterval *int `json:"geo-update-interval"`
|
||||
}
|
||||
|
||||
type tunSchema struct {
|
||||
@@ -123,12 +125,20 @@ type Message struct {
|
||||
}
|
||||
|
||||
const (
|
||||
LogMessage MessageType = "log"
|
||||
DelayMessage MessageType = "delay"
|
||||
RequestMessage MessageType = "request"
|
||||
LoadedMessage MessageType = "loaded"
|
||||
LogMessage MessageType = "log"
|
||||
DelayMessage MessageType = "delay"
|
||||
RequestMessage MessageType = "request"
|
||||
LoadedMessage MessageType = "loaded"
|
||||
GeoUpdateMessage MessageType = "geoUpdate"
|
||||
)
|
||||
|
||||
type GeoUpdateStatus struct {
|
||||
Type string `json:"type"`
|
||||
Updating bool `json:"updating"`
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (message *Message) Json() (string, error) {
|
||||
data, err := json.Marshal(message)
|
||||
return string(data), err
|
||||
|
||||
@@ -17,13 +17,15 @@ require (
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/coder/websocket v1.8.12 // indirect
|
||||
github.com/coreos/go-iptables v0.8.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.12.0 // indirect
|
||||
github.com/dunglas/httpsfv v1.0.2 // indirect
|
||||
github.com/enfein/mieru/v3 v3.31.0 // indirect
|
||||
github.com/enfein/mieru/v3 v3.33.0 // indirect
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
|
||||
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
|
||||
@@ -42,6 +44,7 @@ require (
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
@@ -51,6 +54,7 @@ require (
|
||||
github.com/klauspost/reedsolomon v1.12.3 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/metacubex/age v0.0.0-20260603010618-28d156b4ea78 // indirect
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d // indirect
|
||||
github.com/metacubex/ascon v0.1.0 // indirect
|
||||
github.com/metacubex/bart v0.26.0 // indirect
|
||||
@@ -67,30 +71,31 @@ require (
|
||||
github.com/metacubex/hkdf v0.1.0 // indirect
|
||||
github.com/metacubex/hpke v0.1.0 // indirect
|
||||
github.com/metacubex/http v0.1.6 // indirect
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260513175203-1c6abea7534c // indirect
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260518173308-f4597c22f1df // indirect
|
||||
github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 // indirect
|
||||
github.com/metacubex/mhurl v0.1.0 // indirect
|
||||
github.com/metacubex/mlkem v0.1.0 // indirect
|
||||
github.com/metacubex/nftables v0.0.0-20260426003805-208c2c1ba2cb // indirect
|
||||
github.com/metacubex/qpack v0.6.0 // indirect
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260413153657-53bb22f2c306 // indirect
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260520020949-fcd18c7b6ace // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // indirect
|
||||
github.com/metacubex/restls-client-go v0.1.7 // indirect
|
||||
github.com/metacubex/sevenzip v1.6.4 // indirect
|
||||
github.com/metacubex/sing v0.5.7 // indirect
|
||||
github.com/metacubex/sing-mux v0.3.9 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20260512151354-8475655be853 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20260527143057-68e10a6afdc3 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.7 // indirect
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
|
||||
github.com/metacubex/sing-tun v0.4.18 // indirect
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20260517015314-c11c36474edc // indirect
|
||||
github.com/metacubex/sing-tun v0.4.20 // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.5 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260507084707-690d479ec947 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260520151737-7e7c7c1b854c // indirect
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141 // indirect
|
||||
github.com/metacubex/ssh v0.1.0 // indirect
|
||||
github.com/metacubex/tailscale v0.0.0-20260516120020-a21c2c99dcbe // indirect
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260513233728-8bc7ee255d04 // indirect
|
||||
github.com/metacubex/tailscale v0.0.0-20260520011538-f23132fac4b7 // indirect
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260521124654-e1bf77ef79af // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 // indirect
|
||||
github.com/metacubex/tls v0.1.5 // indirect
|
||||
github.com/metacubex/tls v0.1.6 // indirect
|
||||
github.com/metacubex/utls v1.8.4 // indirect
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect
|
||||
github.com/metacubex/yamux v0.0.0-20250918083631-dd5f17c0be49 // indirect
|
||||
@@ -100,8 +105,9 @@ require (
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
|
||||
github.com/openacid/low v0.1.21 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.27 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.0 // indirect
|
||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/samber/lo v1.53.0 // indirect
|
||||
@@ -109,11 +115,13 @@ require (
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
|
||||
github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/stangelandcl/ppmd v0.1.1 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d // indirect
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
|
||||
@@ -12,11 +12,15 @@ github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||
github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4=
|
||||
github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM=
|
||||
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
||||
@@ -30,8 +34,8 @@ github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz
|
||||
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0=
|
||||
github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
|
||||
github.com/enfein/mieru/v3 v3.31.0 h1:Fl2ocRCRXJzMygzdRjBHgqI996ZuIDHUmyQyovSf9sA=
|
||||
github.com/enfein/mieru/v3 v3.31.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/enfein/mieru/v3 v3.33.0 h1:hv2jK8nqYHwpSG86U2rpZR2I8Aff1/J3ifRmd9NBbFc=
|
||||
github.com/enfein/mieru/v3 v3.33.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
|
||||
@@ -75,6 +79,8 @@ github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQu
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I=
|
||||
github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4=
|
||||
@@ -90,10 +96,16 @@ github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/4
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.12.3 h1:tzUznbfc3OFwJaTebv/QdhnFf2Xvb7gZ24XaHLBPmdc=
|
||||
github.com/klauspost/reedsolomon v1.12.3/go.mod h1:3K5rXwABAvzGeR01r6pWZieUALXO/Tq7bFKGIb4m4WI=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/age v0.0.0-20260603010618-28d156b4ea78 h1:LqWr0vb9zDNuQS+jJd4fnRYk/SEI7KJ7TDe/L4WFK48=
|
||||
github.com/metacubex/age v0.0.0-20260603010618-28d156b4ea78/go.mod h1:BTBG/iVY7rg3qq5WdVCg0GFk58CSvCDSbjy8I7kEx/c=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d h1:vAJ0ZT4aO803F1uw2roIA9yH7Sxzox34tVVyye1bz6c=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
|
||||
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
|
||||
@@ -126,8 +138,8 @@ github.com/metacubex/hpke v0.1.0 h1:gu2jUNhraehWi0P/z5HX2md3d7L1FhPQE6/Q0E9r9xQ=
|
||||
github.com/metacubex/hpke v0.1.0/go.mod h1:vfDm6gfgrwlXUxKDkWbcE44hXtmc1uxLDm2BcR11b3U=
|
||||
github.com/metacubex/http v0.1.6 h1:xvXuvXMCMxCWMF5nEJF4yiKvXL+p2atWMzs37e80m1I=
|
||||
github.com/metacubex/http v0.1.6/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg=
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260513175203-1c6abea7534c h1:KGhBHDe6FveU0ury+9RyX329nclM1CHODa0Fi+uOAYM=
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260513175203-1c6abea7534c/go.mod h1:F4sVXat6QjPXkNsKRDyyG3BhSkxPFFnRPEIwmmyCgbg=
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260518173308-f4597c22f1df h1:S0vBzqjXok24VopstOgPd1JdgglW9tXehrqvwpQWbQ8=
|
||||
github.com/metacubex/jsonv2 v0.0.0-20260518173308-f4597c22f1df/go.mod h1:F4sVXat6QjPXkNsKRDyyG3BhSkxPFFnRPEIwmmyCgbg=
|
||||
github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI=
|
||||
github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc=
|
||||
github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE=
|
||||
@@ -138,42 +150,44 @@ github.com/metacubex/nftables v0.0.0-20260426003805-208c2c1ba2cb h1:wk6mHYPURSUv
|
||||
github.com/metacubex/nftables v0.0.0-20260426003805-208c2c1ba2cb/go.mod h1:73ZrCfhdkW4F2E2GAlta3km/S2RHhFNogCMtWZV2anQ=
|
||||
github.com/metacubex/qpack v0.6.0 h1:YqClGIMOpiRYLjV1qOs483Od08MdPgRnHjt90FuaAKw=
|
||||
github.com/metacubex/qpack v0.6.0/go.mod h1:lKGSi7Xk94IMvHGOmxS9eIei3bvIqpOAImEBsaOwTkA=
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260413153657-53bb22f2c306 h1:HlGLmLsWJMLSu0CMI9z/BmEnithB4oXM5Rom6/0Qxtg=
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260413153657-53bb22f2c306/go.mod h1:oNzMrmylS897M3zSMuapIdwSwfq6F2qW01Z3NhVRJhk=
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260520020949-fcd18c7b6ace h1:KXacx7dp1GYVMgxezwXRt5BMsEbvAYuA6rPFUmdAvcQ=
|
||||
github.com/metacubex/quic-go v0.59.1-0.20260520020949-fcd18c7b6ace/go.mod h1:2YEQEvFrZ5V76oynMBDTlN+4fdnSHCa2uNJxv3cm1HU=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
|
||||
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
|
||||
github.com/metacubex/sevenzip v1.6.4 h1:OIL+DeOeSAbKNsjqxcYUMiarRmX6Kaxakb0GT7E9Oik=
|
||||
github.com/metacubex/sevenzip v1.6.4/go.mod h1:FP3X9bzFKj9wPxifGN9B3w2fIEicMjzKYIGIhnu+1pw=
|
||||
github.com/metacubex/sing v0.5.7 h1:8OC+fhKFSv/l9ehEhJRaZZAOuthfZo68SteBVLe8QqM=
|
||||
github.com/metacubex/sing v0.5.7/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.9 h1:/aoBD2+sK2qsXDlNDe3hkR0GZuFDtwIZhOeGUx9W0Yk=
|
||||
github.com/metacubex/sing-mux v0.3.9/go.mod h1:8bT7ZKT3clRrJjYc/x5CRYibC1TX/bK73a3r3+2E+Fc=
|
||||
github.com/metacubex/sing-quic v0.0.0-20260512151354-8475655be853 h1:nZ5WNU6kjj6kBu4+2eMySFkUVGCop64rZnLMm+HPh8w=
|
||||
github.com/metacubex/sing-quic v0.0.0-20260512151354-8475655be853/go.mod h1:6ayFGfzzBE85csgQkM3gf4neFq6s0losHlPRSxY+nuk=
|
||||
github.com/metacubex/sing-quic v0.0.0-20260527143057-68e10a6afdc3 h1:PnMby5+kZXTl/CFDHfxMbMTaSRD+uMKMsrDYVQyAmX8=
|
||||
github.com/metacubex/sing-quic v0.0.0-20260527143057-68e10a6afdc3/go.mod h1:6ayFGfzzBE85csgQkM3gf4neFq6s0losHlPRSxY+nuk=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6wVj3PPBVhor3A=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.7/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.18 h1:WRzAosG0YkT3aZq5RJWtF+RdCgeJ8EpooS5ZM1lkXo0=
|
||||
github.com/metacubex/sing-tun v0.4.18/go.mod h1:g4I/JNplDBhXLF+aQWgFbhNeJPSXQOWS9HvLeNvkgeA=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20260517015314-c11c36474edc h1:8wLoFfYQ88iGPL+krQ5tJsI8IAmkFjKpQL2q+y3pvss=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20260517015314-c11c36474edc/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.20 h1:xdupzizRoZKyDzP0l68WAx5Sk4ooiuT1GiWsiJyOGPw=
|
||||
github.com/metacubex/sing-tun v0.4.20/go.mod h1:g4I/JNplDBhXLF+aQWgFbhNeJPSXQOWS9HvLeNvkgeA=
|
||||
github.com/metacubex/sing-vmess v0.2.5 h1:m9Zt5I27lB9fmLMZfism9sH2LcnAfShZfwSkf6/KJoE=
|
||||
github.com/metacubex/sing-vmess v0.2.5/go.mod h1:AwtlzUgf8COe9tRYAKqWZ+leDH7p5U98a0ZUpYehl8Q=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260507084707-690d479ec947 h1:IB03BvRQtvjWScyOK5jSQVJYY8osmZXHL+4VCEFMWcM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260507084707-690d479ec947/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260520151737-7e7c7c1b854c h1:tH9FuQW357zp2xAGzkoZTGpNGMVmEFZov0iV5M2S5ew=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20260520151737-7e7c7c1b854c/go.mod h1:eQZDJTx+IH3k4mXqaOJ3VJ9h9ZqOl60F7TLi5wAU51Q=
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141 h1:DK2l6m2Fc85H2BhiAPgbJygiWhesPlfGmF+9Vw6ARdk=
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141/go.mod h1:/yI4OiGOSn0SURhZdJF3CbtPg3nwK700bG8TZLMBvAg=
|
||||
github.com/metacubex/ssh v0.1.0 h1:iGfr99qk/eMHzUnQ/0bTxXT8+8SWqLSHBWDHoAhngzw=
|
||||
github.com/metacubex/ssh v0.1.0/go.mod h1:NUtl0d+/f2cG9ECEpMM8iCVOpmggQlC13oLeDUONDlU=
|
||||
github.com/metacubex/tailscale v0.0.0-20260516120020-a21c2c99dcbe h1:ZdAKshacNruZGuKTE8WMTuxyGgpv/LySLoE/EEmgF9c=
|
||||
github.com/metacubex/tailscale v0.0.0-20260516120020-a21c2c99dcbe/go.mod h1:2G1V82OGXgxT7m7046GA80I9SlcvczljCK0C7NQ3c10=
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260513233728-8bc7ee255d04 h1:zk+mDDSBl5lv80WWtaFUbpj8XLb7AhjCUbn2pB37N0U=
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260513233728-8bc7ee255d04/go.mod h1:pKUKBy7IcQ5r0i66gWENHgxKvBn8tlgAGx0DZMq8h5M=
|
||||
github.com/metacubex/tailscale v0.0.0-20260520011538-f23132fac4b7 h1:LoJR4NMyNKHeEJoeGDtcsao7sV0NRkzMeV5H/0J0MIE=
|
||||
github.com/metacubex/tailscale v0.0.0-20260520011538-f23132fac4b7/go.mod h1:MAo3HhE7968rIwmDvYTYE8xCsV4x+hLnkChdXeP3X4c=
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260521124654-e1bf77ef79af h1:c60IbBMUq2h1M2m7+grMJJmBmrObxL8SwvNtm6Ozbwk=
|
||||
github.com/metacubex/tailscale-wireguard-go v0.0.0-20260521124654-e1bf77ef79af/go.mod h1:i3zLKytWkOnyT1i9OmiLevWvrN5J5HE1+yjE7UYNfcQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/tls v0.1.5 h1:ECcB83dj+zadnhlKcLnUUf1Sq6+vU0f/zoyU0+9oPTc=
|
||||
github.com/metacubex/tls v0.1.5/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/tls v0.1.6 h1:t2ubLneYa4ceyIC++54a57BLqZFA/QYUrhdjLk2GPwo=
|
||||
github.com/metacubex/tls v0.1.6/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
|
||||
@@ -195,13 +209,16 @@ github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs
|
||||
github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk=
|
||||
github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
|
||||
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs=
|
||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M=
|
||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
@@ -216,10 +233,19 @@ github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIF
|
||||
github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8=
|
||||
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
github.com/stangelandcl/ppmd v0.1.1 h1:c25QazhlWUn5nmR1QOzafKhQxBicAr7GGCKER2aJ8H8=
|
||||
github.com/stangelandcl/ppmd v0.1.1/go.mod h1:Rrv7M+/2P5jYr/GMLhBl7Ug3uJ1bUiVzr5LbbaV6xgY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d h1:JcGKBZAL7ePLwOhUdN8qGQZlP5GueEiIZwY7R62pejE=
|
||||
@@ -232,6 +258,8 @@ github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+y
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
@@ -245,6 +273,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 h1:UNrDfkQqiEYzdMlNsVvBYOAJWZjdktqFE9tQh5BT2+4=
|
||||
@@ -302,8 +332,9 @@ golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -347,36 +347,22 @@ func handleGetExternalProvider(externalProviderName string) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func handleUpdateGeoData(geoType string, geoName string, fn func(value string)) {
|
||||
func handleUpdateGeoData(geoType string) {
|
||||
go func() {
|
||||
path := constant.Path.Resolve(geoName)
|
||||
switch geoType {
|
||||
case "MMDB":
|
||||
err := updater.UpdateMMDBWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
updater.UpdateMMDB()
|
||||
return
|
||||
case "ASN":
|
||||
err := updater.UpdateASNWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
updater.UpdateASN()
|
||||
return
|
||||
case "GEOIP":
|
||||
err := updater.UpdateGeoIpWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
updater.UpdateGeoIp()
|
||||
return
|
||||
case "GEOSITE":
|
||||
err := updater.UpdateGeoSiteWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
updater.UpdateGeoSite()
|
||||
return
|
||||
}
|
||||
fn("")
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -568,4 +554,18 @@ func init() {
|
||||
Data: providerName,
|
||||
})
|
||||
}
|
||||
updater.GeoUpdateHook = func(geoType string, updating bool, skipped bool, updateErr error) {
|
||||
status := GeoUpdateStatus{
|
||||
Type: geoType,
|
||||
Updating: updating,
|
||||
Skipped: skipped,
|
||||
}
|
||||
if updateErr != nil {
|
||||
status.Error = updateErr.Error()
|
||||
}
|
||||
sendMessage(Message{
|
||||
Type: GeoUpdateMessage,
|
||||
Data: status,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export 'future.dart';
|
||||
export 'http.dart';
|
||||
export 'icons.dart';
|
||||
export 'indexing.dart';
|
||||
export 'input_limits.dart';
|
||||
export 'iterable.dart';
|
||||
export 'javascript.dart';
|
||||
export 'keyboard.dart';
|
||||
@@ -29,7 +30,6 @@ export 'package.dart';
|
||||
export 'path.dart';
|
||||
export 'permission.dart';
|
||||
export 'picker.dart';
|
||||
export 'pipe.dart';
|
||||
export 'preferences.dart';
|
||||
export 'print.dart';
|
||||
export 'protocol.dart';
|
||||
|
||||
@@ -7,7 +7,7 @@ class FixedList<T> {
|
||||
final List<T> _list;
|
||||
|
||||
FixedList(this.maxLength, {List<T>? list})
|
||||
: _list = (list ?? [])..truncate(maxLength);
|
||||
: _list = (list ?? [])..truncate(maxLength);
|
||||
|
||||
void add(T item) {
|
||||
_list.add(item);
|
||||
@@ -25,10 +25,7 @@ class FixedList<T> {
|
||||
T operator [](int index) => _list[index];
|
||||
|
||||
FixedList<T> copyWith() {
|
||||
return FixedList(
|
||||
maxLength,
|
||||
list: List.of(_list),
|
||||
);
|
||||
return FixedList(maxLength, list: List.of(_list));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +38,7 @@ class FixedMap<K, V> {
|
||||
}
|
||||
|
||||
V updateCacheValue(K key, ValueCallback<V> callback) {
|
||||
final realValue = _map.updateCacheValue(
|
||||
key,
|
||||
callback,
|
||||
);
|
||||
final realValue = _map.updateCacheValue(key, callback);
|
||||
_adjustMap();
|
||||
return realValue;
|
||||
}
|
||||
@@ -65,9 +59,7 @@ class FixedMap<K, V> {
|
||||
|
||||
void _adjustMap() {
|
||||
if (_map.length > maxLength) {
|
||||
_map = Map.fromEntries(
|
||||
map.entries.toList()..truncate(maxLength),
|
||||
);
|
||||
_map = Map.fromEntries(map.entries.toList()..truncate(maxLength));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
abstract final class TextInputLimits {
|
||||
static const name = 64;
|
||||
static const groupName = 64;
|
||||
static const url = 2048;
|
||||
static const uri = url;
|
||||
static const iconUrl = url;
|
||||
static const dnsServer = url;
|
||||
static const hostValue = url;
|
||||
static const userName = 128;
|
||||
static const password = 512;
|
||||
static const userAgent = 512;
|
||||
static const fileName = 255;
|
||||
static const port = 5;
|
||||
static const number = 10;
|
||||
static const interval = number;
|
||||
static const search = 256;
|
||||
static const rule = 1024;
|
||||
static const filter = 1024;
|
||||
static const status = 128;
|
||||
static const dnsListen = 255;
|
||||
static const domain = 512;
|
||||
static const geoSite = 128;
|
||||
static const geoIpCode = 16;
|
||||
static const cidr = 64;
|
||||
|
||||
static List<TextInputFormatter> limit(int maxLength) {
|
||||
return [LengthLimitingTextInputFormatter(maxLength)];
|
||||
}
|
||||
|
||||
static List<TextInputFormatter> digitsOnly(int maxLength) {
|
||||
return [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
LengthLimitingTextInputFormatter(maxLength),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,13 @@ extension ListExt<T> on List<T> {
|
||||
return newList;
|
||||
}
|
||||
|
||||
List<T> copyAndReorder(int oldIndex, int newIndex) {
|
||||
final newList = List<T>.from(this);
|
||||
final item = newList.removeAt(oldIndex);
|
||||
newList.insert(newIndex, item);
|
||||
return newList;
|
||||
}
|
||||
|
||||
List<T> safeSublist(int start, [int? end]) {
|
||||
if (start <= 0) return this;
|
||||
if (start > length) return [];
|
||||
|
||||
@@ -5,90 +5,90 @@ import 'system.dart';
|
||||
|
||||
final Map<PhysicalKeyboardKey, String> _knownKeyLabels =
|
||||
<PhysicalKeyboardKey, String>{
|
||||
PhysicalKeyboardKey.keyA: 'A',
|
||||
PhysicalKeyboardKey.keyB: 'B',
|
||||
PhysicalKeyboardKey.keyC: 'C',
|
||||
PhysicalKeyboardKey.keyD: 'D',
|
||||
PhysicalKeyboardKey.keyE: 'E',
|
||||
PhysicalKeyboardKey.keyF: 'F',
|
||||
PhysicalKeyboardKey.keyG: 'G',
|
||||
PhysicalKeyboardKey.keyH: 'H',
|
||||
PhysicalKeyboardKey.keyI: 'I',
|
||||
PhysicalKeyboardKey.keyJ: 'J',
|
||||
PhysicalKeyboardKey.keyK: 'K',
|
||||
PhysicalKeyboardKey.keyL: 'L',
|
||||
PhysicalKeyboardKey.keyM: 'M',
|
||||
PhysicalKeyboardKey.keyN: 'N',
|
||||
PhysicalKeyboardKey.keyO: 'O',
|
||||
PhysicalKeyboardKey.keyP: 'P',
|
||||
PhysicalKeyboardKey.keyQ: 'Q',
|
||||
PhysicalKeyboardKey.keyR: 'R',
|
||||
PhysicalKeyboardKey.keyS: 'S',
|
||||
PhysicalKeyboardKey.keyT: 'T',
|
||||
PhysicalKeyboardKey.keyU: 'U',
|
||||
PhysicalKeyboardKey.keyV: 'V',
|
||||
PhysicalKeyboardKey.keyW: 'W',
|
||||
PhysicalKeyboardKey.keyX: 'X',
|
||||
PhysicalKeyboardKey.keyY: 'Y',
|
||||
PhysicalKeyboardKey.keyZ: 'Z',
|
||||
PhysicalKeyboardKey.digit1: '1',
|
||||
PhysicalKeyboardKey.digit2: '2',
|
||||
PhysicalKeyboardKey.digit3: '3',
|
||||
PhysicalKeyboardKey.digit4: '4',
|
||||
PhysicalKeyboardKey.digit5: '5',
|
||||
PhysicalKeyboardKey.digit6: '6',
|
||||
PhysicalKeyboardKey.digit7: '7',
|
||||
PhysicalKeyboardKey.digit8: '8',
|
||||
PhysicalKeyboardKey.digit9: '9',
|
||||
PhysicalKeyboardKey.digit0: '0',
|
||||
PhysicalKeyboardKey.enter: 'ENTER',
|
||||
PhysicalKeyboardKey.escape: 'ESCAPE',
|
||||
PhysicalKeyboardKey.backspace: 'BACKSPACE',
|
||||
PhysicalKeyboardKey.tab: 'TAB',
|
||||
PhysicalKeyboardKey.space: 'SPACE',
|
||||
PhysicalKeyboardKey.minus: '-',
|
||||
PhysicalKeyboardKey.equal: '=',
|
||||
PhysicalKeyboardKey.bracketLeft: '[',
|
||||
PhysicalKeyboardKey.bracketRight: ']',
|
||||
PhysicalKeyboardKey.backslash: '\\',
|
||||
PhysicalKeyboardKey.semicolon: ';',
|
||||
PhysicalKeyboardKey.quote: '"',
|
||||
PhysicalKeyboardKey.backquote: '`',
|
||||
PhysicalKeyboardKey.comma: ',',
|
||||
PhysicalKeyboardKey.period: '.',
|
||||
PhysicalKeyboardKey.slash: '/',
|
||||
PhysicalKeyboardKey.capsLock: 'CAPSLOCK',
|
||||
PhysicalKeyboardKey.f1: 'F1',
|
||||
PhysicalKeyboardKey.f2: 'F2',
|
||||
PhysicalKeyboardKey.f3: 'F3',
|
||||
PhysicalKeyboardKey.f4: 'F4',
|
||||
PhysicalKeyboardKey.f5: 'F5',
|
||||
PhysicalKeyboardKey.f6: 'F6',
|
||||
PhysicalKeyboardKey.f7: 'F7',
|
||||
PhysicalKeyboardKey.f8: 'F8',
|
||||
PhysicalKeyboardKey.f9: 'F9',
|
||||
PhysicalKeyboardKey.f10: 'F10',
|
||||
PhysicalKeyboardKey.f11: 'F11',
|
||||
PhysicalKeyboardKey.f12: 'F12',
|
||||
PhysicalKeyboardKey.home: 'HOME',
|
||||
PhysicalKeyboardKey.pageUp: 'PAGEUP',
|
||||
PhysicalKeyboardKey.delete: 'DELETE',
|
||||
PhysicalKeyboardKey.end: 'END',
|
||||
PhysicalKeyboardKey.pageDown: 'PAGEDOWN',
|
||||
PhysicalKeyboardKey.arrowRight: '→',
|
||||
PhysicalKeyboardKey.arrowLeft: '←',
|
||||
PhysicalKeyboardKey.arrowDown: '↓',
|
||||
PhysicalKeyboardKey.arrowUp: '↑',
|
||||
PhysicalKeyboardKey.controlLeft: 'CTRL',
|
||||
PhysicalKeyboardKey.shiftLeft: 'SHIFT',
|
||||
PhysicalKeyboardKey.altLeft: 'ALT',
|
||||
PhysicalKeyboardKey.metaLeft: system.isMacOS ? '⌘' : 'WIN',
|
||||
PhysicalKeyboardKey.controlRight: 'CTRL',
|
||||
PhysicalKeyboardKey.shiftRight: 'SHIFT',
|
||||
PhysicalKeyboardKey.altRight: 'ALT',
|
||||
PhysicalKeyboardKey.metaRight: system.isMacOS ? '⌘' : 'WIN',
|
||||
PhysicalKeyboardKey.fn: 'FN',
|
||||
};
|
||||
PhysicalKeyboardKey.keyA: 'A',
|
||||
PhysicalKeyboardKey.keyB: 'B',
|
||||
PhysicalKeyboardKey.keyC: 'C',
|
||||
PhysicalKeyboardKey.keyD: 'D',
|
||||
PhysicalKeyboardKey.keyE: 'E',
|
||||
PhysicalKeyboardKey.keyF: 'F',
|
||||
PhysicalKeyboardKey.keyG: 'G',
|
||||
PhysicalKeyboardKey.keyH: 'H',
|
||||
PhysicalKeyboardKey.keyI: 'I',
|
||||
PhysicalKeyboardKey.keyJ: 'J',
|
||||
PhysicalKeyboardKey.keyK: 'K',
|
||||
PhysicalKeyboardKey.keyL: 'L',
|
||||
PhysicalKeyboardKey.keyM: 'M',
|
||||
PhysicalKeyboardKey.keyN: 'N',
|
||||
PhysicalKeyboardKey.keyO: 'O',
|
||||
PhysicalKeyboardKey.keyP: 'P',
|
||||
PhysicalKeyboardKey.keyQ: 'Q',
|
||||
PhysicalKeyboardKey.keyR: 'R',
|
||||
PhysicalKeyboardKey.keyS: 'S',
|
||||
PhysicalKeyboardKey.keyT: 'T',
|
||||
PhysicalKeyboardKey.keyU: 'U',
|
||||
PhysicalKeyboardKey.keyV: 'V',
|
||||
PhysicalKeyboardKey.keyW: 'W',
|
||||
PhysicalKeyboardKey.keyX: 'X',
|
||||
PhysicalKeyboardKey.keyY: 'Y',
|
||||
PhysicalKeyboardKey.keyZ: 'Z',
|
||||
PhysicalKeyboardKey.digit1: '1',
|
||||
PhysicalKeyboardKey.digit2: '2',
|
||||
PhysicalKeyboardKey.digit3: '3',
|
||||
PhysicalKeyboardKey.digit4: '4',
|
||||
PhysicalKeyboardKey.digit5: '5',
|
||||
PhysicalKeyboardKey.digit6: '6',
|
||||
PhysicalKeyboardKey.digit7: '7',
|
||||
PhysicalKeyboardKey.digit8: '8',
|
||||
PhysicalKeyboardKey.digit9: '9',
|
||||
PhysicalKeyboardKey.digit0: '0',
|
||||
PhysicalKeyboardKey.enter: 'ENTER',
|
||||
PhysicalKeyboardKey.escape: 'ESCAPE',
|
||||
PhysicalKeyboardKey.backspace: 'BACKSPACE',
|
||||
PhysicalKeyboardKey.tab: 'TAB',
|
||||
PhysicalKeyboardKey.space: 'SPACE',
|
||||
PhysicalKeyboardKey.minus: '-',
|
||||
PhysicalKeyboardKey.equal: '=',
|
||||
PhysicalKeyboardKey.bracketLeft: '[',
|
||||
PhysicalKeyboardKey.bracketRight: ']',
|
||||
PhysicalKeyboardKey.backslash: '\\',
|
||||
PhysicalKeyboardKey.semicolon: ';',
|
||||
PhysicalKeyboardKey.quote: '"',
|
||||
PhysicalKeyboardKey.backquote: '`',
|
||||
PhysicalKeyboardKey.comma: ',',
|
||||
PhysicalKeyboardKey.period: '.',
|
||||
PhysicalKeyboardKey.slash: '/',
|
||||
PhysicalKeyboardKey.capsLock: 'CAPSLOCK',
|
||||
PhysicalKeyboardKey.f1: 'F1',
|
||||
PhysicalKeyboardKey.f2: 'F2',
|
||||
PhysicalKeyboardKey.f3: 'F3',
|
||||
PhysicalKeyboardKey.f4: 'F4',
|
||||
PhysicalKeyboardKey.f5: 'F5',
|
||||
PhysicalKeyboardKey.f6: 'F6',
|
||||
PhysicalKeyboardKey.f7: 'F7',
|
||||
PhysicalKeyboardKey.f8: 'F8',
|
||||
PhysicalKeyboardKey.f9: 'F9',
|
||||
PhysicalKeyboardKey.f10: 'F10',
|
||||
PhysicalKeyboardKey.f11: 'F11',
|
||||
PhysicalKeyboardKey.f12: 'F12',
|
||||
PhysicalKeyboardKey.home: 'HOME',
|
||||
PhysicalKeyboardKey.pageUp: 'PAGEUP',
|
||||
PhysicalKeyboardKey.delete: 'DELETE',
|
||||
PhysicalKeyboardKey.end: 'END',
|
||||
PhysicalKeyboardKey.pageDown: 'PAGEDOWN',
|
||||
PhysicalKeyboardKey.arrowRight: '→',
|
||||
PhysicalKeyboardKey.arrowLeft: '←',
|
||||
PhysicalKeyboardKey.arrowDown: '↓',
|
||||
PhysicalKeyboardKey.arrowUp: '↑',
|
||||
PhysicalKeyboardKey.controlLeft: 'CTRL',
|
||||
PhysicalKeyboardKey.shiftLeft: 'SHIFT',
|
||||
PhysicalKeyboardKey.altLeft: 'ALT',
|
||||
PhysicalKeyboardKey.metaLeft: system.isMacOS ? '⌘' : 'WIN',
|
||||
PhysicalKeyboardKey.controlRight: 'CTRL',
|
||||
PhysicalKeyboardKey.shiftRight: 'SHIFT',
|
||||
PhysicalKeyboardKey.altRight: 'ALT',
|
||||
PhysicalKeyboardKey.metaRight: system.isMacOS ? '⌘' : 'WIN',
|
||||
PhysicalKeyboardKey.fn: 'FN',
|
||||
};
|
||||
|
||||
extension KeyboardKeyExt on KeyboardKey {
|
||||
String get label {
|
||||
|
||||
@@ -16,21 +16,20 @@ class LinkManager {
|
||||
}
|
||||
|
||||
Future<void> initAppLinksListen(
|
||||
Function(String url) installConfigCallBack) async {
|
||||
Function(String url) installConfigCallBack,
|
||||
) async {
|
||||
commonPrint.log('initAppLinksListen');
|
||||
destroy();
|
||||
subscription = _appLinks.uriLinkStream.listen(
|
||||
(uri) {
|
||||
commonPrint.log('onAppLink: $uri');
|
||||
if (uri.host == 'install-config') {
|
||||
final parameters = uri.queryParameters;
|
||||
final url = parameters['url'];
|
||||
if (url != null) {
|
||||
installConfigCallBack(url);
|
||||
}
|
||||
subscription = _appLinks.uriLinkStream.listen((uri) {
|
||||
commonPrint.log('onAppLink: $uri');
|
||||
if (uri.host == 'install-config') {
|
||||
final parameters = uri.queryParameters;
|
||||
final url = parameters['url'];
|
||||
if (url != null) {
|
||||
installConfigCallBack(url);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
|
||||
@@ -6,8 +6,8 @@ import 'common.dart';
|
||||
|
||||
extension PackageInfoExtension on PackageInfo {
|
||||
String get ua => [
|
||||
'$appName/v$version',
|
||||
'clash-verge',
|
||||
'Platform/${Platform.operatingSystem}',
|
||||
].join(' ');
|
||||
'$appName/v$version',
|
||||
'clash-verge',
|
||||
'Platform/${Platform.operatingSystem}',
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
@@ -7,13 +7,8 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
|
||||
class Picker {
|
||||
Future<PlatformFile?> pickerFile({bool withData = true}) async {
|
||||
final filePickerResult = await FilePicker.pickFiles(
|
||||
withData: withData,
|
||||
allowMultiple: false,
|
||||
initialDirectory: await appPath.downloadDirPath,
|
||||
);
|
||||
return filePickerResult?.files.first;
|
||||
Future<PlatformFile?> pickerFile() async {
|
||||
return FilePicker.pickFile(initialDirectory: await appPath.downloadDirPath);
|
||||
}
|
||||
|
||||
Future<String?> saveFile(String fileName, Uint8List bytes) async {
|
||||
@@ -34,15 +29,12 @@ class Picker {
|
||||
if (!await localFile.exists()) {
|
||||
await localFile.create(recursive: true);
|
||||
}
|
||||
final bytes = Platform.isAndroid ? await localFile.readAsBytes() : null;
|
||||
final bytes = await localFile.readAsBytes();
|
||||
final path = await FilePicker.saveFile(
|
||||
fileName: fileName,
|
||||
initialDirectory: await appPath.downloadDirPath,
|
||||
bytes: bytes,
|
||||
);
|
||||
if (path != null && bytes == null) {
|
||||
await localFile.copy(path);
|
||||
}
|
||||
await localFile.safeDelete();
|
||||
return path;
|
||||
}
|
||||
@@ -65,4 +57,10 @@ class Picker {
|
||||
}
|
||||
}
|
||||
|
||||
extension PlatformFileExt on PlatformFile {
|
||||
Future<Uint8List> readBytes() {
|
||||
return readAsBytes();
|
||||
}
|
||||
}
|
||||
|
||||
final picker = Picker();
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
const _pipeBufferSize = 256 * 1024;
|
||||
|
||||
class _PipeCmd {
|
||||
final int type; // 0 = write, 1 = shutdown
|
||||
final Uint8List? data;
|
||||
|
||||
const _PipeCmd(this.type, this.data);
|
||||
}
|
||||
|
||||
void _pipeIsolate(List<Object> args) {
|
||||
final pipeName = args[0] as String;
|
||||
final dataPort = args[1] as SendPort;
|
||||
|
||||
final namePtr = pipeName.toNativeUtf16();
|
||||
|
||||
final handle = CreateNamedPipe(
|
||||
namePtr,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
1,
|
||||
_pipeBufferSize,
|
||||
_pipeBufferSize,
|
||||
0,
|
||||
nullptr,
|
||||
);
|
||||
|
||||
calloc.free(namePtr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
dataPort.send(
|
||||
'error:CreateNamedPipe failed, Win32 error=${GetLastError()}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final writeRx = ReceivePort();
|
||||
|
||||
final readBuf = calloc<Uint8>(_pipeBufferSize);
|
||||
final bytesRead = calloc<Uint32>();
|
||||
final overlapped = calloc<OVERLAPPED>();
|
||||
final readEvent = CreateEvent(nullptr, 1, 0, nullptr);
|
||||
overlapped.ref.hEvent = readEvent;
|
||||
|
||||
var running = true;
|
||||
var clientConnected = false;
|
||||
|
||||
writeRx.listen((msg) {
|
||||
if (msg is _PipeCmd) {
|
||||
if (msg.type == 0) {
|
||||
if (clientConnected && msg.data != null) {
|
||||
final buf = calloc<Uint8>(msg.data!.length);
|
||||
final written = calloc<Uint32>();
|
||||
buf.asTypedList(msg.data!.length).setAll(0, msg.data!);
|
||||
WriteFile(handle, buf, msg.data!.length, written, nullptr);
|
||||
calloc.free(written);
|
||||
calloc.free(buf);
|
||||
}
|
||||
} else if (msg.type == 1) {
|
||||
running = false;
|
||||
if (clientConnected) {
|
||||
DisconnectNamedPipe(handle);
|
||||
clientConnected = false;
|
||||
}
|
||||
writeRx.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final connectEvent = CreateEvent(nullptr, 1, 0, nullptr);
|
||||
final connectOverlapped = calloc<OVERLAPPED>();
|
||||
connectOverlapped.ref.hEvent = connectEvent;
|
||||
|
||||
while (running) {
|
||||
final cr = ConnectNamedPipe(handle, connectOverlapped);
|
||||
if (cr == 0) {
|
||||
final err = GetLastError();
|
||||
if (err == ERROR_IO_PENDING) {
|
||||
while (running) {
|
||||
final wr = WaitForSingleObject(connectEvent, 100);
|
||||
if (wr == WAIT_OBJECT_0) break;
|
||||
}
|
||||
if (!running) break;
|
||||
} else if (err != ERROR_PIPE_CONNECTED) {
|
||||
dataPort.send('error:ConnectNamedPipe failed, Win32 error=$err');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!running) break;
|
||||
|
||||
clientConnected = true;
|
||||
dataPort.send(writeRx.sendPort);
|
||||
|
||||
var readPending = false;
|
||||
while (running && clientConnected) {
|
||||
if (!readPending) {
|
||||
bytesRead.value = 0;
|
||||
final readResult = ReadFile(
|
||||
handle,
|
||||
readBuf,
|
||||
_pipeBufferSize,
|
||||
bytesRead,
|
||||
overlapped,
|
||||
);
|
||||
if (readResult != 0) {
|
||||
if (bytesRead.value > 0) {
|
||||
dataPort.send(
|
||||
Uint8List.fromList(readBuf.asTypedList(bytesRead.value)),
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
final err = GetLastError();
|
||||
if (err == ERROR_IO_PENDING) {
|
||||
readPending = true;
|
||||
} else if (bytesRead.value > 0) {
|
||||
dataPort.send(
|
||||
Uint8List.fromList(readBuf.asTypedList(bytesRead.value)),
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (readPending) {
|
||||
final wr = WaitForSingleObject(readEvent, 100);
|
||||
if (wr == WAIT_OBJECT_0) {
|
||||
final got = GetOverlappedResult(handle, overlapped, bytesRead, 0);
|
||||
if (got != 0 && bytesRead.value > 0) {
|
||||
dataPort.send(
|
||||
Uint8List.fromList(readBuf.asTypedList(bytesRead.value)),
|
||||
);
|
||||
readPending = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (wr != WAIT_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (running && clientConnected) {
|
||||
DisconnectNamedPipe(handle);
|
||||
clientConnected = false;
|
||||
dataPort.send('closed');
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(readEvent);
|
||||
CloseHandle(connectEvent);
|
||||
calloc.free(connectOverlapped);
|
||||
calloc.free(overlapped);
|
||||
calloc.free(bytesRead);
|
||||
calloc.free(readBuf);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
class NamedPipeServer {
|
||||
final String pipeName;
|
||||
Isolate? _isolate;
|
||||
SendPort? _writePort;
|
||||
ReceivePort? _responsePort;
|
||||
StreamSubscription? _responseSub;
|
||||
|
||||
final _dataController = StreamController<Uint8List>.broadcast();
|
||||
Completer<void> _connectionCompleter = Completer<void>();
|
||||
|
||||
void Function()? onDisconnect;
|
||||
|
||||
NamedPipeServer._(this.pipeName);
|
||||
|
||||
Stream<Uint8List> get dataStream => _dataController.stream;
|
||||
Completer<void> get connectionCompleter => _connectionCompleter;
|
||||
|
||||
static Future<NamedPipeServer> bind(String pipeName) async {
|
||||
final server = NamedPipeServer._(pipeName);
|
||||
server._responsePort = ReceivePort();
|
||||
|
||||
server._responseSub = server._responsePort!.listen((message) {
|
||||
if (message is SendPort) {
|
||||
server._writePort = message;
|
||||
if (server._connectionCompleter.isCompleted) {
|
||||
server._connectionCompleter = Completer<void>();
|
||||
}
|
||||
server._connectionCompleter.complete();
|
||||
} else if (message is Uint8List) {
|
||||
server._dataController.add(message);
|
||||
} else if (message == 'closed') {
|
||||
server._connectionCompleter = Completer<void>();
|
||||
server.onDisconnect?.call();
|
||||
} else if (message is String && message.startsWith('error:')) {
|
||||
commonPrint.log('[NamedPipeServer] $message', logLevel: LogLevel.error);
|
||||
}
|
||||
});
|
||||
|
||||
server._isolate = await Isolate.spawn(_pipeIsolate, [
|
||||
pipeName,
|
||||
server._responsePort!.sendPort,
|
||||
]);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void writeln(String message) {
|
||||
final wp = _writePort;
|
||||
if (wp == null) return;
|
||||
final str = '$message\n';
|
||||
wp.send(_PipeCmd(0, Uint8List.fromList(str.codeUnits)));
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
final wp = _writePort;
|
||||
if (wp == null) return;
|
||||
_writePort = null;
|
||||
wp.send(const _PipeCmd(1, null));
|
||||
_responseSub?.cancel();
|
||||
_responsePort?.close();
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
_isolate?.kill();
|
||||
_isolate = null;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,26 @@ import 'dart:io';
|
||||
|
||||
import 'package:win32_registry/win32_registry.dart';
|
||||
|
||||
class ProtocolRegistrationPlan {
|
||||
final String scheme;
|
||||
final String executable;
|
||||
|
||||
const ProtocolRegistrationPlan({
|
||||
required this.scheme,
|
||||
required this.executable,
|
||||
});
|
||||
|
||||
String get protocolKey => 'Software\\Classes\\$scheme';
|
||||
|
||||
String get commandKey => 'shell\\open\\command';
|
||||
|
||||
String get protocolValueName => 'URL Protocol';
|
||||
|
||||
String get protocolValue => '';
|
||||
|
||||
String get command => '"$executable" "%1"';
|
||||
}
|
||||
|
||||
class Protocol {
|
||||
static Protocol? _instance;
|
||||
|
||||
@@ -13,19 +33,25 @@ class Protocol {
|
||||
}
|
||||
|
||||
void register(String scheme) {
|
||||
final String protocolRegKey = 'Software\\Classes\\$scheme';
|
||||
const RegistryValue protocolRegValue = RegistryValue.string(
|
||||
'URL Protocol',
|
||||
'',
|
||||
final plan = ProtocolRegistrationPlan(
|
||||
scheme: scheme,
|
||||
executable: Platform.resolvedExecutable,
|
||||
);
|
||||
const String protocolCmdRegKey = 'shell\\open\\command';
|
||||
final RegistryValue protocolCmdRegValue = RegistryValue.string(
|
||||
'',
|
||||
'"${Platform.resolvedExecutable}" "%1"',
|
||||
);
|
||||
final regKey = Registry.currentUser.createKey(protocolRegKey);
|
||||
regKey.createValue(protocolRegValue);
|
||||
regKey.createKey(protocolCmdRegKey).createValue(protocolCmdRegValue);
|
||||
final regKey = CURRENT_USER.create(plan.protocolKey);
|
||||
try {
|
||||
regKey.setValue(
|
||||
plan.protocolValueName,
|
||||
RegistryValue.string(plan.protocolValue),
|
||||
);
|
||||
final commandKey = regKey.create(plan.commandKey);
|
||||
try {
|
||||
commandKey.setValue('', RegistryValue.string(plan.command));
|
||||
} finally {
|
||||
commandKey.close();
|
||||
}
|
||||
} finally {
|
||||
regKey.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,30 +113,30 @@ class Request {
|
||||
|
||||
final future = dio
|
||||
.get<Map<String, dynamic>>(
|
||||
source.key,
|
||||
cancelToken: token,
|
||||
options: Options(responseType: ResponseType.json),
|
||||
)
|
||||
source.key,
|
||||
cancelToken: token,
|
||||
options: Options(responseType: ResponseType.json),
|
||||
)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
future
|
||||
.then((res) {
|
||||
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||
completer.complete(Result.success(source.value(res.data!)));
|
||||
return;
|
||||
}
|
||||
commonPrint.log('checkIp data empty', logLevel: LogLevel.info);
|
||||
failureCount++;
|
||||
handleFailRes();
|
||||
})
|
||||
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||
completer.complete(Result.success(source.value(res.data!)));
|
||||
return;
|
||||
}
|
||||
commonPrint.log('checkIp data empty', logLevel: LogLevel.info);
|
||||
failureCount++;
|
||||
handleFailRes();
|
||||
})
|
||||
.catchError((e) {
|
||||
failureCount++;
|
||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
||||
completer.complete(Result.error('cancelled'));
|
||||
return;
|
||||
}
|
||||
commonPrint.log('checkIp error $e', logLevel: LogLevel.warning);
|
||||
handleFailRes();
|
||||
});
|
||||
failureCount++;
|
||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
||||
completer.complete(Result.error('cancelled'));
|
||||
return;
|
||||
}
|
||||
commonPrint.log('checkIp error $e', logLevel: LogLevel.warning);
|
||||
handleFailRes();
|
||||
});
|
||||
return completer.future;
|
||||
});
|
||||
final res = await Future.any(futures);
|
||||
@@ -149,9 +149,9 @@ class Request {
|
||||
try {
|
||||
final response = await dio
|
||||
.get(
|
||||
'http://$localhost:$helperPort/ping',
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
'http://$localhost:$helperPort/ping',
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
@@ -166,10 +166,10 @@ class Request {
|
||||
try {
|
||||
final response = await dio
|
||||
.post(
|
||||
'http://$localhost:$helperPort/start',
|
||||
data: json.encode({'path': appPath.corePath, 'arg': arg}),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
'http://$localhost:$helperPort/start',
|
||||
data: json.encode({'path': appPath.corePath, 'arg': arg}),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
@@ -185,9 +185,9 @@ class Request {
|
||||
try {
|
||||
final response = await dio
|
||||
.post(
|
||||
'http://$localhost:$helperPort/stop',
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
'http://$localhost:$helperPort/stop',
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
|
||||
@@ -104,6 +104,7 @@ class System {
|
||||
obscureText: true,
|
||||
title: currentAppLocalizations.pleaseInputAdminPassword,
|
||||
value: '',
|
||||
inputFormatters: TextInputLimits.limit(TextInputLimits.password),
|
||||
),
|
||||
);
|
||||
if (password == null || password.isEmpty) {
|
||||
|
||||
@@ -183,7 +183,7 @@ Future<VM2<String, String>> _makeRealProfileTask(
|
||||
}
|
||||
}
|
||||
rawConfig['profile']['store-selected'] = false;
|
||||
rawConfig['geox-url'] = realPatchConfig.geoXUrl.toJson();
|
||||
rawConfig['geox-url'] = realPatchConfig.geoXUrl.raw;
|
||||
rawConfig['global-ua'] = realPatchConfig.globalUa ?? defaultUA;
|
||||
if (rawConfig['hosts'] == null) {
|
||||
rawConfig['hosts'] = {};
|
||||
@@ -331,10 +331,10 @@ Future<String> _encodeLogsTask(List<Log> data) async {
|
||||
|
||||
Future<MigrationData> oldToNowTask(Map<String, Object?> data) async {
|
||||
final homeDir = await appPath.homeDirPath;
|
||||
return compute<
|
||||
VM3<Map<String, Object?>, String, String>,
|
||||
MigrationData
|
||||
>(_oldToNowTask, VM3(data, homeDir, homeDir));
|
||||
return compute<VM3<Map<String, Object?>, String, String>, MigrationData>(
|
||||
_oldToNowTask,
|
||||
VM3(data, homeDir, homeDir),
|
||||
);
|
||||
}
|
||||
|
||||
Future<MigrationData> _oldToNowTask(
|
||||
|
||||
@@ -11,11 +11,8 @@ extension TextStyleExtension on TextStyle {
|
||||
|
||||
TextStyle get toBold => copyWith(fontWeight: FontWeight.bold);
|
||||
|
||||
TextStyle get toJetBrainsMono => copyWith(
|
||||
fontFamily: FontFamily.jetBrainsMono.value,
|
||||
);
|
||||
TextStyle get toJetBrainsMono =>
|
||||
copyWith(fontFamily: FontFamily.jetBrainsMono.value);
|
||||
|
||||
TextStyle adjustSize(int size) => copyWith(
|
||||
fontSize: fontSize! + size,
|
||||
);
|
||||
TextStyle adjustSize(int size) => copyWith(fontSize: fontSize! + size);
|
||||
}
|
||||
|
||||
@@ -177,8 +177,8 @@ class CoreController {
|
||||
return ExternalProvider.fromJson(json.decode(externalProvidersRawString));
|
||||
}
|
||||
|
||||
Future<String> updateGeoData(UpdateGeoDataParams params) {
|
||||
return _interface.updateGeoData(params);
|
||||
Future<String> updateGeoData(String type) {
|
||||
return _interface.updateGeoData(type);
|
||||
}
|
||||
|
||||
Future<String> sideLoadExternalProvider({
|
||||
|
||||
@@ -14,6 +14,13 @@ abstract mixin class CoreEventListener {
|
||||
void onLoaded(String providerName) {}
|
||||
|
||||
void onCrash(String message) {}
|
||||
|
||||
void onGeoUpdate(
|
||||
String geoType,
|
||||
bool updating,
|
||||
bool skipped,
|
||||
String? error,
|
||||
) {}
|
||||
}
|
||||
|
||||
class CoreEventManager {
|
||||
@@ -38,6 +45,15 @@ class CoreEventManager {
|
||||
case CoreEventType.crash:
|
||||
listener.onCrash(event.data);
|
||||
break;
|
||||
case CoreEventType.geoUpdate:
|
||||
final data = event.data as Map<String, dynamic>;
|
||||
listener.onGeoUpdate(
|
||||
data['type'] as String,
|
||||
data['updating'] as bool,
|
||||
data['skipped'] as bool? ?? false,
|
||||
data['error'] as String?,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ mixin CoreInterface {
|
||||
|
||||
Future<String>? getExternalProvider(String externalProviderName);
|
||||
|
||||
Future<String> updateGeoData(UpdateGeoDataParams params);
|
||||
Future<String> updateGeoData(String type);
|
||||
|
||||
Future<String> sideLoadExternalProvider({
|
||||
required String providerName,
|
||||
@@ -214,10 +214,10 @@ abstract class CoreHandlerInterface with CoreInterface {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> updateGeoData(UpdateGeoDataParams params) async {
|
||||
Future<String> updateGeoData(String type) async {
|
||||
return await _invoke<String>(
|
||||
method: ActionMethod.updateGeoData,
|
||||
data: json.encode(params),
|
||||
data: type,
|
||||
) ??
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -34,50 +34,50 @@ class IPCCoreTransport {
|
||||
try {
|
||||
final stream = restartIpcServer(name: address);
|
||||
_subscription = stream.listen(
|
||||
(data) {
|
||||
if (data.isEmpty) return;
|
||||
final type = data[0];
|
||||
final payload = data.length > 1 ? data.sublist(1) : Uint8List(0);
|
||||
switch (type) {
|
||||
case _typeReady:
|
||||
commonPrint.log('IPC Ready');
|
||||
if (_readyCompleter.isCompleted) {
|
||||
(data) {
|
||||
if (data.isEmpty) return;
|
||||
final type = data[0];
|
||||
final payload = data.length > 1 ? data.sublist(1) : Uint8List(0);
|
||||
switch (type) {
|
||||
case _typeReady:
|
||||
commonPrint.log('IPC Ready');
|
||||
if (_readyCompleter.isCompleted) {
|
||||
break;
|
||||
}
|
||||
_readyCompleter.complete();
|
||||
break;
|
||||
}
|
||||
_readyCompleter.complete();
|
||||
break;
|
||||
case _typeConnected:
|
||||
commonPrint.log('IPC Connected');
|
||||
if (_completer.isCompleted) {
|
||||
case _typeConnected:
|
||||
commonPrint.log('IPC Connected');
|
||||
if (_completer.isCompleted) {
|
||||
break;
|
||||
}
|
||||
_completer.complete();
|
||||
break;
|
||||
}
|
||||
_completer.complete();
|
||||
break;
|
||||
case _typeDisconnected:
|
||||
commonPrint.log('IPC Disconnected');
|
||||
_completer = Completer<void>();
|
||||
onDisconnect?.call();
|
||||
break;
|
||||
case _typeData:
|
||||
_dataController.add(payload);
|
||||
break;
|
||||
case _typeError:
|
||||
final msg = utf8.decode(payload);
|
||||
commonPrint.log('IPC error: $msg', logLevel: LogLevel.error);
|
||||
break;
|
||||
default:
|
||||
commonPrint.log(
|
||||
'IPC unknown frame type: $type',
|
||||
logLevel: LogLevel.warning,
|
||||
);
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
commonPrint.log('IPC error: $error', logLevel: LogLevel.error);
|
||||
},
|
||||
cancelOnError: false,
|
||||
);
|
||||
await _readyCompleter.future;
|
||||
case _typeDisconnected:
|
||||
commonPrint.log('IPC Disconnected');
|
||||
_completer = Completer<void>();
|
||||
onDisconnect?.call();
|
||||
break;
|
||||
case _typeData:
|
||||
_dataController.add(payload);
|
||||
break;
|
||||
case _typeError:
|
||||
final msg = utf8.decode(payload);
|
||||
commonPrint.log('IPC error: $msg', logLevel: LogLevel.error);
|
||||
break;
|
||||
default:
|
||||
commonPrint.log(
|
||||
'IPC unknown frame type: $type',
|
||||
logLevel: LogLevel.warning,
|
||||
);
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
commonPrint.log('IPC error: $error', logLevel: LogLevel.error);
|
||||
},
|
||||
cancelOnError: false,
|
||||
);
|
||||
await _readyCompleter.future;
|
||||
} catch (e) {
|
||||
commonPrint.log(
|
||||
'Failed to start IPC server: $e',
|
||||
|
||||
@@ -135,7 +135,7 @@ enum ResultType {
|
||||
error,
|
||||
}
|
||||
|
||||
enum CoreEventType { log, delay, request, loaded, crash }
|
||||
enum CoreEventType { log, delay, request, loaded, crash, geoUpdate }
|
||||
|
||||
enum InvokeMessageType { protect, process }
|
||||
|
||||
@@ -331,6 +331,40 @@ enum DashboardWidget {
|
||||
|
||||
enum GeodataLoader { standard, memconservative }
|
||||
|
||||
enum GeoResource {
|
||||
@JsonValue('mmdb')
|
||||
MMDB,
|
||||
@JsonValue('asn')
|
||||
ASN,
|
||||
@JsonValue('geo-ip')
|
||||
GEOIP,
|
||||
@JsonValue('geo-site')
|
||||
GEOSITE;
|
||||
|
||||
static GeoResource fromJson(String value) {
|
||||
return switch (value) {
|
||||
'mmdb' => GeoResource.MMDB,
|
||||
'asn' => GeoResource.ASN,
|
||||
'geo-ip' || 'geoip' => GeoResource.GEOIP,
|
||||
'geo-site' || 'geosite' => GeoResource.GEOSITE,
|
||||
_ => throw ArgumentError.value(value, 'value', 'Invalid geo resource'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extension GeoResourceExt on GeoResource {
|
||||
String get value {
|
||||
return switch (this) {
|
||||
GeoResource.MMDB => 'mmdb',
|
||||
GeoResource.ASN => 'asn',
|
||||
GeoResource.GEOIP => 'geo-ip',
|
||||
GeoResource.GEOSITE => 'geo-site',
|
||||
};
|
||||
}
|
||||
|
||||
String get updatingKey => 'geo_resource_$name';
|
||||
}
|
||||
|
||||
enum PageLabel {
|
||||
dashboard,
|
||||
proxies,
|
||||
|
||||
@@ -251,7 +251,7 @@ class _AddOrEditRuleDialogState extends State<AddOrEditRuleDialog> {
|
||||
return;
|
||||
}
|
||||
final rule = Rule(
|
||||
id: widget.rule?.id ?? -1,
|
||||
id: widget.rule?.id ?? snowflake.id,
|
||||
ruleAction: _ruleAction,
|
||||
content: _contentController.text,
|
||||
ruleTarget: _ruleTargetController.text,
|
||||
@@ -310,6 +310,9 @@ class _AddOrEditRuleDialogState extends State<AddOrEditRuleDialog> {
|
||||
const SizedBox(height: 24),
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.text,
|
||||
inputFormatters: TextInputLimits.limit(
|
||||
TextInputLimits.rule,
|
||||
),
|
||||
onFieldSubmitted: (_) {
|
||||
_handleSubmit();
|
||||
},
|
||||
|
||||
@@ -33,40 +33,52 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m4(label) => "${label} cannot be empty";
|
||||
|
||||
static String m5(label) => "Current ${label} already exists";
|
||||
static String m5(count) => "${count} entries";
|
||||
|
||||
static String m6(count) =>
|
||||
static String m6(label) => "Current ${label} already exists";
|
||||
|
||||
static String m7(name) => "${name} skipped";
|
||||
|
||||
static String m8(name) => "${name} updated";
|
||||
|
||||
static String m9(name) => "Updating ${name}...";
|
||||
|
||||
static String m10(count) =>
|
||||
"${Intl.plural(count, one: '1 hour ago', other: '${count} hours ago')}";
|
||||
|
||||
static String m7(target) => "${target} is an invalid policy";
|
||||
static String m11(count) => "${count} hours";
|
||||
|
||||
static String m8(proxyName) => "${proxyName} is an invalid proxy";
|
||||
static String m12(target) => "${target} is an invalid policy";
|
||||
|
||||
static String m9(providerName) =>
|
||||
static String m13(proxyName) => "${proxyName} is an invalid proxy";
|
||||
|
||||
static String m14(providerName) =>
|
||||
"${providerName} is an invalid proxy provider";
|
||||
|
||||
static String m10(subRule) => "${subRule} is an invalid SUB_RULE";
|
||||
static String m15(subRule) => "${subRule} is an invalid SUB_RULE";
|
||||
|
||||
static String m11(appName) =>
|
||||
static String m16(appName) =>
|
||||
"1. Open System Settings > Privacy & Security\n2. Choose Location Services\n3. Find and check ${appName} in the right list\n\nAfter completing the setup, return to the app and use it normally. Thank you for your cooperation.";
|
||||
|
||||
static String m12(count) =>
|
||||
static String m17(count) =>
|
||||
"${Intl.plural(count, one: '1 minute ago', other: '${count} minutes ago')}";
|
||||
|
||||
static String m13(count) =>
|
||||
static String m18(count) =>
|
||||
"${Intl.plural(count, one: '1 month ago', other: '${count} months ago')}";
|
||||
|
||||
static String m14(label) => "No ${label} yet";
|
||||
static String m19(label) => "No ${label} yet";
|
||||
|
||||
static String m15(label) => "${label} must be a number";
|
||||
static String m20(label) => "${label} must be a number";
|
||||
|
||||
static String m16(label) => "${label} must be between 1024 and 49151";
|
||||
static String m21(label) => "${label} must be between 1024 and 49151";
|
||||
|
||||
static String m17(count) => "${count} items have been selected";
|
||||
static String m22(count) => "${count} seconds";
|
||||
|
||||
static String m18(label) => "${label} must be a url";
|
||||
static String m23(count) => "${count} items have been selected";
|
||||
|
||||
static String m19(count) =>
|
||||
static String m24(label) => "${label} must be a url";
|
||||
|
||||
static String m25(count) =>
|
||||
"${Intl.plural(count, one: '1 year ago', other: '${count} years ago')}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
@@ -343,6 +355,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"emptyTip": m4,
|
||||
"en": MessageLookupByLibrary.simpleMessage("English"),
|
||||
"entries": MessageLookupByLibrary.simpleMessage(" entries"),
|
||||
"entriesCount": m5,
|
||||
"exclude": MessageLookupByLibrary.simpleMessage("Hidden from recent tasks"),
|
||||
"excludeDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"When the app is in the background, the app is hidden from the recent task",
|
||||
@@ -355,7 +368,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"When connected to an excluded SSID Wi-Fi, the app running state will be automatically switched.",
|
||||
),
|
||||
"excludeType": MessageLookupByLibrary.simpleMessage("Exclude type"),
|
||||
"existsTip": m5,
|
||||
"existsTip": m6,
|
||||
"exit": MessageLookupByLibrary.simpleMessage("Exit"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("Standard"),
|
||||
"expectedStatus": MessageLookupByLibrary.simpleMessage("Expected status"),
|
||||
@@ -394,6 +407,18 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"fruitSaladScheme": MessageLookupByLibrary.simpleMessage("FruitSalad"),
|
||||
"general": MessageLookupByLibrary.simpleMessage("General"),
|
||||
"geoAutoUpdate": MessageLookupByLibrary.simpleMessage("Auto Update"),
|
||||
"geoAutoUpdateInterval": MessageLookupByLibrary.simpleMessage(
|
||||
"Auto Update Interval",
|
||||
),
|
||||
"geoAutoUpdateIntervalTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Auto update interval must be greater than 0",
|
||||
),
|
||||
"geoOptions": MessageLookupByLibrary.simpleMessage("Geo Options"),
|
||||
"geoResources": MessageLookupByLibrary.simpleMessage("Geo Resources"),
|
||||
"geoSkipped": m7,
|
||||
"geoUpdated": m8,
|
||||
"geoUpdating": m9,
|
||||
"geodataLoader": MessageLookupByLibrary.simpleMessage(
|
||||
"Geo Low Memory Mode",
|
||||
),
|
||||
@@ -420,7 +445,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"hotkeyManagementDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Use keyboard to control applications",
|
||||
),
|
||||
"hoursAgo": m6,
|
||||
"hours": MessageLookupByLibrary.simpleMessage("hours"),
|
||||
"hoursAgo": m10,
|
||||
"hoursCount": m11,
|
||||
"icon": MessageLookupByLibrary.simpleMessage("Icon"),
|
||||
"iconRecords": MessageLookupByLibrary.simpleMessage("Icon records"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("Icon style"),
|
||||
@@ -464,10 +491,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"invalidBackupFile": MessageLookupByLibrary.simpleMessage(
|
||||
"Invalid backup file",
|
||||
),
|
||||
"invalidPolicy": m7,
|
||||
"invalidProxy": m8,
|
||||
"invalidProxyProvider": m9,
|
||||
"invalidSubRule": m10,
|
||||
"invalidPolicy": m12,
|
||||
"invalidProxy": m13,
|
||||
"invalidProxyProvider": m14,
|
||||
"invalidSubRule": m15,
|
||||
"ipcidr": MessageLookupByLibrary.simpleMessage("Ipcidr"),
|
||||
"ipv6Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"When turned on it will be able to receive IPv6 traffic",
|
||||
@@ -501,7 +528,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"locationPermissionDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"According to system requirements, obtaining the Wi-Fi name requires you to grant location permission.",
|
||||
),
|
||||
"locationPermissionGuide": m11,
|
||||
"locationPermissionGuide": m16,
|
||||
"locationPermissionRequired": MessageLookupByLibrary.simpleMessage(
|
||||
"Location Permission Required",
|
||||
),
|
||||
@@ -531,11 +558,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"minimizeOnExitDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Modify the default system exit event",
|
||||
),
|
||||
"minutesAgo": m12,
|
||||
"minutesAgo": m17,
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("Mixed Port"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("Mode"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("Monochrome"),
|
||||
"monthsAgo": m13,
|
||||
"monthsAgo": m18,
|
||||
"more": MessageLookupByLibrary.simpleMessage("More"),
|
||||
"name": MessageLookupByLibrary.simpleMessage("Name"),
|
||||
"nameserver": MessageLookupByLibrary.simpleMessage("Nameserver"),
|
||||
@@ -581,8 +608,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"nullProfileDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"No profile, Please add a profile",
|
||||
),
|
||||
"nullTip": m14,
|
||||
"numberTip": m15,
|
||||
"nullTip": m19,
|
||||
"numberTip": m20,
|
||||
"onDemand": MessageLookupByLibrary.simpleMessage("On Demand"),
|
||||
"onDemandDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Configure the program running state for specific scenarios",
|
||||
@@ -631,7 +658,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Please enter a different port",
|
||||
),
|
||||
"portTip": m16,
|
||||
"portTip": m21,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Prioritize the use of DOH\'s http/3",
|
||||
),
|
||||
@@ -888,6 +915,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"search": MessageLookupByLibrary.simpleMessage("Search"),
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("Seconds"),
|
||||
"secondsCount": m22,
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("Select all"),
|
||||
"selectProxies": MessageLookupByLibrary.simpleMessage("Select proxies"),
|
||||
"selectProxyProviders": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -903,7 +931,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Please select sub rule",
|
||||
),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("Selected"),
|
||||
"selectedCountTitle": m17,
|
||||
"selectedCountTitle": m23,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Settings"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("Show"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("Shrink"),
|
||||
@@ -1003,9 +1031,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Obtain profile through URL",
|
||||
),
|
||||
"urlTip": m18,
|
||||
"urlTip": m24,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("Use hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("Use system hosts"),
|
||||
"userAgent": MessageLookupByLibrary.simpleMessage("User-Agent"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("Value"),
|
||||
"vibrantScheme": MessageLookupByLibrary.simpleMessage("Vibrant"),
|
||||
"view": MessageLookupByLibrary.simpleMessage("View"),
|
||||
@@ -1022,7 +1051,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"WebDAV configuration",
|
||||
),
|
||||
"whitelistMode": MessageLookupByLibrary.simpleMessage("Whitelist mode"),
|
||||
"yearsAgo": m19,
|
||||
"yearsAgo": m25,
|
||||
"zh_CN": MessageLookupByLibrary.simpleMessage("Simplified Chinese"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,36 +30,48 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m4(label) => "${label}は空欄にできません";
|
||||
|
||||
static String m5(label) => "現在の${label}は既に存在しています";
|
||||
static String m5(count) => "${count} エントリ";
|
||||
|
||||
static String m6(count) => "${count}時間前";
|
||||
static String m6(label) => "現在の${label}は既に存在しています";
|
||||
|
||||
static String m7(target) => "${target} は無効なポリシーです";
|
||||
static String m7(name) => "${name} スキップ済み";
|
||||
|
||||
static String m8(proxyName) => "${proxyName} は無効なプロキシです";
|
||||
static String m8(name) => "${name} 更新済み";
|
||||
|
||||
static String m9(providerName) => "${providerName} は無効なプロキシプロバイダーです";
|
||||
static String m9(name) => "${name}を更新中...";
|
||||
|
||||
static String m10(subRule) => "${subRule} は無効なSUB_RULEです";
|
||||
static String m10(count) => "${count}時間前";
|
||||
|
||||
static String m11(appName) =>
|
||||
static String m11(count) => "${count} 時間";
|
||||
|
||||
static String m12(target) => "${target} は無効なポリシーです";
|
||||
|
||||
static String m13(proxyName) => "${proxyName} は無効なプロキシです";
|
||||
|
||||
static String m14(providerName) => "${providerName} は無効なプロキシプロバイダーです";
|
||||
|
||||
static String m15(subRule) => "${subRule} は無効なSUB_RULEです";
|
||||
|
||||
static String m16(appName) =>
|
||||
"1. Open System Settings > Privacy & Security\n2. Choose Location Services\n3. Find and check ${appName} in the right list\n\nAfter completing the setup, return to the app and use it normally. Thank you for your cooperation.";
|
||||
|
||||
static String m12(count) => "${count}分前";
|
||||
static String m17(count) => "${count}分前";
|
||||
|
||||
static String m13(count) => "${count}ヶ月前";
|
||||
static String m18(count) => "${count}ヶ月前";
|
||||
|
||||
static String m14(label) => "まだ${label}はありません";
|
||||
static String m19(label) => "まだ${label}はありません";
|
||||
|
||||
static String m15(label) => "${label}は数字でなければなりません";
|
||||
static String m20(label) => "${label}は数字でなければなりません";
|
||||
|
||||
static String m16(label) => "${label} は 1024 から 49151 の間でなければなりません";
|
||||
static String m21(label) => "${label} は 1024 から 49151 の間でなければなりません";
|
||||
|
||||
static String m17(count) => "${count} 項目が選択されています";
|
||||
static String m22(count) => "${count} 秒";
|
||||
|
||||
static String m18(label) => "${label}はURLである必要があります";
|
||||
static String m23(count) => "${count} 項目が選択されています";
|
||||
|
||||
static String m19(count) => "${count}年前";
|
||||
static String m24(label) => "${label}はURLである必要があります";
|
||||
|
||||
static String m25(count) => "${count}年前";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -265,6 +277,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"emptyTip": m4,
|
||||
"en": MessageLookupByLibrary.simpleMessage("英語"),
|
||||
"entries": MessageLookupByLibrary.simpleMessage(" エントリ"),
|
||||
"entriesCount": m5,
|
||||
"exclude": MessageLookupByLibrary.simpleMessage("最近のタスクから非表示"),
|
||||
"excludeDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"アプリがバックグラウンド時に最近のタスクから非表示",
|
||||
@@ -275,7 +288,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"When connected to an excluded SSID Wi-Fi, the app running state will be automatically switched.",
|
||||
),
|
||||
"excludeType": MessageLookupByLibrary.simpleMessage("除外タイプ"),
|
||||
"existsTip": m5,
|
||||
"existsTip": m6,
|
||||
"exit": MessageLookupByLibrary.simpleMessage("終了"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("標準"),
|
||||
"expectedStatus": MessageLookupByLibrary.simpleMessage("期待されるステータス"),
|
||||
@@ -310,6 +323,16 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"fruitSaladScheme": MessageLookupByLibrary.simpleMessage("フルーツサラダ"),
|
||||
"general": MessageLookupByLibrary.simpleMessage("一般"),
|
||||
"geoAutoUpdate": MessageLookupByLibrary.simpleMessage("自動更新"),
|
||||
"geoAutoUpdateInterval": MessageLookupByLibrary.simpleMessage("自動更新間隔"),
|
||||
"geoAutoUpdateIntervalTip": MessageLookupByLibrary.simpleMessage(
|
||||
"自動更新間隔は0より大きくなければなりません",
|
||||
),
|
||||
"geoOptions": MessageLookupByLibrary.simpleMessage("Geoオプション"),
|
||||
"geoResources": MessageLookupByLibrary.simpleMessage("Geoリソース"),
|
||||
"geoSkipped": m7,
|
||||
"geoUpdated": m8,
|
||||
"geoUpdating": m9,
|
||||
"geodataLoader": MessageLookupByLibrary.simpleMessage("Geo低メモリモード"),
|
||||
"geodataLoaderDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"有効化するとGeo低メモリローダーを使用",
|
||||
@@ -328,7 +351,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"hotkeyManagementDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"キーボードでアプリを制御",
|
||||
),
|
||||
"hoursAgo": m6,
|
||||
"hours": MessageLookupByLibrary.simpleMessage("時間"),
|
||||
"hoursAgo": m10,
|
||||
"hoursCount": m11,
|
||||
"icon": MessageLookupByLibrary.simpleMessage("アイコン"),
|
||||
"iconRecords": MessageLookupByLibrary.simpleMessage("アイコン履歴"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("アイコンスタイル"),
|
||||
@@ -360,10 +385,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"interval": MessageLookupByLibrary.simpleMessage("インターバル"),
|
||||
"intranetIP": MessageLookupByLibrary.simpleMessage("イントラネットIP"),
|
||||
"invalidBackupFile": MessageLookupByLibrary.simpleMessage("無効なバックアップファイル"),
|
||||
"invalidPolicy": m7,
|
||||
"invalidProxy": m8,
|
||||
"invalidProxyProvider": m9,
|
||||
"invalidSubRule": m10,
|
||||
"invalidPolicy": m12,
|
||||
"invalidProxy": m13,
|
||||
"invalidProxyProvider": m14,
|
||||
"invalidSubRule": m15,
|
||||
"ipcidr": MessageLookupByLibrary.simpleMessage("IPCIDR"),
|
||||
"ipv6Desc": MessageLookupByLibrary.simpleMessage("有効化するとIPv6トラフィックを受信可能"),
|
||||
"ipv6InboundDesc": MessageLookupByLibrary.simpleMessage("IPv6インバウンドを許可"),
|
||||
@@ -391,7 +416,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"locationPermissionDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"According to system requirements, obtaining the Wi-Fi name requires you to grant location permission.",
|
||||
),
|
||||
"locationPermissionGuide": m11,
|
||||
"locationPermissionGuide": m16,
|
||||
"locationPermissionRequired": MessageLookupByLibrary.simpleMessage(
|
||||
"Location Permission Required",
|
||||
),
|
||||
@@ -415,11 +440,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"minimizeOnExitDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"システムの終了イベントを変更",
|
||||
),
|
||||
"minutesAgo": m12,
|
||||
"minutesAgo": m17,
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("混合ポート"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("モード"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("モノクローム"),
|
||||
"monthsAgo": m13,
|
||||
"monthsAgo": m18,
|
||||
"more": MessageLookupByLibrary.simpleMessage("詳細"),
|
||||
"name": MessageLookupByLibrary.simpleMessage("名前"),
|
||||
"nameserver": MessageLookupByLibrary.simpleMessage("ネームサーバー"),
|
||||
@@ -453,8 +478,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"nullProfileDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"プロファイルがありません。追加してください",
|
||||
),
|
||||
"nullTip": m14,
|
||||
"numberTip": m15,
|
||||
"nullTip": m19,
|
||||
"numberTip": m20,
|
||||
"onDemand": MessageLookupByLibrary.simpleMessage("On Demand"),
|
||||
"onDemandDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Configure the program running state for specific scenarios",
|
||||
@@ -497,7 +522,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("ポート"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage("別のポートを入力してください"),
|
||||
"portTip": m16,
|
||||
"portTip": m21,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("DOHのHTTP/3を優先使用"),
|
||||
"prerequisites": MessageLookupByLibrary.simpleMessage("Prerequisites"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("キーボードを押してください"),
|
||||
@@ -716,6 +741,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"search": MessageLookupByLibrary.simpleMessage("検索"),
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("秒"),
|
||||
"secondsCount": m22,
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("すべて選択"),
|
||||
"selectProxies": MessageLookupByLibrary.simpleMessage("プロキシを選択"),
|
||||
"selectProxyProviders": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -727,7 +753,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"selectSubRule": MessageLookupByLibrary.simpleMessage("サブルールを選択してください"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("選択済み"),
|
||||
"selectedCountTitle": m17,
|
||||
"selectedCountTitle": m23,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("設定"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("表示"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("縮小"),
|
||||
@@ -809,9 +835,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upload": MessageLookupByLibrary.simpleMessage("アップロード"),
|
||||
"url": MessageLookupByLibrary.simpleMessage("URL"),
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage("URL経由でプロファイルを取得"),
|
||||
"urlTip": m18,
|
||||
"urlTip": m24,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("ホストを使用"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("システムホストを使用"),
|
||||
"userAgent": MessageLookupByLibrary.simpleMessage("ユーザーエージェント"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("値"),
|
||||
"vibrantScheme": MessageLookupByLibrary.simpleMessage("ビブラント"),
|
||||
"view": MessageLookupByLibrary.simpleMessage("表示"),
|
||||
@@ -824,7 +851,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"vpnTip": MessageLookupByLibrary.simpleMessage("変更はVPN再起動後に有効"),
|
||||
"webDAVConfiguration": MessageLookupByLibrary.simpleMessage("WebDAV設定"),
|
||||
"whitelistMode": MessageLookupByLibrary.simpleMessage("ホワイトリストモード"),
|
||||
"yearsAgo": m19,
|
||||
"yearsAgo": m25,
|
||||
"zh_CN": MessageLookupByLibrary.simpleMessage("簡体字中国語"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,40 +32,52 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m4(label) => "${label} не может быть пустым";
|
||||
|
||||
static String m5(label) => "Текущий ${label} уже существует";
|
||||
static String m5(count) => "${count} записей";
|
||||
|
||||
static String m6(count) =>
|
||||
static String m6(label) => "Текущий ${label} уже существует";
|
||||
|
||||
static String m7(name) => "${name} пропущено";
|
||||
|
||||
static String m8(name) => "${name} обновлено";
|
||||
|
||||
static String m9(name) => "Обновление ${name}...";
|
||||
|
||||
static String m10(count) =>
|
||||
"${Intl.plural(count, one: '${count} час назад', few: '${count} часа назад', many: '${count} часов назад', other: '${count} часа назад')}";
|
||||
|
||||
static String m7(target) => "${target} является недопустимой политикой";
|
||||
static String m11(count) => "${count} часов";
|
||||
|
||||
static String m8(proxyName) => "${proxyName} является недопустимым прокси";
|
||||
static String m12(target) => "${target} является недопустимой политикой";
|
||||
|
||||
static String m9(providerName) =>
|
||||
static String m13(proxyName) => "${proxyName} является недопустимым прокси";
|
||||
|
||||
static String m14(providerName) =>
|
||||
"${providerName} является недопустимым провайдером прокси";
|
||||
|
||||
static String m10(subRule) => "${subRule} является недопустимым подправилом";
|
||||
static String m15(subRule) => "${subRule} является недопустимым подправилом";
|
||||
|
||||
static String m11(appName) =>
|
||||
static String m16(appName) =>
|
||||
"1. Open System Settings > Privacy & Security\n2. Choose Location Services\n3. Find and check ${appName} in the right list\n\nAfter completing the setup, return to the app and use it normally. Thank you for your cooperation.";
|
||||
|
||||
static String m12(count) =>
|
||||
static String m17(count) =>
|
||||
"${Intl.plural(count, one: '${count} минута назад', few: '${count} минуты назад', many: '${count} минут назад', other: '${count} минуты назад')}";
|
||||
|
||||
static String m13(count) =>
|
||||
static String m18(count) =>
|
||||
"${Intl.plural(count, one: '${count} месяц назад', few: '${count} месяца назад', many: '${count} месяцев назад', other: '${count} месяца назад')}";
|
||||
|
||||
static String m14(label) => "${label} пока отсутствуют";
|
||||
static String m19(label) => "${label} пока отсутствуют";
|
||||
|
||||
static String m15(label) => "${label} должно быть числом";
|
||||
static String m20(label) => "${label} должно быть числом";
|
||||
|
||||
static String m16(label) => "${label} должен быть числом от 1024 до 49151";
|
||||
static String m21(label) => "${label} должен быть числом от 1024 до 49151";
|
||||
|
||||
static String m17(count) => "Выбрано ${count} элементов";
|
||||
static String m22(count) => "${count} секунд";
|
||||
|
||||
static String m18(label) => "${label} должен быть URL";
|
||||
static String m23(count) => "Выбрано ${count} элементов";
|
||||
|
||||
static String m19(count) =>
|
||||
static String m24(label) => "${label} должен быть URL";
|
||||
|
||||
static String m25(count) =>
|
||||
"${Intl.plural(count, one: '${count} год назад', few: '${count} года назад', many: '${count} лет назад', other: '${count} года назад')}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
@@ -352,6 +364,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"emptyTip": m4,
|
||||
"en": MessageLookupByLibrary.simpleMessage("Английский"),
|
||||
"entries": MessageLookupByLibrary.simpleMessage(" записей"),
|
||||
"entriesCount": m5,
|
||||
"exclude": MessageLookupByLibrary.simpleMessage(
|
||||
"Скрыть из последних задач",
|
||||
),
|
||||
@@ -366,7 +379,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"When connected to an excluded SSID Wi-Fi, the app running state will be automatically switched.",
|
||||
),
|
||||
"excludeType": MessageLookupByLibrary.simpleMessage("Тип исключения"),
|
||||
"existsTip": m5,
|
||||
"existsTip": m6,
|
||||
"exit": MessageLookupByLibrary.simpleMessage("Выход"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("Стандартный"),
|
||||
"expectedStatus": MessageLookupByLibrary.simpleMessage("Ожидаемый статус"),
|
||||
@@ -409,6 +422,18 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"fruitSaladScheme": MessageLookupByLibrary.simpleMessage("Фруктовый микс"),
|
||||
"general": MessageLookupByLibrary.simpleMessage("Общие"),
|
||||
"geoAutoUpdate": MessageLookupByLibrary.simpleMessage("Автообновление"),
|
||||
"geoAutoUpdateInterval": MessageLookupByLibrary.simpleMessage(
|
||||
"Интервал автообновления",
|
||||
),
|
||||
"geoAutoUpdateIntervalTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Интервал автообновления должен быть больше 0",
|
||||
),
|
||||
"geoOptions": MessageLookupByLibrary.simpleMessage("Настройки Geo"),
|
||||
"geoResources": MessageLookupByLibrary.simpleMessage("Ресурсы Geo"),
|
||||
"geoSkipped": m7,
|
||||
"geoUpdated": m8,
|
||||
"geoUpdating": m9,
|
||||
"geodataLoader": MessageLookupByLibrary.simpleMessage(
|
||||
"Режим низкого потребления памяти для геоданных",
|
||||
),
|
||||
@@ -437,7 +462,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"hotkeyManagementDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Использование клавиатуры для управления приложением",
|
||||
),
|
||||
"hoursAgo": m6,
|
||||
"hours": MessageLookupByLibrary.simpleMessage("часов"),
|
||||
"hoursAgo": m10,
|
||||
"hoursCount": m11,
|
||||
"icon": MessageLookupByLibrary.simpleMessage("Иконка"),
|
||||
"iconRecords": MessageLookupByLibrary.simpleMessage("История иконок"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("Стиль иконки"),
|
||||
@@ -483,10 +510,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"invalidBackupFile": MessageLookupByLibrary.simpleMessage(
|
||||
"Неверный файл резервной копии",
|
||||
),
|
||||
"invalidPolicy": m7,
|
||||
"invalidProxy": m8,
|
||||
"invalidProxyProvider": m9,
|
||||
"invalidSubRule": m10,
|
||||
"invalidPolicy": m12,
|
||||
"invalidProxy": m13,
|
||||
"invalidProxyProvider": m14,
|
||||
"invalidSubRule": m15,
|
||||
"ipcidr": MessageLookupByLibrary.simpleMessage("IPCIDR"),
|
||||
"ipv6Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"При включении будет возможно получать IPv6 трафик",
|
||||
@@ -520,7 +547,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"locationPermissionDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"According to system requirements, obtaining the Wi-Fi name requires you to grant location permission.",
|
||||
),
|
||||
"locationPermissionGuide": m11,
|
||||
"locationPermissionGuide": m16,
|
||||
"locationPermissionRequired": MessageLookupByLibrary.simpleMessage(
|
||||
"Location Permission Required",
|
||||
),
|
||||
@@ -558,11 +585,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"minimizeOnExitDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Изменить стандартное событие выхода из системы",
|
||||
),
|
||||
"minutesAgo": m12,
|
||||
"minutesAgo": m17,
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("Смешанный порт"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("Режим"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("Монохром"),
|
||||
"monthsAgo": m13,
|
||||
"monthsAgo": m18,
|
||||
"more": MessageLookupByLibrary.simpleMessage("Еще"),
|
||||
"name": MessageLookupByLibrary.simpleMessage("Имя"),
|
||||
"nameserver": MessageLookupByLibrary.simpleMessage("Сервер имен"),
|
||||
@@ -608,8 +635,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"nullProfileDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Нет профиля, пожалуйста, добавьте профиль",
|
||||
),
|
||||
"nullTip": m14,
|
||||
"numberTip": m15,
|
||||
"nullTip": m19,
|
||||
"numberTip": m20,
|
||||
"onDemand": MessageLookupByLibrary.simpleMessage("On Demand"),
|
||||
"onDemandDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Configure the program running state for specific scenarios",
|
||||
@@ -666,7 +693,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите другой порт",
|
||||
),
|
||||
"portTip": m16,
|
||||
"portTip": m21,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Приоритетное использование HTTP/3 для DOH",
|
||||
),
|
||||
@@ -935,6 +962,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"search": MessageLookupByLibrary.simpleMessage("Поиск"),
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("Секунд"),
|
||||
"secondsCount": m22,
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("Выбрать все"),
|
||||
"selectProxies": MessageLookupByLibrary.simpleMessage("Выбрать прокси"),
|
||||
"selectProxyProviders": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -950,7 +978,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Пожалуйста, выберите подправило",
|
||||
),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("Выбрано"),
|
||||
"selectedCountTitle": m17,
|
||||
"selectedCountTitle": m23,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Настройки"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("Показать"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("Сжать"),
|
||||
@@ -1064,11 +1092,12 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Получить профиль через URL",
|
||||
),
|
||||
"urlTip": m18,
|
||||
"urlTip": m24,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("Использовать hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage(
|
||||
"Использовать системные hosts",
|
||||
),
|
||||
"userAgent": MessageLookupByLibrary.simpleMessage("User-Agent"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("Значение"),
|
||||
"vibrantScheme": MessageLookupByLibrary.simpleMessage("Яркие"),
|
||||
"view": MessageLookupByLibrary.simpleMessage("Просмотр"),
|
||||
@@ -1087,7 +1116,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"whitelistMode": MessageLookupByLibrary.simpleMessage(
|
||||
"Режим белого списка",
|
||||
),
|
||||
"yearsAgo": m19,
|
||||
"yearsAgo": m25,
|
||||
"zh_CN": MessageLookupByLibrary.simpleMessage("Упрощенный китайский"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,36 +30,48 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m4(label) => "${label}不能为空";
|
||||
|
||||
static String m5(label) => "${label}当前已存在";
|
||||
static String m5(count) => "${count} 个条目";
|
||||
|
||||
static String m6(count) => "${count} 小时前";
|
||||
static String m6(label) => "${label}当前已存在";
|
||||
|
||||
static String m7(target) => "${target} 是一个无效的策略";
|
||||
static String m7(name) => "${name} 已跳过";
|
||||
|
||||
static String m8(proxyName) => "${proxyName} 是一个无效的代理";
|
||||
static String m8(name) => "${name} 已更新";
|
||||
|
||||
static String m9(providerName) => "${providerName} 是一个无效的代理集";
|
||||
static String m9(name) => "正在更新 ${name}...";
|
||||
|
||||
static String m10(subRule) => "${subRule} 是一个无效的SUB_RULE";
|
||||
static String m10(count) => "${count} 小时前";
|
||||
|
||||
static String m11(appName) =>
|
||||
static String m11(count) => "${count} 小时";
|
||||
|
||||
static String m12(target) => "${target} 是一个无效的策略";
|
||||
|
||||
static String m13(proxyName) => "${proxyName} 是一个无效的代理";
|
||||
|
||||
static String m14(providerName) => "${providerName} 是一个无效的代理集";
|
||||
|
||||
static String m15(subRule) => "${subRule} 是一个无效的SUB_RULE";
|
||||
|
||||
static String m16(appName) =>
|
||||
"1. 打开 系统设置 > 隐私与安全性\n2. 选择 定位服务\n3. 在右侧列表中找到并勾选 ${appName}\n\n完成设置后,返回应用即可正常使用。感谢您的配合。";
|
||||
|
||||
static String m12(count) => "${count} 分钟前";
|
||||
static String m17(count) => "${count} 分钟前";
|
||||
|
||||
static String m13(count) => "${count} 个月前";
|
||||
static String m18(count) => "${count} 个月前";
|
||||
|
||||
static String m14(label) => "暂无${label}";
|
||||
static String m19(label) => "暂无${label}";
|
||||
|
||||
static String m15(label) => "${label}必须为数字";
|
||||
static String m20(label) => "${label}必须为数字";
|
||||
|
||||
static String m16(label) => "${label} 必须在 1024 到 49151 之间";
|
||||
static String m21(label) => "${label} 必须在 1024 到 49151 之间";
|
||||
|
||||
static String m17(count) => "已选择 ${count} 项";
|
||||
static String m22(count) => "${count} 秒";
|
||||
|
||||
static String m18(label) => "${label}必须为URL";
|
||||
static String m23(count) => "已选择 ${count} 项";
|
||||
|
||||
static String m19(count) => "${count} 年前";
|
||||
static String m24(label) => "${label}必须为URL";
|
||||
|
||||
static String m25(count) => "${count} 年前";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -237,6 +249,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"emptyTip": m4,
|
||||
"en": MessageLookupByLibrary.simpleMessage("英语"),
|
||||
"entries": MessageLookupByLibrary.simpleMessage("个条目"),
|
||||
"entriesCount": m5,
|
||||
"exclude": MessageLookupByLibrary.simpleMessage("从最近任务中隐藏"),
|
||||
"excludeDesc": MessageLookupByLibrary.simpleMessage("应用在后台时,从最近任务中隐藏应用"),
|
||||
"excludeProxyFilter": MessageLookupByLibrary.simpleMessage("排除节点过滤器"),
|
||||
@@ -245,7 +258,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"连接到被排除SSID的WIFI时,将会自动切换应用运行状态",
|
||||
),
|
||||
"excludeType": MessageLookupByLibrary.simpleMessage("排除类型"),
|
||||
"existsTip": m5,
|
||||
"existsTip": m6,
|
||||
"exit": MessageLookupByLibrary.simpleMessage("退出"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("标准"),
|
||||
"expectedStatus": MessageLookupByLibrary.simpleMessage("预期状态"),
|
||||
@@ -274,6 +287,16 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"forceRestartCoreTip": MessageLookupByLibrary.simpleMessage("您确定要强制重启核心吗?"),
|
||||
"fruitSaladScheme": MessageLookupByLibrary.simpleMessage("果缤纷"),
|
||||
"general": MessageLookupByLibrary.simpleMessage("常规"),
|
||||
"geoAutoUpdate": MessageLookupByLibrary.simpleMessage("自动更新"),
|
||||
"geoAutoUpdateInterval": MessageLookupByLibrary.simpleMessage("自动更新间隔"),
|
||||
"geoAutoUpdateIntervalTip": MessageLookupByLibrary.simpleMessage(
|
||||
"自动更新间隔必须大于0",
|
||||
),
|
||||
"geoOptions": MessageLookupByLibrary.simpleMessage("Geo 选项"),
|
||||
"geoResources": MessageLookupByLibrary.simpleMessage("Geo 资源"),
|
||||
"geoSkipped": m7,
|
||||
"geoUpdated": m8,
|
||||
"geoUpdating": m9,
|
||||
"geodataLoader": MessageLookupByLibrary.simpleMessage("Geo低内存模式"),
|
||||
"geodataLoaderDesc": MessageLookupByLibrary.simpleMessage("开启将使用Geo低内存加载器"),
|
||||
"geoipCode": MessageLookupByLibrary.simpleMessage("Geoip代码"),
|
||||
@@ -288,7 +311,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"hotkeyConflict": MessageLookupByLibrary.simpleMessage("快捷键冲突"),
|
||||
"hotkeyManagement": MessageLookupByLibrary.simpleMessage("快捷键管理"),
|
||||
"hotkeyManagementDesc": MessageLookupByLibrary.simpleMessage("使用键盘控制应用程序"),
|
||||
"hoursAgo": m6,
|
||||
"hours": MessageLookupByLibrary.simpleMessage("小时"),
|
||||
"hoursAgo": m10,
|
||||
"hoursCount": m11,
|
||||
"icon": MessageLookupByLibrary.simpleMessage("图片"),
|
||||
"iconRecords": MessageLookupByLibrary.simpleMessage("图标记录"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("图标样式"),
|
||||
@@ -316,10 +341,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"interval": MessageLookupByLibrary.simpleMessage("间隔"),
|
||||
"intranetIP": MessageLookupByLibrary.simpleMessage("内网 IP"),
|
||||
"invalidBackupFile": MessageLookupByLibrary.simpleMessage("无效备份文件"),
|
||||
"invalidPolicy": m7,
|
||||
"invalidProxy": m8,
|
||||
"invalidProxyProvider": m9,
|
||||
"invalidSubRule": m10,
|
||||
"invalidPolicy": m12,
|
||||
"invalidProxy": m13,
|
||||
"invalidProxyProvider": m14,
|
||||
"invalidSubRule": m15,
|
||||
"ipcidr": MessageLookupByLibrary.simpleMessage("IP/掩码"),
|
||||
"ipv6Desc": MessageLookupByLibrary.simpleMessage("开启后将可以接收IPv6流量"),
|
||||
"ipv6InboundDesc": MessageLookupByLibrary.simpleMessage("允许IPv6入站"),
|
||||
@@ -343,7 +368,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"locationPermissionDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"根据系统要求,获取Wi-Fi名称需要您授予位置权限。",
|
||||
),
|
||||
"locationPermissionGuide": m11,
|
||||
"locationPermissionGuide": m16,
|
||||
"locationPermissionRequired": MessageLookupByLibrary.simpleMessage(
|
||||
"需要位置权限",
|
||||
),
|
||||
@@ -365,11 +390,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"min": MessageLookupByLibrary.simpleMessage("最小"),
|
||||
"minimizeOnExit": MessageLookupByLibrary.simpleMessage("退出时最小化"),
|
||||
"minimizeOnExitDesc": MessageLookupByLibrary.simpleMessage("修改系统默认退出事件"),
|
||||
"minutesAgo": m12,
|
||||
"minutesAgo": m17,
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("混合端口"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("模式"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("单色"),
|
||||
"monthsAgo": m13,
|
||||
"monthsAgo": m18,
|
||||
"more": MessageLookupByLibrary.simpleMessage("更多"),
|
||||
"name": MessageLookupByLibrary.simpleMessage("名称"),
|
||||
"nameserver": MessageLookupByLibrary.simpleMessage("域名服务器"),
|
||||
@@ -395,8 +420,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"none": MessageLookupByLibrary.simpleMessage("无"),
|
||||
"notSelectedTip": MessageLookupByLibrary.simpleMessage("当前代理组无法选中"),
|
||||
"nullProfileDesc": MessageLookupByLibrary.simpleMessage("没有配置文件,请先添加配置文件"),
|
||||
"nullTip": m14,
|
||||
"numberTip": m15,
|
||||
"nullTip": m19,
|
||||
"numberTip": m20,
|
||||
"onDemand": MessageLookupByLibrary.simpleMessage("按需运行"),
|
||||
"onDemandDesc": MessageLookupByLibrary.simpleMessage("配置程序特定场景运行状态"),
|
||||
"onlyIcon": MessageLookupByLibrary.simpleMessage("仅图标"),
|
||||
@@ -431,7 +456,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("端口"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage("请输入不同的端口"),
|
||||
"portTip": m16,
|
||||
"portTip": m21,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"),
|
||||
"prerequisites": MessageLookupByLibrary.simpleMessage("前置条件"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("请按下按键"),
|
||||
@@ -614,6 +639,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"search": MessageLookupByLibrary.simpleMessage("搜索"),
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("秒"),
|
||||
"secondsCount": m22,
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("全选"),
|
||||
"selectProxies": MessageLookupByLibrary.simpleMessage("选择代理"),
|
||||
"selectProxyProviders": MessageLookupByLibrary.simpleMessage("选择代理集"),
|
||||
@@ -621,7 +647,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"selectSplitStrategy": MessageLookupByLibrary.simpleMessage("请选择分流策略"),
|
||||
"selectSubRule": MessageLookupByLibrary.simpleMessage("请选择子规则"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("已选择"),
|
||||
"selectedCountTitle": m17,
|
||||
"selectedCountTitle": m23,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("设置"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("显示"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("紧凑"),
|
||||
@@ -697,9 +723,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upload": MessageLookupByLibrary.simpleMessage("上传"),
|
||||
"url": MessageLookupByLibrary.simpleMessage("URL"),
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage("通过URL获取配置文件"),
|
||||
"urlTip": m18,
|
||||
"urlTip": m24,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("使用Hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("使用系统Hosts"),
|
||||
"userAgent": MessageLookupByLibrary.simpleMessage("用户代理"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("值"),
|
||||
"vibrantScheme": MessageLookupByLibrary.simpleMessage("活力"),
|
||||
"view": MessageLookupByLibrary.simpleMessage("查看"),
|
||||
@@ -712,7 +739,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"vpnTip": MessageLookupByLibrary.simpleMessage("重启VPN后改变生效"),
|
||||
"webDAVConfiguration": MessageLookupByLibrary.simpleMessage("WebDAV配置"),
|
||||
"whitelistMode": MessageLookupByLibrary.simpleMessage("白名单模式"),
|
||||
"yearsAgo": m19,
|
||||
"yearsAgo": m25,
|
||||
"zh_CN": MessageLookupByLibrary.simpleMessage("中文简体"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1039,6 +1039,11 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
/// `User-Agent`
|
||||
String get userAgent {
|
||||
return Intl.message('User-Agent', name: 'userAgent', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Unified delay`
|
||||
String get unifiedDelay {
|
||||
return Intl.message(
|
||||
@@ -4378,6 +4383,116 @@ class AppLocalizations {
|
||||
String get suspended {
|
||||
return Intl.message('Suspended...', name: 'suspended', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Geo Options`
|
||||
String get geoOptions {
|
||||
return Intl.message('Geo Options', name: 'geoOptions', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Auto Update`
|
||||
String get geoAutoUpdate {
|
||||
return Intl.message(
|
||||
'Auto Update',
|
||||
name: 'geoAutoUpdate',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Auto Update Interval`
|
||||
String get geoAutoUpdateInterval {
|
||||
return Intl.message(
|
||||
'Auto Update Interval',
|
||||
name: 'geoAutoUpdateInterval',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Auto update interval must be greater than 0`
|
||||
String get geoAutoUpdateIntervalTip {
|
||||
return Intl.message(
|
||||
'Auto update interval must be greater than 0',
|
||||
name: 'geoAutoUpdateIntervalTip',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `hours`
|
||||
String get hours {
|
||||
return Intl.message('hours', name: 'hours', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `{count} hours`
|
||||
String hoursCount(Object count) {
|
||||
return Intl.message(
|
||||
'$count hours',
|
||||
name: 'hoursCount',
|
||||
desc: '',
|
||||
args: [count],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Geo Resources`
|
||||
String get geoResources {
|
||||
return Intl.message(
|
||||
'Geo Resources',
|
||||
name: 'geoResources',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Updating {name}...`
|
||||
String geoUpdating(Object name) {
|
||||
return Intl.message(
|
||||
'Updating $name...',
|
||||
name: 'geoUpdating',
|
||||
desc: '',
|
||||
args: [name],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{name} skipped`
|
||||
String geoSkipped(Object name) {
|
||||
return Intl.message(
|
||||
'$name skipped',
|
||||
name: 'geoSkipped',
|
||||
desc: '',
|
||||
args: [name],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{name} updated`
|
||||
String geoUpdated(Object name) {
|
||||
return Intl.message(
|
||||
'$name updated',
|
||||
name: 'geoUpdated',
|
||||
desc: '',
|
||||
args: [name],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{count} seconds`
|
||||
String secondsCount(Object count) {
|
||||
return Intl.message(
|
||||
'$count seconds',
|
||||
name: 'secondsCount',
|
||||
desc: '',
|
||||
args: [count],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{count} entries`
|
||||
String entriesCount(Object count) {
|
||||
return Intl.message(
|
||||
'$count entries',
|
||||
name: 'entriesCount',
|
||||
desc: '',
|
||||
args: [count],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
|
||||
@@ -11,8 +11,8 @@ import 'application.dart';
|
||||
import 'common/common.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
try {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
if (system.isDesktop) {
|
||||
await RustLib.init();
|
||||
}
|
||||
@@ -26,7 +26,7 @@ Future<void> main() async {
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
return runApp(
|
||||
runApp(
|
||||
MaterialApp(
|
||||
home: InitErrorScreen(error: e, stack: s),
|
||||
),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/core/core.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
@@ -72,7 +74,7 @@ class _CoreContainerState extends ConsumerState<CoreManager>
|
||||
|
||||
@override
|
||||
void onLog(Log log) {
|
||||
// ref.read(logsProvider.notifier).add(log);
|
||||
ref.read(logsProvider.notifier).add(log);
|
||||
if (log.logLevel == LogLevel.error) {
|
||||
globalState.showNotifier(log.payload);
|
||||
}
|
||||
@@ -109,4 +111,23 @@ class _CoreContainerState extends ConsumerState<CoreManager>
|
||||
await coreController.shutdown(false);
|
||||
super.onCrash(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void onGeoUpdate(String geoType, bool updating, bool skipped, String? error) {
|
||||
final geoResource = GeoResource.fromJson(geoType.toLowerCase());
|
||||
final key = geoResource.updatingKey;
|
||||
final l10n = currentAppLocalizations;
|
||||
if (updating) {
|
||||
globalState.showNotifier(l10n.geoUpdating(geoResource.name));
|
||||
} else if (skipped) {
|
||||
globalState.showNotifier(l10n.geoSkipped(geoResource.name));
|
||||
} else {
|
||||
globalState.showNotifier(l10n.geoUpdated(geoResource.name));
|
||||
}
|
||||
ref.read(isUpdatingProvider(key).notifier).value = updating;
|
||||
if (!updating && error != null && error.isNotEmpty) {
|
||||
globalState.showNotifier(error);
|
||||
}
|
||||
super.onGeoUpdate(geoType, updating, skipped, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class _HotKeyManagerState extends ConsumerState<HotKeyManager> {
|
||||
await Future.wait(hotkeyActionHandles);
|
||||
}
|
||||
|
||||
Shortcuts _buildShortcuts(Widget child) {
|
||||
Shortcuts _buildCloseShortcuts(Widget child) {
|
||||
return Shortcuts(
|
||||
shortcuts: {
|
||||
utils.controlSingleActivator(LogicalKeyboardKey.keyW):
|
||||
@@ -84,7 +84,7 @@ class _HotKeyManagerState extends ConsumerState<HotKeyManager> {
|
||||
CloseWindowIntent: CallbackAction<CloseWindowIntent>(
|
||||
onInvoke: (_) => globalState.container
|
||||
.read(systemActionProvider.notifier)
|
||||
.handleBackOrExit(),
|
||||
.handleClose(false),
|
||||
),
|
||||
DoNothingIntent: CallbackAction<DoNothingIntent>(
|
||||
onInvoke: (_) => null,
|
||||
@@ -97,6 +97,6 @@ class _HotKeyManagerState extends ConsumerState<HotKeyManager> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _buildShortcuts(widget.child);
|
||||
return _buildCloseShortcuts(widget.child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'dart:math';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/common/theme.dart';
|
||||
import 'package:fl_clash/providers/action.dart';
|
||||
import 'package:fl_clash/providers/app.dart';
|
||||
import 'package:fl_clash/providers/config.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -21,41 +20,25 @@ class ThemeManager extends ConsumerWidget {
|
||||
if (!system.isAndroid) {
|
||||
return child;
|
||||
}
|
||||
return AnnotatedRegion<SystemUiMode>(
|
||||
sized: false,
|
||||
value: SystemUiMode.edgeToEdge,
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final brightness = ref.watch(currentBrightnessProvider);
|
||||
final iconBrightness = brightness == Brightness.light
|
||||
? Brightness.dark
|
||||
: Brightness.light;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref
|
||||
.read(systemUiOverlayStyleStateProvider.notifier)
|
||||
.update(
|
||||
(state) => state.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarColor: context.colorScheme.surface,
|
||||
systemNavigationBarDividerColor: Colors.transparent,
|
||||
),
|
||||
);
|
||||
});
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarColor: context.colorScheme.surface,
|
||||
systemNavigationBarDividerColor: Colors.transparent,
|
||||
),
|
||||
sized: false,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
return Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final brightness = ref.watch(currentBrightnessProvider);
|
||||
final iconBrightness = brightness == Brightness.light
|
||||
? Brightness.dark
|
||||
: Brightness.light;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarIconBrightness: iconBrightness,
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarDividerColor: Colors.transparent,
|
||||
systemNavigationBarContrastEnforced: false,
|
||||
),
|
||||
sized: false,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class _WindowContainerState extends ConsumerState<WindowManager>
|
||||
|
||||
@override
|
||||
void onWindowClose() async {
|
||||
await ref.read(systemActionProvider.notifier).handleBackOrExit();
|
||||
await ref.read(systemActionProvider.notifier).handleClose();
|
||||
super.onWindowClose();
|
||||
}
|
||||
|
||||
@@ -178,7 +178,10 @@ class _WindowHeaderState extends State<WindowHeader> {
|
||||
windowExtManager.setWindowCornerPreference(round: false);
|
||||
}
|
||||
}
|
||||
isMaximizedNotifier.value = await windowManager.isMaximized();
|
||||
final res = await windowManager.isMaximized();
|
||||
if (mounted) {
|
||||
isMaximizedNotifier.value = res;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updatePin() async {
|
||||
@@ -226,7 +229,7 @@ class _WindowHeaderState extends State<WindowHeader> {
|
||||
onPressed: () {
|
||||
globalState.container
|
||||
.read(systemActionProvider.notifier)
|
||||
.handleBackOrExit();
|
||||
.handleClose();
|
||||
},
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
|
||||
@@ -3,13 +3,23 @@ import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'generated/clash_config.freezed.dart';
|
||||
|
||||
part 'generated/clash_config.g.dart';
|
||||
|
||||
const defaultClashConfig = PatchClashConfig();
|
||||
|
||||
const defaultTun = Tun();
|
||||
const defaultDns = Dns();
|
||||
const defaultGeoXUrl = GeoXUrl();
|
||||
const defaultGeoXUrl = {
|
||||
GeoResource.MMDB:
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb',
|
||||
GeoResource.ASN:
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb',
|
||||
GeoResource.GEOIP:
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat',
|
||||
GeoResource.GEOSITE:
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
|
||||
};
|
||||
|
||||
const defaultMixedPort = 7890;
|
||||
const defaultKeepAliveInterval = 30;
|
||||
@@ -309,42 +319,6 @@ abstract class Dns with _$Dns {
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class GeoXUrl with _$GeoXUrl {
|
||||
const factory GeoXUrl({
|
||||
@Default(
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb',
|
||||
)
|
||||
String mmdb,
|
||||
@Default(
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb',
|
||||
)
|
||||
String asn,
|
||||
@Default(
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat',
|
||||
)
|
||||
String geoip,
|
||||
@Default(
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
|
||||
)
|
||||
String geosite,
|
||||
}) = _GeoXUrl;
|
||||
|
||||
factory GeoXUrl.fromJson(Map<String, Object?> json) =>
|
||||
_$GeoXUrlFromJson(json);
|
||||
|
||||
factory GeoXUrl.safeFormJson(Map<String, Object?>? json) {
|
||||
if (json == null) {
|
||||
return defaultGeoXUrl;
|
||||
}
|
||||
try {
|
||||
return GeoXUrl.fromJson(json);
|
||||
} catch (_) {
|
||||
return defaultGeoXUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class Rule with _$Rule {
|
||||
const factory Rule({
|
||||
@@ -542,6 +516,24 @@ abstract class ClashConfig with _$ClashConfig {
|
||||
_$ClashConfigFromJson(json);
|
||||
}
|
||||
|
||||
extension GeoResourceUrlMapExt on Map<GeoResource, String> {
|
||||
Map<String, String> get raw =>
|
||||
map((key, value) => MapEntry(key.value, value));
|
||||
}
|
||||
|
||||
Map<GeoResource, String> _geoXUrlFromJson(Map<String, Object?>? json) {
|
||||
if (json == null) {
|
||||
return defaultGeoXUrl;
|
||||
}
|
||||
return json.map(
|
||||
(key, value) => MapEntry(GeoResource.fromJson(key), value as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, String> _geoXUrlToJson(Map<GeoResource, String> value) {
|
||||
return value.raw;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class PatchClashConfig with _$PatchClashConfig {
|
||||
const factory PatchClashConfig({
|
||||
@@ -568,8 +560,12 @@ abstract class PatchClashConfig with _$PatchClashConfig {
|
||||
@Default(defaultTun) @JsonKey(fromJson: Tun.safeFormJson) Tun tun,
|
||||
@Default(defaultDns) @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,
|
||||
@Default(defaultGeoXUrl)
|
||||
@JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson)
|
||||
GeoXUrl geoXUrl,
|
||||
@JsonKey(
|
||||
name: 'geox-url',
|
||||
fromJson: _geoXUrlFromJson,
|
||||
toJson: _geoXUrlToJson,
|
||||
)
|
||||
Map<GeoResource, String> geoXUrl,
|
||||
@Default(GeodataLoader.memconservative)
|
||||
@JsonKey(name: 'geodata-loader')
|
||||
GeodataLoader geodataLoader,
|
||||
@@ -578,6 +574,8 @@ abstract class PatchClashConfig with _$PatchClashConfig {
|
||||
@JsonKey(name: 'external-controller')
|
||||
ExternalControllerStatus externalController,
|
||||
@Default({}) Map<String, String> hosts,
|
||||
@Default(false) @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,
|
||||
@Default(24) @JsonKey(name: 'geo-update-interval') int geoUpdateInterval,
|
||||
}) = _PatchClashConfig;
|
||||
|
||||
factory PatchClashConfig.fromJson(Map<String, Object?> json) =>
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'clash_config.dart';
|
||||
|
||||
part 'generated/common.freezed.dart';
|
||||
|
||||
part 'generated/common.g.dart';
|
||||
|
||||
@freezed
|
||||
@@ -271,7 +272,7 @@ extension TrafficExt on Traffic {
|
||||
}
|
||||
|
||||
String get trayTitle {
|
||||
return '${up.shortTraffic.show}/s \n ${down.shortTraffic.show}/s';
|
||||
return '${up.shortTraffic.show}/s\n${down.shortTraffic.show}/s';
|
||||
}
|
||||
|
||||
num get speed => up + down;
|
||||
|
||||
@@ -84,6 +84,7 @@ abstract class AppSettingProps with _$AppSettingProps {
|
||||
@Default(false) bool developerMode,
|
||||
@Default(RestoreStrategy.compatible) RestoreStrategy restoreStrategy,
|
||||
@Default(true) bool showTrayTitle,
|
||||
@Default('') String customUserAgent,
|
||||
}) = _AppSettingProps;
|
||||
|
||||
factory AppSettingProps.fromJson(Map<String, Object?> json) =>
|
||||
|
||||
@@ -31,6 +31,8 @@ abstract class UpdateParams with _$UpdateParams {
|
||||
@JsonKey(name: 'external-controller')
|
||||
required ExternalControllerStatus externalController,
|
||||
@JsonKey(name: 'unified-delay') required bool unifiedDelay,
|
||||
@Default(false) @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,
|
||||
@Default(24) @JsonKey(name: 'geo-update-interval') int geoUpdateInterval,
|
||||
}) = _UpdateParams;
|
||||
|
||||
factory UpdateParams.fromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -3000,278 +3000,6 @@ $FallbackFilterCopyWith<$Res> get fallbackFilter {
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$GeoXUrl {
|
||||
|
||||
String get mmdb; String get asn; String get geoip; String get geosite;
|
||||
/// Create a copy of GeoXUrl
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$GeoXUrlCopyWith<GeoXUrl> get copyWith => _$GeoXUrlCopyWithImpl<GeoXUrl>(this as GeoXUrl, _$identity);
|
||||
|
||||
/// Serializes this GeoXUrl to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is GeoXUrl&&(identical(other.mmdb, mmdb) || other.mmdb == mmdb)&&(identical(other.asn, asn) || other.asn == asn)&&(identical(other.geoip, geoip) || other.geoip == geoip)&&(identical(other.geosite, geosite) || other.geosite == geosite));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mmdb,asn,geoip,geosite);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GeoXUrl(mmdb: $mmdb, asn: $asn, geoip: $geoip, geosite: $geosite)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $GeoXUrlCopyWith<$Res> {
|
||||
factory $GeoXUrlCopyWith(GeoXUrl value, $Res Function(GeoXUrl) _then) = _$GeoXUrlCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String mmdb, String asn, String geoip, String geosite
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$GeoXUrlCopyWithImpl<$Res>
|
||||
implements $GeoXUrlCopyWith<$Res> {
|
||||
_$GeoXUrlCopyWithImpl(this._self, this._then);
|
||||
|
||||
final GeoXUrl _self;
|
||||
final $Res Function(GeoXUrl) _then;
|
||||
|
||||
/// Create a copy of GeoXUrl
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? mmdb = null,Object? asn = null,Object? geoip = null,Object? geosite = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
mmdb: null == mmdb ? _self.mmdb : mmdb // ignore: cast_nullable_to_non_nullable
|
||||
as String,asn: null == asn ? _self.asn : asn // ignore: cast_nullable_to_non_nullable
|
||||
as String,geoip: null == geoip ? _self.geoip : geoip // ignore: cast_nullable_to_non_nullable
|
||||
as String,geosite: null == geosite ? _self.geosite : geosite // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [GeoXUrl].
|
||||
extension GeoXUrlPatterns on GeoXUrl {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _GeoXUrl value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _GeoXUrl value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _GeoXUrl value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String mmdb, String asn, String geoip, String geosite)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl() when $default != null:
|
||||
return $default(_that.mmdb,_that.asn,_that.geoip,_that.geosite);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String mmdb, String asn, String geoip, String geosite) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl():
|
||||
return $default(_that.mmdb,_that.asn,_that.geoip,_that.geosite);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String mmdb, String asn, String geoip, String geosite)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _GeoXUrl() when $default != null:
|
||||
return $default(_that.mmdb,_that.asn,_that.geoip,_that.geosite);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _GeoXUrl implements GeoXUrl {
|
||||
const _GeoXUrl({this.mmdb = 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb', this.asn = 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb', this.geoip = 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat', this.geosite = 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat'});
|
||||
factory _GeoXUrl.fromJson(Map<String, dynamic> json) => _$GeoXUrlFromJson(json);
|
||||
|
||||
@override@JsonKey() final String mmdb;
|
||||
@override@JsonKey() final String asn;
|
||||
@override@JsonKey() final String geoip;
|
||||
@override@JsonKey() final String geosite;
|
||||
|
||||
/// Create a copy of GeoXUrl
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$GeoXUrlCopyWith<_GeoXUrl> get copyWith => __$GeoXUrlCopyWithImpl<_GeoXUrl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$GeoXUrlToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GeoXUrl&&(identical(other.mmdb, mmdb) || other.mmdb == mmdb)&&(identical(other.asn, asn) || other.asn == asn)&&(identical(other.geoip, geoip) || other.geoip == geoip)&&(identical(other.geosite, geosite) || other.geosite == geosite));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mmdb,asn,geoip,geosite);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GeoXUrl(mmdb: $mmdb, asn: $asn, geoip: $geoip, geosite: $geosite)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$GeoXUrlCopyWith<$Res> implements $GeoXUrlCopyWith<$Res> {
|
||||
factory _$GeoXUrlCopyWith(_GeoXUrl value, $Res Function(_GeoXUrl) _then) = __$GeoXUrlCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String mmdb, String asn, String geoip, String geosite
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$GeoXUrlCopyWithImpl<$Res>
|
||||
implements _$GeoXUrlCopyWith<$Res> {
|
||||
__$GeoXUrlCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _GeoXUrl _self;
|
||||
final $Res Function(_GeoXUrl) _then;
|
||||
|
||||
/// Create a copy of GeoXUrl
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? mmdb = null,Object? asn = null,Object? geoip = null,Object? geosite = null,}) {
|
||||
return _then(_GeoXUrl(
|
||||
mmdb: null == mmdb ? _self.mmdb : mmdb // ignore: cast_nullable_to_non_nullable
|
||||
as String,asn: null == asn ? _self.asn : asn // ignore: cast_nullable_to_non_nullable
|
||||
as String,geoip: null == geoip ? _self.geoip : geoip // ignore: cast_nullable_to_non_nullable
|
||||
as String,geosite: null == geosite ? _self.geosite : geosite // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Rule {
|
||||
|
||||
@@ -3885,7 +3613,7 @@ as Map<String, String>,
|
||||
/// @nodoc
|
||||
mixin _$PatchClashConfig {
|
||||
|
||||
@JsonKey(name: 'mixed-port') int get mixedPort;@JsonKey(name: 'socks-port') int get socksPort;@JsonKey(name: 'port') int get port;@JsonKey(name: 'redir-port') int get redirPort;@JsonKey(name: 'tproxy-port') int get tproxyPort; Mode get mode;@JsonKey(name: 'allow-lan') bool get allowLan;@JsonKey(name: 'log-level') LogLevel get logLevel; bool get ipv6;@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode get findProcessMode;@JsonKey(name: 'keep-alive-interval') int get keepAliveInterval;@JsonKey(name: 'unified-delay') bool get unifiedDelay;@JsonKey(name: 'tcp-concurrent') bool get tcpConcurrent;@JsonKey(fromJson: Tun.safeFormJson) Tun get tun;@JsonKey(fromJson: Dns.safeDnsFromJson) Dns get dns;@JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl get geoXUrl;@JsonKey(name: 'geodata-loader') GeodataLoader get geodataLoader;@JsonKey(name: 'global-ua') String? get globalUa;@JsonKey(name: 'external-controller') ExternalControllerStatus get externalController; Map<String, String> get hosts;
|
||||
@JsonKey(name: 'mixed-port') int get mixedPort;@JsonKey(name: 'socks-port') int get socksPort;@JsonKey(name: 'port') int get port;@JsonKey(name: 'redir-port') int get redirPort;@JsonKey(name: 'tproxy-port') int get tproxyPort; Mode get mode;@JsonKey(name: 'allow-lan') bool get allowLan;@JsonKey(name: 'log-level') LogLevel get logLevel; bool get ipv6;@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode get findProcessMode;@JsonKey(name: 'keep-alive-interval') int get keepAliveInterval;@JsonKey(name: 'unified-delay') bool get unifiedDelay;@JsonKey(name: 'tcp-concurrent') bool get tcpConcurrent;@JsonKey(fromJson: Tun.safeFormJson) Tun get tun;@JsonKey(fromJson: Dns.safeDnsFromJson) Dns get dns;@JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> get geoXUrl;@JsonKey(name: 'geodata-loader') GeodataLoader get geodataLoader;@JsonKey(name: 'global-ua') String? get globalUa;@JsonKey(name: 'external-controller') ExternalControllerStatus get externalController; Map<String, String> get hosts;@JsonKey(name: 'geo-auto-update') bool get geoAutoUpdate;@JsonKey(name: 'geo-update-interval') int get geoUpdateInterval;
|
||||
/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -3898,16 +3626,16 @@ $PatchClashConfigCopyWith<PatchClashConfig> get copyWith => _$PatchClashConfigCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PatchClashConfig&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.socksPort, socksPort) || other.socksPort == socksPort)&&(identical(other.port, port) || other.port == port)&&(identical(other.redirPort, redirPort) || other.redirPort == redirPort)&&(identical(other.tproxyPort, tproxyPort) || other.tproxyPort == tproxyPort)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.keepAliveInterval, keepAliveInterval) || other.keepAliveInterval == keepAliveInterval)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.dns, dns) || other.dns == dns)&&(identical(other.geoXUrl, geoXUrl) || other.geoXUrl == geoXUrl)&&(identical(other.geodataLoader, geodataLoader) || other.geodataLoader == geodataLoader)&&(identical(other.globalUa, globalUa) || other.globalUa == globalUa)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&const DeepCollectionEquality().equals(other.hosts, hosts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PatchClashConfig&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.socksPort, socksPort) || other.socksPort == socksPort)&&(identical(other.port, port) || other.port == port)&&(identical(other.redirPort, redirPort) || other.redirPort == redirPort)&&(identical(other.tproxyPort, tproxyPort) || other.tproxyPort == tproxyPort)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.keepAliveInterval, keepAliveInterval) || other.keepAliveInterval == keepAliveInterval)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.dns, dns) || other.dns == dns)&&const DeepCollectionEquality().equals(other.geoXUrl, geoXUrl)&&(identical(other.geodataLoader, geodataLoader) || other.geodataLoader == geodataLoader)&&(identical(other.globalUa, globalUa) || other.globalUa == globalUa)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&const DeepCollectionEquality().equals(other.hosts, hosts)&&(identical(other.geoAutoUpdate, geoAutoUpdate) || other.geoAutoUpdate == geoAutoUpdate)&&(identical(other.geoUpdateInterval, geoUpdateInterval) || other.geoUpdateInterval == geoUpdateInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,mixedPort,socksPort,port,redirPort,tproxyPort,mode,allowLan,logLevel,ipv6,findProcessMode,keepAliveInterval,unifiedDelay,tcpConcurrent,tun,dns,geoXUrl,geodataLoader,globalUa,externalController,const DeepCollectionEquality().hash(hosts)]);
|
||||
int get hashCode => Object.hashAll([runtimeType,mixedPort,socksPort,port,redirPort,tproxyPort,mode,allowLan,logLevel,ipv6,findProcessMode,keepAliveInterval,unifiedDelay,tcpConcurrent,tun,dns,const DeepCollectionEquality().hash(geoXUrl),geodataLoader,globalUa,externalController,const DeepCollectionEquality().hash(hosts),geoAutoUpdate,geoUpdateInterval]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PatchClashConfig(mixedPort: $mixedPort, socksPort: $socksPort, port: $port, redirPort: $redirPort, tproxyPort: $tproxyPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, globalUa: $globalUa, externalController: $externalController, hosts: $hosts)';
|
||||
return 'PatchClashConfig(mixedPort: $mixedPort, socksPort: $socksPort, port: $port, redirPort: $redirPort, tproxyPort: $tproxyPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, globalUa: $globalUa, externalController: $externalController, hosts: $hosts, geoAutoUpdate: $geoAutoUpdate, geoUpdateInterval: $geoUpdateInterval)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3918,11 +3646,11 @@ abstract mixin class $PatchClashConfigCopyWith<$Res> {
|
||||
factory $PatchClashConfigCopyWith(PatchClashConfig value, $Res Function(PatchClashConfig) _then) = _$PatchClashConfigCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'socks-port') int socksPort,@JsonKey(name: 'port') int port,@JsonKey(name: 'redir-port') int redirPort,@JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode,@JsonKey(name: 'keep-alive-interval') int keepAliveInterval,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(fromJson: Tun.safeFormJson) Tun tun,@JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,@JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl geoXUrl,@JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader,@JsonKey(name: 'global-ua') String? globalUa,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts
|
||||
@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'socks-port') int socksPort,@JsonKey(name: 'port') int port,@JsonKey(name: 'redir-port') int redirPort,@JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode,@JsonKey(name: 'keep-alive-interval') int keepAliveInterval,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(fromJson: Tun.safeFormJson) Tun tun,@JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,@JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> geoXUrl,@JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader,@JsonKey(name: 'global-ua') String? globalUa,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts,@JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,@JsonKey(name: 'geo-update-interval') int geoUpdateInterval
|
||||
});
|
||||
|
||||
|
||||
$TunCopyWith<$Res> get tun;$DnsCopyWith<$Res> get dns;$GeoXUrlCopyWith<$Res> get geoXUrl;
|
||||
$TunCopyWith<$Res> get tun;$DnsCopyWith<$Res> get dns;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -3935,7 +3663,7 @@ class _$PatchClashConfigCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? mixedPort = null,Object? socksPort = null,Object? port = null,Object? redirPort = null,Object? tproxyPort = null,Object? mode = null,Object? allowLan = null,Object? logLevel = null,Object? ipv6 = null,Object? findProcessMode = null,Object? keepAliveInterval = null,Object? unifiedDelay = null,Object? tcpConcurrent = null,Object? tun = null,Object? dns = null,Object? geoXUrl = null,Object? geodataLoader = null,Object? globalUa = freezed,Object? externalController = null,Object? hosts = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? mixedPort = null,Object? socksPort = null,Object? port = null,Object? redirPort = null,Object? tproxyPort = null,Object? mode = null,Object? allowLan = null,Object? logLevel = null,Object? ipv6 = null,Object? findProcessMode = null,Object? keepAliveInterval = null,Object? unifiedDelay = null,Object? tcpConcurrent = null,Object? tun = null,Object? dns = null,Object? geoXUrl = null,Object? geodataLoader = null,Object? globalUa = freezed,Object? externalController = null,Object? hosts = null,Object? geoAutoUpdate = null,Object? geoUpdateInterval = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
mixedPort: null == mixedPort ? _self.mixedPort : mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,socksPort: null == socksPort ? _self.socksPort : socksPort // ignore: cast_nullable_to_non_nullable
|
||||
@@ -3953,11 +3681,13 @@ as bool,tcpConcurrent: null == tcpConcurrent ? _self.tcpConcurrent : tcpConcurre
|
||||
as bool,tun: null == tun ? _self.tun : tun // ignore: cast_nullable_to_non_nullable
|
||||
as Tun,dns: null == dns ? _self.dns : dns // ignore: cast_nullable_to_non_nullable
|
||||
as Dns,geoXUrl: null == geoXUrl ? _self.geoXUrl : geoXUrl // ignore: cast_nullable_to_non_nullable
|
||||
as GeoXUrl,geodataLoader: null == geodataLoader ? _self.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable
|
||||
as Map<GeoResource, String>,geodataLoader: null == geodataLoader ? _self.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable
|
||||
as GeodataLoader,globalUa: freezed == globalUa ? _self.globalUa : globalUa // ignore: cast_nullable_to_non_nullable
|
||||
as String?,externalController: null == externalController ? _self.externalController : externalController // ignore: cast_nullable_to_non_nullable
|
||||
as ExternalControllerStatus,hosts: null == hosts ? _self.hosts : hosts // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, String>,
|
||||
as Map<String, String>,geoAutoUpdate: null == geoAutoUpdate ? _self.geoAutoUpdate : geoAutoUpdate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,geoUpdateInterval: null == geoUpdateInterval ? _self.geoUpdateInterval : geoUpdateInterval // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
/// Create a copy of PatchClashConfig
|
||||
@@ -3978,15 +3708,6 @@ $DnsCopyWith<$Res> get dns {
|
||||
return $DnsCopyWith<$Res>(_self.dns, (value) {
|
||||
return _then(_self.copyWith(dns: value));
|
||||
});
|
||||
}/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$GeoXUrlCopyWith<$Res> get geoXUrl {
|
||||
|
||||
return $GeoXUrlCopyWith<$Res>(_self.geoXUrl, (value) {
|
||||
return _then(_self.copyWith(geoXUrl: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4069,10 +3790,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PatchClashConfig() when $default != null:
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts);case _:
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -4090,10 +3811,10 @@ return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PatchClashConfig():
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts);case _:
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -4110,10 +3831,10 @@ return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'socks-port') int socksPort, @JsonKey(name: 'port') int port, @JsonKey(name: 'redir-port') int redirPort, @JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode, @JsonKey(name: 'keep-alive-interval') int keepAliveInterval, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(fromJson: Tun.safeFormJson) Tun tun, @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, @JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> geoXUrl, @JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader, @JsonKey(name: 'global-ua') String? globalUa, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PatchClashConfig() when $default != null:
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts);case _:
|
||||
return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that.tproxyPort,_that.mode,_that.allowLan,_that.logLevel,_that.ipv6,_that.findProcessMode,_that.keepAliveInterval,_that.unifiedDelay,_that.tcpConcurrent,_that.tun,_that.dns,_that.geoXUrl,_that.geodataLoader,_that.globalUa,_that.externalController,_that.hosts,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -4125,7 +3846,7 @@ return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that
|
||||
@JsonSerializable()
|
||||
|
||||
class _PatchClashConfig implements PatchClashConfig {
|
||||
const _PatchClashConfig({@JsonKey(name: 'mixed-port') this.mixedPort = defaultMixedPort, @JsonKey(name: 'socks-port') this.socksPort = 0, @JsonKey(name: 'port') this.port = 0, @JsonKey(name: 'redir-port') this.redirPort = 0, @JsonKey(name: 'tproxy-port') this.tproxyPort = 0, this.mode = Mode.rule, @JsonKey(name: 'allow-lan') this.allowLan = false, @JsonKey(name: 'log-level') this.logLevel = LogLevel.error, this.ipv6 = false, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) this.findProcessMode = FindProcessMode.always, @JsonKey(name: 'keep-alive-interval') this.keepAliveInterval = defaultKeepAliveInterval, @JsonKey(name: 'unified-delay') this.unifiedDelay = true, @JsonKey(name: 'tcp-concurrent') this.tcpConcurrent = true, @JsonKey(fromJson: Tun.safeFormJson) this.tun = defaultTun, @JsonKey(fromJson: Dns.safeDnsFromJson) this.dns = defaultDns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) this.geoXUrl = defaultGeoXUrl, @JsonKey(name: 'geodata-loader') this.geodataLoader = GeodataLoader.memconservative, @JsonKey(name: 'global-ua') this.globalUa, @JsonKey(name: 'external-controller') this.externalController = ExternalControllerStatus.close, final Map<String, String> hosts = const {}}): _hosts = hosts;
|
||||
const _PatchClashConfig({@JsonKey(name: 'mixed-port') this.mixedPort = defaultMixedPort, @JsonKey(name: 'socks-port') this.socksPort = 0, @JsonKey(name: 'port') this.port = 0, @JsonKey(name: 'redir-port') this.redirPort = 0, @JsonKey(name: 'tproxy-port') this.tproxyPort = 0, this.mode = Mode.rule, @JsonKey(name: 'allow-lan') this.allowLan = false, @JsonKey(name: 'log-level') this.logLevel = LogLevel.error, this.ipv6 = false, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) this.findProcessMode = FindProcessMode.always, @JsonKey(name: 'keep-alive-interval') this.keepAliveInterval = defaultKeepAliveInterval, @JsonKey(name: 'unified-delay') this.unifiedDelay = true, @JsonKey(name: 'tcp-concurrent') this.tcpConcurrent = true, @JsonKey(fromJson: Tun.safeFormJson) this.tun = defaultTun, @JsonKey(fromJson: Dns.safeDnsFromJson) this.dns = defaultDns, @JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) final Map<GeoResource, String> geoXUrl = defaultGeoXUrl, @JsonKey(name: 'geodata-loader') this.geodataLoader = GeodataLoader.memconservative, @JsonKey(name: 'global-ua') this.globalUa, @JsonKey(name: 'external-controller') this.externalController = ExternalControllerStatus.close, final Map<String, String> hosts = const {}, @JsonKey(name: 'geo-auto-update') this.geoAutoUpdate = false, @JsonKey(name: 'geo-update-interval') this.geoUpdateInterval = 24}): _geoXUrl = geoXUrl,_hosts = hosts;
|
||||
factory _PatchClashConfig.fromJson(Map<String, dynamic> json) => _$PatchClashConfigFromJson(json);
|
||||
|
||||
@override@JsonKey(name: 'mixed-port') final int mixedPort;
|
||||
@@ -4143,7 +3864,13 @@ class _PatchClashConfig implements PatchClashConfig {
|
||||
@override@JsonKey(name: 'tcp-concurrent') final bool tcpConcurrent;
|
||||
@override@JsonKey(fromJson: Tun.safeFormJson) final Tun tun;
|
||||
@override@JsonKey(fromJson: Dns.safeDnsFromJson) final Dns dns;
|
||||
@override@JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) final GeoXUrl geoXUrl;
|
||||
final Map<GeoResource, String> _geoXUrl;
|
||||
@override@JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> get geoXUrl {
|
||||
if (_geoXUrl is EqualUnmodifiableMapView) return _geoXUrl;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_geoXUrl);
|
||||
}
|
||||
|
||||
@override@JsonKey(name: 'geodata-loader') final GeodataLoader geodataLoader;
|
||||
@override@JsonKey(name: 'global-ua') final String? globalUa;
|
||||
@override@JsonKey(name: 'external-controller') final ExternalControllerStatus externalController;
|
||||
@@ -4154,6 +3881,8 @@ class _PatchClashConfig implements PatchClashConfig {
|
||||
return EqualUnmodifiableMapView(_hosts);
|
||||
}
|
||||
|
||||
@override@JsonKey(name: 'geo-auto-update') final bool geoAutoUpdate;
|
||||
@override@JsonKey(name: 'geo-update-interval') final int geoUpdateInterval;
|
||||
|
||||
/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -4168,16 +3897,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PatchClashConfig&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.socksPort, socksPort) || other.socksPort == socksPort)&&(identical(other.port, port) || other.port == port)&&(identical(other.redirPort, redirPort) || other.redirPort == redirPort)&&(identical(other.tproxyPort, tproxyPort) || other.tproxyPort == tproxyPort)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.keepAliveInterval, keepAliveInterval) || other.keepAliveInterval == keepAliveInterval)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.dns, dns) || other.dns == dns)&&(identical(other.geoXUrl, geoXUrl) || other.geoXUrl == geoXUrl)&&(identical(other.geodataLoader, geodataLoader) || other.geodataLoader == geodataLoader)&&(identical(other.globalUa, globalUa) || other.globalUa == globalUa)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&const DeepCollectionEquality().equals(other._hosts, _hosts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PatchClashConfig&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.socksPort, socksPort) || other.socksPort == socksPort)&&(identical(other.port, port) || other.port == port)&&(identical(other.redirPort, redirPort) || other.redirPort == redirPort)&&(identical(other.tproxyPort, tproxyPort) || other.tproxyPort == tproxyPort)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.keepAliveInterval, keepAliveInterval) || other.keepAliveInterval == keepAliveInterval)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.dns, dns) || other.dns == dns)&&const DeepCollectionEquality().equals(other._geoXUrl, _geoXUrl)&&(identical(other.geodataLoader, geodataLoader) || other.geodataLoader == geodataLoader)&&(identical(other.globalUa, globalUa) || other.globalUa == globalUa)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&const DeepCollectionEquality().equals(other._hosts, _hosts)&&(identical(other.geoAutoUpdate, geoAutoUpdate) || other.geoAutoUpdate == geoAutoUpdate)&&(identical(other.geoUpdateInterval, geoUpdateInterval) || other.geoUpdateInterval == geoUpdateInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,mixedPort,socksPort,port,redirPort,tproxyPort,mode,allowLan,logLevel,ipv6,findProcessMode,keepAliveInterval,unifiedDelay,tcpConcurrent,tun,dns,geoXUrl,geodataLoader,globalUa,externalController,const DeepCollectionEquality().hash(_hosts)]);
|
||||
int get hashCode => Object.hashAll([runtimeType,mixedPort,socksPort,port,redirPort,tproxyPort,mode,allowLan,logLevel,ipv6,findProcessMode,keepAliveInterval,unifiedDelay,tcpConcurrent,tun,dns,const DeepCollectionEquality().hash(_geoXUrl),geodataLoader,globalUa,externalController,const DeepCollectionEquality().hash(_hosts),geoAutoUpdate,geoUpdateInterval]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PatchClashConfig(mixedPort: $mixedPort, socksPort: $socksPort, port: $port, redirPort: $redirPort, tproxyPort: $tproxyPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, globalUa: $globalUa, externalController: $externalController, hosts: $hosts)';
|
||||
return 'PatchClashConfig(mixedPort: $mixedPort, socksPort: $socksPort, port: $port, redirPort: $redirPort, tproxyPort: $tproxyPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, globalUa: $globalUa, externalController: $externalController, hosts: $hosts, geoAutoUpdate: $geoAutoUpdate, geoUpdateInterval: $geoUpdateInterval)';
|
||||
}
|
||||
|
||||
|
||||
@@ -4188,11 +3917,11 @@ abstract mixin class _$PatchClashConfigCopyWith<$Res> implements $PatchClashConf
|
||||
factory _$PatchClashConfigCopyWith(_PatchClashConfig value, $Res Function(_PatchClashConfig) _then) = __$PatchClashConfigCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'socks-port') int socksPort,@JsonKey(name: 'port') int port,@JsonKey(name: 'redir-port') int redirPort,@JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode,@JsonKey(name: 'keep-alive-interval') int keepAliveInterval,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(fromJson: Tun.safeFormJson) Tun tun,@JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,@JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) GeoXUrl geoXUrl,@JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader,@JsonKey(name: 'global-ua') String? globalUa,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts
|
||||
@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'socks-port') int socksPort,@JsonKey(name: 'port') int port,@JsonKey(name: 'redir-port') int redirPort,@JsonKey(name: 'tproxy-port') int tproxyPort, Mode mode,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) FindProcessMode findProcessMode,@JsonKey(name: 'keep-alive-interval') int keepAliveInterval,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(fromJson: Tun.safeFormJson) Tun tun,@JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,@JsonKey(name: 'geox-url', fromJson: _geoXUrlFromJson, toJson: _geoXUrlToJson) Map<GeoResource, String> geoXUrl,@JsonKey(name: 'geodata-loader') GeodataLoader geodataLoader,@JsonKey(name: 'global-ua') String? globalUa,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController, Map<String, String> hosts,@JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,@JsonKey(name: 'geo-update-interval') int geoUpdateInterval
|
||||
});
|
||||
|
||||
|
||||
@override $TunCopyWith<$Res> get tun;@override $DnsCopyWith<$Res> get dns;@override $GeoXUrlCopyWith<$Res> get geoXUrl;
|
||||
@override $TunCopyWith<$Res> get tun;@override $DnsCopyWith<$Res> get dns;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -4205,7 +3934,7 @@ class __$PatchClashConfigCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? mixedPort = null,Object? socksPort = null,Object? port = null,Object? redirPort = null,Object? tproxyPort = null,Object? mode = null,Object? allowLan = null,Object? logLevel = null,Object? ipv6 = null,Object? findProcessMode = null,Object? keepAliveInterval = null,Object? unifiedDelay = null,Object? tcpConcurrent = null,Object? tun = null,Object? dns = null,Object? geoXUrl = null,Object? geodataLoader = null,Object? globalUa = freezed,Object? externalController = null,Object? hosts = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? mixedPort = null,Object? socksPort = null,Object? port = null,Object? redirPort = null,Object? tproxyPort = null,Object? mode = null,Object? allowLan = null,Object? logLevel = null,Object? ipv6 = null,Object? findProcessMode = null,Object? keepAliveInterval = null,Object? unifiedDelay = null,Object? tcpConcurrent = null,Object? tun = null,Object? dns = null,Object? geoXUrl = null,Object? geodataLoader = null,Object? globalUa = freezed,Object? externalController = null,Object? hosts = null,Object? geoAutoUpdate = null,Object? geoUpdateInterval = null,}) {
|
||||
return _then(_PatchClashConfig(
|
||||
mixedPort: null == mixedPort ? _self.mixedPort : mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,socksPort: null == socksPort ? _self.socksPort : socksPort // ignore: cast_nullable_to_non_nullable
|
||||
@@ -4222,12 +3951,14 @@ as int,unifiedDelay: null == unifiedDelay ? _self.unifiedDelay : unifiedDelay //
|
||||
as bool,tcpConcurrent: null == tcpConcurrent ? _self.tcpConcurrent : tcpConcurrent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,tun: null == tun ? _self.tun : tun // ignore: cast_nullable_to_non_nullable
|
||||
as Tun,dns: null == dns ? _self.dns : dns // ignore: cast_nullable_to_non_nullable
|
||||
as Dns,geoXUrl: null == geoXUrl ? _self.geoXUrl : geoXUrl // ignore: cast_nullable_to_non_nullable
|
||||
as GeoXUrl,geodataLoader: null == geodataLoader ? _self.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable
|
||||
as Dns,geoXUrl: null == geoXUrl ? _self._geoXUrl : geoXUrl // ignore: cast_nullable_to_non_nullable
|
||||
as Map<GeoResource, String>,geodataLoader: null == geodataLoader ? _self.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable
|
||||
as GeodataLoader,globalUa: freezed == globalUa ? _self.globalUa : globalUa // ignore: cast_nullable_to_non_nullable
|
||||
as String?,externalController: null == externalController ? _self.externalController : externalController // ignore: cast_nullable_to_non_nullable
|
||||
as ExternalControllerStatus,hosts: null == hosts ? _self._hosts : hosts // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, String>,
|
||||
as Map<String, String>,geoAutoUpdate: null == geoAutoUpdate ? _self.geoAutoUpdate : geoAutoUpdate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,geoUpdateInterval: null == geoUpdateInterval ? _self.geoUpdateInterval : geoUpdateInterval // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -4249,15 +3980,6 @@ $DnsCopyWith<$Res> get dns {
|
||||
return $DnsCopyWith<$Res>(_self.dns, (value) {
|
||||
return _then(_self.copyWith(dns: value));
|
||||
});
|
||||
}/// Create a copy of PatchClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$GeoXUrlCopyWith<$Res> get geoXUrl {
|
||||
|
||||
return $GeoXUrlCopyWith<$Res>(_self.geoXUrl, (value) {
|
||||
return _then(_self.copyWith(geoXUrl: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,28 +295,6 @@ const _$DnsModeEnumMap = {
|
||||
DnsMode.hosts: 'hosts',
|
||||
};
|
||||
|
||||
_GeoXUrl _$GeoXUrlFromJson(Map<String, dynamic> json) => _GeoXUrl(
|
||||
mmdb:
|
||||
json['mmdb'] as String? ??
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb',
|
||||
asn:
|
||||
json['asn'] as String? ??
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb',
|
||||
geoip:
|
||||
json['geoip'] as String? ??
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat',
|
||||
geosite:
|
||||
json['geosite'] as String? ??
|
||||
'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GeoXUrlToJson(_GeoXUrl instance) => <String, dynamic>{
|
||||
'mmdb': instance.mmdb,
|
||||
'asn': instance.asn,
|
||||
'geoip': instance.geoip,
|
||||
'geosite': instance.geosite,
|
||||
};
|
||||
|
||||
_Rule _$RuleFromJson(Map<String, dynamic> json) => _Rule(
|
||||
id: (json['id'] as num?)?.toInt() ?? -1,
|
||||
ruleAction:
|
||||
@@ -451,7 +429,7 @@ _PatchClashConfig _$PatchClashConfigFromJson(Map<String, dynamic> json) =>
|
||||
: Dns.safeDnsFromJson(json['dns'] as Map<String, Object?>),
|
||||
geoXUrl: json['geox-url'] == null
|
||||
? defaultGeoXUrl
|
||||
: GeoXUrl.safeFormJson(json['geox-url'] as Map<String, Object?>?),
|
||||
: _geoXUrlFromJson(json['geox-url'] as Map<String, Object?>?),
|
||||
geodataLoader:
|
||||
$enumDecodeNullable(_$GeodataLoaderEnumMap, json['geodata-loader']) ??
|
||||
GeodataLoader.memconservative,
|
||||
@@ -467,6 +445,8 @@ _PatchClashConfig _$PatchClashConfigFromJson(Map<String, dynamic> json) =>
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
) ??
|
||||
const {},
|
||||
geoAutoUpdate: json['geo-auto-update'] as bool? ?? false,
|
||||
geoUpdateInterval: (json['geo-update-interval'] as num?)?.toInt() ?? 24,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PatchClashConfigToJson(_PatchClashConfig instance) =>
|
||||
@@ -486,12 +466,14 @@ Map<String, dynamic> _$PatchClashConfigToJson(_PatchClashConfig instance) =>
|
||||
'tcp-concurrent': instance.tcpConcurrent,
|
||||
'tun': instance.tun,
|
||||
'dns': instance.dns,
|
||||
'geox-url': instance.geoXUrl,
|
||||
'geox-url': _geoXUrlToJson(instance.geoXUrl),
|
||||
'geodata-loader': _$GeodataLoaderEnumMap[instance.geodataLoader]!,
|
||||
'global-ua': instance.globalUa,
|
||||
'external-controller':
|
||||
_$ExternalControllerStatusEnumMap[instance.externalController]!,
|
||||
'hosts': instance.hosts,
|
||||
'geo-auto-update': instance.geoAutoUpdate,
|
||||
'geo-update-interval': instance.geoUpdateInterval,
|
||||
};
|
||||
|
||||
const _$ModeEnumMap = {
|
||||
|
||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$AppSettingProps {
|
||||
|
||||
String? get locale;@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> get dashboardWidgets; bool get onlyStatisticsProxy; bool get autoLaunch; bool get silentLaunch; bool get autoRun; bool get openLogs; bool get closeConnections; String get testUrl; bool get isAnimateToPage; bool get autoCheckUpdate; bool get showLabel; bool get disclaimerAccepted; bool get crashlyticsTip; bool get crashlytics; bool get minimizeOnExit; bool get hidden; bool get developerMode; RestoreStrategy get restoreStrategy; bool get showTrayTitle;
|
||||
String? get locale;@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> get dashboardWidgets; bool get onlyStatisticsProxy; bool get autoLaunch; bool get silentLaunch; bool get autoRun; bool get openLogs; bool get closeConnections; String get testUrl; bool get isAnimateToPage; bool get autoCheckUpdate; bool get showLabel; bool get disclaimerAccepted; bool get crashlyticsTip; bool get crashlytics; bool get minimizeOnExit; bool get hidden; bool get developerMode; RestoreStrategy get restoreStrategy; bool get showTrayTitle; String get customUserAgent;
|
||||
/// Create a copy of AppSettingProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $AppSettingPropsCopyWith<AppSettingProps> get copyWith => _$AppSettingPropsCopyW
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettingProps&&(identical(other.locale, locale) || other.locale == locale)&&const DeepCollectionEquality().equals(other.dashboardWidgets, dashboardWidgets)&&(identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || other.onlyStatisticsProxy == onlyStatisticsProxy)&&(identical(other.autoLaunch, autoLaunch) || other.autoLaunch == autoLaunch)&&(identical(other.silentLaunch, silentLaunch) || other.silentLaunch == silentLaunch)&&(identical(other.autoRun, autoRun) || other.autoRun == autoRun)&&(identical(other.openLogs, openLogs) || other.openLogs == openLogs)&&(identical(other.closeConnections, closeConnections) || other.closeConnections == closeConnections)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl)&&(identical(other.isAnimateToPage, isAnimateToPage) || other.isAnimateToPage == isAnimateToPage)&&(identical(other.autoCheckUpdate, autoCheckUpdate) || other.autoCheckUpdate == autoCheckUpdate)&&(identical(other.showLabel, showLabel) || other.showLabel == showLabel)&&(identical(other.disclaimerAccepted, disclaimerAccepted) || other.disclaimerAccepted == disclaimerAccepted)&&(identical(other.crashlyticsTip, crashlyticsTip) || other.crashlyticsTip == crashlyticsTip)&&(identical(other.crashlytics, crashlytics) || other.crashlytics == crashlytics)&&(identical(other.minimizeOnExit, minimizeOnExit) || other.minimizeOnExit == minimizeOnExit)&&(identical(other.hidden, hidden) || other.hidden == hidden)&&(identical(other.developerMode, developerMode) || other.developerMode == developerMode)&&(identical(other.restoreStrategy, restoreStrategy) || other.restoreStrategy == restoreStrategy)&&(identical(other.showTrayTitle, showTrayTitle) || other.showTrayTitle == showTrayTitle));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettingProps&&(identical(other.locale, locale) || other.locale == locale)&&const DeepCollectionEquality().equals(other.dashboardWidgets, dashboardWidgets)&&(identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || other.onlyStatisticsProxy == onlyStatisticsProxy)&&(identical(other.autoLaunch, autoLaunch) || other.autoLaunch == autoLaunch)&&(identical(other.silentLaunch, silentLaunch) || other.silentLaunch == silentLaunch)&&(identical(other.autoRun, autoRun) || other.autoRun == autoRun)&&(identical(other.openLogs, openLogs) || other.openLogs == openLogs)&&(identical(other.closeConnections, closeConnections) || other.closeConnections == closeConnections)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl)&&(identical(other.isAnimateToPage, isAnimateToPage) || other.isAnimateToPage == isAnimateToPage)&&(identical(other.autoCheckUpdate, autoCheckUpdate) || other.autoCheckUpdate == autoCheckUpdate)&&(identical(other.showLabel, showLabel) || other.showLabel == showLabel)&&(identical(other.disclaimerAccepted, disclaimerAccepted) || other.disclaimerAccepted == disclaimerAccepted)&&(identical(other.crashlyticsTip, crashlyticsTip) || other.crashlyticsTip == crashlyticsTip)&&(identical(other.crashlytics, crashlytics) || other.crashlytics == crashlytics)&&(identical(other.minimizeOnExit, minimizeOnExit) || other.minimizeOnExit == minimizeOnExit)&&(identical(other.hidden, hidden) || other.hidden == hidden)&&(identical(other.developerMode, developerMode) || other.developerMode == developerMode)&&(identical(other.restoreStrategy, restoreStrategy) || other.restoreStrategy == restoreStrategy)&&(identical(other.showTrayTitle, showTrayTitle) || other.showTrayTitle == showTrayTitle)&&(identical(other.customUserAgent, customUserAgent) || other.customUserAgent == customUserAgent));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,locale,const DeepCollectionEquality().hash(dashboardWidgets),onlyStatisticsProxy,autoLaunch,silentLaunch,autoRun,openLogs,closeConnections,testUrl,isAnimateToPage,autoCheckUpdate,showLabel,disclaimerAccepted,crashlyticsTip,crashlytics,minimizeOnExit,hidden,developerMode,restoreStrategy,showTrayTitle]);
|
||||
int get hashCode => Object.hashAll([runtimeType,locale,const DeepCollectionEquality().hash(dashboardWidgets),onlyStatisticsProxy,autoLaunch,silentLaunch,autoRun,openLogs,closeConnections,testUrl,isAnimateToPage,autoCheckUpdate,showLabel,disclaimerAccepted,crashlyticsTip,crashlytics,minimizeOnExit,hidden,developerMode,restoreStrategy,showTrayTitle,customUserAgent]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettingProps(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, crashlyticsTip: $crashlyticsTip, crashlytics: $crashlytics, minimizeOnExit: $minimizeOnExit, hidden: $hidden, developerMode: $developerMode, restoreStrategy: $restoreStrategy, showTrayTitle: $showTrayTitle)';
|
||||
return 'AppSettingProps(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, crashlyticsTip: $crashlyticsTip, crashlytics: $crashlytics, minimizeOnExit: $minimizeOnExit, hidden: $hidden, developerMode: $developerMode, restoreStrategy: $restoreStrategy, showTrayTitle: $showTrayTitle, customUserAgent: $customUserAgent)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ abstract mixin class $AppSettingPropsCopyWith<$Res> {
|
||||
factory $AppSettingPropsCopyWith(AppSettingProps value, $Res Function(AppSettingProps) _then) = _$AppSettingPropsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String? locale,@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle
|
||||
String? locale,@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle, String customUserAgent
|
||||
});
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class _$AppSettingPropsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettingProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? locale = freezed,Object? dashboardWidgets = null,Object? onlyStatisticsProxy = null,Object? autoLaunch = null,Object? silentLaunch = null,Object? autoRun = null,Object? openLogs = null,Object? closeConnections = null,Object? testUrl = null,Object? isAnimateToPage = null,Object? autoCheckUpdate = null,Object? showLabel = null,Object? disclaimerAccepted = null,Object? crashlyticsTip = null,Object? crashlytics = null,Object? minimizeOnExit = null,Object? hidden = null,Object? developerMode = null,Object? restoreStrategy = null,Object? showTrayTitle = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? locale = freezed,Object? dashboardWidgets = null,Object? onlyStatisticsProxy = null,Object? autoLaunch = null,Object? silentLaunch = null,Object? autoRun = null,Object? openLogs = null,Object? closeConnections = null,Object? testUrl = null,Object? isAnimateToPage = null,Object? autoCheckUpdate = null,Object? showLabel = null,Object? disclaimerAccepted = null,Object? crashlyticsTip = null,Object? crashlytics = null,Object? minimizeOnExit = null,Object? hidden = null,Object? developerMode = null,Object? restoreStrategy = null,Object? showTrayTitle = null,Object? customUserAgent = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
locale: freezed == locale ? _self.locale : locale // ignore: cast_nullable_to_non_nullable
|
||||
as String?,dashboardWidgets: null == dashboardWidgets ? _self.dashboardWidgets : dashboardWidgets // ignore: cast_nullable_to_non_nullable
|
||||
@@ -87,7 +87,8 @@ as bool,hidden: null == hidden ? _self.hidden : hidden // ignore: cast_nullable_
|
||||
as bool,developerMode: null == developerMode ? _self.developerMode : developerMode // ignore: cast_nullable_to_non_nullable
|
||||
as bool,restoreStrategy: null == restoreStrategy ? _self.restoreStrategy : restoreStrategy // ignore: cast_nullable_to_non_nullable
|
||||
as RestoreStrategy,showTrayTitle: null == showTrayTitle ? _self.showTrayTitle : showTrayTitle // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,customUserAgent: null == customUserAgent ? _self.customUserAgent : customUserAgent // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -172,10 +173,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle, String customUserAgent)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettingProps() when $default != null:
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle);case _:
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle,_that.customUserAgent);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -193,10 +194,10 @@ return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_t
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle, String customUserAgent) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettingProps():
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle);case _:
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle,_that.customUserAgent);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -213,10 +214,10 @@ return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_t
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle, String customUserAgent)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettingProps() when $default != null:
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle);case _:
|
||||
return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_that.autoLaunch,_that.silentLaunch,_that.autoRun,_that.openLogs,_that.closeConnections,_that.testUrl,_that.isAnimateToPage,_that.autoCheckUpdate,_that.showLabel,_that.disclaimerAccepted,_that.crashlyticsTip,_that.crashlytics,_that.minimizeOnExit,_that.hidden,_that.developerMode,_that.restoreStrategy,_that.showTrayTitle,_that.customUserAgent);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -228,7 +229,7 @@ return $default(_that.locale,_that.dashboardWidgets,_that.onlyStatisticsProxy,_t
|
||||
@JsonSerializable()
|
||||
|
||||
class _AppSettingProps implements AppSettingProps {
|
||||
const _AppSettingProps({this.locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) final List<DashboardWidget> dashboardWidgets = defaultDashboardWidgets, this.onlyStatisticsProxy = false, this.autoLaunch = false, this.silentLaunch = false, this.autoRun = false, this.openLogs = false, this.closeConnections = true, this.testUrl = defaultTestUrl, this.isAnimateToPage = true, this.autoCheckUpdate = true, this.showLabel = false, this.disclaimerAccepted = false, this.crashlyticsTip = false, this.crashlytics = false, this.minimizeOnExit = true, this.hidden = false, this.developerMode = false, this.restoreStrategy = RestoreStrategy.compatible, this.showTrayTitle = true}): _dashboardWidgets = dashboardWidgets;
|
||||
const _AppSettingProps({this.locale, @JsonKey(fromJson: dashboardWidgetsSafeFormJson) final List<DashboardWidget> dashboardWidgets = defaultDashboardWidgets, this.onlyStatisticsProxy = false, this.autoLaunch = false, this.silentLaunch = false, this.autoRun = false, this.openLogs = false, this.closeConnections = true, this.testUrl = defaultTestUrl, this.isAnimateToPage = true, this.autoCheckUpdate = true, this.showLabel = false, this.disclaimerAccepted = false, this.crashlyticsTip = false, this.crashlytics = false, this.minimizeOnExit = true, this.hidden = false, this.developerMode = false, this.restoreStrategy = RestoreStrategy.compatible, this.showTrayTitle = true, this.customUserAgent = ''}): _dashboardWidgets = dashboardWidgets;
|
||||
factory _AppSettingProps.fromJson(Map<String, dynamic> json) => _$AppSettingPropsFromJson(json);
|
||||
|
||||
@override final String? locale;
|
||||
@@ -257,6 +258,7 @@ class _AppSettingProps implements AppSettingProps {
|
||||
@override@JsonKey() final bool developerMode;
|
||||
@override@JsonKey() final RestoreStrategy restoreStrategy;
|
||||
@override@JsonKey() final bool showTrayTitle;
|
||||
@override@JsonKey() final String customUserAgent;
|
||||
|
||||
/// Create a copy of AppSettingProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -271,16 +273,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettingProps&&(identical(other.locale, locale) || other.locale == locale)&&const DeepCollectionEquality().equals(other._dashboardWidgets, _dashboardWidgets)&&(identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || other.onlyStatisticsProxy == onlyStatisticsProxy)&&(identical(other.autoLaunch, autoLaunch) || other.autoLaunch == autoLaunch)&&(identical(other.silentLaunch, silentLaunch) || other.silentLaunch == silentLaunch)&&(identical(other.autoRun, autoRun) || other.autoRun == autoRun)&&(identical(other.openLogs, openLogs) || other.openLogs == openLogs)&&(identical(other.closeConnections, closeConnections) || other.closeConnections == closeConnections)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl)&&(identical(other.isAnimateToPage, isAnimateToPage) || other.isAnimateToPage == isAnimateToPage)&&(identical(other.autoCheckUpdate, autoCheckUpdate) || other.autoCheckUpdate == autoCheckUpdate)&&(identical(other.showLabel, showLabel) || other.showLabel == showLabel)&&(identical(other.disclaimerAccepted, disclaimerAccepted) || other.disclaimerAccepted == disclaimerAccepted)&&(identical(other.crashlyticsTip, crashlyticsTip) || other.crashlyticsTip == crashlyticsTip)&&(identical(other.crashlytics, crashlytics) || other.crashlytics == crashlytics)&&(identical(other.minimizeOnExit, minimizeOnExit) || other.minimizeOnExit == minimizeOnExit)&&(identical(other.hidden, hidden) || other.hidden == hidden)&&(identical(other.developerMode, developerMode) || other.developerMode == developerMode)&&(identical(other.restoreStrategy, restoreStrategy) || other.restoreStrategy == restoreStrategy)&&(identical(other.showTrayTitle, showTrayTitle) || other.showTrayTitle == showTrayTitle));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettingProps&&(identical(other.locale, locale) || other.locale == locale)&&const DeepCollectionEquality().equals(other._dashboardWidgets, _dashboardWidgets)&&(identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || other.onlyStatisticsProxy == onlyStatisticsProxy)&&(identical(other.autoLaunch, autoLaunch) || other.autoLaunch == autoLaunch)&&(identical(other.silentLaunch, silentLaunch) || other.silentLaunch == silentLaunch)&&(identical(other.autoRun, autoRun) || other.autoRun == autoRun)&&(identical(other.openLogs, openLogs) || other.openLogs == openLogs)&&(identical(other.closeConnections, closeConnections) || other.closeConnections == closeConnections)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl)&&(identical(other.isAnimateToPage, isAnimateToPage) || other.isAnimateToPage == isAnimateToPage)&&(identical(other.autoCheckUpdate, autoCheckUpdate) || other.autoCheckUpdate == autoCheckUpdate)&&(identical(other.showLabel, showLabel) || other.showLabel == showLabel)&&(identical(other.disclaimerAccepted, disclaimerAccepted) || other.disclaimerAccepted == disclaimerAccepted)&&(identical(other.crashlyticsTip, crashlyticsTip) || other.crashlyticsTip == crashlyticsTip)&&(identical(other.crashlytics, crashlytics) || other.crashlytics == crashlytics)&&(identical(other.minimizeOnExit, minimizeOnExit) || other.minimizeOnExit == minimizeOnExit)&&(identical(other.hidden, hidden) || other.hidden == hidden)&&(identical(other.developerMode, developerMode) || other.developerMode == developerMode)&&(identical(other.restoreStrategy, restoreStrategy) || other.restoreStrategy == restoreStrategy)&&(identical(other.showTrayTitle, showTrayTitle) || other.showTrayTitle == showTrayTitle)&&(identical(other.customUserAgent, customUserAgent) || other.customUserAgent == customUserAgent));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,locale,const DeepCollectionEquality().hash(_dashboardWidgets),onlyStatisticsProxy,autoLaunch,silentLaunch,autoRun,openLogs,closeConnections,testUrl,isAnimateToPage,autoCheckUpdate,showLabel,disclaimerAccepted,crashlyticsTip,crashlytics,minimizeOnExit,hidden,developerMode,restoreStrategy,showTrayTitle]);
|
||||
int get hashCode => Object.hashAll([runtimeType,locale,const DeepCollectionEquality().hash(_dashboardWidgets),onlyStatisticsProxy,autoLaunch,silentLaunch,autoRun,openLogs,closeConnections,testUrl,isAnimateToPage,autoCheckUpdate,showLabel,disclaimerAccepted,crashlyticsTip,crashlytics,minimizeOnExit,hidden,developerMode,restoreStrategy,showTrayTitle,customUserAgent]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettingProps(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, crashlyticsTip: $crashlyticsTip, crashlytics: $crashlytics, minimizeOnExit: $minimizeOnExit, hidden: $hidden, developerMode: $developerMode, restoreStrategy: $restoreStrategy, showTrayTitle: $showTrayTitle)';
|
||||
return 'AppSettingProps(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, crashlyticsTip: $crashlyticsTip, crashlytics: $crashlytics, minimizeOnExit: $minimizeOnExit, hidden: $hidden, developerMode: $developerMode, restoreStrategy: $restoreStrategy, showTrayTitle: $showTrayTitle, customUserAgent: $customUserAgent)';
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +293,7 @@ abstract mixin class _$AppSettingPropsCopyWith<$Res> implements $AppSettingProps
|
||||
factory _$AppSettingPropsCopyWith(_AppSettingProps value, $Res Function(_AppSettingProps) _then) = __$AppSettingPropsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String? locale,@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle
|
||||
String? locale,@JsonKey(fromJson: dashboardWidgetsSafeFormJson) List<DashboardWidget> dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, bool silentLaunch, bool autoRun, bool openLogs, bool closeConnections, String testUrl, bool isAnimateToPage, bool autoCheckUpdate, bool showLabel, bool disclaimerAccepted, bool crashlyticsTip, bool crashlytics, bool minimizeOnExit, bool hidden, bool developerMode, RestoreStrategy restoreStrategy, bool showTrayTitle, String customUserAgent
|
||||
});
|
||||
|
||||
|
||||
@@ -308,7 +310,7 @@ class __$AppSettingPropsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettingProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? locale = freezed,Object? dashboardWidgets = null,Object? onlyStatisticsProxy = null,Object? autoLaunch = null,Object? silentLaunch = null,Object? autoRun = null,Object? openLogs = null,Object? closeConnections = null,Object? testUrl = null,Object? isAnimateToPage = null,Object? autoCheckUpdate = null,Object? showLabel = null,Object? disclaimerAccepted = null,Object? crashlyticsTip = null,Object? crashlytics = null,Object? minimizeOnExit = null,Object? hidden = null,Object? developerMode = null,Object? restoreStrategy = null,Object? showTrayTitle = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? locale = freezed,Object? dashboardWidgets = null,Object? onlyStatisticsProxy = null,Object? autoLaunch = null,Object? silentLaunch = null,Object? autoRun = null,Object? openLogs = null,Object? closeConnections = null,Object? testUrl = null,Object? isAnimateToPage = null,Object? autoCheckUpdate = null,Object? showLabel = null,Object? disclaimerAccepted = null,Object? crashlyticsTip = null,Object? crashlytics = null,Object? minimizeOnExit = null,Object? hidden = null,Object? developerMode = null,Object? restoreStrategy = null,Object? showTrayTitle = null,Object? customUserAgent = null,}) {
|
||||
return _then(_AppSettingProps(
|
||||
locale: freezed == locale ? _self.locale : locale // ignore: cast_nullable_to_non_nullable
|
||||
as String?,dashboardWidgets: null == dashboardWidgets ? _self._dashboardWidgets : dashboardWidgets // ignore: cast_nullable_to_non_nullable
|
||||
@@ -330,7 +332,8 @@ as bool,hidden: null == hidden ? _self.hidden : hidden // ignore: cast_nullable_
|
||||
as bool,developerMode: null == developerMode ? _self.developerMode : developerMode // ignore: cast_nullable_to_non_nullable
|
||||
as bool,restoreStrategy: null == restoreStrategy ? _self.restoreStrategy : restoreStrategy // ignore: cast_nullable_to_non_nullable
|
||||
as RestoreStrategy,showTrayTitle: null == showTrayTitle ? _self.showTrayTitle : showTrayTitle // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,customUserAgent: null == customUserAgent ? _self.customUserAgent : customUserAgent // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ _AppSettingProps _$AppSettingPropsFromJson(Map<String, dynamic> json) =>
|
||||
) ??
|
||||
RestoreStrategy.compatible,
|
||||
showTrayTitle: json['showTrayTitle'] as bool? ?? true,
|
||||
customUserAgent: json['customUserAgent'] as String? ?? '',
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AppSettingPropsToJson(_AppSettingProps instance) =>
|
||||
@@ -61,6 +62,7 @@ Map<String, dynamic> _$AppSettingPropsToJson(_AppSettingProps instance) =>
|
||||
'developerMode': instance.developerMode,
|
||||
'restoreStrategy': _$RestoreStrategyEnumMap[instance.restoreStrategy]!,
|
||||
'showTrayTitle': instance.showTrayTitle,
|
||||
'customUserAgent': instance.customUserAgent,
|
||||
};
|
||||
|
||||
const _$RestoreStrategyEnumMap = {
|
||||
|
||||
@@ -287,7 +287,7 @@ as String,
|
||||
/// @nodoc
|
||||
mixin _$UpdateParams {
|
||||
|
||||
Tun get tun;@JsonKey(name: 'mixed-port') int get mixedPort;@JsonKey(name: 'allow-lan') bool get allowLan;@JsonKey(name: 'find-process-mode') FindProcessMode get findProcessMode; Mode get mode;@JsonKey(name: 'log-level') LogLevel get logLevel; bool get ipv6;@JsonKey(name: 'tcp-concurrent') bool get tcpConcurrent;@JsonKey(name: 'external-controller') ExternalControllerStatus get externalController;@JsonKey(name: 'unified-delay') bool get unifiedDelay;
|
||||
Tun get tun;@JsonKey(name: 'mixed-port') int get mixedPort;@JsonKey(name: 'allow-lan') bool get allowLan;@JsonKey(name: 'find-process-mode') FindProcessMode get findProcessMode; Mode get mode;@JsonKey(name: 'log-level') LogLevel get logLevel; bool get ipv6;@JsonKey(name: 'tcp-concurrent') bool get tcpConcurrent;@JsonKey(name: 'external-controller') ExternalControllerStatus get externalController;@JsonKey(name: 'unified-delay') bool get unifiedDelay;@JsonKey(name: 'geo-auto-update') bool get geoAutoUpdate;@JsonKey(name: 'geo-update-interval') int get geoUpdateInterval;
|
||||
/// Create a copy of UpdateParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -300,16 +300,16 @@ $UpdateParamsCopyWith<UpdateParams> get copyWith => _$UpdateParamsCopyWithImpl<U
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is UpdateParams&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is UpdateParams&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.geoAutoUpdate, geoAutoUpdate) || other.geoAutoUpdate == geoAutoUpdate)&&(identical(other.geoUpdateInterval, geoUpdateInterval) || other.geoUpdateInterval == geoUpdateInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,tun,mixedPort,allowLan,findProcessMode,mode,logLevel,ipv6,tcpConcurrent,externalController,unifiedDelay);
|
||||
int get hashCode => Object.hash(runtimeType,tun,mixedPort,allowLan,findProcessMode,mode,logLevel,ipv6,tcpConcurrent,externalController,unifiedDelay,geoAutoUpdate,geoUpdateInterval);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdateParams(tun: $tun, mixedPort: $mixedPort, allowLan: $allowLan, findProcessMode: $findProcessMode, mode: $mode, logLevel: $logLevel, ipv6: $ipv6, tcpConcurrent: $tcpConcurrent, externalController: $externalController, unifiedDelay: $unifiedDelay)';
|
||||
return 'UpdateParams(tun: $tun, mixedPort: $mixedPort, allowLan: $allowLan, findProcessMode: $findProcessMode, mode: $mode, logLevel: $logLevel, ipv6: $ipv6, tcpConcurrent: $tcpConcurrent, externalController: $externalController, unifiedDelay: $unifiedDelay, geoAutoUpdate: $geoAutoUpdate, geoUpdateInterval: $geoUpdateInterval)';
|
||||
}
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ abstract mixin class $UpdateParamsCopyWith<$Res> {
|
||||
factory $UpdateParamsCopyWith(UpdateParams value, $Res Function(UpdateParams) _then) = _$UpdateParamsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
Tun tun,@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController,@JsonKey(name: 'unified-delay') bool unifiedDelay
|
||||
Tun tun,@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,@JsonKey(name: 'geo-update-interval') int geoUpdateInterval
|
||||
});
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ class _$UpdateParamsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of UpdateParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? tun = null,Object? mixedPort = null,Object? allowLan = null,Object? findProcessMode = null,Object? mode = null,Object? logLevel = null,Object? ipv6 = null,Object? tcpConcurrent = null,Object? externalController = null,Object? unifiedDelay = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? tun = null,Object? mixedPort = null,Object? allowLan = null,Object? findProcessMode = null,Object? mode = null,Object? logLevel = null,Object? ipv6 = null,Object? tcpConcurrent = null,Object? externalController = null,Object? unifiedDelay = null,Object? geoAutoUpdate = null,Object? geoUpdateInterval = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
tun: null == tun ? _self.tun : tun // ignore: cast_nullable_to_non_nullable
|
||||
as Tun,mixedPort: null == mixedPort ? _self.mixedPort : mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
@@ -349,7 +349,9 @@ as LogLevel,ipv6: null == ipv6 ? _self.ipv6 : ipv6 // ignore: cast_nullable_to_n
|
||||
as bool,tcpConcurrent: null == tcpConcurrent ? _self.tcpConcurrent : tcpConcurrent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,externalController: null == externalController ? _self.externalController : externalController // ignore: cast_nullable_to_non_nullable
|
||||
as ExternalControllerStatus,unifiedDelay: null == unifiedDelay ? _self.unifiedDelay : unifiedDelay // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,geoAutoUpdate: null == geoAutoUpdate ? _self.geoAutoUpdate : geoAutoUpdate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,geoUpdateInterval: null == geoUpdateInterval ? _self.geoUpdateInterval : geoUpdateInterval // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
/// Create a copy of UpdateParams
|
||||
@@ -443,10 +445,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _UpdateParams() when $default != null:
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay);case _:
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -464,10 +466,10 @@ return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _UpdateParams():
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay);case _:
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -484,10 +486,10 @@ return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Tun tun, @JsonKey(name: 'mixed-port') int mixedPort, @JsonKey(name: 'allow-lan') bool allowLan, @JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode, @JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6, @JsonKey(name: 'tcp-concurrent') bool tcpConcurrent, @JsonKey(name: 'external-controller') ExternalControllerStatus externalController, @JsonKey(name: 'unified-delay') bool unifiedDelay, @JsonKey(name: 'geo-auto-update') bool geoAutoUpdate, @JsonKey(name: 'geo-update-interval') int geoUpdateInterval)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _UpdateParams() when $default != null:
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay);case _:
|
||||
return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_that.mode,_that.logLevel,_that.ipv6,_that.tcpConcurrent,_that.externalController,_that.unifiedDelay,_that.geoAutoUpdate,_that.geoUpdateInterval);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -499,7 +501,7 @@ return $default(_that.tun,_that.mixedPort,_that.allowLan,_that.findProcessMode,_
|
||||
@JsonSerializable()
|
||||
|
||||
class _UpdateParams implements UpdateParams {
|
||||
const _UpdateParams({required this.tun, @JsonKey(name: 'mixed-port') required this.mixedPort, @JsonKey(name: 'allow-lan') required this.allowLan, @JsonKey(name: 'find-process-mode') required this.findProcessMode, required this.mode, @JsonKey(name: 'log-level') required this.logLevel, required this.ipv6, @JsonKey(name: 'tcp-concurrent') required this.tcpConcurrent, @JsonKey(name: 'external-controller') required this.externalController, @JsonKey(name: 'unified-delay') required this.unifiedDelay});
|
||||
const _UpdateParams({required this.tun, @JsonKey(name: 'mixed-port') required this.mixedPort, @JsonKey(name: 'allow-lan') required this.allowLan, @JsonKey(name: 'find-process-mode') required this.findProcessMode, required this.mode, @JsonKey(name: 'log-level') required this.logLevel, required this.ipv6, @JsonKey(name: 'tcp-concurrent') required this.tcpConcurrent, @JsonKey(name: 'external-controller') required this.externalController, @JsonKey(name: 'unified-delay') required this.unifiedDelay, @JsonKey(name: 'geo-auto-update') this.geoAutoUpdate = false, @JsonKey(name: 'geo-update-interval') this.geoUpdateInterval = 24});
|
||||
factory _UpdateParams.fromJson(Map<String, dynamic> json) => _$UpdateParamsFromJson(json);
|
||||
|
||||
@override final Tun tun;
|
||||
@@ -512,6 +514,8 @@ class _UpdateParams implements UpdateParams {
|
||||
@override@JsonKey(name: 'tcp-concurrent') final bool tcpConcurrent;
|
||||
@override@JsonKey(name: 'external-controller') final ExternalControllerStatus externalController;
|
||||
@override@JsonKey(name: 'unified-delay') final bool unifiedDelay;
|
||||
@override@JsonKey(name: 'geo-auto-update') final bool geoAutoUpdate;
|
||||
@override@JsonKey(name: 'geo-update-interval') final int geoUpdateInterval;
|
||||
|
||||
/// Create a copy of UpdateParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -526,16 +530,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _UpdateParams&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _UpdateParams&&(identical(other.tun, tun) || other.tun == tun)&&(identical(other.mixedPort, mixedPort) || other.mixedPort == mixedPort)&&(identical(other.allowLan, allowLan) || other.allowLan == allowLan)&&(identical(other.findProcessMode, findProcessMode) || other.findProcessMode == findProcessMode)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.logLevel, logLevel) || other.logLevel == logLevel)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.tcpConcurrent, tcpConcurrent) || other.tcpConcurrent == tcpConcurrent)&&(identical(other.externalController, externalController) || other.externalController == externalController)&&(identical(other.unifiedDelay, unifiedDelay) || other.unifiedDelay == unifiedDelay)&&(identical(other.geoAutoUpdate, geoAutoUpdate) || other.geoAutoUpdate == geoAutoUpdate)&&(identical(other.geoUpdateInterval, geoUpdateInterval) || other.geoUpdateInterval == geoUpdateInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,tun,mixedPort,allowLan,findProcessMode,mode,logLevel,ipv6,tcpConcurrent,externalController,unifiedDelay);
|
||||
int get hashCode => Object.hash(runtimeType,tun,mixedPort,allowLan,findProcessMode,mode,logLevel,ipv6,tcpConcurrent,externalController,unifiedDelay,geoAutoUpdate,geoUpdateInterval);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdateParams(tun: $tun, mixedPort: $mixedPort, allowLan: $allowLan, findProcessMode: $findProcessMode, mode: $mode, logLevel: $logLevel, ipv6: $ipv6, tcpConcurrent: $tcpConcurrent, externalController: $externalController, unifiedDelay: $unifiedDelay)';
|
||||
return 'UpdateParams(tun: $tun, mixedPort: $mixedPort, allowLan: $allowLan, findProcessMode: $findProcessMode, mode: $mode, logLevel: $logLevel, ipv6: $ipv6, tcpConcurrent: $tcpConcurrent, externalController: $externalController, unifiedDelay: $unifiedDelay, geoAutoUpdate: $geoAutoUpdate, geoUpdateInterval: $geoUpdateInterval)';
|
||||
}
|
||||
|
||||
|
||||
@@ -546,7 +550,7 @@ abstract mixin class _$UpdateParamsCopyWith<$Res> implements $UpdateParamsCopyWi
|
||||
factory _$UpdateParamsCopyWith(_UpdateParams value, $Res Function(_UpdateParams) _then) = __$UpdateParamsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
Tun tun,@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController,@JsonKey(name: 'unified-delay') bool unifiedDelay
|
||||
Tun tun,@JsonKey(name: 'mixed-port') int mixedPort,@JsonKey(name: 'allow-lan') bool allowLan,@JsonKey(name: 'find-process-mode') FindProcessMode findProcessMode, Mode mode,@JsonKey(name: 'log-level') LogLevel logLevel, bool ipv6,@JsonKey(name: 'tcp-concurrent') bool tcpConcurrent,@JsonKey(name: 'external-controller') ExternalControllerStatus externalController,@JsonKey(name: 'unified-delay') bool unifiedDelay,@JsonKey(name: 'geo-auto-update') bool geoAutoUpdate,@JsonKey(name: 'geo-update-interval') int geoUpdateInterval
|
||||
});
|
||||
|
||||
|
||||
@@ -563,7 +567,7 @@ class __$UpdateParamsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of UpdateParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? tun = null,Object? mixedPort = null,Object? allowLan = null,Object? findProcessMode = null,Object? mode = null,Object? logLevel = null,Object? ipv6 = null,Object? tcpConcurrent = null,Object? externalController = null,Object? unifiedDelay = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? tun = null,Object? mixedPort = null,Object? allowLan = null,Object? findProcessMode = null,Object? mode = null,Object? logLevel = null,Object? ipv6 = null,Object? tcpConcurrent = null,Object? externalController = null,Object? unifiedDelay = null,Object? geoAutoUpdate = null,Object? geoUpdateInterval = null,}) {
|
||||
return _then(_UpdateParams(
|
||||
tun: null == tun ? _self.tun : tun // ignore: cast_nullable_to_non_nullable
|
||||
as Tun,mixedPort: null == mixedPort ? _self.mixedPort : mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
@@ -575,7 +579,9 @@ as LogLevel,ipv6: null == ipv6 ? _self.ipv6 : ipv6 // ignore: cast_nullable_to_n
|
||||
as bool,tcpConcurrent: null == tcpConcurrent ? _self.tcpConcurrent : tcpConcurrent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,externalController: null == externalController ? _self.externalController : externalController // ignore: cast_nullable_to_non_nullable
|
||||
as ExternalControllerStatus,unifiedDelay: null == unifiedDelay ? _self.unifiedDelay : unifiedDelay // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,geoAutoUpdate: null == geoAutoUpdate ? _self.geoAutoUpdate : geoAutoUpdate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,geoUpdateInterval: null == geoUpdateInterval ? _self.geoUpdateInterval : geoUpdateInterval // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ _UpdateParams _$UpdateParamsFromJson(Map<String, dynamic> json) =>
|
||||
json['external-controller'],
|
||||
),
|
||||
unifiedDelay: json['unified-delay'] as bool,
|
||||
geoAutoUpdate: json['geo-auto-update'] as bool? ?? false,
|
||||
geoUpdateInterval: (json['geo-update-interval'] as num?)?.toInt() ?? 24,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UpdateParamsToJson(_UpdateParams instance) =>
|
||||
@@ -50,6 +52,8 @@ Map<String, dynamic> _$UpdateParamsToJson(_UpdateParams instance) =>
|
||||
'external-controller':
|
||||
_$ExternalControllerStatusEnumMap[instance.externalController]!,
|
||||
'unified-delay': instance.unifiedDelay,
|
||||
'geo-auto-update': instance.geoAutoUpdate,
|
||||
'geo-update-interval': instance.geoUpdateInterval,
|
||||
};
|
||||
|
||||
const _$FindProcessModeEnumMap = {
|
||||
@@ -164,6 +168,7 @@ const _$CoreEventTypeEnumMap = {
|
||||
CoreEventType.request: 'request',
|
||||
CoreEventType.loaded: 'loaded',
|
||||
CoreEventType.crash: 'crash',
|
||||
CoreEventType.geoUpdate: 'geoUpdate',
|
||||
};
|
||||
|
||||
_InvokeMessage _$InvokeMessageFromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -139,7 +139,7 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
final res = utf8.decode(file.bytes?.toList() ?? []);
|
||||
final res = utf8.decode(await file.readBytes());
|
||||
_controller.text = res;
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
title: appLocalizations.import,
|
||||
value: '',
|
||||
labelText: appLocalizations.url,
|
||||
inputFormatters: TextInputLimits.limit(TextInputLimits.url),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations.emptyTip(appLocalizations.value);
|
||||
@@ -442,7 +443,11 @@ class FindPanel extends StatelessWidget implements PreferredSizeWidget {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [bar, const SizedBox(height: 12), _buildFindInput(context, value)],
|
||||
children: [
|
||||
bar,
|
||||
const SizedBox(height: 12),
|
||||
_buildFindInput(context, value),
|
||||
],
|
||||
);
|
||||
}
|
||||
return bar;
|
||||
@@ -499,6 +504,7 @@ class FindPanel extends StatelessWidget implements PreferredSizeWidget {
|
||||
child: TextField(
|
||||
maxLines: 1,
|
||||
focusNode: focusNode,
|
||||
inputFormatters: TextInputLimits.limit(TextInputLimits.search),
|
||||
style: context.textTheme.bodyMedium,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
@@ -30,9 +29,6 @@ class HomePage extends StatelessWidget {
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final state = ref.watch(navigationStateProvider);
|
||||
final systemUiOverlayStyle = ref.read(
|
||||
systemUiOverlayStyleStateProvider,
|
||||
);
|
||||
final isMobile = state.viewMode == ViewMode.mobile;
|
||||
final navigationItems = state.navigationItems;
|
||||
final currentIndex = state.currentIndex;
|
||||
@@ -54,34 +50,28 @@ class HomePage extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
if (isMobile) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: systemUiOverlayStyle.copyWith(
|
||||
systemNavigationBarColor:
|
||||
context.colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: MediaQuery.removePadding(
|
||||
removeTop: false,
|
||||
removeBottom: true,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: child!,
|
||||
),
|
||||
),
|
||||
MediaQuery.removePadding(
|
||||
removeTop: true,
|
||||
removeBottom: false,
|
||||
return Column(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: MediaQuery.removePadding(
|
||||
removeTop: false,
|
||||
removeBottom: true,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: bottomNavigationBar,
|
||||
child: child!,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MediaQuery.removePadding(
|
||||
removeTop: true,
|
||||
removeBottom: false,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: bottomNavigationBar,
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return child!;
|
||||
@@ -287,7 +277,7 @@ class HomeBackScopeContainer extends ConsumerWidget {
|
||||
} else {
|
||||
await globalState.container
|
||||
.read(systemActionProvider.notifier)
|
||||
.handleBackOrExit();
|
||||
.handleClose();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -61,7 +61,10 @@ class _ScanPageState extends State<ScanPage> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double sideLength = min(400, MediaQuery.of(context).size.width * 0.67);
|
||||
final double sideLength = min(
|
||||
400,
|
||||
MediaQuery.of(context).size.width * 0.67,
|
||||
);
|
||||
final scanWindow = Rect.fromCenter(
|
||||
center: MediaQuery.sizeOf(context).center(Offset.zero),
|
||||
width: sideLength,
|
||||
|
||||
@@ -53,9 +53,7 @@ class App {
|
||||
}
|
||||
|
||||
Future<bool?> requestNotificationsPermission() async {
|
||||
return methodChannel.invokeMethod<bool>(
|
||||
'requestNotificationsPermission',
|
||||
);
|
||||
return methodChannel.invokeMethod<bool>('requestNotificationsPermission');
|
||||
}
|
||||
|
||||
Future<bool> openFile(String path) async {
|
||||
@@ -74,9 +72,7 @@ class App {
|
||||
}
|
||||
|
||||
Future<bool?> tip(String? message) async {
|
||||
return methodChannel.invokeMethod<bool>('tip', {
|
||||
'message': '$message',
|
||||
});
|
||||
return methodChannel.invokeMethod<bool>('tip', {'message': '$message'});
|
||||
}
|
||||
|
||||
Future<bool?> initShortcuts() async {
|
||||
|
||||
@@ -224,6 +224,7 @@ class SetupAction extends _$SetupAction {
|
||||
final message = await coreController.updateConfig(
|
||||
updateParams.copyWith.tun(enable: realTunEnable),
|
||||
);
|
||||
ref.read(checkIpNumProvider.notifier).add();
|
||||
if (message.isNotEmpty) throw message;
|
||||
});
|
||||
});
|
||||
@@ -254,7 +255,6 @@ class SetupAction extends _$SetupAction {
|
||||
.read(proxiesActionProvider.notifier)
|
||||
.updateCurrentGroupName(GroupName.GLOBAL.name);
|
||||
}
|
||||
ref.read(checkIpNumProvider.notifier).add();
|
||||
}
|
||||
|
||||
void autoApplyProfile() {
|
||||
@@ -593,9 +593,11 @@ class SystemAction extends _$SystemAction {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleBackOrExit() async {
|
||||
if (ref.read(backBlockProvider)) return;
|
||||
if (ref.read(appSettingProvider).minimizeOnExit) {
|
||||
Future<void> handleClose([bool exit = true]) async {
|
||||
if (!system.isDesktop) {
|
||||
if (ref.read(backBlockProvider)) return;
|
||||
}
|
||||
if (ref.read(appSettingProvider).minimizeOnExit || !exit) {
|
||||
if (system.isDesktop) {
|
||||
await preferences.saveConfig(ref.read(configProvider));
|
||||
}
|
||||
@@ -910,14 +912,14 @@ class ProfilesAction extends _$ProfilesAction {
|
||||
|
||||
Future<void> addProfileFormFile() async {
|
||||
final platformFile = await globalState.safeRun(picker.pickerFile);
|
||||
final bytes = platformFile?.bytes;
|
||||
if (bytes == null) return;
|
||||
if (platformFile == null) return;
|
||||
final bytes = await platformFile.readBytes();
|
||||
globalState.navigatorKey.currentState?.popUntil((route) => route.isFirst);
|
||||
ref.read(currentPageLabelProvider.notifier).toProfiles();
|
||||
final profile = await globalState.loadingRun(
|
||||
tag: LoadingTag.profiles,
|
||||
() async {
|
||||
return Profile.normal(label: platformFile?.name).saveFile(bytes);
|
||||
return Profile.normal(label: platformFile.name).saveFile(bytes);
|
||||
},
|
||||
title: currentAppLocalizations.addProfile,
|
||||
);
|
||||
@@ -973,3 +975,22 @@ class ProfilesAction extends _$ProfilesAction {
|
||||
await coreController.deleteFile(providersDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class GeoResourceAction extends _$GeoResourceAction {
|
||||
@override
|
||||
void build() {}
|
||||
|
||||
Future<void> updateGeoResource(GeoResource geoResource) async {
|
||||
await coreController.updateGeoData(geoResource.name);
|
||||
}
|
||||
|
||||
void updateGeoResourceUrl(GeoResource geoResource, String newUrl) {
|
||||
if (!newUrl.isUrl) {
|
||||
throw 'Invalid url';
|
||||
}
|
||||
ref.read(patchClashConfigProvider.notifier).update((state) {
|
||||
return state.copyWith(geoXUrl: {...state.geoXUrl, geoResource: newUrl});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||