Compare commits

...

282 Commits

Author SHA1 Message Date
747d17f27c 更新 .github/workflows/windows_test.yaml
Some checks failed
Windows Nightly Build / build (push) Failing after 29s
2024-10-02 21:18:45 +08:00
8398de5af1 更新 .github/workflows/windows_test.yaml 2024-10-02 21:16:03 +08:00
a42cb45534 添加 .github/workflows/windows_test.yaml 2024-10-02 21:15:01 +08:00
xkeyC
968a2a957b
Merge pull request #51 from StarCitizenToolBox/dependabot/pub/flutter_lints-5.0.0
build(deps): bump flutter_lints from 4.0.0 to 5.0.0
2024-09-30 09:13:20 +08:00
dependabot[bot]
3757c27939
build(deps): bump flutter_lints from 4.0.0 to 5.0.0
Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 4.0.0 to 5.0.0.
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_lints-v5.0.0/packages)

---
updated-dependencies:
- dependency-name: flutter_lints
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 00:49:29 +00:00
xkeyC
2a940b9312 Release: 2.12.2 56 2024-09-23 21:10:32 +08:00
xkeyC
2f17dba2fa bump: flutter_rust_bridge 2024-09-23 21:09:04 +08:00
xkeyC
6e1e50f34e
Merge pull request #50 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2024-09-23 21:05:46 +08:00
dependabot[bot]
bfc0c5d3d7 build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-23 13:04:19 +00:00
xkeyC
8c6c980bb8 ui optimization 2024-09-23 21:03:45 +08:00
xkeyC
6a6360540b bugfix 2024-09-23 20:35:19 +08:00
xkeyC
d905f8c13e Release: 2.12.1 55 2024-09-11 20:55:57 +08:00
xkeyC
0d70cb711a Release: 2.12.1 55 2024-09-11 20:50:32 +08:00
xkeyC
f283f4db43 feat: hotfix channel support 2024-09-11 20:50:01 +08:00
xkeyC
3ce635075c feat: 启动游戏时不再隐藏浏览器弹窗,以解决长时间加载的问题 2024-09-11 20:48:25 +08:00
xkeyC
ffd32ec7ff fix: game path scan 2024-09-11 20:41:14 +08:00
xkeyC
ba102bbab8
Merge pull request #48 from StarCitizenToolBox/dependabot/pub/ffigen-14.0.0
build(deps): bump ffigen from 13.0.0 to 14.0.0
2024-09-09 09:04:00 +08:00
xkeyC
79d56dd267
Merge pull request #47 from StarCitizenToolBox/dependabot/pub/re_editor-0.4.0
build(deps): bump re_editor from 0.3.1 to 0.4.0
2024-09-09 09:03:53 +08:00
dependabot[bot]
134b4f0983
build(deps): bump ffigen from 13.0.0 to 14.0.0
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 13.0.0 to 14.0.0.
- [Release notes](https://github.com/dart-lang/native/releases)
- [Commits](https://github.com/dart-lang/native/commits/HEAD/pkgs)

---
updated-dependencies:
- dependency-name: ffigen
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 00:45:08 +00:00
dependabot[bot]
6090d772fe
build(deps): bump re_editor from 0.3.1 to 0.4.0
Bumps [re_editor](https://github.com/reqable/re-editor) from 0.3.1 to 0.4.0.
- [Changelog](https://github.com/reqable/re-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/reqable/re-editor/commits/v0.4.0)

---
updated-dependencies:
- dependency-name: re_editor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 00:45:04 +00:00
xkeyC
3da318ec71 fix: l10n 2024-09-04 13:57:38 +08:00
xkeyC
f453821e15 bump: flutter_rust_bridge 2.3.0 2024-09-04 12:22:13 +08:00
xkeyC
de955f1226
Merge pull request #46 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.3.0
build(deps): update flutter_rust_bridge requirement from =2.2.0 to =2.3.0 in /rust
2024-08-22 09:34:22 +08:00
dependabot[bot]
636f5cdb53
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.2.0...v2.3.0)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-19 01:02:26 +00:00
xkeyC
340e38a8e7
Merge pull request #44 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.2.0
build(deps): update flutter_rust_bridge requirement from =2.1.0 to =2.2.0 in /rust
2024-08-12 09:00:26 +08:00
xkeyC
f0a3b527cf
Merge pull request #45 from StarCitizenToolBox/dependabot/pub/window_manager-0.4.0
build(deps): bump window_manager from 0.3.9 to 0.4.0
2024-08-12 09:00:05 +08:00
dependabot[bot]
d1c7f2b72b
build(deps): bump window_manager from 0.3.9 to 0.4.0
Bumps [window_manager](https://github.com/leanflutter/window_manager) from 0.3.9 to 0.4.0.
- [Release notes](https://github.com/leanflutter/window_manager/releases)
- [Changelog](https://github.com/leanflutter/window_manager/blob/main/CHANGELOG.md)
- [Commits](https://github.com/leanflutter/window_manager/compare/v0.3.9...v0.4.0)

---
updated-dependencies:
- dependency-name: window_manager
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 00:25:46 +00:00
dependabot[bot]
e5d83aea04
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 00:13:16 +00:00
xkeyC
cf7230f980 Release: 2.12.0 2024-07-21 17:12:06 +08:00
xkeyC
44ec80cc73 feat: Vulkan Crash 扫描
close: https://github.com/StarCitizenToolBox/app/issues/43
2024-07-21 17:07:38 +08:00
xkeyC
53e44db817 一键诊断:将修改中文用户名指引 更换为 新建一个英文管理员账户,修改操作太困难且风险较高
close https://github.com/StarCitizenToolBox/app/issues/41
2024-07-21 16:58:02 +08:00
xkeyC
41f10e408f bump: pub 2024-07-21 16:57:09 +08:00
xkeyC
bc25c92bba Deprecate: sctoolbox.sccsgo.com 2024-07-13 10:09:24 +08:00
xkeyC
8fee9dba05 feat: Optimize UX 2024-07-07 17:49:15 +08:00
xkeyC
6ff0b7c902 merge: Deprecated 2024-07-07 17:17:09 +08:00
xkeyC
79239de308 Merge remote-tracking branch 'origin/main' 2024-07-07 16:50:34 +08:00
xkeyC
7def53649a bump: flutter_rust_bridge rust/windows 2024-07-07 16:50:23 +08:00
xkeyC
4dd47d02eb Rlease: 2.11.3 53 2024-06-28 23:32:57 +08:00
xkeyC
4d36b5d7c1 Release: 2.11.3 2024-06-28 23:10:09 +08:00
xkeyC
bbd1aa91ff bump: flutter_rust_bridge 2024-06-23 21:35:56 +08:00
xkeyC
26e28799ff fix: remove bilibili RSS 2024-06-22 19:40:51 +08:00
xkeyC
83adfbc303 fix: page switch 2024-06-22 15:48:59 +08:00
xkeyC
a9980208d3 bump: App to 2.11.2 2024-06-17 20:16:56 +08:00
xkeyC
f88f73d3a8 bump: flutter_rust_bridge 40 2024-06-17 19:16:09 +08:00
xkeyC
ae14a26f08
Merge pull request #40 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.40
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.39 to =2.0.0-dev.40 in /rust
2024-06-17 09:14:58 +08:00
dependabot[bot]
c6720baa5e
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.39...v2.0.0-dev.40)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 01:14:10 +00:00
xkeyC
d1716bd873
Merge pull request #39 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.0.0-dev.40
build(deps): bump flutter_rust_bridge from 2.0.0-dev.39 to 2.0.0-dev.40
2024-06-17 09:03:12 +08:00
dependabot[bot]
853b9034c0
build(deps): bump flutter_rust_bridge from 2.0.0-dev.39 to 2.0.0-dev.40
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.0.0-dev.39 to 2.0.0-dev.40.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.39...v2.0.0-dev.40)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 01:01:33 +00:00
xkeyC
c7d70084d8 fix: SCLoggerHelper 2024-06-16 12:11:19 +08:00
xkeyC
2e69068209 fix: HomeUI performance game not install 2024-06-16 12:06:46 +08:00
xkeyC
38a1ddab72 fix: Window Size 2024-06-16 12:03:37 +08:00
xkeyC
6265acb2ad feat: Cross-platform logic updates 2024-06-16 11:52:25 +08:00
xkeyC
cd812cac66 feat: init macos linux support 2024-06-16 10:36:38 +08:00
xkeyC
5cf8d5a0a0 fix https://github.com/StarCitizenToolBox/app/issues/34 : LocalizationUIModel checkLangUpdate 2024-06-16 09:35:07 +08:00
xkeyC
a94f49eca2 fix https://github.com/StarCitizenToolBox/app/issues/33 : getRSILauncherPath 2024-06-16 09:22:07 +08:00
xkeyC
62289b3b30 fix https://github.com/StarCitizenToolBox/app/issues/27 : unp4k missing runtime 2024-06-16 09:14:51 +08:00
xkeyC
536daa176a bump: flutter_rust_bridge 2.0.0-dev.39 2024-06-16 09:07:22 +08:00
xkeyC
cb69211a78 bump: flutter_rust_bridge 2.0.0-dev.38 2024-06-11 19:55:35 +08:00
xkeyC
222b9e8fef
Merge pull request #36 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.38
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.37 to =2.0.0-dev.38 in /rust
2024-06-11 19:41:15 +08:00
xkeyC
8913fe167f
Merge pull request #37 from StarCitizenToolBox/dependabot/cargo/rust/windows-0.57.0
build(deps): update windows requirement from 0.56.0 to 0.57.0 in /rust
2024-06-11 19:41:07 +08:00
xkeyC
8b78c6d052
Merge pull request #38 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.0.0-dev.38
build(deps): bump flutter_rust_bridge from 2.0.0-dev.37 to 2.0.0-dev.38
2024-06-11 19:40:57 +08:00
dependabot[bot]
f413d924ad
build(deps): bump flutter_rust_bridge from 2.0.0-dev.37 to 2.0.0-dev.38
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.0.0-dev.37 to 2.0.0-dev.38.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.37...v2.0.0-dev.38)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 01:22:52 +00:00
dependabot[bot]
ebbce1ed57
build(deps): update windows requirement from 0.56.0 to 0.57.0 in /rust
Updates the requirements on [windows](https://github.com/microsoft/windows-rs) to permit the latest version.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/compare/0.56.0...0.57.0)

---
updated-dependencies:
- dependency-name: windows
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 00:47:19 +00:00
dependabot[bot]
dc5392258f
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.37...v2.0.0-dev.38)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 00:46:42 +00:00
xkeyC
b530742634 feat: RsiLauncherEnhance add zh_TW Support 2024-06-04 20:29:55 +08:00
xkeyC
20227fbd4b bump: flutter_rust_bridge 2.0.0-dev.37 2024-06-04 20:29:31 +08:00
xkeyC
56d4988cfc
Merge pull request #35 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.37
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.36 to =2.0.0-dev.37 in /rust
2024-06-04 20:17:59 +08:00
dependabot[bot]
47c6f2205a
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.36...v2.0.0-dev.37)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 00:58:27 +00:00
xkeyC
003a6d1cb1 bump: flutter_rust_bridge: ^2.0.0-dev.36 2024-05-29 21:52:04 +08:00
xkeyC
f7dfe108c9
Merge pull request #32 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.36
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.35 to =2.0.0-dev.36 in /rust
2024-05-29 21:32:39 +08:00
dependabot[bot]
638f8760b7
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.35...v2.0.0-dev.36)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 01:10:09 +00:00
xkeyC
3f7ee82d45 bump: dependencies 2024-05-22 20:05:50 +08:00
xkeyC
ad70e21e2c
Merge pull request #30 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.0.0-dev.34
build(deps): bump flutter_rust_bridge from 2.0.0-dev.33 to 2.0.0-dev.34
2024-05-22 19:50:32 +08:00
xkeyC
976d3474f9
Merge pull request #31 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.34
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.33 to =2.0.0-dev.34 in /rust
2024-05-22 19:50:13 +08:00
dependabot[bot]
5f0b11d6ef
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.33...v2.0.0-dev.34)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 01:11:33 +00:00
dependabot[bot]
a114f052b1
build(deps): bump flutter_rust_bridge from 2.0.0-dev.33 to 2.0.0-dev.34
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.0.0-dev.33 to 2.0.0-dev.34.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.33...v2.0.0-dev.34)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 00:45:49 +00:00
xkeyC
32b7f2a9fc bump: Flutter 3.22.0 2024-05-14 15:35:48 +08:00
xkeyC
858479f28e bump: Flutter 3.22.0 2024-05-14 15:34:36 +08:00
xkeyC
c90bc803b5
Merge pull request #28 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2024-05-09 14:47:31 +08:00
xkeyC
40dec20b89 Translated using Weblate (English)
Currently translated at 100.0% (480 of 480 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-05-09 06:46:26 +00:00
xkeyC
725277eef7 Release: 2.11.1 51 2024-05-08 17:04:15 +08:00
xkeyC
5eb0c6dda8 fix: LocalizationUIModel savePath.create 2024-05-08 12:21:43 +08:00
xkeyC
6f146ed84b fix: LocalizationUIModel downloadLocalizationFile wait flush 2024-05-08 10:50:52 +08:00
xkeyC
fb8ae2cb4f Release: 2.11.0 50 2024-05-07 21:11:23 +08:00
xkeyC
348704c669 feat: AnalyticsApi update 2024-05-07 21:08:16 +08:00
xkeyC
155c8a0564 feat: rm async-std , use futures 2024-05-07 20:20:08 +08:00
xkeyC
24313ab3b8 feat: fix debug crash 2024-05-07 20:16:03 +08:00
xkeyC
5a6ea3acad bump: flutter_rust_bridge 2024-05-06 22:48:50 +08:00
xkeyC
9ec541299b l10n: update README.md 2024-05-06 20:50:30 +08:00
xkeyC
9b40863169 l10n: update 2024-05-06 20:30:31 +08:00
xkeyC
60ceb84625 l10n: update 2024-05-06 20:29:32 +08:00
xkeyC
b287dfc627 Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2024-05-06 20:23:26 +08:00
xkeyC
6e823dea9f feat: RsiLauncherEnhanceDialogUI fold DownloaderBoost 2024-05-06 20:22:59 +08:00
xkeyC
34d1007e30 feat: UnP4kc fix missing runtime
close https://github.com/StarCitizenToolBox/app/issues/27
2024-05-06 20:21:35 +08:00
xkeyC
4dbcdf2e9f
feat: update README 2024-05-06 10:57:23 +08:00
xkeyC
c9f1bce9fd
feat: update README 2024-05-06 10:54:15 +08:00
xkeyC
1816b18637
Merge pull request #26 from everland-3769/main
README_zh-TW.md 翻譯更新
2024-05-06 10:41:42 +08:00
everland.3769
9b3dbfae6f
Update README_zh-TW.md 2024-05-06 09:44:33 +08:00
xkeyC
f1a424f98c
Merge pull request #25 from everland-3769/main
intl_zh_TW.arb 翻譯更新
2024-05-05 23:10:22 +08:00
澄清石灰水
c7190b5ec5
Update intl_zh_TW.arb 2024-05-05 23:07:08 +08:00
xkeyC
b965c6262f feat: AdvancedLocalizationUI Error Message 2024-05-05 21:50:18 +08:00
xkeyC
0920696444 fix 2024-05-05 21:28:53 +08:00
xkeyC
9af96a2061 l10n: 自定义汉化文件 2024-05-05 21:03:11 +08:00
xkeyC
2c744cc5bd feat: 安装自定义汉化文件 2024-05-05 20:58:58 +08:00
澄清石灰水
dffcf7adea
Update intl_zh_TW.arb 2024-05-05 19:48:57 +08:00
xkeyC
90f254b1d8 fix: string 2024-05-05 18:52:04 +08:00
xkeyC
f8390e0367
Merge pull request #24 from everland-3769/main
README.md 語言切換修正
2024-05-05 18:50:57 +08:00
澄清石灰水
3452d99de6
Merge branch 'StarCitizenToolBox:main' into main 2024-05-05 18:46:43 +08:00
澄清石灰水
d672c3c8a9
Update README_zh-TW.md 2024-05-05 18:43:34 +08:00
澄清石灰水
0c3b15ac7a
Update README.md 2024-05-05 18:43:22 +08:00
xkeyC
1ecd03813d fix: ui.json 2024-05-05 17:08:46 +08:00
xkeyC
3e5a258cf8 feat: Unp4kcState errorMessage 2024-05-05 16:47:42 +08:00
xkeyC
8d2b4983c0 l10n: Update 2024-05-05 16:34:38 +08:00
xkeyC
a8e88983e2 feat: move json file data to code 2024-05-05 15:06:02 +08:00
xkeyC
f392463a84 feat: 高级汉化 2024-05-05 14:59:07 +08:00
xkeyC
0bb0f7deb4 l10n:roll zh_TW 2024-05-05 11:06:54 +08:00
xkeyC
58e0406dd0
Merge pull request #23 from everland-3769/main
更新 intl_zh_TW.arb 與 README.md 內的翻譯與功能
2024-05-05 10:59:09 +08:00
澄清石灰水
817eab3604
Update README.md 2024-05-04 23:03:55 +08:00
澄清石灰水
a44b2a9316
Update README_zh-TW.md 2024-05-04 23:03:14 +08:00
澄清石灰水
af96c53658
Update README_zh-TW.md 2024-05-04 22:57:45 +08:00
澄清石灰水
0e76292882
Update README_zh-TW.md 2024-05-04 22:55:04 +08:00
澄清石灰水
69005a2133
Update README.md 2024-05-04 22:50:51 +08:00
澄清石灰水
b2c0bd91a0
更新 intl_zh_TW.arb 內的大量內容
改善了大量未正確翻譯的字串
2024-05-04 22:38:43 +08:00
xkeyC
9a875fc5a5 feat: AdvancedLocalization Init 2024-05-03 22:35:31 +08:00
xkeyC
4e506a11a0 feat: new LocalizationDialogUI 2024-05-03 14:39:46 +08:00
xkeyC
edc65e68c9 feat: Remove custom localization 2024-05-03 13:13:44 +08:00
xkeyC
dd14a34285 feat: delete logs when inDays > 7 2024-05-03 13:12:11 +08:00
xkeyC
d05aa0d5f8 feat: RSI 启动器增强使用须知 2024-05-01 15:30:17 +08:00
xkeyC
37b584d85b fix: Unp4kCModel 2024-05-01 15:28:32 +08:00
xkeyC
4ebd7b70dc feat: Français in RsiLauncherEnhanceDialogUI 2024-05-01 14:49:45 +08:00
xkeyC
6019cc96fd feat: check RSI Launcher running 2024-05-01 14:30:47 +08:00
xkeyC
f6907f233a feat: RSILauncherEnhance 2024-05-01 13:48:37 +08:00
xkeyC
5d0c3f5fd4 feat: rust/ deprecate lazy_static , use once_cell 2024-04-30 20:04:42 +08:00
xkeyC
3dbf993099 update: rust/ rename to win32_api.rs
fix: setForegroundWindow
2024-04-28 22:28:48 +08:00
xkeyC
288df33b39 update: rust/windows features 2024-04-28 21:58:17 +08:00
xkeyC
c5549cf4c8 feat: Change App Name, add rust/set_foreground_window 2024-04-28 21:50:36 +08:00
xkeyC
e9c494096f bump: dependencies 2024-04-28 20:31:12 +08:00
xkeyC
a7e1d8d0b7 feat: unp4kTools extract_memory 2024-04-27 16:23:57 +08:00
xkeyC
9bdccc3bbf feat: unp4kc use TemporaryDirectory 2024-04-27 14:40:01 +08:00
xkeyC
b5cde95661 Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2024-04-27 14:25:42 +08:00
xkeyC
0f349bee33 feat: use notify-rust, remove dart/windows_ui 2024-04-27 14:25:11 +08:00
xkeyC
1117d2f12f
bump: workflows 2024-04-27 12:53:12 +08:00
xkeyC
d2694a1e25 fix: 因 RSI 官网变更,移除自动填充功能 (不再支持) 2024-04-26 22:55:38 +08:00
xkeyC
2c71f3baba update: Unp4kCModel Duration.zero 2024-04-17 23:37:28 +08:00
xkeyC
a8e91d6332 update: Unp4kCModel 2024-04-17 23:09:28 +08:00
xkeyC
097b9d9bce feat: Optimize RsProcess 2024-04-17 21:40:39 +08:00
xkeyC
603ef46f10 feat: RsProcess 2024-04-16 22:34:50 +08:00
xkeyC
90ff0025d6 bump: flutter_rust_bridge 2.0.0-dev.32 2024-04-16 19:29:19 +08:00
xkeyC
90bb8e6611 feat: unp4kc 2024-04-14 19:52:42 +08:00
xkeyC
dd17ddc92a fix: LocalizationUIModel.checkLangUpdate 2024-04-12 20:09:16 +08:00
xkeyC
bfebeeb1d3 l10n: update 2024-04-12 20:06:06 +08:00
xkeyC
c0f0b54d82 Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2024-04-12 20:05:27 +08:00
xkeyC
6793511bcf feat: compatible RSI launcher 2.0 2024-04-12 20:05:07 +08:00
xkeyC
1ab785fbbc fix: open Dir 2024-04-12 20:02:00 +08:00
xkeyC
4d6a21d02a
Merge pull request #22 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42KIT Weblate
2024-04-12 08:08:24 +08:00
t6u
c7abe8ef24 Translated using Weblate (English)
Currently translated at 100.0% (366 of 366 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-04-11 23:07:16 +00:00
xkeyC
b8c4e05a32 fix: doctor_action_info_game_abnormal_exit info 2024-04-11 20:09:50 +08:00
xkeyC
e302d9e927 feat: 日本語 Support 2024-04-11 20:04:07 +08:00
xkeyC
df54a44e0e bump: flutter_rust_bridge: ^2.0.0-dev.31 2024-04-11 19:52:13 +08:00
xkeyC
cdbf4d7812
Merge pull request #20 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.30
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.28 to =2.0.0-dev.30 in /rust
2024-04-11 19:31:50 +08:00
xkeyC
ded821b29c
Merge pull request #21 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42KIT Weblate
2024-04-10 10:15:42 +08:00
cfdxkk
af00549928 Translated using Weblate (Japanese)
Currently translated at 16.9% (62 of 366 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ja/
2024-04-08 15:30:59 +00:00
dependabot[bot]
a4b97dc7ab
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.28...v2.0.0-dev.30)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 00:53:04 +00:00
xkeyC
38a0c173ef Release: 2.10.10 2024-03-31 16:01:30 +08:00
xkeyC
e5e16838eb fix: open logs 2024-03-31 15:54:07 +08:00
xkeyC
39a2a28dd1 feat: Optimize game startup 2024-03-31 15:43:59 +08:00
xkeyC
c32de21fa1 fix: Swiper 2024-03-31 15:05:06 +08:00
xkeyC
494ae6468d feat: User Agreement and Privacy Policy Dialog 2024-03-31 14:50:27 +08:00
xkeyC
ef715d569f fix: miss TECH-PREVIEW 2024-03-31 13:30:56 +08:00
xkeyC
bb48504016 fix: LocalizationUIModel _cfgFile dir 2024-03-30 15:07:32 +08:00
xkeyC
4d2c0c20d5 Release: V2.10.9 2024-03-26 20:05:01 +08:00
xkeyC
c05814c1fc bump:device_info_plus file_picker flutter_tilt 2024-03-25 20:31:00 +08:00
xkeyC
e1533ae154 fix:showConfirmDialogs 2024-03-23 18:23:16 +08:00
xkeyC
010a184921 fix:dPrint 2024-03-23 17:54:32 +08:00
xkeyC
5e67211685 fix:powershell auto select 2024-03-23 17:53:42 +08:00
xkeyC
3c174dcb49 fix:HostsBoosterDialogUI _readHostsState 2024-03-21 20:16:43 +08:00
xkeyC
6c0f30778f fix:SystemHelper.openDir 2024-03-21 20:14:37 +08:00
xkeyC
8622a5068b feat: merge to reqwest:0.12.0
remove hyper
2024-03-21 20:04:42 +08:00
xkeyC
6c8c7a0273 l10n: gen 2024-03-21 19:51:39 +08:00
xkeyC
75140cc63c Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2024-03-21 19:50:56 +08:00
xkeyC
93137d0146
Merge pull request #18 from everland-3769/patch-4
Update intl_zh_TW.arb
2024-03-21 19:48:08 +08:00
澄清石灰水
9f6519e4ee
Update intl_zh_TW.arb
修改了部分為翻譯完成的文本,並將能效核心改為 E-Core
2024-03-21 14:25:56 +08:00
xkeyC
04eb0658d4
Merge pull request #17 from everland-3769/patch-3
Update intl_zh_TW.arb
2024-03-18 12:20:42 +08:00
澄清石灰水
95492f0694
Update intl_zh_TW.arb 2024-03-18 12:15:42 +08:00
xkeyC
acbf2763bf
Merge pull request #16 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42KIT Weblate
2024-03-18 08:13:38 +08:00
t6u
b5ec6905f2 Translated using Weblate (English)
Currently translated at 100.0% (364 of 364 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-03-18 00:12:49 +00:00
xkeyC
d0ae2ddb6b
Merge pull request #15 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42KIT Weblate
2024-03-17 21:42:22 +08:00
xkeyC
b1a4a584ac Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (364 of 364 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/zh_Hant/
2024-03-17 13:41:37 +00:00
xkeyC
59ec9ef6a7
Update README.md 2024-03-17 21:02:44 +08:00
xkeyC
44f74004eb fix: home game location scan 2024-03-17 20:47:06 +08:00
xkeyC
7afdcad078
Feat: Github Action Nightly Build (#14)
* add workflow
2024-03-17 20:20:49 +08:00
xkeyC
946b465973 l10n: add Japanese 2024-03-17 19:33:34 +08:00
xkeyC
ff07b07cc6 feat: LocalizationUIModel keep selectLang 2024-03-17 17:19:37 +08:00
xkeyC
afa77e0c38 l10: fix for tools_ui.dart 2024-03-17 17:07:25 +08:00
xkeyC
17588dfab8 l10: update common & Lang settings 2024-03-17 16:54:29 +08:00
xkeyC
9d97dfc786
l10n: README.md rename 2024-03-17 14:49:31 +08:00
xkeyC
ba3725be7c
Merge pull request #13 from everland-3769/patch-2
Create README (zh-TW).md
2024-03-17 14:48:27 +08:00
澄清石灰水
477ab4b789
Create README (zh-TW).md 2024-03-17 14:40:32 +08:00
xkeyC
e335ed292f l10: update zh_TW 2024-03-17 14:17:18 +08:00
xkeyC
588761823a
l10n: Merge pull request #12 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42KIT Weblate
2024-03-17 14:13:54 +08:00
澄清石灰水
d19b01fa95 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.7% (334 of 335 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/zh_Hant/
2024-03-17 06:12:35 +00:00
xkeyC
2c27dd6822 Translated using Weblate (English)
Currently translated at 100.0% (335 of 335 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-03-17 06:12:35 +00:00
xkeyC
2387dde8a2
l10n: Merge pull request #11 from everland-3769/patch-1
Update intl_zh_TW.arb
2024-03-17 14:12:30 +08:00
澄清石灰水
86542866d1
Update intl_zh_TW.arb 2024-03-17 14:07:00 +08:00
xkeyC
ead05516aa l10: update 2024-03-17 12:45:03 +08:00
xkeyC
d382484739
Merge pull request #10 from kerbcat-bot/weblate-sctoolbox-CoreApp
l10n: Translations update from 42KIT Weblate
2024-03-17 11:38:37 +08:00
xkeyC
1a5a417151 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.6% (332 of 333 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/zh_Hant/
2024-03-16 12:11:18 +00:00
xkeyC
be580e895c Translated using Weblate (English)
Currently translated at 99.3% (331 of 333 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-03-16 12:11:18 +00:00
xkeyC
e5671e657e Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (333 of 333 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/zh_Hans/
2024-03-16 12:11:18 +00:00
xkeyC
2d178bfa5e fix: performance_action_clear_shaders 2024-03-16 20:11:06 +08:00
xkeyC
085c1e02c3 feat: zh_TW 繁化姬 快速模板 2024-03-16 19:44:26 +08:00
xkeyC
4982aa289e feat: add l10 target zh_TW 2024-03-16 19:15:30 +08:00
xkeyC
a6b69553d5 feat: app full l10n support 2024-03-16 19:13:49 +08:00
xkeyC
66738abf60 fix: l10n 2024-03-16 17:35:52 +08:00
xkeyC
be3aed4060 fix: performance_action_clear_shaders 2024-03-16 17:26:46 +08:00
xkeyC
7882159139 fix: rename args 2024-03-15 00:03:04 +08:00
xkeyC
b2c13a8a6f feat: 多语言 初步引入 2024-03-15 00:01:06 +08:00
xkeyC
eae02be2af feat: 多语言 基础支持 2024-03-14 23:22:56 +08:00
xkeyC
a84852d4f0 feat: 多语言提取器 2024-03-14 21:50:06 +08:00
xkeyC
8426570ced feat: merge to fluent_ui: ^4.8.6 2024-03-14 19:54:37 +08:00
xkeyC
4a4eb9f701 release: 2.10.8 Beta 43 MSE 2024-03-13 23:00:28 +08:00
xkeyC
d619831370 fix:独立用户 -> 累计用户 2024-03-13 22:54:46 +08:00
xkeyC
35ce760b8d release: 2.10.8 Beta 43 2024-03-13 22:42:56 +08:00
xkeyC
b5fa9fdff1 feat: 使用 ffigen with rust bridge 获得更好的性能,以及移除 web 支持 2024-03-13 22:41:28 +08:00
xkeyC
7e8177bdf5 fix: UI 细节调整 2024-03-13 22:40:28 +08:00
xkeyC
b7ccf80d2a fix: 汉化更新提示 2024-03-13 22:40:09 +08:00
xkeyC
73413caca0 feat: 改用 rustls-tls-webpki-roots 以尝试解决某些网络问题 2024-03-12 22:14:13 +08:00
xkeyC
cb924f267c feat: 新增 Hosts 写入功能,通过预设的干净 DNS 获取ip 并 写入 hosts 文件 2024-03-12 22:08:46 +08:00
xkeyC
26b58324c4 feat: [RustHTTP] DNS Host Map 2024-03-12 20:07:06 +08:00
xkeyC
51393317b1 fix: AboutUI 2024-03-11 20:48:56 +08:00
xkeyC
0b1b0ec5c6 upgrade:flutter_rust_bridge: 2.0.0-dev.28 2024-03-11 20:46:59 +08:00
xkeyC
ef5f7c5e2e
Merge pull request #9 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.28
build(deps): update flutter_rust_bridge requirement from =2.0.0-dev.27 to =2.0.0-dev.28 in /rust
2024-03-11 20:43:57 +08:00
xkeyC
b950d5dc8a feat:关于页面 FlowNumberText 2024-03-11 20:43:16 +08:00
dependabot[bot]
4caf3bd1ab
build(deps): update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.27...v2.0.0-dev.28)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 00:37:44 +00:00
xkeyC
1c73217ea7 feat:重新实现汉化更新 2024-03-10 21:25:03 +08:00
xkeyC
d54a84698c fix:mke lint happy 2024-03-10 20:34:38 +08:00
xkeyC
f7a02269d0 fix:移除能效核实验性功能提示 2024-03-10 20:32:13 +08:00
xkeyC
430455c2da upgrade: flutter_rust_bridge@ 2.0.0-dev.27. 2024-03-10 20:28:24 +08:00
xkeyC
00e5f7545b
Merge pull request #8 from StarCitizenToolBox/feat/full_riverpod
Feat: full riverpod
2024-03-10 19:54:22 +08:00
xkeyC
07ae0d1636 feat:riverpod 迁移 AboutUI 2024-03-10 19:52:41 +08:00
xkeyC
46e5dcf01b feat:riverpod 迁移 SettingsUIModel 2024-03-10 19:44:53 +08:00
xkeyC
c4637a8063 feat:riverpod 迁移 ToolsUI 2024-03-10 18:00:46 +08:00
xkeyC
1318b67be8 feat:riverpod 迁移 PartyRoomUI 2024-03-10 17:25:26 +08:00
xkeyC
cf6ab55dd0 feat:riverpod 迁移 HomeDownloaderUI 2024-03-10 17:23:28 +08:00
xkeyC
01f1533ab0 feat:riverpod 迁移 HomePerformanceUI 2024-03-10 16:56:32 +08:00
xkeyC
5c45e23d23 feat:riverpod 迁移 LocalizationUIModel 2024-03-10 16:26:04 +08:00
xkeyC
6dfb6b3cb0 fix:HomeUIModel 2024-03-10 14:21:36 +08:00
xkeyC
c290e832a0 feat:riverpod 迁移 HomeGameDoctorUI 2024-03-10 14:18:30 +08:00
xkeyC
2aa4fb6c09 feat:riverpod 迁移 HomeGameLoginDialogUI 2024-03-10 13:25:13 +08:00
xkeyC
7b195271af feat:riverpod 迁移 HomeMdContentDialogUI 2024-03-10 12:54:34 +08:00
xkeyC
c9bd9ed677 feat:riverpod 迁移 HomeCountdown 2024-03-10 12:17:43 +08:00
xkeyC
a6507a6910 feat:riverpod 迁移 Web 汉化 2024-03-10 12:07:30 +08:00
xkeyC
e70fca4899 feat:riverpod 迁移 HomeUI 2024-03-09 21:53:37 +08:00
xkeyC
248b416277 feat:riverpod 迁移 Aria2TaskNumWidget 2024-03-09 20:37:25 +08:00
xkeyC
6353591935 feat:riverpod 迁移 Index UI 2024-03-09 20:22:44 +08:00
xkeyC
348d072f6e feat:riverpod 迁移 BinaryModuleConf 2024-03-09 19:42:57 +08:00
xkeyC
8e37ebece5 feat:riverpod 迁移 2024-03-07 23:01:45 +08:00
xkeyC
c6b69c4e08 MES: 2.10.7.0 42 2024-03-01 21:06:47 +08:00
xkeyC
e90bce2c1c 增加查看log的选项 2024-03-01 21:05:05 +08:00
xkeyC
e7016ccfe2 output log to files 2024-03-01 20:59:43 +08:00
xkeyC
6e909eb41b upgrade to 2.10.6 Beta 2024-02-26 20:45:02 +08:00
xkeyC
cfc3a48da2 upgrade to flutter_rust_bridge: 2.0.0-dev.25 2024-02-26 19:34:37 +08:00
xkeyC
f1da5cc253
Merge pull request #5 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.0.0-dev.25
Update flutter_rust_bridge requirement from =2.0.0-dev.24 to =2.0.0-dev.25 in /rust
2024-02-26 19:31:18 +08:00
dependabot[bot]
7fc0f6cba6
Update flutter_rust_bridge requirement in /rust
Updates the requirements on [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) to permit the latest version.
- [Release notes](https://github.com/fzyzcjy/flutter_rust_bridge/releases)
- [Changelog](https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fzyzcjy/flutter_rust_bridge/compare/v2.0.0-dev.24...v2.0.0-dev.25)

---
updated-dependencies:
- dependency-name: flutter_rust_bridge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 01:14:56 +00:00
xkeyC
83571ce722 saveSession when cancelTask 2024-02-25 11:35:49 +08:00
xkeyC
c69fbc0876 class rename 2024-02-25 11:33:16 +08:00
xkeyC
2b1a9d67a0 win32job 改为 assign_process 2024-02-25 11:10:21 +08:00
xkeyC
3c0c80abd2 子进程切换到 rust win32job 实现 2024-02-25 10:30:20 +08:00
xkeyC
238e255489 修复重启应用后的限速设置 2024-02-24 21:49:59 +08:00
xkeyC
5b13996591 fix 下载百分比 2024-02-24 21:02:06 +08:00
xkeyC
a6664f750d 分流下载提示 2024-02-24 18:33:13 +08:00
xkeyC
acccd40570 随机端口号,随机密码 2024-02-24 18:30:44 +08:00
xkeyC
3d92508819 从网络获取下载地址 2024-02-24 18:18:35 +08:00
xkeyC
a6a086fea3 增加模块状态指示器 2024-02-24 17:55:03 +08:00
xkeyC
ca2f584f20 aria2c 按需加载 2024-02-24 17:41:44 +08:00
xkeyC
27b5d9259f 限速器 2024-02-24 17:10:40 +08:00
xkeyC
3b025e7b3e 下载管理器 操作更新 2024-02-24 14:57:52 +08:00
xkeyC
e0ca3377ac 下载管理器 2024-02-24 14:42:33 +08:00
xkeyC
65ffd6a92f 改用 aria2 实现下载器 2024-02-23 00:07:48 +08:00
xkeyC
46808e96c5 移除 rust 多线程下载器 2024-02-22 20:38:57 +08:00
xkeyC
02101db99d BinaryModule support 2024-02-22 20:26:13 +08:00
xkeyC
eafd249847 log按钮搬家 2024-02-22 19:34:15 +08:00
225 changed files with 30250 additions and 10654 deletions

3
.fvmrc Normal file
View File

@ -0,0 +1,3 @@
{
"flutter": "stable"
}

71
.github/workflows/windows_nightly.yml vendored Normal file
View File

@ -0,0 +1,71 @@
name: "Windows Nightly Build"
on:
schedule:
- cron: "0 0 * * *" # every day at midnight
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up MSbuild
uses: microsoft/setup-msbuild@v2
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' # optional, change this to force refresh cache
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:' # optional, change this to specify the cache path
- run: flutter --version
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust Version
run: |
rustup --version
cargo --version
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: "rust"
cache-all-crates: true
- name: Set up LLVM
uses: KyleMayes/install-llvm-action@v2
with:
version: "18"
- name: Flutter pub get
run: flutter pub get
- name: Flutter build runner
run: dart run build_runner build --delete-conflicting-outputs
- name: Rust cargo update
run: cargo update
working-directory: rust
- name: Set up Flutter rust bridge
run: |
cargo install cargo-expand
cargo install 'flutter_rust_bridge_codegen@^2.0.0-dev.0'
- name: Flutter Rust bridge generate
run: flutter_rust_bridge_codegen generate
- name: flutter gen l10n
run: |
flutter pub global activate intl_utils
flutter pub global run intl_utils:generate
- name: Flutter build Windows
run: flutter build windows
- name: Archive build
uses: actions/upload-artifact@v4
with:
name: windows
path: build/windows/x64/runner/Release

71
.github/workflows/windows_test.yaml vendored Normal file
View File

@ -0,0 +1,71 @@
name: "Windows Nightly Build"
on:
schedule:
- cron: "19 21 * * *" # every day at midnight
workflow_dispatch:
jobs:
build:
runs-on: windows
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up MSbuild
uses: microsoft/setup-msbuild@v2
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' # optional, change this to force refresh cache
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:' # optional, change this to specify the cache path
- run: flutter --version
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust Version
run: |
rustup --version
cargo --version
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: "rust"
cache-all-crates: true
- name: Set up LLVM
uses: KyleMayes/install-llvm-action@v2
with:
version: "18"
- name: Flutter pub get
run: flutter pub get
- name: Flutter build runner
run: dart run build_runner build --delete-conflicting-outputs
- name: Rust cargo update
run: cargo update
working-directory: rust
- name: Set up Flutter rust bridge
run: |
cargo install cargo-expand
cargo install 'flutter_rust_bridge_codegen@^2.0.0-dev.0'
- name: Flutter Rust bridge generate
run: flutter_rust_bridge_codegen generate
- name: flutter gen l10n
run: |
flutter pub global activate intl_utils
flutter pub global run intl_utils:generate
- name: Flutter build Windows
run: flutter build windows
- name: Archive build
uses: actions/upload-artifact@v4
with:
name: windows
path: build/windows/x64/runner/Release

5
.gitignore vendored
View File

@ -45,3 +45,8 @@ app.*.map.json
/pubspec.lock
/rust/target/
/rust/Cargo.lock
/lib/generated/l10n_temp.json
/lib/generated/l10n_temp_fix.json
# FVM Version Cache
.fvm/

View File

@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
# This file should be version controlled and should not be manually edited.
version:
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
channel: stable
revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3"
channel: "stable"
project_type: app
@ -13,11 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: android
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: ios
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: linux
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: macos
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: web
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: windows
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
# User provided section

View File

@ -1,6 +1,10 @@
# SC 汉化盒子
# SC汉化盒子 / SCToolBox
[简体中文](https://github.com/StarCitizenToolBox/app/blob/main/README.md) / [繁體中文](https://github.com/StarCitizenToolBox/app/blob/main/README_zh-TW.md) / [English](https://github.com/StarCitizenToolBox/app/blob/main/README_en.md)
该工具为 星际公民玩家 提供 一键诊断,官网及工具网站汉化,游戏汉化,游戏性能优化 等功能,给您带来更愉快的游戏体验。
该工具为 星际公民玩家 提供 一键诊断,官网及工具网站汉化,游戏汉化,游戏性能优化 等功能,致力于带来更愉快的游戏体验。
[![Windows Nightly Build](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml/badge.svg)](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml)
[![](https://get.microsoft.com/images/zh-cn%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
@ -13,13 +17,14 @@
- 其他常用工具:包括 p4k分流下载清理着色器重装EAC等多种功能在内的工具箱。
### 📸 屏幕截图
![1.png](https://s2.loli.net/2023/12/06/S7qc2MmnjBeVkPE.png)
![2.png](https://s2.loli.net/2023/12/06/XuwBoWN7EhqL2Ie.png)
![3.png](https://s2.loli.net/2023/12/06/uogbQMVe5Ufs6XG.png)
![4.png](https://s2.loli.net/2023/12/06/y9sJqkUb1IOWj6m.png)
![5.png](https://s2.loli.net/2023/12/06/yf9z4NrhEOiR5FP.png)
![6.png](https://s2.loli.net/2023/12/06/AakZFw97cySI3UQ.png)
![image.png](https://s2.loli.net/2024/05/06/kX2nxsCp3y71lo4.png)
![image.png](https://s2.loli.net/2024/05/06/LIxt6D3WjJeXh5r.png)
![image.png](https://s2.loli.net/2024/05/06/FDXgTIP9HaL5QiW.png)
![image.png](https://s2.loli.net/2024/05/06/q6tSos41xCEAIju.png)
![image.png](https://s2.loli.net/2024/05/06/JScI2sXTFea3tKY.png)
![image.png](https://s2.loli.net/2024/05/06/kMXZrAunSV48YhK.png)
![image.png](https://s2.loli.net/2024/05/06/CAvKrsXmtpRh8Iw.png)
![image.png](https://s2.loli.net/2024/05/06/ZnYy7XpM69rboWP.png)
### ❤️ 鸣谢
![jetbrains.svg](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)

32
README_en.md Normal file
View File

@ -0,0 +1,32 @@
# SCToolBox
[简体中文](https://github.com/StarCitizenToolBox/app/blob/main/README.md) / [繁體中文](https://github.com/StarCitizenToolBox/app/blob/main/README_zh-TW.md) / [English](https://github.com/StarCitizenToolBox/app/blob/main/README_en.md)
This tool provides Star Citizen players with one-click diagnosis, official website and tool website localization, game localization, game performance optimization and other functions, and is committed to bringing a more enjoyable gaming experience.
[![Windows Nightly Build](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml/badge.svg)](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml)
[![](https://get.microsoft.com/images/en-us%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
### ✨ Feature
- Localization management: install the localization of the community and switch languages with one click
- One-click diagnosis: log files from hundreds of guinea pig users, which can handle common problems of Star Citizen
- Website Chineseization: Provide manual translation for the Star Citizen official website and Star Citizen tool website (thanks to the Star Citizen Chinese Encyclopedia project), and also provide [Browser Extension (Github)] (https://github.com/xkeyC/StarCitizenBoxBrowserEx).
- Performance optimization: Add more detailed performance parameter control to the Star Citizen game, which can be used to optimize performance and obtain better image quality.
- Server status indicator: The server status indicator function is added a few hours earlier than the official website launcher, and the indication is more detailed.
- Other commonly used tools: a toolbox including p4k offload downloads, cleaning shaders, reinstalling EAC and other functions.
### 📸 Screenshot
![image.png](https://s2.loli.net/2024/05/06/iHmsGd7htjE9uzy.png)
![image.png](https://s2.loli.net/2024/05/06/yCD9hXMEz8gK6Gk.png)
![image.png](https://s2.loli.net/2024/05/06/DVvyCFJBpjXWbd4.png)
![image.png](https://s2.loli.net/2024/05/06/Ig6lVB3HW4fzQaY.png)
![image.png](https://s2.loli.net/2024/05/06/Wnzfe6TNZPE4LyA.png)
![image.png](https://s2.loli.net/2024/05/06/dINhbev63tYWlnq.png)
![image.png](https://s2.loli.net/2024/05/06/BODvxVHN4RoAhpU.png)
![image.png](https://s2.loli.net/2024/05/06/psXOKoCElFfaJMV.png)
![image.png](https://s2.loli.net/2024/05/06/PCWgYFlnD156rxK.png)
### ❤️ Thanks
![jetbrains.svg](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)
Special thanks to [JetBrains](https://www.jetbrains.com/?from=SCToolbox) for providing free IDE licenses for open source projects.

32
README_zh-TW.md Normal file
View File

@ -0,0 +1,32 @@
# SC 工具箱
[简体中文](https://github.com/StarCitizenToolBox/app/blob/main/README.md) / [繁體中文](https://github.com/StarCitizenToolBox/app/blob/main/README_zh-TW.md)
此工具為星際公民玩家提供疑難排解、官網及工具網站中文翻譯、遊戲翻譯、效能最佳化/畫面改善等功能,帶給您更愉快的遊戲體驗。
[![Windows Nightly Build](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml/badge.svg)](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml)
[![](https://get.microsoft.com/images/zh-tw%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
### ✨ 功能
- 本地化社群翻譯管理:一鍵快速安裝社群翻譯與切換遊戲語言
- 疑難排解:來自上百名小白鼠使用者的日誌文件,可處理常見星際公民問題
- 網站中文翻譯:為星際公民官網,星際公民工具網站提供人工精翻 (感謝星際公民中文百科計畫),亦提供[瀏覽器擴充套件 (Github)](https://github.com/xkeyC/StarCitizenBoxBrowserEx )。
- 效能最佳化/畫面改善:為星際公民遊戲增加更細緻的效能參數控制,可用於最佳化效能,也可用於獲得更好的畫質。
- 伺服器狀態指示器:比官網啟動器早了幾個小時增加了伺服器狀態指示功能,且指示的更為細緻。
- 其他常用工具:包括 p4k分流下載清除著色器快取重新安裝EAC等多種功能在內的工具箱。
### 📸 螢幕截圖
![image.png](https://s2.loli.net/2024/05/06/FrMxJuh9AozfVc7.png)
![image.png](https://s2.loli.net/2024/05/06/8GLnb2Ma7ojeZIl.png)
![image.png](https://s2.loli.net/2024/05/06/IsCUlx7FH9SfAtY.png)
![image.png](https://s2.loli.net/2024/05/06/8ksgbSKQEFWdj15.png)
![image.png](https://s2.loli.net/2024/05/06/IAZeq97BzKV6tax.png)
![image.png](https://s2.loli.net/2024/05/06/K9hPgzCB5SbomyQ.png)
![image.png](https://s2.loli.net/2024/05/06/TlckzswguMUCjZe.png)
### ❤️ 鳴謝
![jetbrains.svg](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)
特別感謝 [JetBrains](https://www.jetbrains.com/?from=SCToolbox) 為開源專案提供免費的 IDE 授權。

View File

@ -26,5 +26,9 @@ linter:
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
dangling_library_doc_comments: false
analyzer:
plugins:
- custom_lint
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

BIN
assets/binary/aria2c.zip Normal file

Binary file not shown.

BIN
assets/binary/unp4kc.zip Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -1,322 +0,0 @@
[
{
"key": "r_ssdo",
"name": "屏幕光线后处理",
"info": "调整光线后处理等级",
"type": "int",
"max": 2,
"min": 0,
"value": 1,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "r_AntialiasingMode",
"name": "抗锯齿",
"info": "0 关闭1 SMAA2 时间过滤+SMAA3 时间滤波和投影矩阵抖动的 SMAA",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_gameeffects",
"name": "特效等级",
"info": "游戏特效等级",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_texture",
"name": "纹理等级",
"info": "模型纹理细节",
"type": "int",
"max": 3,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_volumetriceffects",
"name": "体积效果",
"info": "体积云、体积光照等",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_water",
"name": "水体效果",
"info": "各种水的等级",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_objectdetail",
"name": "对象细节",
"info": "模型对象细节影响LOD等..",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_particles",
"name": "粒子细节",
"info": "",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_physics",
"name": "物理细节",
"info": "物理效果范围",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_shading",
"name": "着色器细节",
"info": "着色器相关",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_shadows",
"name": "阴影细节",
"info": "阴影效果",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "sys_spec_postprocessing",
"name": "后处理细节",
"info": "后处理着色器,动态模糊效果 等",
"type": "int",
"max": 4,
"min": 1,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_Renderer",
"name": "渲染器质量",
"info": "cryengine 渲染器质量",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderDecal",
"name": "贴花质量",
"info": "LOGO、标志等",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderPostProcess",
"name": "着色器质量",
"info": "",
"type": "int",
"max": 3,
"min": 0,
"value": 3,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderFX",
"name": "FX 质量",
"info": "",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderGeneral",
"name": "常规质量",
"info": "整体模型质量",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderGlass",
"name": "玻璃质量",
"info": "窗、镜子等",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderHDR",
"name": "HDR质量",
"info": "HDR色差亮度层级 处理 等",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderParticle",
"name": "粒子质量",
"info": "粒子效果质量",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderTerrain",
"name": "地面质量",
"info": "",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderShadow",
"name": "阴影质量",
"info": "",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "q_ShaderSky",
"name": "天空质量",
"info": "",
"type": "int",
"max": 3,
"min": 0,
"value": 2,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "e_ParticlesObjectCollisions",
"name": "粒子碰撞",
"info": "1 仅静态粒子 2 包括动态粒子",
"type": "int",
"max": 2,
"min": 1,
"value": 1,
"group": "图形(修改后建议清理着色器)"
},
{
"key": "r_displayinfo",
"name": "屏幕信息(展示帧率)",
"info": "在屏幕右上角展示帧率,服务器信息等",
"type": "int",
"max": 4,
"min": 0,
"value": 1,
"group": "设置"
},
{
"key": "sys_maxFps",
"name": "最大帧率",
"info": "调整游戏最高帧率0为不限制",
"type": "int",
"max": 300,
"min": 0,
"value": 0,
"group": "设置"
},
{
"key": "r_DisplaySessionInfo",
"name": "显示会话信息",
"info": "开启后在屏幕上显示一个二维码,用于反馈时让 CIG 快速定位相关信息",
"type": "bool",
"max": 1,
"min": 0,
"value": 0,
"group": "设置"
},
{
"key": "r_VSync",
"name": "垂直同步",
"info": "开启以防止撕裂,关闭以提高帧率",
"type": "bool",
"max": 1,
"min": 0,
"value": 0,
"group": "设置"
},
{
"key": "r_MotionBlur",
"name": "动态模糊",
"info": "开启以提高运动感,关闭提升观感",
"type": "bool",
"max": 1,
"min": 0,
"value": 0,
"group": "设置"
},
{
"key": "cl_fov",
"name": "FOV",
"info": "设置视角FOV",
"type": "int",
"max": 160,
"min": 25,
"value": 90,
"group": "设置"
},
{
"key": "ui_disableScreenFade",
"name": "UI 淡入淡出动画",
"info": "",
"type": "bool",
"max": 1,
"min": 0,
"value": 1,
"group": "设置"
},
{
"key": "customize",
"name": "自定义参数",
"info": "",
"type": "customize",
"max": 1,
"min": 0,
"value": 1,
"group": "自定义"
}
]

View File

@ -221,19 +221,8 @@ InitWebLocalization();
async function getRSILauncherToken(channelId) {
if (!window.location.href.includes("robertsspaceindustries.com")) return;
if (window.location.href.startsWith("https://robertsspaceindustries.com/connect")) {
$(function () {
$('#email').on('input', function () {
let inputEmail = $('#email').val()
sessionStorage.setItem('inputEmail', inputEmail);
});
$('#password').on('input', function () {
let inputPassword = $('#password').val()
sessionStorage.setItem('inputPassword', inputPassword);
});
});
}
let loginBodyElement = $(".c-form.c-signIn");
loginBodyElement.hide();
// check login
let r = await fetch("api/launcher/v3/account/check", {
method: 'POST', headers: {
@ -241,6 +230,7 @@ async function getRSILauncherToken(channelId) {
},
});
if (r.status !== 200) {
loginBodyElement.show();
// wait login
window.chrome.webview.postMessage({action: 'webview_rsi_login_show_window'});
return;
@ -286,11 +276,20 @@ async function getRSILauncherToken(channelId) {
if (releaseR.status !== 200) return;
let releaseDataJson = (await releaseR.json())['data'];
console.log(releaseDataJson);
// get user avatar
let $avatarElement = $(".c-account-sidebar__profile-metas-avatar");
let avatarUrl = $avatarElement.css("background-image");
// get game library
let libraryR = await fetch("api/launcher/v3/games/library", {
method: 'POST', headers: {
'x-rsi-token': $.cookie('Rsi-Token'),
},
body: releaseFormData
});
// post message
let libraryData = (await libraryR.json())["data"]
// get user avatar
let avatarUrl = $(".a-avatarButton__image").attr("src");
//post message
window.chrome.webview.postMessage({
action: 'webview_rsi_login_success', data: {
'webToken': $.cookie('Rsi-Token'),
@ -298,25 +297,7 @@ async function getRSILauncherToken(channelId) {
'authToken': TokenData,
'releaseInfo': releaseDataJson,
"avatar": avatarUrl,
"inputEmail": sessionStorage.getItem("inputEmail"),
"inputPassword": sessionStorage.getItem("inputPassword")
}
});
}
function RSIAutoLogin(email, pwd) {
if (!window.location.href.includes("robertsspaceindustries.com")) return;
$(function () {
if (email !== "") {
$('#email').val(email)
}
if (pwd !== "") {
$('#password').val(pwd)
}
sessionStorage.setItem('inputPassword', '');
if (email !== "" && pwd !== "") {
$("#remember").prop("checked", true);
$('.c-form__submit-button-label').click();
'libraryData': libraryData,
}
});
}
@ -334,5 +315,4 @@ function SCTShowToast(message) {
document.body.removeChild(m)
}, d * 1000);
}, 3500);
}

View File

@ -1,2 +1,4 @@
rust_input: rust/src/api/**/*.rs
dart_output: lib/common/rust/
dart_output: lib/common/rust/
full_dep: true
web: false

View File

@ -1,12 +1,16 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class AnalyticsApi {
static touch(String key) async {
// debug
if (kDebugMode) return;
if (kDebugMode || kProfileMode) {
dPrint("AnalyticsApi.touch === $key skip");
return;
}
dPrint("AnalyticsApi.touch === $key start");
try {
final r = await RSHttp.postData(
@ -17,4 +21,12 @@ class AnalyticsApi {
dPrint("AnalyticsApi.touch === $key Error:$e");
}
}
static Future<Map<String, dynamic>> getAnalyticsData() async {
final r = await RSHttp.get("${URLConf.analyticsApiHome}/analytics");
if (r.data == null) return {};
final jsonData = json.decode(utf8.decode(r.data!));
dPrint("AnalyticsApi.getAnalyticsData");
return jsonData;
}
}

View File

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/data/app_placard_data.dart';
import 'package:starcitizen_doctor/data/app_torrent_data.dart';
import 'package:starcitizen_doctor/data/app_version_data.dart';
import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
@ -50,6 +51,23 @@ class Api {
return l;
}
static Future<List<AppTorrentData>> getAppTorrentDataList() async {
final data = await getRepoData("sc_doctor", "torrent.json");
final dataJson = json.decode(data);
List<AppTorrentData> l = [];
if (dataJson is List) {
for (var value in dataJson) {
l.add(AppTorrentData.fromJson(value));
}
}
return l;
}
static Future<String> getTorrentTrackerList() async {
final data = await getRepoData("sc_doctor", "tracker.list");
return data;
}
static Future<List> getScServerStatus() async {
final r = await RSHttp.getText(
"https://status.robertsspaceindustries.com/index.json");

View File

@ -12,11 +12,9 @@ class RSSApi {
}
static Future<List<RssItem>> getRssText() async {
final r1 = await RSHttp.getText(URLConf.rssTextUrl1);
final r1f = RssFeed.parse(r1);
final r2 = await RSHttp.getText(URLConf.rssTextUrl2);
final r2f = RssFeed.parse(r2);
final items = r1f.items..addAll(r2f.items);
final items = r2f.items;
items.sort((a, b) {
final aDate = HttpDate.parse(a.pubDate ?? "").millisecondsSinceEpoch;
final bDate = HttpDate.parse(b.pubDate ?? "").millisecondsSinceEpoch;

364
lib/app.dart Normal file
View File

@ -0,0 +1,364 @@
import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:go_router/go_router.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/ui/home/performance/performance_ui.dart';
import 'package:starcitizen_doctor/ui/splash_ui.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
import 'api/analytics.dart';
import 'api/api.dart';
import 'common/helper/system_helper.dart';
import 'common/io/rs_http.dart';
import 'common/rust/frb_generated.dart';
import 'common/rust/api/win32_api.dart' as win32;
import 'data/app_version_data.dart';
import 'generated/no_l10n_strings.dart';
import 'ui/home/downloader/home_downloader_ui.dart';
import 'ui/home/game_doctor/game_doctor_ui.dart';
import 'ui/home/localization/advanced_localization_ui.dart';
import 'ui/index_ui.dart';
import 'ui/settings/upgrade_dialog.dart';
import 'ui/tools/unp4kc/unp4kc_ui.dart';
part 'app.g.dart';
part 'app.freezed.dart';
@freezed
class AppGlobalState with _$AppGlobalState {
const factory AppGlobalState({
String? deviceUUID,
String? applicationSupportDir,
String? applicationBinaryModuleDir,
AppVersionData? networkVersionData,
@Default(ThemeConf()) ThemeConf themeConf,
Locale? appLocale,
Box? appConfBox,
}) = _AppGlobalState;
}
@riverpod
GoRouter router(RouterRef ref) {
return GoRouter(
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const SplashUI()),
),
GoRoute(
path: '/index',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const IndexUI()),
routes: [
GoRoute(
path: "downloader",
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeDownloaderUI())),
GoRoute(
path: 'game_doctor',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeGameDoctorUI()),
),
GoRoute(
path: 'performance',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomePerformanceUI()),
),
GoRoute(
path: 'advanced_localization',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const AdvancedLocalizationUI()))
],
),
GoRoute(path: '/tools', builder: (_, __) => const SizedBox(), routes: [
GoRoute(
path: 'unp4kc',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const UnP4kcUI()),
),
]),
],
);
}
@riverpod
class AppGlobalModel extends _$AppGlobalModel {
static Map<Locale, String> get appLocaleSupport => {
const Locale("auto"): S.current.settings_app_language_auto,
const Locale("zh", "CN"): NoL10n.langZHS,
const Locale("zh", "TW"): NoL10n.langZHT,
const Locale("en"): NoL10n.langEn,
const Locale("ja"): NoL10n.langJa,
};
@override
AppGlobalState build() {
return const AppGlobalState();
}
bool _initialized = false;
Future<void> initApp() async {
if (_initialized) return;
// init Data
final applicationSupportDir = await _initAppDir();
// init Rust bridge
await RustLib.init();
await RSHttp.init();
dPrint("---- rust bridge init -----");
// init Hive
try {
Hive.init("$applicationSupportDir/db");
final box = await Hive.openBox("app_conf");
state = state.copyWith(appConfBox: box);
if (box.get("install_id", defaultValue: "") == "") {
await box.put("install_id", const Uuid().v4());
AnalyticsApi.touch("firstLaunch");
}
final deviceUUID = box.get("install_id", defaultValue: "");
final localeCode = box.get("app_locale", defaultValue: null);
Locale? locale;
if (localeCode != null) {
final localeSplit = localeCode.toString().split("_");
if (localeSplit.length == 2 && localeSplit[1].isNotEmpty) {
locale = Locale(localeSplit[0], localeSplit[1]);
} else {
locale = Locale(localeSplit[0]);
}
}
state = state.copyWith(deviceUUID: deviceUUID, appLocale: locale);
} catch (e) {
await win32.setForegroundWindow(windowName: "SCToolBox");
dPrint("exit: db is locking ...");
exit(0);
}
// init powershell
if (Platform.isWindows) {
try {
await SystemHelper.initPowershellPath();
dPrint("---- Powershell init -----");
} catch (e) {
dPrint("powershell init failed : $e");
}
}
// get windows info
WindowsDeviceInfo? windowsDeviceInfo;
try {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
windowsDeviceInfo = await deviceInfo.windowsInfo;
} catch (e) {
dPrint("DeviceInfo.windowsInfo error: $e");
}
// init windows
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setTitle("SCToolBox");
await windowManager.setSkipTaskbar(false);
await windowManager.show();
if (Platform.isWindows) {
await Window.initialize();
await Window.hideWindowControls();
if (windowsDeviceInfo?.productName.contains("Windows 11") ?? false) {
await Window.setEffect(
effect: WindowEffect.acrylic,
);
}
}
});
dPrint("---- Window init -----");
_initialized = true;
ref.keepAlive();
}
String getUpgradePath() {
return "${state.applicationSupportDir}/._upgrade";
}
// ignore: avoid_build_context_in_providers
Future<bool> checkUpdate(BuildContext context) async {
if (!ConstConf.isMSE) {
final dir = Directory(getUpgradePath());
if (await dir.exists()) {
dir.delete(recursive: true);
}
}
dynamic checkUpdateError;
try {
final networkVersionData = await Api.getAppVersion();
checkActivityThemeColor(networkVersionData);
if (ConstConf.isMSE) {
dPrint(
"lastVersion=${networkVersionData.mSELastVersion} ${networkVersionData.mSELastVersionCode}");
} else {
dPrint(
"lastVersion=${networkVersionData.lastVersion} ${networkVersionData.lastVersionCode}");
}
state = state.copyWith(networkVersionData: networkVersionData);
} catch (e) {
checkUpdateError = e;
dPrint("_checkUpdate Error:$e");
}
await Future.delayed(const Duration(milliseconds: 100));
if (state.networkVersionData == null) {
if (!context.mounted) return false;
await showToast(
context,
S.current.app_common_network_error(
ConstConf.appVersionDate, checkUpdateError.toString()));
return false;
}
if (!Platform.isWindows) return false;
final lastVersion = ConstConf.isMSE
? state.networkVersionData?.mSELastVersionCode
: state.networkVersionData?.lastVersionCode;
if ((lastVersion ?? 0) > ConstConf.appVersionCode) {
// need update
if (!context.mounted) return false;
final r = await showDialog(
dismissWithEsc: false,
context: context,
builder: (context) => const UpgradeDialogUI());
if (r != true) {
if (!context.mounted) return false;
await showToast(context, S.current.app_common_upgrade_info_error);
return false;
}
return true;
}
return false;
}
Timer? _activityThemeColorTimer;
checkActivityThemeColor(AppVersionData networkVersionData) {
if (_activityThemeColorTimer != null) {
_activityThemeColorTimer?.cancel();
_activityThemeColorTimer = null;
}
final startTime = networkVersionData.activityColors?.startTime;
final endTime = networkVersionData.activityColors?.endTime;
if (startTime == null || endTime == null) return;
final now = DateTime.now().millisecondsSinceEpoch;
dPrint("now == $now start == $startTime end == $endTime");
if (now < startTime) {
_activityThemeColorTimer = Timer(Duration(milliseconds: startTime - now),
() => checkActivityThemeColor(networkVersionData));
dPrint("start Timer ....");
} else if (now >= startTime && now <= endTime) {
dPrint("update Color ....");
// update Color
final colorCfg = networkVersionData.activityColors;
state = state.copyWith(
themeConf: ThemeConf(
backgroundColor:
HexColor(colorCfg?.background ?? "#132431").withOpacity(.75),
menuColor: HexColor(colorCfg?.menu ?? "#132431").withOpacity(.95),
micaColor: HexColor(colorCfg?.mica ?? "#0A3142"),
),
);
// wait for end
_activityThemeColorTimer = Timer(Duration(milliseconds: endTime - now),
() => checkActivityThemeColor(networkVersionData));
} else {
dPrint("reset Color ....");
state = state.copyWith(
themeConf: ThemeConf(
backgroundColor: HexColor("#132431").withOpacity(.75),
menuColor: HexColor("#132431").withOpacity(.95),
micaColor: HexColor("#0A3142"),
),
);
}
}
void changeLocale(value) async {
final appConfBox = await Hive.openBox("app_conf");
if (value is Locale) {
if (value.languageCode == "auto") {
state = state.copyWith(appLocale: null);
await appConfBox.put("app_locale", null);
return;
}
final localeCode = value.countryCode != null
? "${value.languageCode}_${value.countryCode ?? ""}"
: value.languageCode;
dPrint("changeLocale == $value localeCode=== $localeCode");
await appConfBox.put("app_locale", localeCode);
state = state.copyWith(appLocale: value);
}
}
Future<String> _initAppDir() async {
if (Platform.isWindows) {
final userProfileDir = Platform.environment["USERPROFILE"];
final applicationSupportDir =
(await getApplicationSupportDirectory()).absolute.path;
String? applicationBinaryModuleDir;
try {
await initDPrintFile(applicationSupportDir);
} catch (e) {
dPrint("initDPrintFile Error: $e");
}
if (ConstConf.isMSE && userProfileDir != null) {
applicationBinaryModuleDir =
"$userProfileDir\\AppData\\Local\\Temp\\SCToolbox\\modules";
} else {
applicationBinaryModuleDir = "$applicationSupportDir\\modules";
}
dPrint("applicationSupportDir == $applicationSupportDir");
dPrint("applicationBinaryModuleDir == $applicationBinaryModuleDir");
state = state.copyWith(
applicationSupportDir: applicationSupportDir,
applicationBinaryModuleDir: applicationBinaryModuleDir,
);
return applicationSupportDir;
} else {
final applicationSupportDir =
(await getApplicationSupportDirectory()).absolute.path;
final applicationBinaryModuleDir = "$applicationSupportDir/modules";
dPrint("applicationSupportDir == $applicationSupportDir");
dPrint("applicationBinaryModuleDir == $applicationBinaryModuleDir");
state = state.copyWith(
applicationSupportDir: applicationSupportDir,
applicationBinaryModuleDir: applicationBinaryModuleDir,
);
return applicationSupportDir;
}
}
}
@freezed
class ThemeConf with _$ThemeConf {
const factory ThemeConf({
@Default(Color(0xbf132431)) Color backgroundColor,
@Default(Color(0xf2132431)) Color menuColor,
@Default(Color(0xff0a3142)) Color micaColor,
}) = _ThemeConf;
}

473
lib/app.freezed.dart Normal file
View File

@ -0,0 +1,473 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'app.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$AppGlobalState {
String? get deviceUUID => throw _privateConstructorUsedError;
String? get applicationSupportDir => throw _privateConstructorUsedError;
String? get applicationBinaryModuleDir => throw _privateConstructorUsedError;
AppVersionData? get networkVersionData => throw _privateConstructorUsedError;
ThemeConf get themeConf => throw _privateConstructorUsedError;
Locale? get appLocale => throw _privateConstructorUsedError;
Box<dynamic>? get appConfBox => throw _privateConstructorUsedError;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$AppGlobalStateCopyWith<AppGlobalState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AppGlobalStateCopyWith<$Res> {
factory $AppGlobalStateCopyWith(
AppGlobalState value, $Res Function(AppGlobalState) then) =
_$AppGlobalStateCopyWithImpl<$Res, AppGlobalState>;
@useResult
$Res call(
{String? deviceUUID,
String? applicationSupportDir,
String? applicationBinaryModuleDir,
AppVersionData? networkVersionData,
ThemeConf themeConf,
Locale? appLocale,
Box<dynamic>? appConfBox});
$ThemeConfCopyWith<$Res> get themeConf;
}
/// @nodoc
class _$AppGlobalStateCopyWithImpl<$Res, $Val extends AppGlobalState>
implements $AppGlobalStateCopyWith<$Res> {
_$AppGlobalStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? deviceUUID = freezed,
Object? applicationSupportDir = freezed,
Object? applicationBinaryModuleDir = freezed,
Object? networkVersionData = freezed,
Object? themeConf = null,
Object? appLocale = freezed,
Object? appConfBox = freezed,
}) {
return _then(_value.copyWith(
deviceUUID: freezed == deviceUUID
? _value.deviceUUID
: deviceUUID // ignore: cast_nullable_to_non_nullable
as String?,
applicationSupportDir: freezed == applicationSupportDir
? _value.applicationSupportDir
: applicationSupportDir // ignore: cast_nullable_to_non_nullable
as String?,
applicationBinaryModuleDir: freezed == applicationBinaryModuleDir
? _value.applicationBinaryModuleDir
: applicationBinaryModuleDir // ignore: cast_nullable_to_non_nullable
as String?,
networkVersionData: freezed == networkVersionData
? _value.networkVersionData
: networkVersionData // ignore: cast_nullable_to_non_nullable
as AppVersionData?,
themeConf: null == themeConf
? _value.themeConf
: themeConf // ignore: cast_nullable_to_non_nullable
as ThemeConf,
appLocale: freezed == appLocale
? _value.appLocale
: appLocale // ignore: cast_nullable_to_non_nullable
as Locale?,
appConfBox: freezed == appConfBox
? _value.appConfBox
: appConfBox // ignore: cast_nullable_to_non_nullable
as Box<dynamic>?,
) as $Val);
}
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$ThemeConfCopyWith<$Res> get themeConf {
return $ThemeConfCopyWith<$Res>(_value.themeConf, (value) {
return _then(_value.copyWith(themeConf: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$AppGlobalStateImplCopyWith<$Res>
implements $AppGlobalStateCopyWith<$Res> {
factory _$$AppGlobalStateImplCopyWith(_$AppGlobalStateImpl value,
$Res Function(_$AppGlobalStateImpl) then) =
__$$AppGlobalStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String? deviceUUID,
String? applicationSupportDir,
String? applicationBinaryModuleDir,
AppVersionData? networkVersionData,
ThemeConf themeConf,
Locale? appLocale,
Box<dynamic>? appConfBox});
@override
$ThemeConfCopyWith<$Res> get themeConf;
}
/// @nodoc
class __$$AppGlobalStateImplCopyWithImpl<$Res>
extends _$AppGlobalStateCopyWithImpl<$Res, _$AppGlobalStateImpl>
implements _$$AppGlobalStateImplCopyWith<$Res> {
__$$AppGlobalStateImplCopyWithImpl(
_$AppGlobalStateImpl _value, $Res Function(_$AppGlobalStateImpl) _then)
: super(_value, _then);
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? deviceUUID = freezed,
Object? applicationSupportDir = freezed,
Object? applicationBinaryModuleDir = freezed,
Object? networkVersionData = freezed,
Object? themeConf = null,
Object? appLocale = freezed,
Object? appConfBox = freezed,
}) {
return _then(_$AppGlobalStateImpl(
deviceUUID: freezed == deviceUUID
? _value.deviceUUID
: deviceUUID // ignore: cast_nullable_to_non_nullable
as String?,
applicationSupportDir: freezed == applicationSupportDir
? _value.applicationSupportDir
: applicationSupportDir // ignore: cast_nullable_to_non_nullable
as String?,
applicationBinaryModuleDir: freezed == applicationBinaryModuleDir
? _value.applicationBinaryModuleDir
: applicationBinaryModuleDir // ignore: cast_nullable_to_non_nullable
as String?,
networkVersionData: freezed == networkVersionData
? _value.networkVersionData
: networkVersionData // ignore: cast_nullable_to_non_nullable
as AppVersionData?,
themeConf: null == themeConf
? _value.themeConf
: themeConf // ignore: cast_nullable_to_non_nullable
as ThemeConf,
appLocale: freezed == appLocale
? _value.appLocale
: appLocale // ignore: cast_nullable_to_non_nullable
as Locale?,
appConfBox: freezed == appConfBox
? _value.appConfBox
: appConfBox // ignore: cast_nullable_to_non_nullable
as Box<dynamic>?,
));
}
}
/// @nodoc
class _$AppGlobalStateImpl implements _AppGlobalState {
const _$AppGlobalStateImpl(
{this.deviceUUID,
this.applicationSupportDir,
this.applicationBinaryModuleDir,
this.networkVersionData,
this.themeConf = const ThemeConf(),
this.appLocale,
this.appConfBox});
@override
final String? deviceUUID;
@override
final String? applicationSupportDir;
@override
final String? applicationBinaryModuleDir;
@override
final AppVersionData? networkVersionData;
@override
@JsonKey()
final ThemeConf themeConf;
@override
final Locale? appLocale;
@override
final Box<dynamic>? appConfBox;
@override
String toString() {
return 'AppGlobalState(deviceUUID: $deviceUUID, applicationSupportDir: $applicationSupportDir, applicationBinaryModuleDir: $applicationBinaryModuleDir, networkVersionData: $networkVersionData, themeConf: $themeConf, appLocale: $appLocale, appConfBox: $appConfBox)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$AppGlobalStateImpl &&
(identical(other.deviceUUID, deviceUUID) ||
other.deviceUUID == deviceUUID) &&
(identical(other.applicationSupportDir, applicationSupportDir) ||
other.applicationSupportDir == applicationSupportDir) &&
(identical(other.applicationBinaryModuleDir,
applicationBinaryModuleDir) ||
other.applicationBinaryModuleDir ==
applicationBinaryModuleDir) &&
(identical(other.networkVersionData, networkVersionData) ||
other.networkVersionData == networkVersionData) &&
(identical(other.themeConf, themeConf) ||
other.themeConf == themeConf) &&
(identical(other.appLocale, appLocale) ||
other.appLocale == appLocale) &&
(identical(other.appConfBox, appConfBox) ||
other.appConfBox == appConfBox));
}
@override
int get hashCode => Object.hash(
runtimeType,
deviceUUID,
applicationSupportDir,
applicationBinaryModuleDir,
networkVersionData,
themeConf,
appLocale,
appConfBox);
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$AppGlobalStateImplCopyWith<_$AppGlobalStateImpl> get copyWith =>
__$$AppGlobalStateImplCopyWithImpl<_$AppGlobalStateImpl>(
this, _$identity);
}
abstract class _AppGlobalState implements AppGlobalState {
const factory _AppGlobalState(
{final String? deviceUUID,
final String? applicationSupportDir,
final String? applicationBinaryModuleDir,
final AppVersionData? networkVersionData,
final ThemeConf themeConf,
final Locale? appLocale,
final Box<dynamic>? appConfBox}) = _$AppGlobalStateImpl;
@override
String? get deviceUUID;
@override
String? get applicationSupportDir;
@override
String? get applicationBinaryModuleDir;
@override
AppVersionData? get networkVersionData;
@override
ThemeConf get themeConf;
@override
Locale? get appLocale;
@override
Box<dynamic>? get appConfBox;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$AppGlobalStateImplCopyWith<_$AppGlobalStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ThemeConf {
Color get backgroundColor => throw _privateConstructorUsedError;
Color get menuColor => throw _privateConstructorUsedError;
Color get micaColor => throw _privateConstructorUsedError;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ThemeConfCopyWith<ThemeConf> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ThemeConfCopyWith<$Res> {
factory $ThemeConfCopyWith(ThemeConf value, $Res Function(ThemeConf) then) =
_$ThemeConfCopyWithImpl<$Res, ThemeConf>;
@useResult
$Res call({Color backgroundColor, Color menuColor, Color micaColor});
}
/// @nodoc
class _$ThemeConfCopyWithImpl<$Res, $Val extends ThemeConf>
implements $ThemeConfCopyWith<$Res> {
_$ThemeConfCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? backgroundColor = null,
Object? menuColor = null,
Object? micaColor = null,
}) {
return _then(_value.copyWith(
backgroundColor: null == backgroundColor
? _value.backgroundColor
: backgroundColor // ignore: cast_nullable_to_non_nullable
as Color,
menuColor: null == menuColor
? _value.menuColor
: menuColor // ignore: cast_nullable_to_non_nullable
as Color,
micaColor: null == micaColor
? _value.micaColor
: micaColor // ignore: cast_nullable_to_non_nullable
as Color,
) as $Val);
}
}
/// @nodoc
abstract class _$$ThemeConfImplCopyWith<$Res>
implements $ThemeConfCopyWith<$Res> {
factory _$$ThemeConfImplCopyWith(
_$ThemeConfImpl value, $Res Function(_$ThemeConfImpl) then) =
__$$ThemeConfImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({Color backgroundColor, Color menuColor, Color micaColor});
}
/// @nodoc
class __$$ThemeConfImplCopyWithImpl<$Res>
extends _$ThemeConfCopyWithImpl<$Res, _$ThemeConfImpl>
implements _$$ThemeConfImplCopyWith<$Res> {
__$$ThemeConfImplCopyWithImpl(
_$ThemeConfImpl _value, $Res Function(_$ThemeConfImpl) _then)
: super(_value, _then);
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? backgroundColor = null,
Object? menuColor = null,
Object? micaColor = null,
}) {
return _then(_$ThemeConfImpl(
backgroundColor: null == backgroundColor
? _value.backgroundColor
: backgroundColor // ignore: cast_nullable_to_non_nullable
as Color,
menuColor: null == menuColor
? _value.menuColor
: menuColor // ignore: cast_nullable_to_non_nullable
as Color,
micaColor: null == micaColor
? _value.micaColor
: micaColor // ignore: cast_nullable_to_non_nullable
as Color,
));
}
}
/// @nodoc
class _$ThemeConfImpl implements _ThemeConf {
const _$ThemeConfImpl(
{this.backgroundColor = const Color(0xbf132431),
this.menuColor = const Color(0xf2132431),
this.micaColor = const Color(0xff0a3142)});
@override
@JsonKey()
final Color backgroundColor;
@override
@JsonKey()
final Color menuColor;
@override
@JsonKey()
final Color micaColor;
@override
String toString() {
return 'ThemeConf(backgroundColor: $backgroundColor, menuColor: $menuColor, micaColor: $micaColor)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ThemeConfImpl &&
(identical(other.backgroundColor, backgroundColor) ||
other.backgroundColor == backgroundColor) &&
(identical(other.menuColor, menuColor) ||
other.menuColor == menuColor) &&
(identical(other.micaColor, micaColor) ||
other.micaColor == micaColor));
}
@override
int get hashCode =>
Object.hash(runtimeType, backgroundColor, menuColor, micaColor);
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ThemeConfImplCopyWith<_$ThemeConfImpl> get copyWith =>
__$$ThemeConfImplCopyWithImpl<_$ThemeConfImpl>(this, _$identity);
}
abstract class _ThemeConf implements ThemeConf {
const factory _ThemeConf(
{final Color backgroundColor,
final Color menuColor,
final Color micaColor}) = _$ThemeConfImpl;
@override
Color get backgroundColor;
@override
Color get menuColor;
@override
Color get micaColor;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ThemeConfImplCopyWith<_$ThemeConfImpl> get copyWith =>
throw _privateConstructorUsedError;
}

40
lib/app.g.dart Normal file
View File

@ -0,0 +1,40 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'app.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$routerHash() => r'4fb9802d06347972b530f17ea7d66724a6ded997';
/// See also [router].
@ProviderFor(router)
final routerProvider = AutoDisposeProvider<GoRouter>.internal(
router,
name: r'routerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$routerHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef RouterRef = AutoDisposeProviderRef<GoRouter>;
String _$appGlobalModelHash() => r'cf3d526a61cbadea4252c6f8e096a527d5cef50f';
/// See also [AppGlobalModel].
@ProviderFor(AppGlobalModel)
final appGlobalModelProvider =
AutoDisposeNotifierProvider<AppGlobalModel, AppGlobalState>.internal(
AppGlobalModel.new,
name: r'appGlobalModelProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$appGlobalModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$AppGlobalModel = AutoDisposeNotifier<AppGlobalState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@ -1,181 +0,0 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:starcitizen_doctor/main.dart';
import 'package:starcitizen_doctor/widgets/my_page_route.dart';
import 'package:window_manager/window_manager.dart';
import 'dart:ui' as ui;
import 'ui_model.dart';
export '../common/utils/base_utils.dart';
export '../widgets/widgets.dart';
export 'package:fluent_ui/fluent_ui.dart';
class BaseUIContainer extends ConsumerStatefulWidget {
final ConsumerState<BaseUIContainer> Function() uiCreate;
final dynamic Function() modelCreate;
const BaseUIContainer(
{super.key, required this.uiCreate, required this.modelCreate});
@override
// ignore: no_logic_in_create_state
ConsumerState<BaseUIContainer> createState() => uiCreate();
Future push(BuildContext context) {
return Navigator.push(context, makeRoute(context));
}
// Future pushShowModalBottomSheet(BuildContext context) {
// return showModalBottomSheet(
// context: context,
// isScrollControlled: true,
// builder: (BuildContext context) {
// return this;
// },
// );
// }
///
FluentPageRoute makeRoute(BuildContext context) {
return MyPageRoute(
builder: (BuildContext context) {
return this;
},
);
}
// Future pushAndRemoveUntil(BuildContext context) {
// return Navigator.pushAndRemoveUntil(context,
// MaterialPageRoute(builder: (BuildContext context) {
// return this;
// }), (_) => false);
// }
}
abstract class BaseUI<T extends BaseUIModel>
extends ConsumerState<BaseUIContainer> {
BaseUIModel? _needDisposeModel;
late final ChangeNotifierProvider<T> provider = bindUIModel();
// final GlobalKey<ScaffoldState> scaffoldState = GlobalKey();
// RefreshController? refreshController;
@override
Widget build(BuildContext context) {
// get model
final model = ref.watch(provider);
return buildBody(context, model)!;
}
String getUITitle(BuildContext context, T model);
Widget? buildBody(
BuildContext context,
T model,
);
Widget? getBottomNavigationBar(BuildContext context, T model) => null;
Color? getBackgroundColor(BuildContext context, T model) => null;
Widget? getFloatingActionButton(BuildContext context, T model) => null;
bool getDrawerEnableOpenDragGesture(BuildContext context, T model) => true;
Widget? getDrawer(BuildContext context, T model) => null;
Widget makeDefaultPage(BuildContext context, T model,
{Widget? titleRow,
List<Widget>? actions,
Widget? content,
bool automaticallyImplyLeading = true}) {
return NavigationView(
pane: NavigationPane(
size: const NavigationPaneSize(openWidth: 0),
),
appBar: NavigationAppBar(
automaticallyImplyLeading: automaticallyImplyLeading,
title: DragToMoveArea(
child: titleRow ??
Column(children: [Expanded(
child: Row(
children: [
Text(getUITitle(context, model)),
],
),
)],),
),
actions: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [...?actions, const WindowButtons()],
)),
paneBodyBuilder: (
PaneItem? item,
Widget? body,
) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: content ?? makeLoading(context),
);
},
);
}
@mustCallSuper
@override
void initState() {
dPrint("[base] <$runtimeType> UI Init");
super.initState();
}
@mustCallSuper
@override
void dispose() {
dPrint("[base] <$runtimeType> UI Disposed");
_needDisposeModel?.dispose();
_needDisposeModel = null;
super.dispose();
}
///
dismissKeyBoard() {
FocusManager.instance.primaryFocus?.unfocus();
}
// void updateStatusBarIconColor(BuildContext context) {
// SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
// statusBarBrightness: Theme.of(context).brightness,
// statusBarIconBrightness: getAndroidIconBrightness(context),
// ));
// }
ChangeNotifierProvider<T> bindUIModel() {
final createdModel = widget.modelCreate();
if (createdModel is T) {
_needDisposeModel = createdModel;
return ChangeNotifierProvider<T>((ref) {
return createdModel..context = context;
});
}
return createdModel;
}
// Widget pullToRefreshBody(
// {required BaseUIModel model, required Widget child}) {
// refreshController ??= RefreshController();
// return AppSmartRefresher(
// enablePullUp: false,
// controller: refreshController,
// onRefresh: () async {
// await model.reloadData();
// refreshController?.refreshCompleted();
// },
// child: child,
// );
// }
makeSvgColor(Color color, {BlendMode blendMode = BlendMode.color}) {
return ui.ColorFilter.mode(color, blendMode);
}
}

View File

@ -1,136 +0,0 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grpc/grpc.dart';
import 'ui.dart';
export '../common/utils/base_utils.dart';
export 'ui.dart';
class BaseUIModel extends ChangeNotifier {
String uiErrorMsg = "";
bool _isDisposed = false;
bool get mounted => !_isDisposed;
BuildContext? context;
BaseUIModel() {
initModel();
}
@mustCallSuper
void initModel() {
dPrint("[base] <$runtimeType> Model Init");
loadData();
}
@mustCallSuper
@override
void dispose() {
_isDisposed = true;
_childUIModels?.forEach((k, value) {
(value as BaseUIModel).dispose();
_childUIModels?[k] = null;
});
dPrint("[base] <$runtimeType> Model Disposed");
super.dispose();
}
Future loadData() async {}
Future reloadData() async {
return loadData();
}
Future onErrorReloadData() async {
return loadData();
}
@override
void notifyListeners() {
if (!mounted) return;
super.notifyListeners();
}
Future<T?> handleError<T>(Future<T> Function() requestFunc,
{bool showFullScreenError = false,
String? errorOverride,
bool noAlert = false}) async {
uiErrorMsg = "";
if (mounted) notifyListeners();
try {
return await requestFunc();
} catch (e) {
dPrint("$runtimeType.handleError Error:$e");
String errorMsg = "Unknown Error";
if (e is GrpcError) {
errorMsg = "远程服务器消息: ${e.message ?? "Unknown Error"}";
} else {
errorMsg = e.toString();
}
if (showFullScreenError) {
uiErrorMsg = errorMsg;
notifyListeners();
return null;
}
if (!noAlert) {
showToast(context!, errorOverride ?? errorMsg,
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context!).size.width * .6,
),
title: "出现错误!");
}
}
return null;
}
Map<dynamic, dynamic>? _childUIModels;
Map<dynamic, dynamic>? _childUIProviders;
BaseUIModel? onCreateChildUIModel(modelKey) => null;
dynamic _getChildUIModel(modelKey) {
_childUIModels ??= {};
final cachedModel = _childUIModels![modelKey];
if (cachedModel != null) {
return (cachedModel);
}
final newModel = onCreateChildUIModel(modelKey);
_childUIModels![modelKey] = newModel!;
return newModel;
}
ChangeNotifierProvider<M> getChildUIModelProviders<M extends BaseUIModel>(
modelKey) {
_childUIProviders ??= {};
if (_childUIProviders![modelKey] == null) {
_childUIProviders![modelKey] = ChangeNotifierProvider<M>((ref) {
final c = (_getChildUIModel(modelKey) as M);
return c..context = context;
});
}
return _childUIProviders![modelKey]!;
}
T? getCreatedChildUIModel<T extends BaseUIModel>(String modelKey,
{bool create = false}) {
if (create && _childUIModels?[modelKey] == null) {
_getChildUIModel(modelKey);
}
return _childUIModels?[modelKey] as T?;
}
Future<void> reloadAllChildModels() async {
if (_childUIModels == null) return;
final futureList = <Future>[];
for (var value in _childUIModels!.entries) {
futureList.add(value.value.reloadData());
}
await Future.wait(futureList);
notifyListeners();
}
dismissKeyBoard() {
FocusManager.instance.primaryFocus?.unfocus();
}
}

View File

@ -1,128 +0,0 @@
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/api/api.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/rust/frb_generated.dart';
import 'package:starcitizen_doctor/data/app_version_data.dart';
import 'package:starcitizen_doctor/global_ui_model.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
class AppConf {
static const String appVersion = "2.10.5+1 Beta";
static const int appVersionCode = 40;
static const String appVersionDate = "2024-02-17";
static const gameChannels = ["LIVE", "PTU", "EPTU"];
static String deviceUUID = "";
static late final String applicationSupportDir;
static AppVersionData? networkVersionData;
static bool offlineMode = false;
static late final WindowsDeviceInfo windowsDeviceInfo;
static Color? colorBackground;
static Color? colorMenu;
static Color? colorMica;
static const isMSE =
String.fromEnvironment("MSE", defaultValue: "false") == "true";
static init(List<String> args) async {
dPrint("launch args == $args");
WidgetsFlutterBinding.ensureInitialized();
/// init device info
try {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
windowsDeviceInfo = await deviceInfo.windowsInfo;
} catch (_) {}
/// init Data
applicationSupportDir =
(await getApplicationSupportDirectory()).absolute.path;
dPrint("applicationSupportDir == $applicationSupportDir");
try {
Hive.init("$applicationSupportDir/db");
final box = await Hive.openBox("app_conf");
if (box.get("install_id", defaultValue: "") == "") {
await box.put("install_id", const Uuid().v4());
AnalyticsApi.touch("firstLaunch");
}
deviceUUID = box.get("install_id", defaultValue: "");
} catch (e) {
exit(1);
}
/// check Rust bridge
await RustLib.init();
await RSHttp.init();
dPrint("---- rust bridge inited -----");
await SystemHelper.initPowershellPath();
/// init defaultColor
colorBackground = HexColor("#132431").withOpacity(.75);
colorMenu = HexColor("#132431").withOpacity(.95);
colorMica = HexColor("#0A3142");
/// init windows
await windowManager.ensureInitialized();
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setSize(const Size(1280, 810));
await windowManager.setMinimumSize(const Size(1280, 810));
await windowManager.center(animate: true);
await windowManager.setSkipTaskbar(false);
await windowManager.setTitleBarStyle(
TitleBarStyle.hidden,
windowButtonVisibility: false,
);
await windowManager.show();
await Window.initialize();
await Window.hideWindowControls();
if (windowsDeviceInfo.productName.contains("Windows 11")) {
await Window.setEffect(
effect: WindowEffect.acrylic,
);
}
});
}
static String getUpgradePath() {
return "${AppConf.applicationSupportDir}/._upgrade";
}
static Future<void> checkUpdate() async {
// clean path
if (!isMSE) {
final dir = Directory(getUpgradePath());
if (await dir.exists()) {
dir.delete(recursive: true);
}
}
try {
networkVersionData = await Api.getAppVersion();
globalUIModel.checkActivityThemeColor();
if (isMSE) {
dPrint(
"lastVersion=${networkVersionData?.mSELastVersion} ${networkVersionData?.mSELastVersionCode}");
} else {
dPrint(
"lastVersion=${networkVersionData?.lastVersion} ${networkVersionData?.lastVersionCode}");
}
} catch (e) {
dPrint("_checkUpdate Error:$e");
}
}
}

View File

@ -0,0 +1,47 @@
import 'dart:io';
import 'package:archive/archive.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class BinaryModuleConf {
static const _modules = {
"aria2c": "0",
"unp4kc": "1",
};
static Future extractModule(List<String> modules, String workingDir) async {
for (var m in _modules.entries) {
if (!modules.contains(m.key)) continue;
final name = m.key;
final version = m.value;
final dir = "$workingDir\\$name";
final versionFile = File("$dir\\version");
if (kReleaseMode &&
await versionFile.exists() &&
(await versionFile.readAsString()).trim() == version) {
dPrint(
"BinaryModuleConf.extractModule skip $name version == $version");
continue;
}
// write model file
final zipBuffer = await rootBundle.load("assets/binary/$name.zip");
final decoder = ZipDecoder().decodeBytes(zipBuffer.buffer.asUint8List());
for (var value in decoder.files) {
final filename = value.name;
if (value.isFile) {
final data = value.content as List<int>;
final file = File('$dir\\$filename');
await file.create(recursive: true);
await file.writeAsBytes(data);
} else {
await Directory('$dir\\$filename').create(recursive: true);
}
}
// write version file
await versionFile.writeAsString(version);
dPrint("BinaryModuleConf.extractModule $name $dir");
}
}
}

View File

@ -0,0 +1,8 @@
class ConstConf {
static const String appVersion = "2.12.2";
static const int appVersionCode = 56;
static const String appVersionDate = "2024-6-28";
static const gameChannels = ["LIVE", "PTU", "EPTU", "TECH-PREVIEW", "HOTFIX"];
static const isMSE =
String.fromEnvironment("MSE", defaultValue: "false") == "true";
}

View File

@ -1,11 +1,11 @@
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/rust/http_package.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class URLConf {
/// HOME API
static String gitApiHome = "https://git.sctoolbox.sccsgo.com";
static String rssApiHome = "https://rss.sctoolbox.sccsgo.com";
static String gitApiHome = "https://git.scbox.xkeyc.cn";
static String rssApiHome = "https://rss.scbox.xkeyc.cn";
static const String analyticsApiHome = "https://scbox.org";
static bool isUrlCheckPass = false;
@ -16,6 +16,9 @@ class URLConf {
static String get gitlabLocalizationUrl =>
"$gitApiHome/SCToolBox/LocalizationData";
static String get gitApiRSILauncherEnhanceUrl =>
"$gitApiHome/SCToolBox/RSILauncherEnhance";
static String get apiRepoPath => "$gitApiHome/SCToolBox/api/raw/branch/main";
static String get gitlabApiPath => "$gitApiHome/api/v1/";
@ -26,8 +29,6 @@ class URLConf {
static String get rssVideoUrl =>
"$rssApiHome/bilibili/user/channel/27976358/290653";
static String get rssTextUrl1 => "$rssApiHome/bilibili/user/article/40102960";
static String get rssTextUrl2 =>
"$rssApiHome/baidu/tieba/user/%E7%81%AC%E7%81%ACG%E7%81%AC%E7%81%AC&";

View File

@ -1,48 +0,0 @@
import 'package:fixnum/fixnum.dart';
import 'package:grpc/grpc.dart';
import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pbgrpc.dart';
class PartyRoomGrpcServer {
static const clientVersion = 0;
static final _channel = ClientChannel(
"127.0.0.1",
port: 39399,
options: ChannelOptions(
credentials: const ChannelCredentials.insecure(),
codecRegistry:
CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]),
),
);
static final _indexService = IndexServiceClient(_channel);
static Future<PingData> pingServer() async {
final r = await _indexService.pingServer(PingData(
data: "PING", clientVersion: Int64.parseInt(clientVersion.toString())));
return r;
}
static Future<RoomTypesData> getRoomTypes() async {
final r = await _indexService.getRoomTypes(Empty());
return r;
}
static Future<RoomListData> getRoomList(RoomListPageReqData req) async {
return await _indexService.getRoomList(req);
}
static Future<RoomData> createRoom(RoomData roomData) async {
return await _indexService.createRoom(roomData);
}
static Future<RoomData?> touchUserRoom(String userName, String deviceUUID) {
return _indexService
.touchUser(PreUser(userName: userName, deviceUUID: deviceUUID));
}
static ResponseStream<RoomUpdateMessage> joinRoom(
String roomID, String userName, String deviceUUID) {
return _indexService.joinRoom(
PreUser(roomID: roomID, userName: userName, deviceUUID: deviceUUID));
}
}

View File

@ -2,11 +2,12 @@ import 'dart:convert';
import 'dart:io';
import 'package:hive/hive.dart';
import '../utils/base_utils.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class SCLoggerHelper {
static Future<String?> getLogFilePath() async {
if (!Platform.isWindows) return null;
Map<String, String> envVars = Platform.environment;
final appDataPath = envVars["appdata"];
if (appDataPath == null) {
@ -30,19 +31,16 @@ class SCLoggerHelper {
}
static Future<List?> getLauncherLogList() async {
final jsonLogPath = await getLogFilePath();
if (jsonLogPath == null) return null;
var jsonString = utf8.decode(await File(jsonLogPath).readAsBytes());
if (jsonString.endsWith("\n")) {
jsonString = jsonString.substring(0, jsonString.length - 3);
if (!Platform.isWindows) return [];
try {
final jsonLogPath = await getLogFilePath();
if (jsonLogPath == null) throw "no file path";
var jsonString = utf8.decode(await File(jsonLogPath).readAsBytes());
return jsonString.split("\n");
} catch (e) {
dPrint(e);
return [];
}
if (jsonString.endsWith(" ")) {
jsonString = jsonString.substring(0, jsonString.length - 3);
}
if (jsonString.endsWith(",")) {
jsonString = jsonString.substring(0, jsonString.length - 3);
}
return json.decode("[$jsonString]");
}
static Future<List<String>> getGameInstallPath(List listData,
@ -51,6 +49,8 @@ class SCLoggerHelper {
List<String> scInstallPaths = [];
checkAndAddPath(String path, bool checkExists) async {
// \\ \
path = path.replaceAll(RegExp(r'\\+'), "\\");
if (path.isNotEmpty && !scInstallPaths.contains(path)) {
if (!checkExists) {
dPrint("find installPath == $path");
@ -73,20 +73,29 @@ class SCLoggerHelper {
try {
for (var v in withVersion) {
String pattern =
r'([a-zA-Z]:\\\\[^\\\\]*\\\\[^\\\\]*\\\\StarCitizen\\\\' + v + r')';
RegExp regExp = RegExp(pattern, caseSensitive: false);
for (var i = listData.length - 1; i > 0; i--) {
final m = listData[i];
final info = m["[browser][info] "];
if (info is String) {
String installPath = "";
if (info.contains("Installing Star Citizen $v")) {
installPath = "${info.split(" at ")[1]}\\$v";
final line = listData[i];
final matches = regExp.allMatches(line);
for (var match in matches) {
await checkAndAddPath(match.group(0)!, checkExists);
}
}
}
if (scInstallPaths.isNotEmpty) {
//
for (var fileName in List.from(scInstallPaths)) {
for (var v in withVersion) {
if (fileName.toString().endsWith(v)) {
for (var nv in withVersion) {
final nextName =
"${fileName.toString().replaceAll("\\$v", "")}\\$nv";
await checkAndAddPath(nextName, true);
}
}
if (info.contains("Launching Star Citizen $v from")) {
installPath = info
.replaceAll("Launching Star Citizen $v from (", "")
.replaceAll(")", "");
}
await checkAndAddPath(installPath, checkExists);
}
}
}
@ -95,22 +104,16 @@ class SCLoggerHelper {
if (scInstallPaths.isEmpty) rethrow;
}
if (scInstallPaths.isNotEmpty) {
//
for (var v in withVersion) {
for (var fileName in List.from(scInstallPaths)) {
if (fileName.toString().endsWith(v)) {
for (var nv in withVersion) {
final nextName =
"${fileName.toString().replaceAll("\\$v", "")}\\$nv";
await checkAndAddPath(nextName, true);
}
}
}
return scInstallPaths;
}
static String getGameChannelID(String installPath) {
for (var value in ConstConf.gameChannels) {
if (installPath.endsWith("\\$value")) {
return value;
}
}
return scInstallPaths;
return "UNKNOWN";
}
static Future<List<String>?> getGameRunningLogs(String gameDir) async {
@ -135,35 +138,47 @@ class SCLoggerHelper {
static MapEntry<String, String>? _checkRunningLine(String line) {
if (line.contains("STATUS_CRYENGINE_OUT_OF_SYSMEM")) {
return const MapEntry("可用内存不足", "请尝试增加虚拟内存( 1080p 下, 物理可用+虚拟内存需 > 64G ");
return MapEntry(S.current.doctor_game_error_low_memory,
S.current.doctor_game_error_low_memory_info);
}
if (line.contains("EXCEPTION_ACCESS_VIOLATION")) {
return const MapEntry("游戏触发了最为广泛的崩溃问题,请查看排障指南",
return MapEntry(S.current.doctor_game_error_generic_info,
"https://docs.qq.com/doc/DUURxUVhzTmZoY09Z");
}
if (line.contains("DXGI_ERROR_DEVICE_REMOVED")) {
return const MapEntry(
"您的显卡崩溃啦!请查看排障指南", "https://www.bilibili.com/read/cv19335199");
return MapEntry(S.current.doctor_game_error_gpu_crash,
"https://www.bilibili.com/read/cv19335199");
}
if (line.contains("Wakeup socket sendto error")) {
return const MapEntry("检测到 socket 异常", "如使用 X黑盒 加速器,请尝试更换加速模式");
return MapEntry(S.current.doctor_game_error_socket_error,
S.current.doctor_game_error_socket_error_info);
}
if (line.contains("The requested operation requires elevated")) {
return const MapEntry("权限不足", "请尝试以管理员权限运行启动器,或使用盒子(微软商店版)启动。");
return MapEntry(S.current.doctor_game_error_permissions_error,
S.current.doctor_game_error_permissions_error_info);
}
if (line.contains(
"The process cannot access the file because is is being used by another process")) {
return const MapEntry("游戏进程被占用", "请尝试重启启动器,或直接重启电脑");
return MapEntry(S.current.doctor_game_error_game_process_error,
S.current.doctor_game_error_game_process_error_info);
}
if (line.contains("0xc0000043")) {
return const MapEntry("游戏程序文件损坏", "请尝试删除 Bin64 文件夹 并在启动器校验。");
return MapEntry(S.current.doctor_game_error_game_damaged_file,
S.current.doctor_game_error_game_damaged_file_info);
}
if (line.contains("option to verify the content of the Data.p4k file")) {
return const MapEntry("P4K文件损坏", "请尝试删除 Data.p4k 文件 并在启动器校验 或 使用盒子分流。");
return MapEntry(S.current.doctor_game_error_game_damaged_p4k_file,
S.current.doctor_game_error_game_damaged_p4k_file_info);
}
if (line.contains("OUTOFMEMORY Direct3D could not allocate")) {
return const MapEntry("可用显存不足", "请不要在后台运行其他高显卡占用的 游戏/应用,或更换显卡。");
return MapEntry(S.current.doctor_game_error_low_gpu_memory,
S.current.doctor_game_error_low_gpu_memory_info);
}
if (line.contains(
"try disabling with r_vulkanDisableLayers = 1 in your user.cfg")) {
return MapEntry(S.current.doctor_game_error_gpu_vulkan_crash,
S.current.doctor_game_error_gpu_vulkan_crash_info);
}
/// Unknown

View File

@ -1,15 +1,19 @@
import 'dart:io';
import 'package:hive/hive.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class SystemHelper {
static String powershellPath = "powershell.exe";
static initPowershellPath() async {
var result = await Process.run(powershellPath, ["echo", "ping"]);
if (!result.stdout.toString().startsWith("ping") &&
powershellPath == "powershell.exe") {
try {
var result = await Process.run(powershellPath, ["echo", "pong"]);
if (!result.stdout.toString().startsWith("pong") &&
powershellPath == "powershell.exe") {
throw "powershell check failed";
}
} catch (e) {
Map<String, String> envVars = Platform.environment;
final systemRoot = envVars["SYSTEMROOT"];
if (systemRoot != null) {
@ -17,7 +21,6 @@ class SystemHelper {
"$systemRoot\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
dPrint("auto search powershell path === $autoSearchPath");
powershellPath = autoSearchPath;
initPowershellPath();
}
}
}
@ -79,11 +82,14 @@ class SystemHelper {
}
/// RSI
static Future<String> getRSILauncherPath() async {
static Future<String> getRSILauncherPath({bool skipEXE = false}) async {
final confBox = await Hive.openBox("app_conf");
final path = confBox.get("custom_launcher_path");
if (path != null && path != "") {
if (await File(path).exists()) {
if (skipEXE) {
return "${path.toString().replaceAll("\\RSI Launcher.exe", "")}\\";
}
return path;
}
}
@ -99,6 +105,9 @@ class SystemHelper {
]);
if (r.stdout.toString().contains("RSI Launcher.exe")) {
final start = r.stdout.toString().split("RSI Launcher.exe");
if (skipEXE) {
return start[0];
}
return "${start[0]}RSI Launcher.exe";
}
}
@ -251,4 +260,21 @@ foreach ($adapter in $adapterMemory) {
.padLeft(hexDigits, '0')
.toUpperCase();
}
static Future openDir(path, {bool isFile = false}) async {
dPrint("SystemHelper.openDir path === $path");
if (Platform.isWindows) {
await Process.run(SystemHelper.powershellPath,
["explorer.exe", isFile ? "/select,$path" : "\"/select,\"$path\"\""]);
}
}
static String getHostsFilePath() {
if (Platform.isWindows) {
final envVars = Platform.environment;
final systemRoot = envVars["SYSTEMROOT"];
return "$systemRoot\\System32\\drivers\\etc\\hosts";
}
return "/etc/hosts";
}
}

View File

@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:starcitizen_doctor/common/conf/app_conf.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/rust/api/http_api.dart' as rust_http;
import 'package:starcitizen_doctor/common/rust/api/http_api.dart';
import 'package:starcitizen_doctor/common/rust/http_package.dart';
@ -10,20 +10,23 @@ class RSHttp {
static init() async {
await rust_http.setDefaultHeader(headers: {
"User-Agent":
"SCToolBox/${AppConf.appVersion} (${AppConf.appVersionCode})${AppConf.isMSE ? "" : " DEV"} RSHttp"
"SCToolBox/${ConstConf.appVersion} (${ConstConf.appVersionCode})${ConstConf.isMSE ? "" : " DEV"} RSHttp"
});
}
static Future<RustHttpResponse> get(String url,
{Map<String, String>? headers}) async {
{Map<String, String>? headers, String? withIpAddress}) async {
final r = await rust_http.fetch(
method: MyMethod.gets, url: url, headers: headers);
method: MyMethod.gets,
url: url,
headers: headers,
withIpAddress: withIpAddress);
return r;
}
static Future<String> getText(String url,
{Map<String, String>? headers}) async {
final r = await get(url, headers: headers);
{Map<String, String>? headers, String? withIpAddress}) async {
final r = await get(url, headers: headers, withIpAddress: withIpAddress);
if (r.data == null) return "";
final str = utf8.decode(r.data!);
return str;
@ -32,24 +35,36 @@ class RSHttp {
static Future<RustHttpResponse> postData(String url,
{Map<String, String>? headers,
String? contentType,
Uint8List? data}) async {
Uint8List? data,
String? withIpAddress}) async {
if (contentType != null) {
headers ??= {};
headers["Content-Type"] = contentType;
}
final r = await rust_http.fetch(
method: MyMethod.post, url: url, headers: headers, inputData: data);
method: MyMethod.post,
url: url,
headers: headers,
inputData: data,
withIpAddress: withIpAddress);
return r;
}
static Future<RustHttpResponse> head(String url,
{Map<String, String>? headers}) async {
{Map<String, String>? headers, String? withIpAddress}) async {
final r = await rust_http.fetch(
method: MyMethod.head, url: url, headers: headers);
method: MyMethod.head,
url: url,
headers: headers,
withIpAddress: withIpAddress);
return r;
}
static Future<List<String>> dnsLookupTxt(String host) async {
return await rust_http.dnsLookupTxt(host: host);
}
static Future<List<String>> dnsLookupIps(String host) async {
return await rust_http.dnsLookupIps(host: host);
}
}

View File

@ -0,0 +1,41 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.4.0.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Future<RsiLauncherAsarData> getRsiLauncherAsarData(
{required String asarPath}) =>
RustLib.instance.api
.crateApiAsarApiGetRsiLauncherAsarData(asarPath: asarPath);
class RsiLauncherAsarData {
final String asarPath;
final String mainJsPath;
final Uint8List mainJsContent;
const RsiLauncherAsarData({
required this.asarPath,
required this.mainJsPath,
required this.mainJsContent,
});
Future<void> writeMainJs({required List<int> content}) =>
RustLib.instance.api.crateApiAsarApiRsiLauncherAsarDataWriteMainJs(
that: this, content: content);
@override
int get hashCode =>
asarPath.hashCode ^ mainJsPath.hashCode ^ mainJsContent.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RsiLauncherAsarData &&
runtimeType == other.runtimeType &&
asarPath == other.asarPath &&
mainJsPath == other.mainJsPath &&
mainJsContent == other.mainJsContent;
}

View File

@ -1,24 +0,0 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.24.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../downloader.dart';
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Stream<DownloadCallbackData> startDownload(
{required String url,
required String savePath,
required String fileName,
required int connectionCount,
dynamic hint}) =>
RustLib.instance.api.startDownload(
url: url,
savePath: savePath,
fileName: fileName,
connectionCount: connectionCount,
hint: hint);
Future<void> cancelDownload({required String id, dynamic hint}) =>
RustLib.instance.api.cancelDownload(id: id, hint: hint);

View File

@ -1,5 +1,5 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.24.
// @generated by `flutter_rust_bridge`@ 2.4.0.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
@ -7,44 +7,29 @@ import '../frb_generated.dart';
import '../http_package.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Future<void> setDefaultHeader(
{required Map<String, String> headers, dynamic hint}) =>
RustLib.instance.api.setDefaultHeader(headers: headers, hint: hint);
// These functions are ignored because they are not marked as `pub`: `_my_method_to_hyper_method`
Future<void> setDefaultHeader({required Map<String, String> headers}) =>
RustLib.instance.api.crateApiHttpApiSetDefaultHeader(headers: headers);
Future<RustHttpResponse> fetch(
{required MyMethod method,
required String url,
Map<String, String>? headers,
Uint8List? inputData,
dynamic hint}) =>
RustLib.instance.api.fetch(
String? withIpAddress}) =>
RustLib.instance.api.crateApiHttpApiFetch(
method: method,
url: url,
headers: headers,
inputData: inputData,
hint: hint);
withIpAddress: withIpAddress);
Future<List<String>> dnsLookupTxt({required String host, dynamic hint}) =>
RustLib.instance.api.dnsLookupTxt(host: host, hint: hint);
Future<List<String>> dnsLookupTxt({required String host}) =>
RustLib.instance.api.crateApiHttpApiDnsLookupTxt(host: host);
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::rust_async::RwLock<reqwest :: Version>>
@sealed
class ReqwestVersion extends RustOpaque {
ReqwestVersion.dcoDecode(List<dynamic> wire)
: super.dcoDecode(wire, _kStaticData);
ReqwestVersion.sseDecode(int ptr, int externalSizeOnNative)
: super.sseDecode(ptr, externalSizeOnNative, _kStaticData);
static final _kStaticData = RustArcStaticData(
rustArcIncrementStrongCount:
RustLib.instance.api.rust_arc_increment_strong_count_ReqwestVersion,
rustArcDecrementStrongCount:
RustLib.instance.api.rust_arc_decrement_strong_count_ReqwestVersion,
rustArcDecrementStrongCountPtr:
RustLib.instance.api.rust_arc_decrement_strong_count_ReqwestVersionPtr,
);
}
Future<List<String>> dnsLookupIps({required String host}) =>
RustLib.instance.api.crateApiHttpApiDnsLookupIps(host: host);
enum MyMethod {
options,
@ -56,4 +41,5 @@ enum MyMethod {
trace,
connect,
patch,
;
}

View File

@ -0,0 +1,54 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.4.0.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
// These functions are ignored because they are not marked as `pub`: `_process_output`
// These types are ignored because they are not used by any `pub` functions: `RsProcess`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`
Stream<RsProcessStreamData> start(
{required String executable,
required List<String> arguments,
required String workingDirectory}) =>
RustLib.instance.api.crateApiRsProcessStart(
executable: executable,
arguments: arguments,
workingDirectory: workingDirectory);
Future<void> write({required int rsPid, required String data}) =>
RustLib.instance.api.crateApiRsProcessWrite(rsPid: rsPid, data: data);
class RsProcessStreamData {
final RsProcessStreamDataType dataType;
final String data;
final int rsPid;
const RsProcessStreamData({
required this.dataType,
required this.data,
required this.rsPid,
});
@override
int get hashCode => dataType.hashCode ^ data.hashCode ^ rsPid.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RsProcessStreamData &&
runtimeType == other.runtimeType &&
dataType == other.dataType &&
data == other.data &&
rsPid == other.rsPid;
}
enum RsProcessStreamDataType {
output,
error,
exit,
;
}

View File

@ -0,0 +1,16 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.4.0.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Future<void> sendNotify(
{String? summary, String? body, String? appName, String? appId}) =>
RustLib.instance.api.crateApiWin32ApiSendNotify(
summary: summary, body: body, appName: appName, appId: appId);
Future<bool> setForegroundWindow({required String windowName}) =>
RustLib.instance.api
.crateApiWin32ApiSetForegroundWindow(windowName: windowName);

View File

@ -1,64 +0,0 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.24.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
part 'downloader.freezed.dart';
class DownloadCallbackData {
final String id;
final int total;
final int progress;
final int speed;
final MyDownloaderStatus status;
const DownloadCallbackData({
required this.id,
required this.total,
required this.progress,
required this.speed,
required this.status,
});
@override
int get hashCode =>
id.hashCode ^
total.hashCode ^
progress.hashCode ^
speed.hashCode ^
status.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is DownloadCallbackData &&
runtimeType == other.runtimeType &&
id == other.id &&
total == other.total &&
progress == other.progress &&
speed == other.speed &&
status == other.status;
}
@freezed
sealed class MyDownloaderStatus with _$MyDownloaderStatus {
const factory MyDownloaderStatus.noStart() = MyDownloaderStatus_NoStart;
const factory MyDownloaderStatus.running() = MyDownloaderStatus_Running;
const factory MyDownloaderStatus.pending(
MyNetworkItemPendingType field0,
) = MyDownloaderStatus_Pending;
const factory MyDownloaderStatus.error(
String field0,
) = MyDownloaderStatus_Error;
const factory MyDownloaderStatus.finished() = MyDownloaderStatus_Finished;
}
enum MyNetworkItemPendingType {
queueUp,
starting,
stopping,
initializing,
}

View File

@ -1,778 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'downloader.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$MyDownloaderStatus {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MyDownloaderStatusCopyWith<$Res> {
factory $MyDownloaderStatusCopyWith(
MyDownloaderStatus value, $Res Function(MyDownloaderStatus) then) =
_$MyDownloaderStatusCopyWithImpl<$Res, MyDownloaderStatus>;
}
/// @nodoc
class _$MyDownloaderStatusCopyWithImpl<$Res, $Val extends MyDownloaderStatus>
implements $MyDownloaderStatusCopyWith<$Res> {
_$MyDownloaderStatusCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
}
/// @nodoc
abstract class _$$MyDownloaderStatus_NoStartImplCopyWith<$Res> {
factory _$$MyDownloaderStatus_NoStartImplCopyWith(
_$MyDownloaderStatus_NoStartImpl value,
$Res Function(_$MyDownloaderStatus_NoStartImpl) then) =
__$$MyDownloaderStatus_NoStartImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$MyDownloaderStatus_NoStartImplCopyWithImpl<$Res>
extends _$MyDownloaderStatusCopyWithImpl<$Res,
_$MyDownloaderStatus_NoStartImpl>
implements _$$MyDownloaderStatus_NoStartImplCopyWith<$Res> {
__$$MyDownloaderStatus_NoStartImplCopyWithImpl(
_$MyDownloaderStatus_NoStartImpl _value,
$Res Function(_$MyDownloaderStatus_NoStartImpl) _then)
: super(_value, _then);
}
/// @nodoc
class _$MyDownloaderStatus_NoStartImpl implements MyDownloaderStatus_NoStart {
const _$MyDownloaderStatus_NoStartImpl();
@override
String toString() {
return 'MyDownloaderStatus.noStart()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$MyDownloaderStatus_NoStartImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) {
return noStart();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) {
return noStart?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) {
if (noStart != null) {
return noStart();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) {
return noStart(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) {
return noStart?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) {
if (noStart != null) {
return noStart(this);
}
return orElse();
}
}
abstract class MyDownloaderStatus_NoStart implements MyDownloaderStatus {
const factory MyDownloaderStatus_NoStart() = _$MyDownloaderStatus_NoStartImpl;
}
/// @nodoc
abstract class _$$MyDownloaderStatus_RunningImplCopyWith<$Res> {
factory _$$MyDownloaderStatus_RunningImplCopyWith(
_$MyDownloaderStatus_RunningImpl value,
$Res Function(_$MyDownloaderStatus_RunningImpl) then) =
__$$MyDownloaderStatus_RunningImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$MyDownloaderStatus_RunningImplCopyWithImpl<$Res>
extends _$MyDownloaderStatusCopyWithImpl<$Res,
_$MyDownloaderStatus_RunningImpl>
implements _$$MyDownloaderStatus_RunningImplCopyWith<$Res> {
__$$MyDownloaderStatus_RunningImplCopyWithImpl(
_$MyDownloaderStatus_RunningImpl _value,
$Res Function(_$MyDownloaderStatus_RunningImpl) _then)
: super(_value, _then);
}
/// @nodoc
class _$MyDownloaderStatus_RunningImpl implements MyDownloaderStatus_Running {
const _$MyDownloaderStatus_RunningImpl();
@override
String toString() {
return 'MyDownloaderStatus.running()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$MyDownloaderStatus_RunningImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) {
return running();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) {
return running?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) {
if (running != null) {
return running();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) {
return running(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) {
return running?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) {
if (running != null) {
return running(this);
}
return orElse();
}
}
abstract class MyDownloaderStatus_Running implements MyDownloaderStatus {
const factory MyDownloaderStatus_Running() = _$MyDownloaderStatus_RunningImpl;
}
/// @nodoc
abstract class _$$MyDownloaderStatus_PendingImplCopyWith<$Res> {
factory _$$MyDownloaderStatus_PendingImplCopyWith(
_$MyDownloaderStatus_PendingImpl value,
$Res Function(_$MyDownloaderStatus_PendingImpl) then) =
__$$MyDownloaderStatus_PendingImplCopyWithImpl<$Res>;
@useResult
$Res call({MyNetworkItemPendingType field0});
}
/// @nodoc
class __$$MyDownloaderStatus_PendingImplCopyWithImpl<$Res>
extends _$MyDownloaderStatusCopyWithImpl<$Res,
_$MyDownloaderStatus_PendingImpl>
implements _$$MyDownloaderStatus_PendingImplCopyWith<$Res> {
__$$MyDownloaderStatus_PendingImplCopyWithImpl(
_$MyDownloaderStatus_PendingImpl _value,
$Res Function(_$MyDownloaderStatus_PendingImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? field0 = null,
}) {
return _then(_$MyDownloaderStatus_PendingImpl(
null == field0
? _value.field0
: field0 // ignore: cast_nullable_to_non_nullable
as MyNetworkItemPendingType,
));
}
}
/// @nodoc
class _$MyDownloaderStatus_PendingImpl implements MyDownloaderStatus_Pending {
const _$MyDownloaderStatus_PendingImpl(this.field0);
@override
final MyNetworkItemPendingType field0;
@override
String toString() {
return 'MyDownloaderStatus.pending(field0: $field0)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$MyDownloaderStatus_PendingImpl &&
(identical(other.field0, field0) || other.field0 == field0));
}
@override
int get hashCode => Object.hash(runtimeType, field0);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$MyDownloaderStatus_PendingImplCopyWith<_$MyDownloaderStatus_PendingImpl>
get copyWith => __$$MyDownloaderStatus_PendingImplCopyWithImpl<
_$MyDownloaderStatus_PendingImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) {
return pending(field0);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) {
return pending?.call(field0);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) {
if (pending != null) {
return pending(field0);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) {
return pending(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) {
return pending?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) {
if (pending != null) {
return pending(this);
}
return orElse();
}
}
abstract class MyDownloaderStatus_Pending implements MyDownloaderStatus {
const factory MyDownloaderStatus_Pending(
final MyNetworkItemPendingType field0) = _$MyDownloaderStatus_PendingImpl;
MyNetworkItemPendingType get field0;
@JsonKey(ignore: true)
_$$MyDownloaderStatus_PendingImplCopyWith<_$MyDownloaderStatus_PendingImpl>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$MyDownloaderStatus_ErrorImplCopyWith<$Res> {
factory _$$MyDownloaderStatus_ErrorImplCopyWith(
_$MyDownloaderStatus_ErrorImpl value,
$Res Function(_$MyDownloaderStatus_ErrorImpl) then) =
__$$MyDownloaderStatus_ErrorImplCopyWithImpl<$Res>;
@useResult
$Res call({String field0});
}
/// @nodoc
class __$$MyDownloaderStatus_ErrorImplCopyWithImpl<$Res>
extends _$MyDownloaderStatusCopyWithImpl<$Res,
_$MyDownloaderStatus_ErrorImpl>
implements _$$MyDownloaderStatus_ErrorImplCopyWith<$Res> {
__$$MyDownloaderStatus_ErrorImplCopyWithImpl(
_$MyDownloaderStatus_ErrorImpl _value,
$Res Function(_$MyDownloaderStatus_ErrorImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? field0 = null,
}) {
return _then(_$MyDownloaderStatus_ErrorImpl(
null == field0
? _value.field0
: field0 // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$MyDownloaderStatus_ErrorImpl implements MyDownloaderStatus_Error {
const _$MyDownloaderStatus_ErrorImpl(this.field0);
@override
final String field0;
@override
String toString() {
return 'MyDownloaderStatus.error(field0: $field0)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$MyDownloaderStatus_ErrorImpl &&
(identical(other.field0, field0) || other.field0 == field0));
}
@override
int get hashCode => Object.hash(runtimeType, field0);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$MyDownloaderStatus_ErrorImplCopyWith<_$MyDownloaderStatus_ErrorImpl>
get copyWith => __$$MyDownloaderStatus_ErrorImplCopyWithImpl<
_$MyDownloaderStatus_ErrorImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) {
return error(field0);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) {
return error?.call(field0);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) {
if (error != null) {
return error(field0);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) {
return error(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) {
return error?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) {
if (error != null) {
return error(this);
}
return orElse();
}
}
abstract class MyDownloaderStatus_Error implements MyDownloaderStatus {
const factory MyDownloaderStatus_Error(final String field0) =
_$MyDownloaderStatus_ErrorImpl;
String get field0;
@JsonKey(ignore: true)
_$$MyDownloaderStatus_ErrorImplCopyWith<_$MyDownloaderStatus_ErrorImpl>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$MyDownloaderStatus_FinishedImplCopyWith<$Res> {
factory _$$MyDownloaderStatus_FinishedImplCopyWith(
_$MyDownloaderStatus_FinishedImpl value,
$Res Function(_$MyDownloaderStatus_FinishedImpl) then) =
__$$MyDownloaderStatus_FinishedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$MyDownloaderStatus_FinishedImplCopyWithImpl<$Res>
extends _$MyDownloaderStatusCopyWithImpl<$Res,
_$MyDownloaderStatus_FinishedImpl>
implements _$$MyDownloaderStatus_FinishedImplCopyWith<$Res> {
__$$MyDownloaderStatus_FinishedImplCopyWithImpl(
_$MyDownloaderStatus_FinishedImpl _value,
$Res Function(_$MyDownloaderStatus_FinishedImpl) _then)
: super(_value, _then);
}
/// @nodoc
class _$MyDownloaderStatus_FinishedImpl implements MyDownloaderStatus_Finished {
const _$MyDownloaderStatus_FinishedImpl();
@override
String toString() {
return 'MyDownloaderStatus.finished()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$MyDownloaderStatus_FinishedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() noStart,
required TResult Function() running,
required TResult Function(MyNetworkItemPendingType field0) pending,
required TResult Function(String field0) error,
required TResult Function() finished,
}) {
return finished();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? noStart,
TResult? Function()? running,
TResult? Function(MyNetworkItemPendingType field0)? pending,
TResult? Function(String field0)? error,
TResult? Function()? finished,
}) {
return finished?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? noStart,
TResult Function()? running,
TResult Function(MyNetworkItemPendingType field0)? pending,
TResult Function(String field0)? error,
TResult Function()? finished,
required TResult orElse(),
}) {
if (finished != null) {
return finished();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(MyDownloaderStatus_NoStart value) noStart,
required TResult Function(MyDownloaderStatus_Running value) running,
required TResult Function(MyDownloaderStatus_Pending value) pending,
required TResult Function(MyDownloaderStatus_Error value) error,
required TResult Function(MyDownloaderStatus_Finished value) finished,
}) {
return finished(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(MyDownloaderStatus_NoStart value)? noStart,
TResult? Function(MyDownloaderStatus_Running value)? running,
TResult? Function(MyDownloaderStatus_Pending value)? pending,
TResult? Function(MyDownloaderStatus_Error value)? error,
TResult? Function(MyDownloaderStatus_Finished value)? finished,
}) {
return finished?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(MyDownloaderStatus_NoStart value)? noStart,
TResult Function(MyDownloaderStatus_Running value)? running,
TResult Function(MyDownloaderStatus_Pending value)? pending,
TResult Function(MyDownloaderStatus_Error value)? error,
TResult Function(MyDownloaderStatus_Finished value)? finished,
required TResult orElse(),
}) {
if (finished != null) {
return finished(this);
}
return orElse();
}
}
abstract class MyDownloaderStatus_Finished implements MyDownloaderStatus {
const factory MyDownloaderStatus_Finished() =
_$MyDownloaderStatus_FinishedImpl;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,317 +0,0 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.24.
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
import 'api/downloader_api.dart';
import 'api/http_api.dart';
import 'dart:async';
import 'dart:convert';
import 'downloader.dart';
import 'frb_generated.dart';
import 'http_package.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RustLibApiImplPlatform({
required super.handler,
required super.wire,
required super.generalizedFrbRustBinding,
required super.portManager,
});
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_ReqwestVersionPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion;
@protected
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
ReqwestVersion
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic raw);
@protected
Map<String, String> dco_decode_Map_String_String(dynamic raw);
@protected
ReqwestVersion
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@protected
int dco_decode_box_autoadd_u_64(dynamic raw);
@protected
DownloadCallbackData dco_decode_download_callback_data(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@protected
List<String> dco_decode_list_String(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
List<(String, String)> dco_decode_list_record_string_string(dynamic raw);
@protected
MyDownloaderStatus dco_decode_my_downloader_status(dynamic raw);
@protected
MyMethod dco_decode_my_method(dynamic raw);
@protected
MyNetworkItemPendingType dco_decode_my_network_item_pending_type(dynamic raw);
@protected
Map<String, String>? dco_decode_opt_Map_String_String(dynamic raw);
@protected
int? dco_decode_opt_box_autoadd_u_64(dynamic raw);
@protected
Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw);
@protected
(String, String) dco_decode_record_string_string(dynamic raw);
@protected
RustHttpResponse dco_decode_rust_http_response(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@protected
int dco_decode_u_64(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@protected
void dco_decode_unit(dynamic raw);
@protected
int dco_decode_usize(dynamic raw);
@protected
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
ReqwestVersion
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
SseDeserializer deserializer);
@protected
Map<String, String> sse_decode_Map_String_String(
SseDeserializer deserializer);
@protected
ReqwestVersion
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
SseDeserializer deserializer);
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
int sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
@protected
DownloadCallbackData sse_decode_download_callback_data(
SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@protected
List<String> sse_decode_list_String(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
List<(String, String)> sse_decode_list_record_string_string(
SseDeserializer deserializer);
@protected
MyDownloaderStatus sse_decode_my_downloader_status(
SseDeserializer deserializer);
@protected
MyMethod sse_decode_my_method(SseDeserializer deserializer);
@protected
MyNetworkItemPendingType sse_decode_my_network_item_pending_type(
SseDeserializer deserializer);
@protected
Map<String, String>? sse_decode_opt_Map_String_String(
SseDeserializer deserializer);
@protected
int? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
@protected
Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
(String, String) sse_decode_record_string_string(
SseDeserializer deserializer);
@protected
RustHttpResponse sse_decode_rust_http_response(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@protected
int sse_decode_u_64(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@protected
void sse_decode_unit(SseDeserializer deserializer);
@protected
int sse_decode_usize(SseDeserializer deserializer);
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
void sse_encode_AnyhowException(
AnyhowException self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
ReqwestVersion self, SseSerializer serializer);
@protected
void sse_encode_Map_String_String(
Map<String, String> self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
ReqwestVersion self, SseSerializer serializer);
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_u_64(int self, SseSerializer serializer);
@protected
void sse_encode_download_callback_data(
DownloadCallbackData self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@protected
void sse_encode_list_String(List<String> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
@protected
void sse_encode_list_record_string_string(
List<(String, String)> self, SseSerializer serializer);
@protected
void sse_encode_my_downloader_status(
MyDownloaderStatus self, SseSerializer serializer);
@protected
void sse_encode_my_method(MyMethod self, SseSerializer serializer);
@protected
void sse_encode_my_network_item_pending_type(
MyNetworkItemPendingType self, SseSerializer serializer);
@protected
void sse_encode_opt_Map_String_String(
Map<String, String>? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_u_64(int? self, SseSerializer serializer);
@protected
void sse_encode_opt_list_prim_u_8_strict(
Uint8List? self, SseSerializer serializer);
@protected
void sse_encode_record_string_string(
(String, String) self, SseSerializer serializer);
@protected
void sse_encode_rust_http_response(
RustHttpResponse self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@protected
void sse_encode_u_64(int self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@protected
void sse_encode_unit(void self, SseSerializer serializer);
@protected
void sse_encode_usize(int self, SseSerializer serializer);
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
}
// Section: wire_class
class RustLibWire implements BaseWire {
RustLibWire.fromExternalLibrary(ExternalLibrary lib);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
ptr);
}
@JS('wasm_bindgen')
external RustLibWasmModule get wasmModule;
@JS()
@anonymous
class RustLibWasmModule implements WasmModule {
@override
external Object /* Promise */ call([String? moduleName]);
@override
external RustLibWasmModule bind(dynamic thisArg, String moduleName);
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockreqwestVersion(
dynamic ptr);
}

View File

@ -1,18 +1,27 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.24.
// @generated by `flutter_rust_bridge`@ 2.4.0.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'api/http_api.dart';
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
enum MyHttpVersion {
http09,
http10,
http11,
http2,
http3,
httpUnknown,
;
}
class RustHttpResponse {
final int statusCode;
final Map<String, String> headers;
final String url;
final int? contentLength;
final ReqwestVersion version;
final BigInt? contentLength;
final MyHttpVersion version;
final String remoteAddr;
final Uint8List? data;

View File

@ -0,0 +1,17 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
extension AsyncError on Future {
Future<T?> unwrap<T>({BuildContext? context}) async {
try {
return await this;
} catch (e) {
dPrint("unwrap error:$e");
if (context != null && context.mounted) {
showToast(context, S.current.app_common_error_info(e.toString()));
}
return null;
}
}
}

View File

@ -1,26 +1,23 @@
import 'dart:async';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
void dPrint(src) {
if (kDebugMode) {
print(src);
}
}
import 'package:starcitizen_doctor/generated/l10n.dart';
Future showToast(BuildContext context, String msg,
{BoxConstraints? constraints, String? title}) async {
return showBaseDialog(context,
title: title ?? "提示",
title: title ?? S.current.app_common_tip,
content: Text(msg),
actions: [
FilledButton(
child: const Padding(
padding: EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
child: Text('我知道了'),
child: Padding(
padding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
child: Text(S.current.app_common_tip_i_know),
),
onPressed: () => Navigator.pop(context),
),
@ -30,9 +27,12 @@ Future showToast(BuildContext context, String msg,
Future<bool> showConfirmDialogs(
BuildContext context, String title, Widget content,
{String confirm = "确认",
String cancel = "取消",
{String confirm = "",
String cancel = "",
BoxConstraints? constraints}) async {
if (confirm.isEmpty) confirm = S.current.app_common_tip_confirm;
if (cancel.isEmpty) cancel = S.current.app_common_tip_cancel;
final r = await showBaseDialog(context,
title: title,
content: content,
@ -135,3 +135,9 @@ Future<Uint8List?> widgetToPngImage(GlobalKey repaintBoundaryKey,
double roundDoubleTo(double value, double precision) =>
(value * precision).round() / precision;
int getMinNumber(List<int> list) {
if (list.isEmpty) return 0;
list.sort((a, b) => a.compareTo(b));
return list.first;
}

43
lib/common/utils/log.dart Normal file
View File

@ -0,0 +1,43 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:synchronized/synchronized.dart';
export 'package:starcitizen_doctor/generated/l10n.dart';
var _logLock = Lock();
File? _logFile;
void dPrint(src) async {
if (kDebugMode) {
print(src);
return;
}
await _logLock.synchronized(() async {
try {
await _logFile?.writeAsString("$src\n", mode: FileMode.append);
} catch (_) {}
});
}
Future<void> initDPrintFile(String applicationSupportDir) async {
final now = DateTime.now();
final logFile =
File("$applicationSupportDir/logs/${now.millisecondsSinceEpoch}.log");
await logFile.create(recursive: true);
_logFile = logFile;
final logsDir = Directory("$applicationSupportDir/logs");
await for (final files in logsDir.list()) {
if (files is File) {
final stat = await files.stat();
if (stat.type == FileSystemEntityType.file &&
now.difference(await files.lastModified()).inDays > 7) {
await files.delete();
}
}
}
}
File? getDPrintFile() {
return _logFile;
}

View File

@ -0,0 +1,12 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive/hive.dart';
import 'package:starcitizen_doctor/app.dart';
extension ProviderExtension on AutoDisposeNotifier {
AppGlobalModel get appGlobalModel =>
ref.read(appGlobalModelProvider.notifier);
AppGlobalState get appGlobalState => ref.read(appGlobalModelProvider);
Box<dynamic>? get appConfBox => appGlobalState.appConfBox;
}

View File

@ -1,77 +0,0 @@
// Copyright (c) 2020, Dart | Windows. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Reads and writes credentials
import 'dart:convert';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';
import '../utils/base_utils.dart';
class Win32Credentials {
static void write(
{required String credentialName,
required String userName,
required String password}) {
final examplePassword = utf8.encode(password);
final blob = examplePassword.allocatePointer();
final credential = calloc<CREDENTIAL>()
..ref.Type = CRED_TYPE_GENERIC
..ref.TargetName = credentialName.toNativeUtf16()
..ref.Persist = CRED_PERSIST_LOCAL_MACHINE
..ref.UserName = userName.toNativeUtf16()
..ref.CredentialBlob = blob
..ref.CredentialBlobSize = examplePassword.length;
final result = CredWrite(credential, 0);
if (result != TRUE) {
final errorCode = GetLastError();
dPrint('Error ($result): $errorCode');
return;
}
dPrint('Success (blob size: ${credential.ref.CredentialBlobSize})');
free(blob);
free(credential);
}
static MapEntry<String, String>? read(String credentialName) {
dPrint('Reading $credentialName ...');
final credPointer = calloc<Pointer<CREDENTIAL>>();
final result = CredRead(
credentialName.toNativeUtf16(), CRED_TYPE_GENERIC, 0, credPointer);
if (result != TRUE) {
final errorCode = GetLastError();
var errorText = '$errorCode';
if (errorCode == ERROR_NOT_FOUND) {
errorText += ' Not found.';
}
dPrint('Error ($result): $errorText');
return null;
}
final cred = credPointer.value.ref;
final blob = cred.CredentialBlob.asTypedList(cred.CredentialBlobSize);
final password = utf8.decode(blob);
CredFree(credPointer.value);
free(credPointer);
return MapEntry(cred.UserName.toDartString(), password);
}
static void delete(String credentialName) {
dPrint('Deleting $credentialName');
final result =
CredDelete(credentialName.toNativeUtf16(), CRED_TYPE_GENERIC, 0);
if (result != TRUE) {
final errorCode = GetLastError();
dPrint('Error ($result): $errorCode');
return;
}
dPrint('Successfully deleted credential.');
}
}

View File

@ -0,0 +1,62 @@
class AppAdvancedLocalizationData {
AppAdvancedLocalizationData({
this.classKeys,
});
AppAdvancedLocalizationData.fromJson(dynamic json) {
if (json['class_keys'] != null) {
classKeys = [];
json['class_keys'].forEach((v) {
classKeys?.add(AppAdvancedLocalizationClassKeysData.fromJson(v));
});
}
}
List<AppAdvancedLocalizationClassKeysData>? classKeys;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (classKeys != null) {
map['class_keys'] = classKeys?.map((v) => v.toJson()).toList();
}
return map;
}
}
class AppAdvancedLocalizationClassKeysData {
AppAdvancedLocalizationClassKeysData({
this.id,
this.className,
this.keys,
});
AppAdvancedLocalizationClassKeysData.fromJson(dynamic json) {
id = json['id'];
className = json['class_name'];
keys = json['keys'] != null ? json['keys'].cast<String>() : [];
}
String? id;
String? className;
List<String>? keys;
Map<String, String> valuesMap = {};
AppAdvancedLocalizationClassKeysDataMode mode =
AppAdvancedLocalizationClassKeysDataMode.localization;
bool lockMod = false;
bool isWorking = false;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['class_name'] = className;
map['keys'] = keys;
return map;
}
}
enum AppAdvancedLocalizationClassKeysDataMode {
unLocalization,
localization,
mixed,
mixedNewline,
}

View File

@ -0,0 +1,28 @@
/// name : "Data.p4k"
/// update_at : "2024-02-24 18:00"
/// url : "https://p4k.42kit.com/3.22.1-LIVE.9072370/Data.p4k.torrent"
class AppTorrentData {
AppTorrentData({
this.name,
this.updateAt,
this.url,});
AppTorrentData.fromJson(dynamic json) {
name = json['name'];
updateAt = json['update_at'];
url = json['url'];
}
String? name;
String? updateAt;
String? url;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['name'] = name;
map['update_at'] = updateAt;
map['url'] = url;
return map;
}
}

View File

@ -0,0 +1,60 @@
/// name : "Data\\Textures\\planets\\surface\\ground\\architecture\\city\\city_suburbs_02_displ.dds.6"
/// size : 524288
/// compressedSize : 169812
/// isDirectory : false
/// isFile : true
/// isEncrypted : false
/// isUnicodeText : false
/// dateTime : "2019-12-16T15:11:18"
/// version : 45
class AppUnp4kP4kItemData {
AppUnp4kP4kItemData({
this.name,
this.size,
this.compressedSize,
this.isDirectory,
this.isFile,
this.isEncrypted,
this.isUnicodeText,
this.dateTime,
this.version,
});
AppUnp4kP4kItemData.fromJson(dynamic json) {
name = json['name'];
size = json['size'];
compressedSize = json['compressedSize'];
isDirectory = json['isDirectory'];
isFile = json['isFile'];
isEncrypted = json['isEncrypted'];
isUnicodeText = json['isUnicodeText'];
dateTime = json['dateTime'];
version = json['version'];
}
String? name;
num? size;
num? compressedSize;
bool? isDirectory;
bool? isFile;
bool? isEncrypted;
bool? isUnicodeText;
String? dateTime;
num? version;
List<AppUnp4kP4kItemData> children = [];
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['name'] = name;
map['size'] = size;
map['compressedSize'] = compressedSize;
map['isDirectory'] = isDirectory;
map['isFile'] = isFile;
map['isEncrypted'] = isEncrypted;
map['isUnicodeText'] = isUnicodeText;
map['dateTime'] = dateTime;
map['version'] = version;
return map;
}
}

View File

@ -0,0 +1,107 @@
class RsiGameLibraryData {
RsiGameLibraryData({
this.games,
});
RsiGameLibraryData.fromJson(dynamic json) {
if (json['games'] != null) {
games = [];
json['games'].forEach((v) {
games?.add(RsiGameLibraryGamesData.fromJson(v));
});
}
}
List<RsiGameLibraryGamesData>? games;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (games != null) {
map['games'] = games?.map((v) => v.toJson()).toList();
}
return map;
}
}
class RsiGameLibraryGamesData {
RsiGameLibraryGamesData({
this.id,
this.name,
this.channels,
});
RsiGameLibraryGamesData.fromJson(dynamic json) {
id = json['id'];
name = json['name'];
if (json['channels'] != null) {
channels = [];
json['channels'].forEach((v) {
channels?.add(RsiGameLibraryChannelsData.fromJson(v));
});
}
}
String? id;
String? name;
List<RsiGameLibraryChannelsData>? channels;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['name'] = name;
if (channels != null) {
map['channels'] = channels?.map((v) => v.toJson()).toList();
}
return map;
}
}
class RsiGameLibraryChannelsData {
RsiGameLibraryChannelsData({
this.id,
this.name,
this.version,
this.versionLabel,
this.servicesEndpoint,
this.network,
this.platformId,
this.nid,
this.weight,
});
RsiGameLibraryChannelsData.fromJson(dynamic json) {
id = json['id'];
name = json['name'];
version = json['version'];
versionLabel = json['versionLabel'];
servicesEndpoint = json['servicesEndpoint'];
network = json['network'];
platformId = json['platformId'];
nid = json['nid'];
weight = json['weight'];
}
String? id;
String? name;
num? version;
String? versionLabel;
String? servicesEndpoint;
dynamic network;
String? platformId;
String? nid;
dynamic weight;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['name'] = name;
map['version'] = version;
map['versionLabel'] = versionLabel;
map['servicesEndpoint'] = servicesEndpoint;
map['network'] = network;
map['platformId'] = platformId;
map['nid'] = nid;
map['weight'] = weight;
return map;
}
}

View File

@ -1,159 +0,0 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
import 'chat.pbenum.dart';
export 'chat.pbenum.dart';
class ChatMessage extends $pb.GeneratedMessage {
factory ChatMessage({
$core.String? senderID,
$core.String? receiverID,
ReceiverType? receiverType,
MessageType? messageType,
$core.String? data,
}) {
final $result = create();
if (senderID != null) {
$result.senderID = senderID;
}
if (receiverID != null) {
$result.receiverID = receiverID;
}
if (receiverType != null) {
$result.receiverType = receiverType;
}
if (messageType != null) {
$result.messageType = messageType;
}
if (data != null) {
$result.data = data;
}
return $result;
}
ChatMessage._() : super();
factory ChatMessage.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory ChatMessage.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'ChatMessage',
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'senderID', protoName: 'senderID')
..aOS(2, _omitFieldNames ? '' : 'receiverID', protoName: 'receiverID')
..e<ReceiverType>(
3, _omitFieldNames ? '' : 'receiverType', $pb.PbFieldType.OE,
protoName: 'receiverType',
defaultOrMaker: ReceiverType.RoomMsg,
valueOf: ReceiverType.valueOf,
enumValues: ReceiverType.values)
..e<MessageType>(
4, _omitFieldNames ? '' : 'messageType', $pb.PbFieldType.OE,
protoName: 'messageType',
defaultOrMaker: MessageType.System,
valueOf: MessageType.valueOf,
enumValues: MessageType.values)
..aOS(5, _omitFieldNames ? '' : 'data')
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
ChatMessage clone() => ChatMessage()..mergeFromMessage(this);
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
ChatMessage copyWith(void Function(ChatMessage) updates) =>
super.copyWith((message) => updates(message as ChatMessage))
as ChatMessage;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static ChatMessage create() => ChatMessage._();
ChatMessage createEmptyInstance() => create();
static $pb.PbList<ChatMessage> createRepeated() => $pb.PbList<ChatMessage>();
@$core.pragma('dart2js:noInline')
static ChatMessage getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<ChatMessage>(create);
static ChatMessage? _defaultInstance;
@$pb.TagNumber(1)
$core.String get senderID => $_getSZ(0);
@$pb.TagNumber(1)
set senderID($core.String v) {
$_setString(0, v);
}
@$pb.TagNumber(1)
$core.bool hasSenderID() => $_has(0);
@$pb.TagNumber(1)
void clearSenderID() => clearField(1);
@$pb.TagNumber(2)
$core.String get receiverID => $_getSZ(1);
@$pb.TagNumber(2)
set receiverID($core.String v) {
$_setString(1, v);
}
@$pb.TagNumber(2)
$core.bool hasReceiverID() => $_has(1);
@$pb.TagNumber(2)
void clearReceiverID() => clearField(2);
@$pb.TagNumber(3)
ReceiverType get receiverType => $_getN(2);
@$pb.TagNumber(3)
set receiverType(ReceiverType v) {
setField(3, v);
}
@$pb.TagNumber(3)
$core.bool hasReceiverType() => $_has(2);
@$pb.TagNumber(3)
void clearReceiverType() => clearField(3);
@$pb.TagNumber(4)
MessageType get messageType => $_getN(3);
@$pb.TagNumber(4)
set messageType(MessageType v) {
setField(4, v);
}
@$pb.TagNumber(4)
$core.bool hasMessageType() => $_has(3);
@$pb.TagNumber(4)
void clearMessageType() => clearField(4);
@$pb.TagNumber(5)
$core.String get data => $_getSZ(4);
@$pb.TagNumber(5)
set data($core.String v) {
$_setString(4, v);
}
@$pb.TagNumber(5)
$core.bool hasData() => $_has(4);
@$pb.TagNumber(5)
void clearData() => clearField(5);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
const _omitMessageNames =
$core.bool.fromEnvironment('protobuf.omit_message_names');

View File

@ -1,58 +0,0 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class ReceiverType extends $pb.ProtobufEnum {
static const ReceiverType RoomMsg =
ReceiverType._(0, _omitEnumNames ? '' : 'RoomMsg');
static const ReceiverType PrivateMsg =
ReceiverType._(1, _omitEnumNames ? '' : 'PrivateMsg');
static const $core.List<ReceiverType> values = <ReceiverType>[
RoomMsg,
PrivateMsg,
];
static final $core.Map<$core.int, ReceiverType> _byValue =
$pb.ProtobufEnum.initByValue(values);
static ReceiverType? valueOf($core.int value) => _byValue[value];
const ReceiverType._($core.int v, $core.String n) : super(v, n);
}
class MessageType extends $pb.ProtobufEnum {
static const MessageType System =
MessageType._(0, _omitEnumNames ? '' : 'System');
static const MessageType Text =
MessageType._(1, _omitEnumNames ? '' : 'Text');
static const MessageType Image =
MessageType._(2, _omitEnumNames ? '' : 'Image');
static const MessageType Markdown =
MessageType._(3, _omitEnumNames ? '' : 'Markdown');
static const $core.List<MessageType> values = <MessageType>[
System,
Text,
Image,
Markdown,
];
static final $core.Map<$core.int, MessageType> _byValue =
$pb.ProtobufEnum.initByValue(values);
static MessageType? valueOf($core.int value) => _byValue[value];
const MessageType._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

View File

@ -1,88 +0,0 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:async' as $async;
import 'dart:core' as $core;
import 'package:grpc/service_api.dart' as $grpc;
import 'package:protobuf/protobuf.dart' as $pb;
import 'chat.pb.dart' as $1;
import 'index.pb.dart' as $0;
export 'chat.pb.dart';
@$pb.GrpcServiceName('ChatService')
class ChatServiceClient extends $grpc.Client {
static final _$listenMessage = $grpc.ClientMethod<$0.PreUser, $1.ChatMessage>(
'/ChatService/ListenMessage',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $1.ChatMessage.fromBuffer(value));
static final _$sendMessage =
$grpc.ClientMethod<$1.ChatMessage, $0.BaseRespData>(
'/ChatService/SendMessage',
($1.ChatMessage value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.BaseRespData.fromBuffer(value));
ChatServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions? options,
$core.Iterable<$grpc.ClientInterceptor>? interceptors})
: super(channel, options: options, interceptors: interceptors);
$grpc.ResponseStream<$1.ChatMessage> listenMessage($0.PreUser request,
{$grpc.CallOptions? options}) {
return $createStreamingCall(
_$listenMessage, $async.Stream.fromIterable([request]),
options: options);
}
$grpc.ResponseFuture<$0.BaseRespData> sendMessage($1.ChatMessage request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$sendMessage, request, options: options);
}
}
@$pb.GrpcServiceName('ChatService')
abstract class ChatServiceBase extends $grpc.Service {
$core.String get $name => 'ChatService';
ChatServiceBase() {
$addMethod($grpc.ServiceMethod<$0.PreUser, $1.ChatMessage>(
'ListenMessage',
listenMessage_Pre,
false,
true,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($1.ChatMessage value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$1.ChatMessage, $0.BaseRespData>(
'SendMessage',
sendMessage_Pre,
false,
false,
($core.List<$core.int> value) => $1.ChatMessage.fromBuffer(value),
($0.BaseRespData value) => value.writeToBuffer()));
}
$async.Stream<$1.ChatMessage> listenMessage_Pre(
$grpc.ServiceCall call, $async.Future<$0.PreUser> request) async* {
yield* listenMessage(call, await request);
}
$async.Future<$0.BaseRespData> sendMessage_Pre(
$grpc.ServiceCall call, $async.Future<$1.ChatMessage> request) async {
return sendMessage(call, await request);
}
$async.Stream<$1.ChatMessage> listenMessage(
$grpc.ServiceCall call, $0.PreUser request);
$async.Future<$0.BaseRespData> sendMessage(
$grpc.ServiceCall call, $1.ChatMessage request);
}

View File

@ -1,76 +0,0 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use receiverTypeDescriptor instead')
const ReceiverType$json = {
'1': 'ReceiverType',
'2': [
{'1': 'RoomMsg', '2': 0},
{'1': 'PrivateMsg', '2': 1},
],
};
/// Descriptor for `ReceiverType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List receiverTypeDescriptor = $convert.base64Decode(
'CgxSZWNlaXZlclR5cGUSCwoHUm9vbU1zZxAAEg4KClByaXZhdGVNc2cQAQ==');
@$core.Deprecated('Use messageTypeDescriptor instead')
const MessageType$json = {
'1': 'MessageType',
'2': [
{'1': 'System', '2': 0},
{'1': 'Text', '2': 1},
{'1': 'Image', '2': 2},
{'1': 'Markdown', '2': 3},
],
};
/// Descriptor for `MessageType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List messageTypeDescriptor = $convert.base64Decode(
'CgtNZXNzYWdlVHlwZRIKCgZTeXN0ZW0QABIICgRUZXh0EAESCQoFSW1hZ2UQAhIMCghNYXJrZG'
'93bhAD');
@$core.Deprecated('Use chatMessageDescriptor instead')
const ChatMessage$json = {
'1': 'ChatMessage',
'2': [
{'1': 'senderID', '3': 1, '4': 1, '5': 9, '10': 'senderID'},
{'1': 'receiverID', '3': 2, '4': 1, '5': 9, '10': 'receiverID'},
{
'1': 'receiverType',
'3': 3,
'4': 1,
'5': 14,
'6': '.ReceiverType',
'10': 'receiverType'
},
{
'1': 'messageType',
'3': 4,
'4': 1,
'5': 14,
'6': '.MessageType',
'10': 'messageType'
},
{'1': 'data', '3': 5, '4': 1, '5': 9, '10': 'data'},
],
};
/// Descriptor for `ChatMessage`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List chatMessageDescriptor = $convert.base64Decode(
'CgtDaGF0TWVzc2FnZRIaCghzZW5kZXJJRBgBIAEoCVIIc2VuZGVySUQSHgoKcmVjZWl2ZXJJRB'
'gCIAEoCVIKcmVjZWl2ZXJJRBIxCgxyZWNlaXZlclR5cGUYAyABKA4yDS5SZWNlaXZlclR5cGVS'
'DHJlY2VpdmVyVHlwZRIuCgttZXNzYWdlVHlwZRgEIAEoDjIMLk1lc3NhZ2VUeXBlUgttZXNzYW'
'dlVHlwZRISCgRkYXRhGAUgASgJUgRkYXRh');

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
//
// Generated code. Do not modify.
// source: index.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class RoomStatus extends $pb.ProtobufEnum {
static const RoomStatus All = RoomStatus._(0, _omitEnumNames ? '' : 'All');
static const RoomStatus Open = RoomStatus._(1, _omitEnumNames ? '' : 'Open');
static const RoomStatus Private =
RoomStatus._(2, _omitEnumNames ? '' : 'Private');
static const RoomStatus Full = RoomStatus._(3, _omitEnumNames ? '' : 'Full');
static const RoomStatus Closed =
RoomStatus._(4, _omitEnumNames ? '' : 'Closed');
static const RoomStatus WillOffline =
RoomStatus._(5, _omitEnumNames ? '' : 'WillOffline');
static const RoomStatus Offline =
RoomStatus._(6, _omitEnumNames ? '' : 'Offline');
static const $core.List<RoomStatus> values = <RoomStatus>[
All,
Open,
Private,
Full,
Closed,
WillOffline,
Offline,
];
static final $core.Map<$core.int, RoomStatus> _byValue =
$pb.ProtobufEnum.initByValue(values);
static RoomStatus? valueOf($core.int value) => _byValue[value];
const RoomStatus._($core.int v, $core.String n) : super(v, n);
}
class RoomSortType extends $pb.ProtobufEnum {
static const RoomSortType Default =
RoomSortType._(0, _omitEnumNames ? '' : 'Default');
static const RoomSortType MostPlayerNumber =
RoomSortType._(1, _omitEnumNames ? '' : 'MostPlayerNumber');
static const RoomSortType MinimumPlayerNumber =
RoomSortType._(2, _omitEnumNames ? '' : 'MinimumPlayerNumber');
static const RoomSortType RecentlyCreated =
RoomSortType._(3, _omitEnumNames ? '' : 'RecentlyCreated');
static const RoomSortType OldestCreated =
RoomSortType._(4, _omitEnumNames ? '' : 'OldestCreated');
static const $core.List<RoomSortType> values = <RoomSortType>[
Default,
MostPlayerNumber,
MinimumPlayerNumber,
RecentlyCreated,
OldestCreated,
];
static final $core.Map<$core.int, RoomSortType> _byValue =
$pb.ProtobufEnum.initByValue(values);
static RoomSortType? valueOf($core.int value) => _byValue[value];
const RoomSortType._($core.int v, $core.String n) : super(v, n);
}
class RoomUserStatus extends $pb.ProtobufEnum {
static const RoomUserStatus RoomUserStatusJoin =
RoomUserStatus._(0, _omitEnumNames ? '' : 'RoomUserStatusJoin');
static const RoomUserStatus RoomUserStatusLostOffline =
RoomUserStatus._(1, _omitEnumNames ? '' : 'RoomUserStatusLostOffline');
static const RoomUserStatus RoomUserStatusLeave =
RoomUserStatus._(2, _omitEnumNames ? '' : 'RoomUserStatusLeave');
static const RoomUserStatus RoomUserStatusWaitingConnect =
RoomUserStatus._(3, _omitEnumNames ? '' : 'RoomUserStatusWaitingConnect');
static const $core.List<RoomUserStatus> values = <RoomUserStatus>[
RoomUserStatusJoin,
RoomUserStatusLostOffline,
RoomUserStatusLeave,
RoomUserStatusWaitingConnect,
];
static final $core.Map<$core.int, RoomUserStatus> _byValue =
$pb.ProtobufEnum.initByValue(values);
static RoomUserStatus? valueOf($core.int value) => _byValue[value];
const RoomUserStatus._($core.int v, $core.String n) : super(v, n);
}
class RoomUpdateType extends $pb.ProtobufEnum {
static const RoomUpdateType RoomUpdateData =
RoomUpdateType._(0, _omitEnumNames ? '' : 'RoomUpdateData');
static const RoomUpdateType RoomClose =
RoomUpdateType._(1, _omitEnumNames ? '' : 'RoomClose');
static const $core.List<RoomUpdateType> values = <RoomUpdateType>[
RoomUpdateData,
RoomClose,
];
static final $core.Map<$core.int, RoomUpdateType> _byValue =
$pb.ProtobufEnum.initByValue(values);
static RoomUpdateType? valueOf($core.int value) => _byValue[value];
const RoomUpdateType._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

View File

@ -1,206 +0,0 @@
//
// Generated code. Do not modify.
// source: index.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:async' as $async;
import 'dart:core' as $core;
import 'package:grpc/service_api.dart' as $grpc;
import 'package:protobuf/protobuf.dart' as $pb;
import 'index.pb.dart' as $0;
export 'index.pb.dart';
@$pb.GrpcServiceName('IndexService')
class IndexServiceClient extends $grpc.Client {
static final _$pingServer = $grpc.ClientMethod<$0.PingData, $0.PingData>(
'/IndexService/PingServer',
($0.PingData value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.PingData.fromBuffer(value));
static final _$getRoomTypes = $grpc.ClientMethod<$0.Empty, $0.RoomTypesData>(
'/IndexService/GetRoomTypes',
($0.Empty value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomTypesData.fromBuffer(value));
static final _$createRoom = $grpc.ClientMethod<$0.RoomData, $0.RoomData>(
'/IndexService/CreateRoom',
($0.RoomData value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomData.fromBuffer(value));
static final _$getRoomList =
$grpc.ClientMethod<$0.RoomListPageReqData, $0.RoomListData>(
'/IndexService/GetRoomList',
($0.RoomListPageReqData value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomListData.fromBuffer(value));
static final _$touchUser = $grpc.ClientMethod<$0.PreUser, $0.RoomData>(
'/IndexService/TouchUser',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomData.fromBuffer(value));
static final _$joinRoom =
$grpc.ClientMethod<$0.PreUser, $0.RoomUpdateMessage>(
'/IndexService/JoinRoom',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) =>
$0.RoomUpdateMessage.fromBuffer(value));
static final _$leaveRoom = $grpc.ClientMethod<$0.PreUser, $0.BaseRespData>(
'/IndexService/LeaveRoom',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.BaseRespData.fromBuffer(value));
IndexServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions? options,
$core.Iterable<$grpc.ClientInterceptor>? interceptors})
: super(channel, options: options, interceptors: interceptors);
$grpc.ResponseFuture<$0.PingData> pingServer($0.PingData request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$pingServer, request, options: options);
}
$grpc.ResponseFuture<$0.RoomTypesData> getRoomTypes($0.Empty request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$getRoomTypes, request, options: options);
}
$grpc.ResponseFuture<$0.RoomData> createRoom($0.RoomData request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$createRoom, request, options: options);
}
$grpc.ResponseFuture<$0.RoomListData> getRoomList(
$0.RoomListPageReqData request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$getRoomList, request, options: options);
}
$grpc.ResponseFuture<$0.RoomData> touchUser($0.PreUser request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$touchUser, request, options: options);
}
$grpc.ResponseStream<$0.RoomUpdateMessage> joinRoom($0.PreUser request,
{$grpc.CallOptions? options}) {
return $createStreamingCall(
_$joinRoom, $async.Stream.fromIterable([request]),
options: options);
}
$grpc.ResponseFuture<$0.BaseRespData> leaveRoom($0.PreUser request,
{$grpc.CallOptions? options}) {
return $createUnaryCall(_$leaveRoom, request, options: options);
}
}
@$pb.GrpcServiceName('IndexService')
abstract class IndexServiceBase extends $grpc.Service {
$core.String get $name => 'IndexService';
IndexServiceBase() {
$addMethod($grpc.ServiceMethod<$0.PingData, $0.PingData>(
'PingServer',
pingServer_Pre,
false,
false,
($core.List<$core.int> value) => $0.PingData.fromBuffer(value),
($0.PingData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.Empty, $0.RoomTypesData>(
'GetRoomTypes',
getRoomTypes_Pre,
false,
false,
($core.List<$core.int> value) => $0.Empty.fromBuffer(value),
($0.RoomTypesData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.RoomData, $0.RoomData>(
'CreateRoom',
createRoom_Pre,
false,
false,
($core.List<$core.int> value) => $0.RoomData.fromBuffer(value),
($0.RoomData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.RoomListPageReqData, $0.RoomListData>(
'GetRoomList',
getRoomList_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.RoomListPageReqData.fromBuffer(value),
($0.RoomListData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.RoomData>(
'TouchUser',
touchUser_Pre,
false,
false,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.RoomData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.RoomUpdateMessage>(
'JoinRoom',
joinRoom_Pre,
false,
true,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.RoomUpdateMessage value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.BaseRespData>(
'LeaveRoom',
leaveRoom_Pre,
false,
false,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.BaseRespData value) => value.writeToBuffer()));
}
$async.Future<$0.PingData> pingServer_Pre(
$grpc.ServiceCall call, $async.Future<$0.PingData> request) async {
return pingServer(call, await request);
}
$async.Future<$0.RoomTypesData> getRoomTypes_Pre(
$grpc.ServiceCall call, $async.Future<$0.Empty> request) async {
return getRoomTypes(call, await request);
}
$async.Future<$0.RoomData> createRoom_Pre(
$grpc.ServiceCall call, $async.Future<$0.RoomData> request) async {
return createRoom(call, await request);
}
$async.Future<$0.RoomListData> getRoomList_Pre($grpc.ServiceCall call,
$async.Future<$0.RoomListPageReqData> request) async {
return getRoomList(call, await request);
}
$async.Future<$0.RoomData> touchUser_Pre(
$grpc.ServiceCall call, $async.Future<$0.PreUser> request) async {
return touchUser(call, await request);
}
$async.Stream<$0.RoomUpdateMessage> joinRoom_Pre(
$grpc.ServiceCall call, $async.Future<$0.PreUser> request) async* {
yield* joinRoom(call, await request);
}
$async.Future<$0.BaseRespData> leaveRoom_Pre(
$grpc.ServiceCall call, $async.Future<$0.PreUser> request) async {
return leaveRoom(call, await request);
}
$async.Future<$0.PingData> pingServer(
$grpc.ServiceCall call, $0.PingData request);
$async.Future<$0.RoomTypesData> getRoomTypes(
$grpc.ServiceCall call, $0.Empty request);
$async.Future<$0.RoomData> createRoom(
$grpc.ServiceCall call, $0.RoomData request);
$async.Future<$0.RoomListData> getRoomList(
$grpc.ServiceCall call, $0.RoomListPageReqData request);
$async.Future<$0.RoomData> touchUser(
$grpc.ServiceCall call, $0.PreUser request);
$async.Stream<$0.RoomUpdateMessage> joinRoom(
$grpc.ServiceCall call, $0.PreUser request);
$async.Future<$0.BaseRespData> leaveRoom(
$grpc.ServiceCall call, $0.PreUser request);
}

View File

@ -1,354 +0,0 @@
//
// Generated code. Do not modify.
// source: index.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use roomStatusDescriptor instead')
const RoomStatus$json = {
'1': 'RoomStatus',
'2': [
{'1': 'All', '2': 0},
{'1': 'Open', '2': 1},
{'1': 'Private', '2': 2},
{'1': 'Full', '2': 3},
{'1': 'Closed', '2': 4},
{'1': 'WillOffline', '2': 5},
{'1': 'Offline', '2': 6},
],
};
/// Descriptor for `RoomStatus`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomStatusDescriptor = $convert.base64Decode(
'CgpSb29tU3RhdHVzEgcKA0FsbBAAEggKBE9wZW4QARILCgdQcml2YXRlEAISCAoERnVsbBADEg'
'oKBkNsb3NlZBAEEg8KC1dpbGxPZmZsaW5lEAUSCwoHT2ZmbGluZRAG');
@$core.Deprecated('Use roomSortTypeDescriptor instead')
const RoomSortType$json = {
'1': 'RoomSortType',
'2': [
{'1': 'Default', '2': 0},
{'1': 'MostPlayerNumber', '2': 1},
{'1': 'MinimumPlayerNumber', '2': 2},
{'1': 'RecentlyCreated', '2': 3},
{'1': 'OldestCreated', '2': 4},
],
};
/// Descriptor for `RoomSortType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomSortTypeDescriptor = $convert.base64Decode(
'CgxSb29tU29ydFR5cGUSCwoHRGVmYXVsdBAAEhQKEE1vc3RQbGF5ZXJOdW1iZXIQARIXChNNaW'
'5pbXVtUGxheWVyTnVtYmVyEAISEwoPUmVjZW50bHlDcmVhdGVkEAMSEQoNT2xkZXN0Q3JlYXRl'
'ZBAE');
@$core.Deprecated('Use roomUserStatusDescriptor instead')
const RoomUserStatus$json = {
'1': 'RoomUserStatus',
'2': [
{'1': 'RoomUserStatusJoin', '2': 0},
{'1': 'RoomUserStatusLostOffline', '2': 1},
{'1': 'RoomUserStatusLeave', '2': 2},
{'1': 'RoomUserStatusWaitingConnect', '2': 3},
],
};
/// Descriptor for `RoomUserStatus`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomUserStatusDescriptor = $convert.base64Decode(
'Cg5Sb29tVXNlclN0YXR1cxIWChJSb29tVXNlclN0YXR1c0pvaW4QABIdChlSb29tVXNlclN0YX'
'R1c0xvc3RPZmZsaW5lEAESFwoTUm9vbVVzZXJTdGF0dXNMZWF2ZRACEiAKHFJvb21Vc2VyU3Rh'
'dHVzV2FpdGluZ0Nvbm5lY3QQAw==');
@$core.Deprecated('Use roomUpdateTypeDescriptor instead')
const RoomUpdateType$json = {
'1': 'RoomUpdateType',
'2': [
{'1': 'RoomUpdateData', '2': 0},
{'1': 'RoomClose', '2': 1},
],
};
/// Descriptor for `RoomUpdateType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomUpdateTypeDescriptor = $convert.base64Decode(
'Cg5Sb29tVXBkYXRlVHlwZRISCg5Sb29tVXBkYXRlRGF0YRAAEg0KCVJvb21DbG9zZRAB');
@$core.Deprecated('Use emptyDescriptor instead')
const Empty$json = {
'1': 'Empty',
};
/// Descriptor for `Empty`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List emptyDescriptor =
$convert.base64Decode('CgVFbXB0eQ==');
@$core.Deprecated('Use baseRespDataDescriptor instead')
const BaseRespData$json = {
'1': 'BaseRespData',
'2': [
{'1': 'code', '3': 1, '4': 1, '5': 5, '10': 'code'},
{'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'},
],
};
/// Descriptor for `BaseRespData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List baseRespDataDescriptor = $convert.base64Decode(
'CgxCYXNlUmVzcERhdGESEgoEY29kZRgBIAEoBVIEY29kZRIYCgdtZXNzYWdlGAIgASgJUgdtZX'
'NzYWdl');
@$core.Deprecated('Use basePageRespDataDescriptor instead')
const BasePageRespData$json = {
'1': 'BasePageRespData',
'2': [
{'1': 'code', '3': 1, '4': 1, '5': 5, '10': 'code'},
{'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'},
{'1': 'hasNext', '3': 3, '4': 1, '5': 8, '10': 'hasNext'},
{'1': 'curPageNum', '3': 4, '4': 1, '5': 4, '10': 'curPageNum'},
{'1': 'pageSize', '3': 5, '4': 1, '5': 3, '10': 'pageSize'},
],
};
/// Descriptor for `BasePageRespData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List basePageRespDataDescriptor = $convert.base64Decode(
'ChBCYXNlUGFnZVJlc3BEYXRhEhIKBGNvZGUYASABKAVSBGNvZGUSGAoHbWVzc2FnZRgCIAEoCV'
'IHbWVzc2FnZRIYCgdoYXNOZXh0GAMgASgIUgdoYXNOZXh0Eh4KCmN1clBhZ2VOdW0YBCABKARS'
'CmN1clBhZ2VOdW0SGgoIcGFnZVNpemUYBSABKANSCHBhZ2VTaXpl');
@$core.Deprecated('Use pingDataDescriptor instead')
const PingData$json = {
'1': 'PingData',
'2': [
{'1': 'data', '3': 1, '4': 1, '5': 9, '10': 'data'},
{'1': 'clientVersion', '3': 2, '4': 1, '5': 18, '10': 'clientVersion'},
{'1': 'serverVersion', '3': 3, '4': 1, '5': 18, '10': 'serverVersion'},
],
};
/// Descriptor for `PingData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List pingDataDescriptor = $convert.base64Decode(
'CghQaW5nRGF0YRISCgRkYXRhGAEgASgJUgRkYXRhEiQKDWNsaWVudFZlcnNpb24YAiABKBJSDW'
'NsaWVudFZlcnNpb24SJAoNc2VydmVyVmVyc2lvbhgDIAEoElINc2VydmVyVmVyc2lvbg==');
@$core.Deprecated('Use roomTypesDataDescriptor instead')
const RoomTypesData$json = {
'1': 'RoomTypesData',
'2': [
{
'1': 'roomTypes',
'3': 1,
'4': 3,
'5': 11,
'6': '.RoomType',
'10': 'roomTypes'
},
],
};
/// Descriptor for `RoomTypesData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomTypesDataDescriptor = $convert.base64Decode(
'Cg1Sb29tVHlwZXNEYXRhEicKCXJvb21UeXBlcxgBIAMoCzIJLlJvb21UeXBlUglyb29tVHlwZX'
'M=');
@$core.Deprecated('Use roomTypeDescriptor instead')
const RoomType$json = {
'1': 'RoomType',
'2': [
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
{'1': 'icon', '3': 3, '4': 1, '5': 9, '10': 'icon'},
{'1': 'desc', '3': 4, '4': 1, '5': 9, '10': 'desc'},
{
'1': 'subTypes',
'3': 5,
'4': 3,
'5': 11,
'6': '.RoomSubtype',
'10': 'subTypes'
},
],
};
/// Descriptor for `RoomType`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomTypeDescriptor = $convert.base64Decode(
'CghSb29tVHlwZRIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRpY29uGA'
'MgASgJUgRpY29uEhIKBGRlc2MYBCABKAlSBGRlc2MSKAoIc3ViVHlwZXMYBSADKAsyDC5Sb29t'
'U3VidHlwZVIIc3ViVHlwZXM=');
@$core.Deprecated('Use roomSubtypeDescriptor instead')
const RoomSubtype$json = {
'1': 'RoomSubtype',
'2': [
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `RoomSubtype`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomSubtypeDescriptor = $convert.base64Decode(
'CgtSb29tU3VidHlwZRIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZQ==');
@$core.Deprecated('Use roomDataDescriptor instead')
const RoomData$json = {
'1': 'RoomData',
'2': [
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
{'1': 'roomTypeID', '3': 2, '4': 1, '5': 9, '10': 'roomTypeID'},
{'1': 'roomSubTypeIds', '3': 3, '4': 3, '5': 9, '10': 'roomSubTypeIds'},
{'1': 'owner', '3': 4, '4': 1, '5': 9, '10': 'owner'},
{'1': 'maxPlayer', '3': 5, '4': 1, '5': 5, '10': 'maxPlayer'},
{'1': 'createTime', '3': 6, '4': 1, '5': 3, '10': 'createTime'},
{'1': 'curPlayer', '3': 7, '4': 1, '5': 5, '10': 'curPlayer'},
{
'1': 'status',
'3': 8,
'4': 1,
'5': 14,
'6': '.RoomStatus',
'10': 'status'
},
{'1': 'deviceUUID', '3': 9, '4': 1, '5': 9, '10': 'deviceUUID'},
{'1': 'announcement', '3': 10, '4': 1, '5': 9, '10': 'announcement'},
{'1': 'avatar', '3': 11, '4': 1, '5': 9, '10': 'avatar'},
{'1': 'updateTime', '3': 12, '4': 1, '5': 3, '10': 'updateTime'},
],
};
/// Descriptor for `RoomData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomDataDescriptor = $convert.base64Decode(
'CghSb29tRGF0YRIOCgJpZBgBIAEoCVICaWQSHgoKcm9vbVR5cGVJRBgCIAEoCVIKcm9vbVR5cG'
'VJRBImCg5yb29tU3ViVHlwZUlkcxgDIAMoCVIOcm9vbVN1YlR5cGVJZHMSFAoFb3duZXIYBCAB'
'KAlSBW93bmVyEhwKCW1heFBsYXllchgFIAEoBVIJbWF4UGxheWVyEh4KCmNyZWF0ZVRpbWUYBi'
'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz'
'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV'
'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQSFgoGYXZhdGFyGAsgASgJ'
'UgZhdmF0YXISHgoKdXBkYXRlVGltZRgMIAEoA1IKdXBkYXRlVGltZQ==');
@$core.Deprecated('Use roomListPageReqDataDescriptor instead')
const RoomListPageReqData$json = {
'1': 'RoomListPageReqData',
'2': [
{'1': 'typeID', '3': 1, '4': 1, '5': 9, '10': 'typeID'},
{'1': 'subTypeID', '3': 2, '4': 1, '5': 9, '10': 'subTypeID'},
{
'1': 'status',
'3': 3,
'4': 1,
'5': 14,
'6': '.RoomStatus',
'10': 'status'
},
{'1': 'sort', '3': 4, '4': 1, '5': 14, '6': '.RoomSortType', '10': 'sort'},
{'1': 'pageNum', '3': 5, '4': 1, '5': 4, '10': 'pageNum'},
],
};
/// Descriptor for `RoomListPageReqData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomListPageReqDataDescriptor = $convert.base64Decode(
'ChNSb29tTGlzdFBhZ2VSZXFEYXRhEhYKBnR5cGVJRBgBIAEoCVIGdHlwZUlEEhwKCXN1YlR5cG'
'VJRBgCIAEoCVIJc3ViVHlwZUlEEiMKBnN0YXR1cxgDIAEoDjILLlJvb21TdGF0dXNSBnN0YXR1'
'cxIhCgRzb3J0GAQgASgOMg0uUm9vbVNvcnRUeXBlUgRzb3J0EhgKB3BhZ2VOdW0YBSABKARSB3'
'BhZ2VOdW0=');
@$core.Deprecated('Use roomListDataDescriptor instead')
const RoomListData$json = {
'1': 'RoomListData',
'2': [
{
'1': 'pageData',
'3': 1,
'4': 1,
'5': 11,
'6': '.BasePageRespData',
'10': 'pageData'
},
{'1': 'rooms', '3': 2, '4': 3, '5': 11, '6': '.RoomData', '10': 'rooms'},
],
};
/// Descriptor for `RoomListData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomListDataDescriptor = $convert.base64Decode(
'CgxSb29tTGlzdERhdGESLQoIcGFnZURhdGEYASABKAsyES5CYXNlUGFnZVJlc3BEYXRhUghwYW'
'dlRGF0YRIfCgVyb29tcxgCIAMoCzIJLlJvb21EYXRhUgVyb29tcw==');
@$core.Deprecated('Use preUserDescriptor instead')
const PreUser$json = {
'1': 'PreUser',
'2': [
{'1': 'userName', '3': 1, '4': 1, '5': 9, '10': 'userName'},
{'1': 'deviceUUID', '3': 2, '4': 1, '5': 9, '10': 'deviceUUID'},
{'1': 'roomID', '3': 3, '4': 1, '5': 9, '10': 'roomID'},
],
};
/// Descriptor for `PreUser`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List preUserDescriptor = $convert.base64Decode(
'CgdQcmVVc2VyEhoKCHVzZXJOYW1lGAEgASgJUgh1c2VyTmFtZRIeCgpkZXZpY2VVVUlEGAIgAS'
'gJUgpkZXZpY2VVVUlEEhYKBnJvb21JRBgDIAEoCVIGcm9vbUlE');
@$core.Deprecated('Use roomUserDataDescriptor instead')
const RoomUserData$json = {
'1': 'RoomUserData',
'2': [
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
{'1': 'playerName', '3': 2, '4': 1, '5': 9, '10': 'playerName'},
{'1': 'Avatar', '3': 3, '4': 1, '5': 9, '10': 'Avatar'},
{
'1': 'status',
'3': 4,
'4': 1,
'5': 14,
'6': '.RoomUserStatus',
'10': 'status'
},
],
};
/// Descriptor for `RoomUserData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomUserDataDescriptor = $convert.base64Decode(
'CgxSb29tVXNlckRhdGESDgoCaWQYASABKAlSAmlkEh4KCnBsYXllck5hbWUYAiABKAlSCnBsYX'
'llck5hbWUSFgoGQXZhdGFyGAMgASgJUgZBdmF0YXISJwoGc3RhdHVzGAQgASgOMg8uUm9vbVVz'
'ZXJTdGF0dXNSBnN0YXR1cw==');
@$core.Deprecated('Use roomUpdateMessageDescriptor instead')
const RoomUpdateMessage$json = {
'1': 'RoomUpdateMessage',
'2': [
{
'1': 'roomData',
'3': 1,
'4': 1,
'5': 11,
'6': '.RoomData',
'10': 'roomData'
},
{
'1': 'usersData',
'3': 2,
'4': 3,
'5': 11,
'6': '.RoomUserData',
'10': 'usersData'
},
{
'1': 'roomUpdateType',
'3': 3,
'4': 1,
'5': 14,
'6': '.RoomUpdateType',
'10': 'roomUpdateType'
},
],
};
/// Descriptor for `RoomUpdateMessage`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomUpdateMessageDescriptor = $convert.base64Decode(
'ChFSb29tVXBkYXRlTWVzc2FnZRIlCghyb29tRGF0YRgBIAEoCzIJLlJvb21EYXRhUghyb29tRG'
'F0YRIrCgl1c2Vyc0RhdGEYAiADKAsyDS5Sb29tVXNlckRhdGFSCXVzZXJzRGF0YRI3Cg5yb29t'
'VXBkYXRlVHlwZRgDIAEoDjIPLlJvb21VcGRhdGVUeXBlUg5yb29tVXBkYXRlVHlwZQ==');

View File

@ -0,0 +1,75 @@
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that looks up messages for specific locales by
// delegating to the appropriate library.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:implementation_imports, file_names, unnecessary_new
// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
// ignore_for_file:argument_type_not_assignable, invalid_assignment
// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
// ignore_for_file:comment_references
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
import 'messages_en.dart' as messages_en;
import 'messages_ja.dart' as messages_ja;
import 'messages_zh_CN.dart' as messages_zh_cn;
import 'messages_zh_TW.dart' as messages_zh_tw;
typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en': () => new SynchronousFuture(null),
'ja': () => new SynchronousFuture(null),
'zh_CN': () => new SynchronousFuture(null),
'zh_TW': () => new SynchronousFuture(null),
};
MessageLookupByLibrary? _findExact(String localeName) {
switch (localeName) {
case 'en':
return messages_en.messages;
case 'ja':
return messages_ja.messages;
case 'zh_CN':
return messages_zh_cn.messages;
case 'zh_TW':
return messages_zh_tw.messages;
default:
return null;
}
}
/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) {
var availableLocale = Intl.verifiedLocale(
localeName, (locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new SynchronousFuture(false);
}
var lib = _deferredLibraries[availableLocale];
lib == null ? new SynchronousFuture(false) : lib();
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new SynchronousFuture(true);
}
bool _messagesExistFor(String locale) {
try {
return _findExact(locale) != null;
} catch (e) {
return false;
}
}
MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
var actualLocale =
Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a ja locale. All the
// messages from the main program should be duplicated here with the same
// function name.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes
// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'ja';
static String m2(v0, v1) => "SCToolBox V ${v0} ${v1}";
static String m19(v0, v1) => "ダウンロード: ${v0}/s アップロード:${v1}/s";
static String m20(v0) => "ダウンロード済み:${v0}";
static String m21(v0) => "ダウンロード... (${v0}%)";
static String m22(v0) => "ステータス:${v0}";
static String m23(v1) => "サイズ合計:${v1}";
static String m24(v0) => "アップロード済み:${v0}";
static String m25(v2) => "検証中...${v2}";
static String m35(v1, v2) =>
"RSI サーバレポートのバージョン:${v1} \n\nローカルのバージョン:${v2} \n\nRSI Launcher を使ってゲームをアップデートしてください!";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"about_action_email":
MessageLookupByLibrary.simpleMessage("メール: xkeyc@qq.com"),
"about_action_open_source":
MessageLookupByLibrary.simpleMessage("オープンソース"),
"about_analytics_install_translation":
MessageLookupByLibrary.simpleMessage("日本語化インストール"),
"about_analytics_launch": MessageLookupByLibrary.simpleMessage("起動"),
"about_analytics_launch_game":
MessageLookupByLibrary.simpleMessage("ゲームを起動"),
"about_analytics_p4k_redirection":
MessageLookupByLibrary.simpleMessage("P4Kダウンロード"),
"about_analytics_total_users":
MessageLookupByLibrary.simpleMessage("利用者数"),
"about_analytics_units_times":
MessageLookupByLibrary.simpleMessage(""),
"about_analytics_units_user": MessageLookupByLibrary.simpleMessage(""),
"about_check_update": MessageLookupByLibrary.simpleMessage("更新チェック"),
"about_disclaimer": MessageLookupByLibrary.simpleMessage(
"これは Star Citizen の非公式ツールです、Cloud Imperium Games LLC の所有ではない。 本ソフトウェアのホストまたは使用者によって作成されていないすべての情報は、それぞれの所有者に帰属します。 \nStar Citizen®、Roberts Space Industries®、Cloud Imperium® は Cloud Imperium Rights LLC のトレードマーク。"),
"about_info_latest_version":
MessageLookupByLibrary.simpleMessage("すでに最新バージョンだ!"),
"about_online_feedback":
MessageLookupByLibrary.simpleMessage("フィードバック"),
"action_close": MessageLookupByLibrary.simpleMessage("クローズ"),
"action_open_folder": MessageLookupByLibrary.simpleMessage("フォルダを開く"),
"app_index_version_info": m2,
"app_language_code": MessageLookupByLibrary.simpleMessage("ja"),
"app_language_name": MessageLookupByLibrary.simpleMessage("日本語"),
"downloader_action_cancel_all":
MessageLookupByLibrary.simpleMessage("すべてキャンセル"),
"downloader_action_cancel_download":
MessageLookupByLibrary.simpleMessage("ダウンロードをキャンセル"),
"downloader_action_confirm_cancel_all_tasks":
MessageLookupByLibrary.simpleMessage("すべてのタスクのキャンセルを確認する?"),
"downloader_action_confirm_cancel_download":
MessageLookupByLibrary.simpleMessage("ダウンロードのキャンセルを確認しますか?"),
"downloader_action_continue_download":
MessageLookupByLibrary.simpleMessage("ダウンロードを続ける"),
"downloader_action_options":
MessageLookupByLibrary.simpleMessage("オプション"),
"downloader_action_pause_all":
MessageLookupByLibrary.simpleMessage("すべて一時停止"),
"downloader_action_pause_download":
MessageLookupByLibrary.simpleMessage("ダウンロードの一時停止"),
"downloader_action_resume_all":
MessageLookupByLibrary.simpleMessage("すべて復元"),
"downloader_info_deleted": MessageLookupByLibrary.simpleMessage("削除済み"),
"downloader_info_download_completed":
MessageLookupByLibrary.simpleMessage("ダウンロード完了"),
"downloader_info_download_failed":
MessageLookupByLibrary.simpleMessage("ダウンロード失敗"),
"downloader_info_download_upload_speed": m19,
"downloader_info_downloaded": m20,
"downloader_info_downloading": m21,
"downloader_info_downloading_status":
MessageLookupByLibrary.simpleMessage("ダウンロード中..."),
"downloader_info_manual_file_deletion_note":
MessageLookupByLibrary.simpleMessage(
"ダウンロードしたファイルが不要になった場合は、手動で削除する必要があります。"),
"downloader_info_no_download_tasks":
MessageLookupByLibrary.simpleMessage("ダウンロードタスクなし"),
"downloader_info_paused": MessageLookupByLibrary.simpleMessage("一時停止中"),
"downloader_info_status": m22,
"downloader_info_total_size": m23,
"downloader_info_uploaded": m24,
"downloader_info_verifying": m25,
"downloader_info_waiting": MessageLookupByLibrary.simpleMessage("待機中"),
"downloader_speed_limit_settings":
MessageLookupByLibrary.simpleMessage("速度制限設定"),
"downloader_title_downloading":
MessageLookupByLibrary.simpleMessage("ダウンロード中"),
"downloader_title_ended": MessageLookupByLibrary.simpleMessage("終了"),
"home_action_login_rsi_account":
MessageLookupByLibrary.simpleMessage("RSI アカウントログイン"),
"home_action_one_click_launch":
MessageLookupByLibrary.simpleMessage("ワンクリック起動"),
"home_holiday_countdown":
MessageLookupByLibrary.simpleMessage("祝日カウントダウン"),
"home_holiday_countdown_disclaimer":
MessageLookupByLibrary.simpleMessage(
"* 上記の祝日は手作業で収集・管理されているため、誤りがある可能性があります、フィードバックは歓迎する!!"),
"home_login_action_title_box_one_click_launch":
MessageLookupByLibrary.simpleMessage("ボックスワンクリック起動"),
"home_login_action_title_need_webview2_runtime":
MessageLookupByLibrary.simpleMessage("WebView2 Runtime のインストールが必要"),
"home_login_info_action_ignore":
MessageLookupByLibrary.simpleMessage("無視する"),
"home_login_info_game_version_outdated":
MessageLookupByLibrary.simpleMessage("ゲームバージョンが古すぎる"),
"home_login_info_one_click_launch_description":
MessageLookupByLibrary.simpleMessage(
"この機能は、ゲームをより便利に起動するのに役立ちます。\n\nアカウントのセキュリティを確保するため、この機能はローカライズブラウザを使用してログイン状態を保持し、パスワード情報を保存しません(自動入力オンの場合を除く)。\n\nこの機能を使用してアカウントにログインする際は、SCToolBox が信頼できるソースからダウンロードされていることを確認してください。"),
"home_login_info_rsi_server_report": m35,
"home_login_title_launching_game":
MessageLookupByLibrary.simpleMessage("ゲーム起動中..."),
"home_login_title_welcome_back":
MessageLookupByLibrary.simpleMessage("お帰りなさい!"),
"home_title_logging_in":
MessageLookupByLibrary.simpleMessage("ログイン中...")
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4905
lib/generated/l10n.dart Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
class NoL10n {
static const String langZHS = '简体中文';
static const String langZHT = '繁體中文';
static const String langEn = 'English';
static const String langJa = '日本語';
static const String langFR = 'Français';
}

View File

@ -1,101 +0,0 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hexcolor/hexcolor.dart';
import 'base/ui_model.dart';
import 'common/conf/app_conf.dart';
import 'ui/settings/upgrade_dialog_ui.dart';
import 'ui/settings/upgrade_dialog_ui_model.dart';
final globalUIModel = AppGlobalUIModel();
final globalUIModelProvider = ChangeNotifierProvider((ref) => globalUIModel);
class AppGlobalUIModel extends BaseUIModel {
Timer? activityThemeColorTimer;
Future<String?> getRunningGameUser() async {
await Future.delayed(const Duration(milliseconds: 300));
///TODO
return "xkeyC";
}
Future<bool> doCheckUpdate(BuildContext context, {bool init = true}) async {
dynamic checkUpdateError;
if (!init) {
try {
await AppConf.checkUpdate();
} catch (e) {
checkUpdateError = e;
}
}
await Future.delayed(const Duration(milliseconds: 100));
if (AppConf.networkVersionData == null) {
showToast(context,
"网络异常!\n这可能是您的网络环境存在DNS污染请尝试更换DNS。\n或服务器正在维护或遭受攻击,稍后再试。 \n进入离线模式... \n\n请谨慎在离线模式中使用。 \n当前版本构建日期:${AppConf.appVersionDate}\n QQ群940696487 \n错误信息:$checkUpdateError");
return false;
}
final lastVersion = AppConf.isMSE
? AppConf.networkVersionData?.mSELastVersionCode
: AppConf.networkVersionData?.lastVersionCode;
if ((lastVersion ?? 0) > AppConf.appVersionCode) {
// need update
final r = await showDialog(
dismissWithEsc: false,
context: context,
builder: (context) => BaseUIContainer(
uiCreate: () => UpgradeDialogUI(),
modelCreate: () => UpgradeDialogUIModel()));
if (r != true) {
showToast(context, "获取更新信息失败,请稍后重试。");
return false;
}
return true;
}
return false;
}
checkActivityThemeColor() {
if (activityThemeColorTimer != null) {
activityThemeColorTimer?.cancel();
activityThemeColorTimer = null;
}
if (AppConf.networkVersionData == null ||
AppConf.networkVersionData?.activityColors?.enable != true) return;
final startTime = AppConf.networkVersionData!.activityColors?.startTime;
final endTime = AppConf.networkVersionData!.activityColors?.endTime;
if (startTime == null || endTime == null) return;
final now = DateTime.now().millisecondsSinceEpoch;
dPrint("now == $now start == $startTime end == $endTime");
if (now < startTime) {
activityThemeColorTimer = Timer(
Duration(milliseconds: startTime - now), checkActivityThemeColor);
dPrint("start Timer ....");
} else if (now >= startTime && now <= endTime) {
dPrint("update Color ....");
// update Color
final colorCfg = AppConf.networkVersionData!.activityColors;
AppConf.colorBackground =
HexColor(colorCfg?.background ?? "#132431").withOpacity(.75);
AppConf.colorMenu =
HexColor(colorCfg?.menu ?? "#132431").withOpacity(.95);
AppConf.colorMica = HexColor(colorCfg?.mica ?? "#0A3142");
notifyListeners();
// wait for end
activityThemeColorTimer =
Timer(Duration(milliseconds: endTime - now), checkActivityThemeColor);
} else {
dPrint("reset Color ....");
AppConf.colorBackground = HexColor("#132431").withOpacity(.75);
AppConf.colorMenu = HexColor("#132431").withOpacity(.95);
AppConf.colorMica = HexColor("#0A3142");
notifyListeners();
}
notifyListeners();
}
}

965
lib/l10n/intl_en.arb Normal file
View File

@ -0,0 +1,965 @@
{
"@@locale": "en",
"@@auto_translate_locale": "en",
"app_language_name": "English",
"@app_language_name": {},
"app_language_code": "en",
"@app_language_code": {},
"app_index_version_info": "SCToolBox V {v0} {v1}",
"@app_index_version_info": {},
"app_shortcut_name": "SCToolBox.lnk",
"@app_shortcut_name": {},
"about_check_update": "Check for updates",
"@about_check_update": {},
"about_app_description": "Not just about localization!\n\nThe SCToolBox is your helper to explore the verse. We are committed to solving common in-game problems for citizens, in addition to facilitating localization from the community, game performance tuning, and localization of some commonly used website.",
"@about_app_description": {},
"about_online_feedback": "Online feedback",
"@about_online_feedback": {},
"about_action_qq_group": "QQ group: 940696487",
"@about_action_qq_group": {},
"about_action_email": "Email: xkeyc@qq.com",
"@about_action_email": {},
"about_action_open_source": "Open source",
"@about_action_open_source": {},
"about_disclaimer": "This is an unofficial Star Citizen fan-made tools, not affiliated with the Cloud Imperium group of companies. All content on this Software not authored by its host or users are property of their respective owners. \nStar Citizen®, Roberts Space Industries® and Cloud Imperium® are registered trademarks of Cloud Imperium Rights LLC.",
"@about_disclaimer": {},
"about_analytics_launch": "Start up",
"@about_analytics_launch": {},
"about_analytics_launch_game": "Game launches",
"@about_analytics_launch_game": {},
"about_analytics_total_users": "Cumulative users",
"@about_analytics_total_users": {},
"about_analytics_install_translation": "Localization installs",
"@about_analytics_install_translation": {},
"about_analytics_performance_optimization": "Performance tuning",
"@about_analytics_performance_optimization": {},
"about_analytics_p4k_redirection": "P4k diversion",
"@about_analytics_p4k_redirection": {},
"about_analytics_units_user": "users",
"@about_analytics_units_user": {},
"about_analytics_units_times": "Times",
"@about_analytics_units_times": {},
"about_info_latest_version": "It is already the latest version!",
"@about_info_latest_version": {},
"home_holiday_countdown": "Countdown",
"@home_holiday_countdown": {},
"home_holiday_countdown_disclaimer": "* The above festival dates are added and maintained manually. There may be errors and we welcome any feedback!",
"@home_holiday_countdown_disclaimer": {},
"home_action_one_click_launch": "One-click launch",
"@home_action_one_click_launch": {},
"home_title_logging_in": "Logging in...",
"@home_title_logging_in": {},
"home_login_title_welcome_back": "Welcome back!",
"@home_login_title_welcome_back": {},
"home_login_title_launching_game": "Launching game for you ...",
"@home_login_title_launching_game": {},
"home_action_login_rsi_account": "Log in to RSI account",
"@home_action_login_rsi_account": {},
"home_login_info_game_version_outdated": "Outdated game version",
"@home_login_info_game_version_outdated": {},
"home_login_info_rsi_server_report": "RSI server report version number: {v1}\n\nLocal version number: {v2}\n\nIt is recommended to use RSI Launcher to update the game!",
"@home_login_info_rsi_server_report": {},
"home_login_info_action_ignore": "Neglect",
"@home_login_info_action_ignore": {},
"home_login_action_title_box_one_click_launch": "Box one -click start",
"@home_login_action_title_box_one_click_launch": {},
"home_login_info_one_click_launch_description": "This feature can help you start the game more conveniently.\n\nTo ensure the security of the account, this function uses the Localization browser to retain the login status and will not save your password information (unless you enable the automatic filling function).\n\nWhen logging in to the account, please make sure your SCToolBox is downloaded from a trusted source.",
"@home_login_info_one_click_launch_description": {},
"home_login_action_title_need_webview2_runtime": "Need to install WebView2 Runtime",
"@home_login_action_title_need_webview2_runtime": {},
"action_close": "Close",
"@action_close": {},
"downloader_speed_limit_settings": "Speed limit setting",
"@downloader_speed_limit_settings": {},
"downloader_action_pause_all": "All of the suspension",
"@downloader_action_pause_all": {},
"downloader_action_resume_all": "Restore all",
"@downloader_action_resume_all": {},
"downloader_action_cancel_all": "Cancel all of them",
"@downloader_action_cancel_all": {},
"downloader_info_no_download_tasks": "No download task",
"@downloader_info_no_download_tasks": {},
"downloader_info_total_size": "Total size: {v1}",
"@downloader_info_total_size": {},
"downloader_info_verifying": "In the verification ... ({v2})",
"@downloader_info_verifying": {},
"downloader_info_downloading": "Download ... ({v0}%)",
"@downloader_info_downloading": {},
"downloader_info_status": "Status: {v0}",
"@downloader_info_status": {},
"downloader_info_uploaded": "Uploaded: {v0}",
"@downloader_info_uploaded": {},
"downloader_info_downloaded": "Downloaded: {v0}",
"@downloader_info_downloaded": {},
"downloader_action_options": "Option",
"@downloader_action_options": {},
"downloader_action_continue_download": "Continue download",
"@downloader_action_continue_download": {},
"downloader_action_pause_download": "Pause download",
"@downloader_action_pause_download": {},
"downloader_action_cancel_download": "Cancel download",
"@downloader_action_cancel_download": {},
"action_open_folder": "Open the folder",
"@action_open_folder": {},
"downloader_info_download_upload_speed": "Download: {v0}/s Upload: {v1}/s",
"@downloader_info_download_upload_speed": {},
"downloader_info_downloading_status": "Downloading...",
"@downloader_info_downloading_status": {},
"downloader_info_waiting": "Waiting",
"@downloader_info_waiting": {},
"downloader_info_paused": "Paused",
"@downloader_info_paused": {},
"downloader_info_download_failed": "Download failed",
"@downloader_info_download_failed": {},
"downloader_info_download_completed": "Download completed",
"@downloader_info_download_completed": {},
"downloader_info_deleted": "Deleted",
"@downloader_info_deleted": {},
"downloader_title_downloading": "Downloading",
"@downloader_title_downloading": {},
"downloader_title_ended": "Over",
"@downloader_title_ended": {},
"downloader_action_confirm_cancel_all_tasks": "Confirm the cancellation of all tasks?",
"@downloader_action_confirm_cancel_all_tasks": {},
"downloader_info_manual_file_deletion_note": "If the file is no longer needed, you may need to delete the download file manually.",
"@downloader_info_manual_file_deletion_note": {},
"downloader_action_confirm_cancel_download": "Confirm the cancellation download?",
"@downloader_action_confirm_cancel_download": {},
"downloader_info_p2p_network_note": "The SCToolBox uses the P2P network to accelerate file download. If you have limited traffic, you can set the upload bandwidth to 1 (byte) here.",
"@downloader_info_p2p_network_note": {},
"downloader_info_download_unit_input_prompt": "Please enter the download unit.",
"@downloader_info_download_unit_input_prompt": {},
"downloader_input_upload_speed_limit": "Upload speed limit:",
"@downloader_input_upload_speed_limit": {},
"downloader_input_download_speed_limit": "Download speed limit:",
"@downloader_input_download_speed_limit": {},
"downloader_input_info_p2p_upload_note": "* P2P upload is only performed when downloading files, and the P2P connection will be turned off after downloading. If you want to participate in planting, please contact us about the page.",
"@downloader_input_info_p2p_upload_note": {},
"doctor_title_one_click_diagnosis": "One -click diagnosis-> {v0}",
"@doctor_title_one_click_diagnosis": {},
"doctor_action_rsi_launcher_log": "RSI Launcher log",
"@doctor_action_rsi_launcher_log": {},
"doctor_action_game_run_log": "Game running log",
"@doctor_action_game_run_log": {},
"doctor_info_scan_complete_no_issues": "After scanning, no problem was found!",
"@doctor_info_scan_complete_no_issues": {},
"doctor_info_processing": "Treatment ...",
"@doctor_info_processing": {},
"doctor_info_game_rescue_service_note": "You are about to go to the game abnormal rescue services provided by the Deep Space Treatment Center (QQ group number: 536454632), which mainly solve the failure and frequent flashback of game installation. If you are a gameplay problem, please do not add groups.",
"@doctor_info_game_rescue_service_note": {},
"doctor_info_need_help": "Need help? Click to seek free artificial support!",
"@doctor_info_need_help": {},
"doctor_info_tool_check_result_note": "Note: The test results of this tool are for reference only. If you do not understand the following operations, please provide screenshots for experienced players!",
"@doctor_info_tool_check_result_note": {},
"doctor_info_result_unsupported_os": "The operating system that does not support, the game may not be able to run",
"@doctor_info_result_unsupported_os": {},
"doctor_info_result_upgrade_system": "Please upgrade your system ({v0})",
"@doctor_info_result_upgrade_system": {},
"doctor_info_result_missing_live_folder": "The installation directory lacks a Live folder, which may cause the installation to fail",
"@doctor_info_result_missing_live_folder": {},
"doctor_info_result_create_live_folder": "Click to fix the Live folder for you, and install it after completion. ({v0})",
"@doctor_info_result_create_live_folder": {},
"doctor_info_result_incompatible_nvme_device": "The new NVME device is not compatible with the RSI Launcher for the time being, which may cause the installation to fail",
"@doctor_info_result_incompatible_nvme_device": {},
"doctor_info_result_add_registry_value": "Add ForcedPhysicalsectorsizeinbytes value to the registry item to simulate old devices. Hard disk partition ({v0})",
"@doctor_info_result_add_registry_value": {},
"doctor_info_result_missing_easyanticheat_files": "Easyanticheat file loss",
"@doctor_info_result_missing_easyanticheat_files": {},
"doctor_info_result_verify_files_with_rsi_launcher": "Not found the EasyAnticheat file or file incomplete in the Live folder, please use the RSI Launcher to check the file",
"@doctor_info_result_verify_files_with_rsi_launcher": {},
"doctor_info_result_easyanticheat_not_installed": "Easyanticheat is not installed or not withdrawn normally",
"@doctor_info_result_easyanticheat_not_installed": {},
"doctor_info_result_install_easyanticheat": "Easyanticheat is not installed, please click to repair it for you one click. (Before the game starts normally and ends, the problem will always appear. If you retreat for other reasons, you can ignore this entry)",
"@doctor_info_result_install_easyanticheat": {},
"doctor_info_result_chinese_username": "No-English username!",
"@doctor_info_result_chinese_username": {},
"doctor_info_result_chinese_username_error": "The No-English username may cause the game to start/install errors! Click the repair button to view the modification tutorial!",
"@doctor_info_result_chinese_username_error": {},
"doctor_info_result_chinese_install_path": "No-English installation path!",
"@doctor_info_result_chinese_install_path": {},
"doctor_info_result_chinese_install_path_error": "No-English installation path! This may cause the game to start/install errors! ({v0}), please replace the installation path at the RSI Launcher.",
"@doctor_info_result_chinese_install_path_error": {},
"doctor_info_result_low_physical_memory": "Paralying memory is too low",
"@doctor_info_result_low_physical_memory": {},
"doctor_info_result_memory_requirement": "You need at least 16GB of physical memory (Memory) to run this game. (Current size: {v0})",
"@doctor_info_result_memory_requirement": {},
"doctor_info_result_fix_suggestion": "Repair suggestions: {v0}",
"@doctor_info_result_fix_suggestion": {},
"doctor_info_result_no_solution": "No solution, please take screenshots feedback",
"@doctor_info_result_no_solution": {},
"doctor_info_action_fix": "Repair",
"@doctor_info_action_fix": {},
"doctor_action_view_solution": "View solution",
"@doctor_action_view_solution": {},
"doctor_tip_title_select_game_directory": "Please select the game installation directory on the homepage.",
"@doctor_tip_title_select_game_directory": {},
"doctor_action_result_try_latest_windows": "If your hardware meets the standard, try to install the latest Windows system.",
"@doctor_action_result_try_latest_windows": {},
"doctor_action_result_create_folder_success": "Create a folder success, try to continue download the game!",
"@doctor_action_result_create_folder_success": {},
"doctor_action_result_create_folder_fail": "Create a folder failed, please try to create manually.\nDirectory: {v0}\nError: {v1}",
"@doctor_action_result_create_folder_fail": {},
"doctor_action_result_fix_success": "If the repair is successful, try to restart and continue to install the game! If the registry modification operation causes compatibility problems with other software, please use the NVMe registry in the tool to clean up.",
"@doctor_action_result_fix_success": {},
"doctor_action_result_fix_fail": "Failure to repair, {v0}",
"@doctor_action_result_fix_fail": {},
"doctor_action_result_game_start_success": "If the repair is successful, try to start the game. (If the problem cannot be solved, please use the toolbox's \"Reinstall EAC\")",
"@doctor_action_result_game_start_success": {},
"doctor_action_result_redirect_warning": "The tutorial is about to jump, the tutorial comes from the Internet, please operate carefully ...",
"@doctor_action_result_redirect_warning": {},
"doctor_action_result_issue_not_supported": "This problem does not support automatic processing for the time being, please provide screenshots for help",
"@doctor_action_result_issue_not_supported": {},
"doctor_action_analyzing": "Analysing...",
"@doctor_action_analyzing": {},
"doctor_action_result_analysis_no_issue": "After the analysis, no problems are found",
"@doctor_action_result_analysis_no_issue": {},
"doctor_action_result_analysis_issues_found": "After the analysis, I found that {v0} questions",
"@doctor_action_result_analysis_issues_found": {},
"doctor_action_result_toast_scan_no_issue": "After scanning, no problem is found. If you still fail, try to use the RSI Launcher administrator mode in the toolbox.",
"@doctor_action_result_toast_scan_no_issue": {},
"doctor_action_tip_checking_game_log": "Inspection: Game.log",
"@doctor_action_tip_checking_game_log": {},
"doctor_action_info_game_abnormal_exit": "Game abnormal exit: {v0}",
"@doctor_action_info_game_abnormal_exit": {},
"doctor_action_info_game_abnormal_exit_unknown": "Game abnormal exit: unknown abnormalities",
"@doctor_action_info_game_abnormal_exit_unknown": {},
"doctor_action_info_info_feedback": "Info: {v0}, please click to add group feedback in the lower right corner.",
"@doctor_action_info_info_feedback": {},
"doctor_action_info_checking_eac": "Inspection: EAC",
"@doctor_action_info_checking_eac": {},
"doctor_action_info_checking_runtime": "Inspection: operating environment",
"@doctor_action_info_checking_runtime": {},
"doctor_action_result_info_unsupported_os": "Operating system that does not support: {v0}",
"@doctor_action_result_info_unsupported_os": {},
"doctor_action_info_checking_install_info": "Inspection: Installation information",
"@doctor_action_info_checking_install_info": {},
"doctor_action_view_details": "Check the details",
"@doctor_action_view_details": {},
"home_install_location": "Installation location:",
"@home_install_location": {},
"home_not_installed_or_failed": "Unpacking or installation failed",
"@home_not_installed_or_failed": {},
"home_action_star_citizen_website_localization": "SC Official Localization",
"@home_action_star_citizen_website_localization": {},
"home_action_info_roberts_space_industries_origin": "Roberts Aerospace Industry Corporation, the origin of all things",
"@home_action_info_roberts_space_industries_origin": {},
"home_action_uex_localization": "UEX Localization",
"@home_action_uex_localization": {},
"home_action_info_mining_refining_trade_calculator": "Mining, refining, trade calculator, price, ship information",
"@home_action_info_mining_refining_trade_calculator": {},
"home_action_dps_calculator_localization": "DPS calculator Localization",
"@home_action_dps_calculator_localization": {},
"home_action_info_ship_upgrade_damage_value_query": "Change the ship online, query the damage value and accessories location",
"@home_action_info_ship_upgrade_damage_value_query": {},
"home_action_external_browser_extension": "External browser expansion:",
"@home_action_external_browser_extension": {},
"home_action_one_click_diagnosis": "Auto diagnosis",
"@home_action_one_click_diagnosis": {},
"home_action_info_one_click_diagnosis_star_citizen": "Auto scan diagnosis of common problems in interstellar citizens",
"@home_action_info_one_click_diagnosis_star_citizen": {},
"home_action_localization_management": "Localizations",
"@home_action_localization_management": {},
"home_action_info_quick_install_localization_resources": "Fast installation of localization resources",
"@home_action_info_quick_install_localization_resources": {},
"home_action_performance_optimization": "Performance optimization",
"@home_action_performance_optimization": {},
"home_action_info_engine_config_optimization": "Adjust the engine configuration file to optimize the game performance",
"@home_action_info_engine_config_optimization": {},
"home_action_rsi_status_platform": "Platform",
"@home_action_rsi_status_platform": {},
"home_action_rsi_status_persistent_universe": "PU",
"@home_action_rsi_status_persistent_universe": {},
"home_action_rsi_status_electronic_access": "EV",
"@home_action_rsi_status_electronic_access": {},
"home_action_rsi_status_arena_commander": "AC",
"@home_action_rsi_status_arena_commander": {},
"home_action_rsi_status_rsi_server_status": "RSI server status",
"@home_action_rsi_status_rsi_server_status": {},
"home_action_rsi_status_status": "State:",
"@home_action_rsi_status_status": {},
"home_announcement_details": "Announcement details",
"@home_announcement_details": {},
"home_action_info_valid_install_location_required": "This function requires an effective installation location\n\nIf your game is not downloaded, wait for the download after downloading.\n\nIf your game has been downloaded but not recognized, please reopen the box after starting the game or manually set the installation position in the setting option.",
"@home_action_info_valid_install_location_required": {},
"home_action_info_scanning": "Scanning ...",
"@home_action_info_scanning": {},
"home_action_info_scan_complete_valid_directories_found": "Scan completed, find {v0} valid installation directory",
"@home_action_info_scan_complete_valid_directories_found": {},
"home_action_info_log_file_parse_fail": "Analysis of LOG files failed!",
"@home_action_info_log_file_parse_fail": {},
"home_action_title_star_citizen_website_localization": "Star Citizen Website Localization",
"@home_action_title_star_citizen_website_localization": {},
"home_action_info_web_localization_plugin_disclaimer": "This plug -in function is for general browsing, not responsible for any problems related to this function! Please pay attention to confirming the original content of the website before the account operation!\n\n\nWhen logging in to the account, please make sure your SCToolBox is downloaded from a trusted source.",
"@home_action_info_web_localization_plugin_disclaimer": {},
"home_action_info_initializing_resources": "It is initialized Localization resources ...",
"@home_action_info_initializing_resources": {},
"home_action_info_initialization_failed": "Initialized webpage Localization resources failed! {v0}",
"@home_action_info_initialization_failed": {},
"home_title_app_name": "SCToolBox",
"@home_title_app_name": {},
"home_localization_new_version_available": "Localization has a new version!",
"@home_localization_new_version_available": {},
"home_localization_new_version_installed": "You have a new version of the Localization you installed in {v0}!",
"@home_localization_new_version_installed": {},
"home_info_valid_installation_required": "This function requires an effective installation location",
"@home_info_valid_installation_required": {},
"home_info_one_click_launch_warning": "One -click start -up function prompt",
"@home_info_one_click_launch_warning": {},
"home_info_account_security_warning": "In order to ensure the security of the account, the one -click startup function has been disabled in the development version, and we will provide this feature in the Microsoft store version.\n\nThe Microsoft Store Edition is provided with a reliable distribution download and digital signature by Microsoft, which can effectively prevent software from being maliciously tampered with.\n\nTip: You can use Localization without using a box to start the game.",
"@home_info_account_security_warning": {},
"home_action_install_microsoft_store_version": "Install Microsoft Store Version",
"@home_action_install_microsoft_store_version": {},
"home_action_cancel": "Cancel",
"@home_action_cancel": {},
"home_action_info_abnormal_game_exit": "The game exits normally\nexitCode = {v0}\nstdout = {v1}\nstderr = {v2}\n\nDiagnostic information: {v3}\n{v4}",
"@home_action_info_abnormal_game_exit": {},
"home_action_info_unknown_error": "Unknown errors, please use one -click diagnosis to add group feedback.",
"@home_action_info_unknown_error": {},
"home_action_info_check_web_link": "Please check the pop -up web link to get detailed information.",
"@home_action_info_check_web_link": {},
"home_action_info_game_built_in": "Built -in game",
"@home_action_info_game_built_in": {},
"home_action_info_warning": "Warn",
"@home_action_info_warning": {},
"localization_info_machine_translation_warning": "You are using the game built -in text. The official text is currently a machine translation (as of 3.21.0), and it is recommended that you install community Localization below.",
"@localization_info_machine_translation_warning": {},
"localization_info_translation": "Game localization",
"@localization_info_translation": {},
"localization_info_enabled": "Enable ({v0}):",
"@localization_info_enabled": {},
"localization_info_installed_version": "The installed version: {v0}",
"@localization_info_installed_version": {},
"localization_action_translation_feedback": "Feedback",
"@localization_action_translation_feedback": {},
"localization_action_uninstall_translation": "Uninstall",
"@localization_action_uninstall_translation": {},
"localization_info_note": "Remark:",
"@localization_info_note": {},
"localization_info_community_translation": "Community Localization",
"@localization_info_community_translation": {},
"localization_info_no_translation_available": "This language/version is not available for Localization, so stay tuned!",
"@localization_info_no_translation_available": {},
"localization_action_install": "Install",
"@localization_action_install": {},
"localization_info_version_number": "Version number: {v0}",
"@localization_info_version_number": {},
"localization_info_channel": "Channel: {v0}",
"@localization_info_channel": {},
"localization_info_update_time": "Update Time: {v0}",
"@localization_info_update_time": {},
"localization_info_installed": "Installed",
"@localization_info_installed": {},
"localization_info_unavailable": "Unavailable",
"@localization_info_unavailable": {},
"localization_info_language": "Language: ",
"@localization_info_language": {},
"localization_info_remove_incompatible_translation_params": "Whether to remove incompatible Localization parameters",
"@localization_info_remove_incompatible_translation_params": {},
"localization_info_incompatible_translation_params_warning": "User.cfg contains incompatible Localization parameters, which may be the residual information of the previous Localization file.\n\nThis may lead to ineffective or garbled Localization, click to confirm that you are removed with one click (it will not affect other configuration).",
"@localization_info_incompatible_translation_params_warning": {},
"localization_info_corrupted_file": "The file is damaged, please download again",
"@localization_info_corrupted_file": {},
"localization_info_installation_error": "Install an error!\n\n {v0}",
"@localization_info_installation_error": {},
"localization_info_custom_files": "Custom file",
"@localization_info_custom_files": {},
"performance_info_graphic_optimization_hint": "Graph optimization tips",
"@performance_info_graphic_optimization_hint": {},
"performance_info_graphic_optimization_warning": "This function is very helpful for optimizing the bottleneck of the graphics card, but it may have a reverse effect on the CPU bottleneck. If your graphics card performance is strong, you can try to use better picture quality to obtain higher graphics card utilization.",
"@performance_info_graphic_optimization_warning": {},
"performance_info_current_status": "Current status: {v0}",
"@performance_info_current_status": {},
"performance_info_applied": "Applied",
"@performance_info_applied": {},
"performance_info_not_applied": "Unused",
"@performance_info_not_applied": {},
"performance_action_preset": "Preset:",
"@performance_action_preset": {},
"performance_action_low": "Low",
"@performance_action_low": {},
"performance_action_medium": "Middle",
"@performance_action_medium": {},
"performance_action_high": "High",
"@performance_action_high": {},
"performance_action_super": "Super",
"@performance_action_super": {},
"performance_action_info_preset_only_changes_graphics": "(Only graphic)",
"@performance_action_info_preset_only_changes_graphics": {},
"performance_action_reset_to_default": " Reset",
"@performance_action_reset_to_default": {},
"performance_action_apply": "Apply",
"@performance_action_apply": {},
"performance_action_apply_and_clear_shaders": "Apply and clean up",
"@performance_action_apply_and_clear_shaders": {},
"performance_title_performance_optimization": "Performance Optimization -> {v0}",
"@performance_title_performance_optimization": {},
"performance_action_custom_parameters_input": "You can enter the custom parameters that are not included in the box here. Configuration example:\n\nR_DISPLAYINFO = 0\nr_vsync = 0",
"@performance_action_custom_parameters_input": {},
"performance_info_min_max_values": "{v0} minimum value: {v1} / maximum value: {v2}",
"@performance_info_min_max_values": {},
"performance_info_graphics": "Graphic",
"@performance_info_graphics": {},
"performance_info_delete_config_file": "Delete the configuration file ...",
"@performance_info_delete_config_file": {},
"performance_action_clear_shaders": "Clean the color device",
"@performance_action_clear_shaders": {},
"performance_info_done": "Finish...",
"@performance_info_done": {},
"performance_info_shader_clearing_warning": "After cleaning up the color device, it may appear stutter when entering the game for the first time. Please wait patiently for the initialization of the game.",
"@performance_info_shader_clearing_warning": {},
"performance_info_generate_config_file": "Generate configuration file",
"@performance_info_generate_config_file": {},
"performance_info_write_out_config_file": "Write the configuration file",
"@performance_info_write_out_config_file": {},
"app_index_menu_home": "Home",
"@app_index_menu_home": {},
"app_index_menu_lobby": "Lobby",
"@app_index_menu_lobby": {},
"app_index_menu_tools": "Tools",
"@app_index_menu_tools": {},
"app_index_menu_settings": "Settings",
"@app_index_menu_settings": {},
"app_index_menu_about": "About",
"@app_index_menu_about": {},
"lobby_online_lobby_coming_soon": "The online lobby, so stay tuned!",
"@lobby_online_lobby_coming_soon": {},
"lobby_invitation_to_participate": "Sincerely invite you to participate ",
"@lobby_invitation_to_participate": {},
"lobby_survey": "Questionnaire.",
"@lobby_survey": {},
"setting_action_create_settings_shortcut": "Create shortcut",
"@setting_action_create_settings_shortcut": {},
"setting_action_create_desktop_shortcut": "Create \"SC Localization Box\" shortcut on the desktop",
"@setting_action_create_desktop_shortcut": {},
"setting_action_reset_auto_password_fill": "Reset automatic password filling",
"@setting_action_reset_auto_password_fill": {},
"setting_action_ignore_efficiency_cores_on_launch": "When starting the game, ignore the core of energy efficiency (suitable for Intel 12th+ processor)",
"@setting_action_ignore_efficiency_cores_on_launch": {},
"setting_action_set_core_count": "Core quantity that has been set: {v0} (This function is suitable for the box -click startup or RSI Launcher manager mode on the homepage, which is not enabled when it is 0)",
"@setting_action_set_core_count": {},
"setting_action_set_launcher_file": "Set the promoter file (RSI Launcher.exe)",
"@setting_action_set_launcher_file": {},
"setting_action_info_manual_launcher_location_setting": "Set the position of the RSI Launcher manually, it is recommended to use it only when the installation position cannot be automatically scanned automatically",
"@setting_action_info_manual_launcher_location_setting": {},
"setting_action_set_game_file": "Set the game file (StarCitizen.exe)",
"@setting_action_set_game_file": {},
"setting_action_info_manual_game_location_setting": "Manually set the game installation location, it is recommended to use it only when the installation location cannot be automatically scanned",
"@setting_action_info_manual_game_location_setting": {},
"setting_action_clear_translation_file_cache": "Clean up the Localization file cache",
"@setting_action_clear_translation_file_cache": {},
"setting_action_info_cache_clearing_info": "The cache size {v0} MB, clean up the Localization -based file cache of the download of the box, will not affect the installed Localization",
"@setting_action_info_cache_clearing_info": {},
"setting_action_tool_site_access_acceleration": "Tool station access acceleration",
"@setting_action_tool_site_access_acceleration": {},
"setting_action_info_mirror_server_info": "Use a mirror server to accelerate access to tool websites such as DPS UEX. If you access abnormal access, please turn off the function. To protect the security of the account, the RSI official website will not be accelerated in any case.",
"@setting_action_info_mirror_server_info": {},
"setting_action_view_log": "View log",
"@setting_action_view_log": {},
"setting_action_info_view_log_file": "Check the log file of the SCToolBox to locate the bug of the box",
"@setting_action_info_view_log_file": {},
"setting_action_info_confirm_reset_autofill": "Confirm that resetting automatic filling?",
"@setting_action_info_confirm_reset_autofill": {},
"setting_action_info_delete_local_account_warning": "This will delete local account records, or it will automatically fill in the next time the game starts the game to disable automatic filling.",
"@setting_action_info_delete_local_account_warning": {},
"setting_action_info_autofill_data_cleared": "Automatic filling data has been cleaned up",
"@setting_action_info_autofill_data_cleared": {},
"setting_action_info_enter_cpu_core_to_ignore": "Please enter the core number of CPUs to be ignored",
"@setting_action_info_enter_cpu_core_to_ignore": {},
"setting_action_info_cpu_core_tip": "Tip: Input a few of your equipment with a few energy efficiency cores, please keep 0 non -large and small nuclear equipment 0\n\nThis function is suitable for the box of one -click startup or the RSI Launcher Admin mode in the box on the homepage. This function is not enabled when it is 0.",
"@setting_action_info_cpu_core_tip": {},
"setting_action_info_select_rsi_launcher_location": "Please select the RSI Launcher position (RSI LAUNCHER.EXE)",
"@setting_action_info_select_rsi_launcher_location": {},
"setting_action_info_setting_success": "Successfully set, click refresh on the corresponding page to scan the new path",
"@setting_action_info_setting_success": {},
"setting_action_info_file_error": "The file is wrong!",
"@setting_action_info_file_error": {},
"setting_action_info_select_game_install_location": "Please select the game installation position (StarCitizen.exe)",
"@setting_action_info_select_game_install_location": {},
"setting_action_info_confirm_clear_cache": "Confirmation of cleaning the Localization cache?",
"@setting_action_info_confirm_clear_cache": {},
"setting_action_info_clear_cache_warning": "This will not affect the installed Localization.",
"@setting_action_info_clear_cache_warning": {},
"setting_action_info_microsoft_version_limitation": "Due to Microsoft's version restrictions, manually drag the SCToolBox to the desktop in the next window to create a shortcut.",
"@setting_action_info_microsoft_version_limitation": {},
"setting_action_info_shortcut_created": "After the creation, please return to the desktop to view",
"@setting_action_info_shortcut_created": {},
"app_upgrade_title_new_version_found": "Discover the new version-> {v0}",
"@app_upgrade_title_new_version_found": {},
"app_upgrade_info_getting_new_version_details": "Get the new version details ...",
"@app_upgrade_info_getting_new_version_details": {},
"app_upgrade_info_update_server_tip": "Tip: The current diversion server is updated, and the download speed may decline, but it will help us perform cost control. If you download the exception, please click here to jump and manually install it.",
"@app_upgrade_info_update_server_tip": {},
"app_upgrade_info_installing": "Installing: ",
"@app_upgrade_info_installing": {},
"app_upgrade_info_downloading": "Downloading: {v0}% ",
"@app_upgrade_info_downloading": {},
"app_upgrade_action_update_now": "Update immediately",
"@app_upgrade_action_update_now": {},
"app_upgrade_action_next_time": "Next time",
"@app_upgrade_action_next_time": {},
"app_upgrade_info_download_failed": "Failure to download, please try to install manually!",
"@app_upgrade_info_download_failed": {},
"app_upgrade_info_run_failed": "Failure to run, try to install manually!",
"@app_upgrade_info_run_failed": {},
"app_splash_checking_availability": "It is detection availability, which may take a little time ...",
"@app_splash_checking_availability": {},
"app_splash_checking_for_updates": "Inspection and update ...",
"@app_splash_checking_for_updates": {},
"app_splash_almost_done": "Finish quickly…",
"@app_splash_almost_done": {},
"tools_hosts_info_rsi_official_website": "RSI official website",
"@tools_hosts_info_rsi_official_website": {},
"tools_hosts_info_rsi_customer_service": "RSI customer service station",
"@tools_hosts_info_rsi_customer_service": {},
"tools_hosts_info_dns_query_and_test": "Inquiring about DNS and testing accessibility, please wait patiently ...",
"@tools_hosts_info_dns_query_and_test": {},
"tools_hosts_info_writing_hosts": "I am writing Hosts ...",
"@tools_hosts_info_writing_hosts": {},
"tools_hosts_info_reading_config": "Read the configuration ...",
"@tools_hosts_info_reading_config": {},
"tools_hosts_info_hosts_acceleration": "Hosts accelerate",
"@tools_hosts_info_hosts_acceleration": {},
"tools_hosts_info_open_hosts_file": "Open the hosts file",
"@tools_hosts_info_open_hosts_file": {},
"tools_hosts_info_status": "Status",
"@tools_hosts_info_status": {},
"tools_hosts_info_site": "Site",
"@tools_hosts_info_site": {},
"tools_hosts_info_enable": "Whether to enable",
"@tools_hosts_info_enable": {},
"tools_hosts_action_one_click_acceleration": "One -click acceleration",
"@tools_hosts_action_one_click_acceleration": {},
"tools_info_scanning": "Scanning...",
"@tools_info_scanning": {},
"tools_info_processing_failed": "Failure to handle! : {v0}",
"@tools_info_processing_failed": {},
"tools_info_game_install_location": "Game installation location: ",
"@tools_info_game_install_location": {},
"tools_info_rsi_launcher_location": "RSI Launcher position:",
"@tools_info_rsi_launcher_location": {},
"tools_action_view_system_info": "View system information",
"@tools_action_view_system_info": {},
"tools_action_info_view_critical_system_info": "Check the key information of the system for quick consultation\n\nTime -consuming operation, please wait patiently.",
"@tools_action_info_view_critical_system_info": {},
"tools_action_p4k_download_repair": "P4k diversion download / repair",
"@tools_action_p4k_download_repair": {},
"tools_action_info_p4k_download_repair_tip": "The diversion download service provided by citizenwiki.cn can be used to download or fix P4K.\nLimited resources, please do not abuse.",
"@tools_action_info_p4k_download_repair_tip": {},
"tools_action_hosts_acceleration_experimental": "Hosts acceleration (experimental)",
"@tools_action_hosts_acceleration_experimental": {},
"tools_action_info_hosts_acceleration_experimental_tip": "Write the IP information into the hosts file to solve problems such as DNS pollution in some regions that cannot log in to the official website.\nThis function is undergoing the first stage of testing. Please report it in time when you encounter problems.",
"@tools_action_info_hosts_acceleration_experimental_tip": {},
"tools_action_reinstall_easyanticheat": "Reinstall EasyAnticheat",
"@tools_action_reinstall_easyanticheat": {},
"tools_action_info_reinstall_eac": "If you encounter EAC errors and are invalid automatically, try using this feature to reinstall EAC.",
"@tools_action_info_reinstall_eac": {},
"tools_action_rsi_launcher_admin_mode": "RSI Launcher administrator mode",
"@tools_action_rsi_launcher_admin_mode": {},
"tools_action_info_run_rsi_as_admin": "Run RSI startups as an administrator may solve some problems.\n\nIf the energy efficiency core shielding parameters are set, it will also be applied here.",
"@tools_action_info_run_rsi_as_admin": {},
"tools_action_info_init_failed": "Initialization failed, please take a screenshot report to the developer. {v0}",
"@tools_action_info_init_failed": {},
"tools_action_rsi_launcher_log_fix": "RSI LAUNCHER LOG repair",
"@tools_action_rsi_launcher_log_fix": {},
"tools_action_info_rsi_launcher_log_issue": "In some cases, the LOG file of the RSI promoter will be damaged, causing the problem to be scanned, and using this tool to clean up the damaged log file.\n\nCurrent log file size: {v0} MB",
"@tools_action_info_rsi_launcher_log_issue": {},
"tools_action_remove_nvme_registry_patch": "Remove the NVMe registry patch",
"@tools_action_remove_nvme_registry_patch": {},
"tools_action_info_nvme_patch_issue": "If you have a problem with the NVME patch, run this tool. (It may cause game installation/update to be unavailable.)\n\nCurrent patch status: {v0}",
"@tools_action_info_nvme_patch_issue": {},
"tools_action_info_not_installed": "Not Installed",
"@tools_action_info_not_installed": {},
"tools_action_info_removed_restart_effective": "Remove the computer to take effect!",
"@tools_action_info_removed_restart_effective": {},
"tools_action_write_nvme_registry_patch": "Write in the NVMe registry patch",
"@tools_action_write_nvme_registry_patch": {},
"tools_action_info_manual_nvme_patch": "Manually write the NVM patch, this function is used only when you know what you do",
"@tools_action_info_manual_nvme_patch": {},
"tools_action_info_fix_success_restart": "If the repair is successful, please try to restart the computer and continue to install the game! If the registry modification operation causes compatibility problems with other software, please use the NVMe registry in the tool to clean up.",
"@tools_action_info_fix_success_restart": {},
"tools_action_clear_shader_cache": "Clean up the color device cache",
"@tools_action_clear_shader_cache": {},
"tools_action_info_shader_cache_issue": "If the game screen appears abnormal or the version is updated, you can use the tool to clean the expired color (when it is greater than 500m, it is recommended to clean it)\n\nCache size: {v0} MB",
"@tools_action_info_shader_cache_issue": {},
"tools_action_close_photography_mode": "Turn off the photography mode",
"@tools_action_close_photography_mode": {},
"tools_action_open_photography_mode": "Turn on the photography mode",
"@tools_action_open_photography_mode": {},
"tools_action_info_restore_lens_shake": "Restoring the lens shaking effect.\n\n@Lapernum offers parameter information.",
"@tools_action_info_restore_lens_shake": {},
"tools_action_info_one_key_close_lens_shake": "Close the game endoscope shaking to facilitate photography operations.\n\n @Lapernum offers parameter information.",
"@tools_action_info_one_key_close_lens_shake": {},
"tools_action_info_log_file_parse_failed": "Analysis of LOG files failed!\nTry to use RSI Launcher Log repair tool!",
"@tools_action_info_log_file_parse_failed": {},
"tools_action_info_rsi_launcher_not_found": "If the RSI label is not found, try to reinstall it or add it manually in the settings.",
"@tools_action_info_rsi_launcher_not_found": {},
"tools_action_info_star_citizen_not_found": "If the interstellar game installation location is not found, please complete the game startup operation at least once or add it manually in the settings.",
"@tools_action_info_star_citizen_not_found": {},
"tools_action_info_valid_game_directory_needed": "This function requires an effective game installation directory",
"@tools_action_info_valid_game_directory_needed": {},
"tools_action_info_eac_file_removed": "Remove the EAC file for you, and then open the RSI startup for you. Please go to Settings-> Verify to reinstall EAC.",
"@tools_action_info_eac_file_removed": {},
"tools_action_info_error_occurred": "Error: {v0}",
"@tools_action_info_error_occurred": {},
"tools_action_info_system_info_content": "System: {v0}\n\nProcessor: {v1}\n\nMemory size: {v2} gb\n\nGraphics card information:\n{v3}\n\nStorage information:\n{v4}\n\n",
"@tools_action_info_system_info_content": {},
"tools_action_info_rsi_launcher_directory_not_found": "If the RSI Launcher directory is not found, please try manually.",
"@tools_action_info_rsi_launcher_directory_not_found": {},
"tools_action_info_log_file_not_exist": "The log file does not exist, please try to start a game startup or game installation, and exit the RSI Launcher. If the problem cannot be solved, try to update the launcher to the latest version!",
"@tools_action_info_log_file_not_exist": {},
"tools_action_info_cleanup_complete": "After cleaning up, complete the installation / game startup operation once.",
"@tools_action_info_cleanup_complete": {},
"tools_action_info_cleanup_failed": "Failure to clean up, please remove manually, file location: {v0}",
"@tools_action_info_cleanup_failed": {},
"tools_action_info_system_info_title": "System message",
"@tools_action_info_system_info_title": {},
"tools_action_info_rsi_launcher_running_warning": "The RSI Launcher is running! Please turn off the label first and then use this feature!",
"@tools_action_info_rsi_launcher_running_warning": {},
"tools_action_info_p4k_file_description": "P4K is the core game file of interstellar citizens, as high as 100GB+. The offline download provided by the box is to help some P4K files download super slow users or to repair the P4K file that the official launch cannot be repaired.\n\nNext, you will pop up the window and ask you to save the position (you can choose the Star Citizens Folder or you can choose elsewhere). After downloading, please make sure that the P4K folder is located in the LIVE folder, and then use the RSI Launcher to check it.",
"@tools_action_info_p4k_file_description": {},
"tools_action_info_p4k_download_in_progress": "There is already a P4K download task in progress, please go to the download manager to view!",
"@tools_action_info_p4k_download_in_progress": {},
"tools_action_info_function_under_maintenance": "During functional maintenance, please try it later!",
"@tools_action_info_function_under_maintenance": {},
"tools_action_info_config_file_not_exist": "The configuration file does not exist, please try to run the game once",
"@tools_action_info_config_file_not_exist": {},
"webview_localization_name_member": "Member",
"@webview_localization_name_member": {},
"webview_localization_total_invitations": "Total invitation:",
"@webview_localization_total_invitations": {},
"webview_localization_unfinished_invitations": "Undead invitation",
"@webview_localization_unfinished_invitations": {},
"webview_localization_finished_invitations": "Completed invitations",
"@webview_localization_finished_invitations": {},
"app_init_failed_with_reason": "Initialization failure: {v0}",
"@app_init_failed_with_reason": {},
"settings_app_language": "Language",
"@settings_app_language": {},
"settings_app_language_auto": "Automatic",
"@settings_app_language_auto": {},
"app_common_network_error": "Network anomaly!\nThis may be that your network environment has DNS pollution, please try to replace DNS.\nOr the server is being maintained or attacked and tried it later.\nEnter the offline mode ...\n\nPlease use it carefully in the offline mode.\nThe current version of the construction date: {v0}\n QQ group: 940696487\nError message: {v1}",
"@app_common_network_error": {},
"app_common_upgrade_info_error": "If the update information fails, please try it later.",
"@app_common_upgrade_info_error": {},
"doctor_game_error_low_memory": "Insufficient memory",
"@doctor_game_error_low_memory": {},
"doctor_game_error_low_memory_info": "Please try to increase virtual memory (under 1080P, physical available+virtual memory need> 64g)",
"@doctor_game_error_low_memory_info": {},
"doctor_game_error_generic_info": "The game triggered a generic crash, please check the trouble shooting guide",
"@doctor_game_error_generic_info": {},
"doctor_game_error_gpu_crash": "Your graphics card crashes! Please check the barrier guide",
"@doctor_game_error_gpu_crash": {},
"doctor_game_error_socket_error": "Detected SOCKET abnormalities",
"@doctor_game_error_socket_error": {},
"doctor_game_error_socket_error_info": "If you use the X black box accelerator, try to replace the acceleration mode",
"@doctor_game_error_socket_error_info": {},
"doctor_game_error_permissions_error": "Insufficient permissions",
"@doctor_game_error_permissions_error": {},
"doctor_game_error_permissions_error_info": "Please try to run a RSI Launcher at the administrator authority, or use the box (Microsoft Store version) to start.",
"@doctor_game_error_permissions_error_info": {},
"doctor_game_error_game_process_error": "The game process is occupied",
"@doctor_game_error_game_process_error": {},
"doctor_game_error_game_process_error_info": "Please try to restart the RSI Launcher, or restart the computer directly",
"@doctor_game_error_game_process_error_info": {},
"doctor_game_error_game_damaged_file": "Game program file damage",
"@doctor_game_error_game_damaged_file": {},
"doctor_game_error_game_damaged_file_info": "Please try to delete the Bin64 folder and check in the launcher.",
"@doctor_game_error_game_damaged_file_info": {},
"doctor_game_error_game_damaged_p4k_file": "P4K file damage",
"@doctor_game_error_game_damaged_p4k_file": {},
"doctor_game_error_game_damaged_p4k_file_info": "Please try to delete the data.p4k file and check or use the box to divert in the promoter.",
"@doctor_game_error_game_damaged_p4k_file_info": {},
"doctor_game_error_low_gpu_memory": "Insufficient VRAM",
"@doctor_game_error_low_gpu_memory": {},
"doctor_game_error_low_gpu_memory_info": "Please do not run the game/application occupied by other high graphics cards in the background, or change the graphics card.",
"@doctor_game_error_low_gpu_memory_info": {},
"app_common_error_info": "Error: {v0}",
"@app_common_error_info": {},
"app_common_tip": "Hint",
"@app_common_tip": {},
"app_common_tip_i_know": "I understand",
"@app_common_tip_i_know": {},
"app_common_tip_confirm": "Confirm",
"@app_common_tip_confirm": {},
"app_common_tip_cancel": "Cancel",
"@app_common_tip_cancel": {},
"settings_app_language_switch_info": "Switch application Display language",
"@settings_app_language_switch_info": {},
"home_holiday_countdown_days": "{v0} Day ",
"@home_holiday_countdown_days": {},
"home_holiday_countdown_in_progress": "In progress",
"@home_holiday_countdown_in_progress": {},
"app_common_loading_images": "Loading image ...",
"@app_common_loading_images": {},
"app_splash_dialog_u_a_p_p": "User Agreement and Privacy Policy",
"@app_splash_dialog_u_a_p_p": {},
"app_splash_dialog_u_a_p_p_content": "Thank you for choosing the SCToolBox box. We are committed to providing you with a safe, convenient and reliable experience. Before you start using your application, please read and agree to the following:\n\n 1. This application is an open source software under the GNU General Public License V3.0 protocol. You can use, modify, and distribute this software freely under the premise of obeying the agreement. Our source code is located at: [Github.com/StarCitizenToolBox/app](https://github.com/StarCitizenToolBox/app).\n2. The copyright of the Internet content in this application (including but not limited to localized documents, tool websites, news, videos, etc.) is created by its authors and is not part of GPL. Please use it under the corresponding authorization agreement.\n3. The official free release channels for this application are: [Microsoft App Store] (https://apps.microsoft.com/detail/9NF3SWFWNKL1) and [Official Website of Star Citizen Chinese] ), If you get from other third parties, please identify it carefully to avoid suffering from property losses.\n4. This application will send anonymous statistics to our server during use to improve software quality, and we will not collect any personal privacy information of your personal privacy.\n5. This application is supported by the community and has no direct connection with Cloud Imperium Games or other third -party commercial companies.\n6. We provide limited community support. If necessary, please go to the page to learn how to contact us.",
"@app_splash_dialog_u_a_p_p_content": {},
"tools_unp4k_msg_init": "Initialization ...",
"@tools_unp4k_msg_init": {},
"tools_unp4k_msg_reading": "Reading P4K file ...",
"@tools_unp4k_msg_reading": {},
"tools_unp4k_msg_reading2": "Treatment files ...",
"@tools_unp4k_msg_reading2": {},
"tools_unp4k_msg_reading3": "Processing files ({v0}/{v1}) ...",
"@tools_unp4k_msg_reading3": {},
"tools_unp4k_msg_read_completed": "After loading: {v0} a file, time: {v1} ms",
"@tools_unp4k_msg_read_completed": {},
"tools_unp4k_msg_open_file": "Open the file: {v0}",
"@tools_unp4k_msg_open_file": {},
"tools_unp4k_msg_read_file": "Read file: {v0} ...",
"@tools_unp4k_msg_read_file": {},
"home_localization_advanced_title": "Advanced Localization -> {v0}",
"@home_localization_advanced_title": {},
"home_localization_advanced_msg_version": "Localization version has been loaded: {v0}",
"@home_localization_advanced_msg_version": {},
"home_localization_advanced_title_msg": "Localization text lines: {v0} P4K text lines: {v1}",
"@home_localization_advanced_title_msg": {},
"home_localization_advanced_action_install": "Installation of Localization",
"@home_localization_advanced_action_install": {},
"home_localization_advanced_action_mod_change": "The text is being re -generated ...",
"@home_localization_advanced_action_mod_change": {},
"home_localization_advanced_action_mode": "Model",
"@home_localization_advanced_action_mode": {},
"home_localization_advanced_title_preview": "Preview: {v0}",
"@home_localization_advanced_title_preview": {},
"home_localization_advanced_json_text_location_other": "Location-Other",
"@home_localization_advanced_json_text_location_other": {},
"home_localization_advanced_json_text_location_used": "Location-Commonly used",
"@home_localization_advanced_json_text_location_used": {},
"home_localization_advanced_json_text_things_other": "Items-Other",
"@home_localization_advanced_json_text_things_other": {},
"home_localization_advanced_json_text_things_used": "Items-Commonly used",
"@home_localization_advanced_json_text_things_used": {},
"home_localization_advanced_json_text_vehicle_other": "Vehicle-Other",
"@home_localization_advanced_json_text_vehicle_other": {},
"home_localization_advanced_json_text_vehicle_used": "Vehicle-Commonly used",
"@home_localization_advanced_json_text_vehicle_used": {},
"home_localization_advanced_json_text_mission_or_logs": "Mission/Log",
"@home_localization_advanced_json_text_mission_or_logs": {},
"home_localization_advanced_json_text_subtitle": "Subtitle",
"@home_localization_advanced_json_text_subtitle": {},
"home_localization_advanced_json_text_ui_or_hud_or_menu": "UI/HUD/menu",
"@home_localization_advanced_json_text_ui_or_hud_or_menu": {},
"home_localization_advanced_json_text_un_localization": "Unwaver",
"@home_localization_advanced_json_text_un_localization": {},
"home_localization_advanced_json_text_others": "Other",
"@home_localization_advanced_json_text_others": {},
"home_localization_advanced_action_mod_change_localization": "Localization",
"@home_localization_advanced_action_mod_change_localization": {},
"home_localization_advanced_action_mod_change_un_localization": "Original English",
"@home_localization_advanced_action_mod_change_un_localization": {},
"home_localization_advanced_action_mod_change_mixed": "Bilingual",
"@home_localization_advanced_action_mod_change_mixed": {},
"home_localization_advanced_action_mod_change_mixed_newline": "Bilingual (newline)",
"@home_localization_advanced_action_mod_change_mixed_newline": {},
"home_localization_advanced_msg_classifying": "Classified ...",
"@home_localization_advanced_msg_classifying": {},
"home_localization_advanced_msg_reading_p4k": "Read p4k file ...",
"@home_localization_advanced_msg_reading_p4k": {},
"home_localization_advanced_msg_reading_server_localization_text": "Get Localization text ...",
"@home_localization_advanced_msg_reading_server_localization_text": {},
"home_localization_advanced_msg_gen_localization_text": "Generate Localization file ...",
"@home_localization_advanced_msg_gen_localization_text": {},
"home_localization_advanced_msg_gen_localization_install": "Install Localization file ...",
"@home_localization_advanced_msg_gen_localization_install": {},
"home_localization_msg_version_advanced": "(Advanced)",
"@home_localization_msg_version_advanced": {},
"home_localization_msg_no_note": "This version does not provide a description",
"@home_localization_msg_no_note": {},
"home_localization_action_rsi_launcher_localization": "RSILauncher Localization",
"@home_localization_action_rsi_launcher_localization": {},
"home_localization_action_advanced": "Advanced Localization",
"@home_localization_action_advanced": {},
"home_localization_action_install_customize": "Install custom file",
"@home_localization_action_install_customize": {},
"home_localization_title_localization_tools": "Localization tool",
"@home_localization_title_localization_tools": {},
"performance_json_text_ssdo": "Swip light after the screen light",
"@performance_json_text_ssdo": {},
"performance_json_text_ssdo_info": "After adjusting the light, processing level",
"@performance_json_text_ssdo_info": {},
"performance_json_text_title_graphics": "Graphic",
"@performance_json_text_title_graphics": {},
"performance_json_text_antialiasing": "Anti -aliasing",
"@performance_json_text_antialiasing": {},
"performance_json_text_antialiasing_info": "0 Close, 1 SMAA, 2 time filter+SMAA, 3 time filtering and projection matrix shake SMAA",
"@performance_json_text_antialiasing_info": {},
"performance_json_text_game_effects": "Special effect level",
"@performance_json_text_game_effects": {},
"performance_json_text_game_effects_info": "Game special effect level",
"@performance_json_text_game_effects_info": {},
"performance_json_text_texture": "Grade",
"@performance_json_text_texture": {},
"performance_json_text_texture_info": "Model texture details",
"@performance_json_text_texture_info": {},
"performance_json_text_volumetric_effects": "Volume effect",
"@performance_json_text_volumetric_effects": {},
"performance_json_text_volumetric_effects_info": "Volume cloud, volume light, etc.",
"@performance_json_text_volumetric_effects_info": {},
"performance_json_text_water": "Water effect",
"@performance_json_text_water": {},
"performance_json_text_water_info": "Grade of various water",
"@performance_json_text_water_info": {},
"performance_json_text_object_detail": "Object detail",
"@performance_json_text_object_detail": {},
"performance_json_text_object_detail_info": "Model object details, affect LOD, etc.",
"@performance_json_text_object_detail_info": {},
"performance_json_text_particles": "Particle details",
"@performance_json_text_particles": {},
"performance_json_text_physics": "Physical details",
"@performance_json_text_physics": {},
"performance_json_text_physics_info": "Scope of physical effects",
"@performance_json_text_physics_info": {},
"performance_json_text_shading": "Colorrhea details",
"@performance_json_text_shading": {},
"performance_json_text_shading_info": "Coloror related",
"@performance_json_text_shading_info": {},
"performance_json_text_shadows": "Shadow details",
"@performance_json_text_shadows": {},
"performance_json_text_shadows_info": "Shadow effect",
"@performance_json_text_shadows_info": {},
"performance_json_text_postprocessing": "Post -processing details",
"@performance_json_text_postprocessing": {},
"performance_json_text_postprocessing_info": "After the color device, dynamic blur effect, etc.",
"@performance_json_text_postprocessing_info": {},
"performance_json_text_renderer": "Rendering device quality",
"@performance_json_text_renderer": {},
"performance_json_text_renderer_info": "Cryengine rendereer quality",
"@performance_json_text_renderer_info": {},
"performance_json_text_shader_decal": "Quality",
"@performance_json_text_shader_decal": {},
"performance_json_text_shader_decal_info": "(LOGO, logo, etc.)",
"@performance_json_text_shader_decal_info": {},
"performance_json_text_shader_post_process": "Color quality",
"@performance_json_text_shader_post_process": {},
"performance_json_text_shader_fx": "FX quality",
"@performance_json_text_shader_fx": {},
"performance_json_text_shader_general": "Conventional quality",
"@performance_json_text_shader_general": {},
"performance_json_text_shader_general_info": "Overall model quality",
"@performance_json_text_shader_general_info": {},
"performance_json_text_shader_glass": "Glass quality",
"@performance_json_text_shader_glass": {},
"performance_json_text_shader_glass_info": "Window, mirror, etc.",
"@performance_json_text_shader_glass_info": {},
"performance_json_text_shader_hdr": "HDR quality",
"@performance_json_text_shader_hdr": {},
"performance_json_text_shader_hdr_info": "HDR color difference, brightness level treatment, etc.",
"@performance_json_text_shader_hdr_info": {},
"performance_json_text_shader_particle": "Particle quality",
"@performance_json_text_shader_particle": {},
"performance_json_text_shader_particle_info": "Particle effect quality",
"@performance_json_text_shader_particle_info": {},
"performance_json_text_shader_terrain": "Ground quality",
"@performance_json_text_shader_terrain": {},
"performance_json_text_shader_shadow": "Shadow quality",
"@performance_json_text_shader_shadow": {},
"performance_json_text_shader_sky": "Sky quality",
"@performance_json_text_shader_sky": {},
"performance_json_text_particles_object_collisions": "Particle collision",
"@performance_json_text_particles_object_collisions": {},
"performance_json_text_particles_object_collisions_info": "1 Static particles 2 include dynamic particles",
"@performance_json_text_particles_object_collisions_info": {},
"performance_json_text_displayinfo": "Screen information (display frame rate)",
"@performance_json_text_displayinfo": {},
"performance_json_text_displayinfo_info": "Display frame rates, server information, etc. in the upper right corner of the screen",
"@performance_json_text_displayinfo_info": {},
"performance_json_text_max_fps": "Maximum frame rate",
"@performance_json_text_max_fps": {},
"performance_json_text_max_fps_info": "Adjust the maximum frame rate of the game, 0 is not limited",
"@performance_json_text_max_fps_info": {},
"performance_json_text_display_session": "Display session information",
"@performance_json_text_display_session": {},
"performance_json_text_display_session_info": "After turning on, display a QR code on the screen to allow CIG to quickly locate related information when feedback",
"@performance_json_text_display_session_info": {},
"performance_json_text_vsync": "Vertical sync",
"@performance_json_text_vsync": {},
"performance_json_text_vsync_info": "Open to prevent tearing, turn off to increase the frame rate",
"@performance_json_text_vsync_info": {},
"performance_json_text_motion_blur": "Dynamic blur",
"@performance_json_text_motion_blur": {},
"performance_json_text_motion_blur_info": "Open to improve the sense of movement, turn off and enhance the perception",
"@performance_json_text_motion_blur_info": {},
"performance_json_text_fov": "Set viewing angle FOV",
"@performance_json_text_fov": {},
"performance_json_text_ui_animation": "UI fades into the animation",
"@performance_json_text_ui_animation": {},
"performance_json_text_custom_parameters": "Custom parameter",
"@performance_json_text_custom_parameters": {},
"performance_json_text_title_custom": "Customize",
"@performance_json_text_title_custom": {},
"tools_rsi_launcher_enhance_init_msg1": "Read the RSI Launcher information ...",
"@tools_rsi_launcher_enhance_init_msg1": {},
"tools_rsi_launcher_enhance_init_msg2": "Obtaining enhanced data from the Internet ...",
"@tools_rsi_launcher_enhance_init_msg2": {},
"tools_rsi_launcher_enhance_working_msg1": "Generate patch ...",
"@tools_rsi_launcher_enhance_working_msg1": {},
"tools_rsi_launcher_enhance_working_msg2": "Installation patch takes a little time, depending on your computer performance ...",
"@tools_rsi_launcher_enhance_working_msg2": {},
"tools_rsi_launcher_enhance_title": "RSI Launcher enhancement",
"@tools_rsi_launcher_enhance_title": {},
"tools_rsi_launcher_enhance_msg_version": "Internal version information of the RSI Launcher: {v0}",
"@tools_rsi_launcher_enhance_msg_version": {},
"tools_rsi_launcher_enhance_msg_patch_status": "Patch status: {v0}",
"@tools_rsi_launcher_enhance_msg_patch_status": {},
"tools_rsi_launcher_enhance_msg_error": "Obtaining enhanced data failure may be the network problem or the current version does not support",
"@tools_rsi_launcher_enhance_msg_error": {},
"tools_rsi_launcher_enhance_title_localization": "RSI startup localization",
"@tools_rsi_launcher_enhance_title_localization": {},
"tools_rsi_launcher_enhance_subtitle_localization": "Add multi -language support to the RSI Launcher.",
"@tools_rsi_launcher_enhance_subtitle_localization": {},
"tools_rsi_launcher_enhance_title_download_booster": "RSI Launcher download enhancement",
"@tools_rsi_launcher_enhance_title_download_booster": {},
"tools_rsi_launcher_enhance_subtitle_download_booster": "When downloading the game, you can use more threads to increase the download speed.",
"@tools_rsi_launcher_enhance_subtitle_download_booster": {},
"tools_rsi_launcher_enhance_action_install": "Installation enhanced patch",
"@tools_rsi_launcher_enhance_action_install": {},
"tools_rsi_launcher_enhance_msg_uninstall": "* If you need to uninstall the enhanced patch, cover the installation RSI promoter.",
"@tools_rsi_launcher_enhance_msg_uninstall": {},
"tools_rsi_launcher_enhance_msg_error_launcher_notfound": "No RSI promoter was found",
"@tools_rsi_launcher_enhance_msg_error_launcher_notfound": {},
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error": "Reading the Launcher information failed!",
"@tools_rsi_launcher_enhance_msg_error_get_launcher_info_error": {},
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error_with_args": "Read the RSI Launcher information failure: {v0}",
"@tools_rsi_launcher_enhance_msg_error_get_launcher_info_error_with_args": {},
"tools_action_rsi_launcher_enhance_info": "Enhanced launcher Localization、 download thread",
"@tools_action_rsi_launcher_enhance_info": {},
"tools_rsi_launcher_enhance_note_title": "Instructions for the use of RSI Launcher enhancement",
"@tools_rsi_launcher_enhance_note_title": {},
"tools_rsi_launcher_enhance_note_msg": "RSI Launcher enhancement is a community function. It will unpack \"RSI LAUNCHER\" on your computer and add additional enhancement functions. What functions are determined by you.\n\nAt present, the official (CIG) only permits us to perform multi -language operations. The launch of the booter download enhancement is an extra function we think of it. Violation of the CIG user protocol (https://robertsspaceindustries.com/eula) may cause serious consequences such as accounts. Whether or not you are determined by yourself, we are not responsible for the possible consequences (game damage, account ban, etc.).\n\nFor the modified content of the Launcher, we are open from: https://github.com/starcitizentoolbox/rsilauncherenhance. If necessary, you can check it yourself.\n\nIf you need to cancel this enhanced patch for any reason, cover the installation of the official RSI Launcher directly.",
"@tools_rsi_launcher_enhance_note_msg": {},
"tools_action_unp4k": "P4K viewer",
"@tools_action_unp4k": {},
"tools_action_unp4k_info": "Package Star Citizen P4K File",
"@tools_action_unp4k_info": {},
"tools_unp4k_title": "P4k viewer -> {v0}",
"@tools_unp4k_title": {},
"tools_unp4k_view_file": "Click the file to preview",
"@tools_unp4k_view_file": {},
"tools_unp4k_msg_unknown_file_type": "Unknown file type\n{v0}",
"@tools_unp4k_msg_unknown_file_type": {},
"home_localization_select_customize_file_ini": "Please select INI file",
"@home_localization_select_customize_file_ini": {},
"home_localization_select_customize_file": "Please select custom Localization file",
"@home_localization_select_customize_file": {},
"home_localization_action_select_customize_file": "Click to select INI file",
"@home_localization_action_select_customize_file": {},
"home_localization_ptu_advanced_localization_tip_title": "Recommended advanced localization",
"@home_localization_ptu_advanced_localization_tip_title": {},
"home_localization_ptu_advanced_localization_tip_title_info": "On PTU/EPTU and other test channels, the current localization text text may not be synchronized with the game, and the use of advanced localization can reduce garbled production.",
"@home_localization_ptu_advanced_localization_tip_title_info": {},
"tools_rsi_launcher_enhance_action_fold": "Put up the additional function",
"@tools_rsi_launcher_enhance_action_fold": {},
"tools_rsi_launcher_enhance_action_expand": "Expand additional features",
"@tools_rsi_launcher_enhance_action_expand": {},
"tools_unp4k_missing_runtime": "Lack of runtime",
"@tools_unp4k_missing_runtime": {},
"tools_unp4k_missing_runtime_info": "Use this function to install the .NET8 runtime, please click the button below to download and install it. After the installation is successful, reopen this page to continue to use.",
"@tools_unp4k_missing_runtime_info": {},
"tools_unp4k_missing_runtime_action_install": "Install the runtime",
"@tools_unp4k_missing_runtime_action_install": {},
"home_localization_action_rsi_launcher_no_game_path_msg": "You are not currently installed in the game body or the game installation directory is not selected, and you can only use the promoter Chinese function. Please make sure the game is installed or adds the game installation directory in the box settings.",
"doctor_game_error_gpu_vulkan_crash": "GPU Vulkan Crash",
"doctor_game_error_gpu_vulkan_crash_info": "Vulkan Crash! This may be the problem of driving version or game engine, please try to update the GPU driver or use the color cleaner function to return to DX11"
}

120
lib/l10n/intl_ja.arb Normal file
View File

@ -0,0 +1,120 @@
{
"@@locale": "ja",
"@@auto_translate_locale": "ja",
"app_language_name": "日本語",
"@app_language_name": {},
"app_language_code": "ja",
"@app_language_code": {},
"app_index_version_info": "SCToolBox V {v0} {v1}",
"@app_index_version_info": {},
"about_check_update": "更新チェック",
"@about_check_update": {},
"about_online_feedback": "フィードバック",
"@about_online_feedback": {},
"about_action_email": "メール: xkeyc@qq.com",
"@about_action_email": {},
"about_action_open_source": "オープンソース",
"@about_action_open_source": {},
"about_disclaimer": "これは Star Citizen の非公式ツールです、Cloud Imperium Games LLC の所有ではない。 本ソフトウェアのホストまたは使用者によって作成されていないすべての情報は、それぞれの所有者に帰属します。 \nStar Citizen®、Roberts Space Industries®、Cloud Imperium® は Cloud Imperium Rights LLC のトレードマーク。",
"@about_disclaimer": {},
"about_analytics_launch": "起動",
"@about_analytics_launch": {},
"about_analytics_launch_game": "ゲームを起動",
"@about_analytics_launch_game": {},
"about_analytics_install_translation": "日本語化インストール",
"@about_analytics_install_translation": {},
"about_analytics_p4k_redirection": "P4Kダウンロード",
"@about_analytics_p4k_redirection": {},
"about_analytics_total_users": "利用者数",
"@about_analytics_total_users": {},
"about_analytics_units_user": "人",
"@about_analytics_units_user": {},
"about_analytics_units_times": "回",
"@about_analytics_units_times": {},
"about_info_latest_version": "すでに最新バージョンだ!",
"@about_info_latest_version": {},
"home_holiday_countdown": "祝日カウントダウン",
"@home_holiday_countdown": {},
"home_holiday_countdown_disclaimer": "* 上記の祝日は手作業で収集・管理されているため、誤りがある可能性があります、フィードバックは歓迎する!!",
"@home_holiday_countdown_disclaimer": {},
"home_action_one_click_launch": "ワンクリック起動",
"@home_action_one_click_launch": {},
"home_title_logging_in": "ログイン中...",
"@home_title_logging_in": {},
"home_login_title_welcome_back": "お帰りなさい!",
"@home_login_title_welcome_back": {},
"home_login_title_launching_game": "ゲーム起動中...",
"@home_login_title_launching_game": {},
"home_action_login_rsi_account": "RSI アカウントログイン",
"@home_action_login_rsi_account": {},
"home_login_info_game_version_outdated": "ゲームバージョンが古すぎる",
"@home_login_info_game_version_outdated": {},
"home_login_info_rsi_server_report": "RSI サーバレポートのバージョン:{v1} \n\nローカルのバージョン{v2} \n\nRSI Launcher を使ってゲームをアップデートしてください!",
"@home_login_info_rsi_server_report": {},
"home_login_info_action_ignore": "無視する",
"@home_login_info_action_ignore": {},
"home_login_action_title_box_one_click_launch": "ボックスワンクリック起動",
"@home_login_action_title_box_one_click_launch": {},
"home_login_action_title_need_webview2_runtime": "WebView2 Runtime のインストールが必要",
"@home_login_action_title_need_webview2_runtime": {},
"action_close": "クローズ",
"@action_close": {},
"downloader_speed_limit_settings": "速度制限設定",
"@downloader_speed_limit_settings": {},
"downloader_action_pause_all": "すべて一時停止",
"@downloader_action_pause_all": {},
"downloader_action_resume_all": "すべて復元",
"@downloader_action_resume_all": {},
"downloader_action_cancel_all": "すべてキャンセル",
"@downloader_action_cancel_all": {},
"downloader_info_no_download_tasks": "ダウンロードタスクなし",
"@downloader_info_no_download_tasks": {},
"downloader_info_total_size": "サイズ合計:{v1}",
"@downloader_info_total_size": {},
"downloader_info_uploaded": "アップロード済み:{v0}",
"@downloader_info_uploaded": {},
"downloader_info_verifying": "検証中...{v2}",
"@downloader_info_verifying": {},
"downloader_info_downloading": "ダウンロード... ({v0}%)",
"@downloader_info_downloading": {},
"downloader_info_status": "ステータス:{v0}",
"@downloader_info_status": {},
"downloader_info_downloaded": "ダウンロード済み:{v0}",
"@downloader_info_downloaded": {},
"downloader_action_options": "オプション",
"@downloader_action_options": {},
"downloader_action_continue_download": "ダウンロードを続ける",
"@downloader_action_continue_download": {},
"downloader_action_pause_download": "ダウンロードの一時停止",
"@downloader_action_pause_download": {},
"downloader_action_cancel_download": "ダウンロードをキャンセル",
"@downloader_action_cancel_download": {},
"action_open_folder": "フォルダを開く",
"@action_open_folder": {},
"downloader_info_download_upload_speed": "ダウンロード: {v0}/s アップロード:{v1}/s",
"@downloader_info_download_upload_speed": {},
"downloader_info_waiting": "待機中",
"@downloader_info_waiting": {},
"downloader_info_downloading_status": "ダウンロード中...",
"@downloader_info_downloading_status": {},
"downloader_info_paused": "一時停止中",
"@downloader_info_paused": {},
"downloader_info_download_failed": "ダウンロード失敗",
"@downloader_info_download_failed": {},
"downloader_info_download_completed": "ダウンロード完了",
"@downloader_info_download_completed": {},
"downloader_info_deleted": "削除済み",
"@downloader_info_deleted": {},
"downloader_title_downloading": "ダウンロード中",
"@downloader_title_downloading": {},
"downloader_title_ended": "終了",
"@downloader_title_ended": {},
"downloader_action_confirm_cancel_all_tasks": "すべてのタスクのキャンセルを確認する?",
"@downloader_action_confirm_cancel_all_tasks": {},
"downloader_action_confirm_cancel_download": "ダウンロードのキャンセルを確認しますか?",
"@downloader_action_confirm_cancel_download": {},
"home_login_info_one_click_launch_description": "この機能は、ゲームをより便利に起動するのに役立ちます。\n\nアカウントのセキュリティを確保するため、この機能はローカライズブラウザを使用してログイン状態を保持し、パスワード情報を保存しません自動入力オンの場合を除く。\n\nこの機能を使用してアカウントにログインする際は、SCToolBox が信頼できるソースからダウンロードされていることを確認してください。",
"@home_login_info_one_click_launch_description": {},
"downloader_info_manual_file_deletion_note": "ダウンロードしたファイルが不要になった場合は、手動で削除する必要があります。",
"@downloader_info_manual_file_deletion_note": {}
}

801
lib/l10n/intl_zh_CN.arb Normal file
View File

@ -0,0 +1,801 @@
{
"@@locale": "zh_CN",
"@@auto_translate_locale": "zh-cn",
"app_language_name": "简体中文",
"@app_language_name": {},
"app_language_code": "zh_CN",
"app_index_version_info": "SC汉化盒子 V{v0} {v1}",
"@app_index_version_info": {},
"app_shortcut_name": "SC汉化盒子DEV.lnk",
"@app_shortcut_name": {},
"about_check_update": "检查更新",
"@about_check_update": {},
"about_app_description": "不仅仅是汉化!\n\nSC汉化盒子是你探索宇宙的好帮手我们致力于为各位公民解决游戏中的常见问题并为社区汉化、性能调优、常用网站汉化 等操作提供便利。",
"@about_app_description": {},
"about_online_feedback": "在线反馈",
"@about_online_feedback": {},
"about_action_qq_group": "QQ群: 940696487",
"@about_action_qq_group": {},
"about_action_email": "邮箱: xkeyc@qq.com",
"@about_action_email": {},
"about_action_open_source": "开源",
"@about_action_open_source": {},
"about_disclaimer": "这是一个非官方的星际公民工具,不隶属于 Cloud Imperium 公司集团。 本软件中非由其主机或用户创作的所有内容均为其各自所有者的财产。 \nStar Citizen®、Roberts Space Industries® 和 Cloud Imperium® 是 Cloud Imperium Rights LLC 的注册商标。",
"@about_disclaimer": {},
"about_analytics_launch": "启动",
"@about_analytics_launch": {},
"about_analytics_launch_game": "启动游戏",
"@about_analytics_launch_game": {},
"about_analytics_total_users": "累计用户",
"@about_analytics_total_users": {},
"about_analytics_install_translation": "汉化安装",
"@about_analytics_install_translation": {},
"about_analytics_performance_optimization": "性能调优",
"@about_analytics_performance_optimization": {},
"about_analytics_p4k_redirection": "P4K分流",
"@about_analytics_p4k_redirection": {},
"about_analytics_units_user": "位",
"@about_analytics_units_user": {},
"about_analytics_units_times": "次",
"@about_analytics_units_times": {},
"about_info_latest_version": "已经是最新版本!",
"@about_info_latest_version": {},
"home_holiday_countdown": "节日倒计时",
"@home_holiday_countdown": {},
"home_holiday_countdown_disclaimer": "* 以上节日日期由人工收录、维护,可能存在错误,欢迎反馈!",
"@home_holiday_countdown_disclaimer": {},
"home_action_one_click_launch": "一键启动",
"@home_action_one_click_launch": {},
"home_title_logging_in": "登录中...",
"@home_title_logging_in": {},
"home_login_title_welcome_back": "欢迎回来!",
"@home_login_title_welcome_back": {},
"home_login_title_launching_game": "正在为您启动游戏...",
"@home_login_title_launching_game": {},
"home_action_login_rsi_account": "登录 RSI 账户",
"@home_action_login_rsi_account": {},
"home_login_info_game_version_outdated": "游戏版本过期",
"@home_login_info_game_version_outdated": {},
"home_login_info_rsi_server_report": "RSI 服务器报告版本号:{v1} \n\n本地版本号{v2} \n\n建议使用 RSI Launcher 更新游戏!",
"@home_login_info_rsi_server_report": {},
"home_login_info_action_ignore": "忽略",
"@home_login_info_action_ignore": {},
"home_login_action_title_box_one_click_launch": "盒子一键启动",
"@home_login_action_title_box_one_click_launch": {},
"home_login_info_one_click_launch_description": "本功能可以帮您更加便利的启动游戏。\n\n为确保账户安全 ,本功能使用汉化浏览器保留登录状态,且不会保存您的密码信息(除非你启用了自动填充功能)。\n\n使用此功能登录账号时请确保您的 SC汉化盒子 是从可信任的来源下载。",
"@home_login_info_one_click_launch_description": {},
"home_login_action_title_need_webview2_runtime": "需要安装 WebView2 Runtime",
"@home_login_action_title_need_webview2_runtime": {},
"action_close": "关闭",
"@action_close": {},
"downloader_speed_limit_settings": "限速设置",
"@downloader_speed_limit_settings": {},
"downloader_action_pause_all": "全部暂停",
"@downloader_action_pause_all": {},
"downloader_action_resume_all": "恢复全部",
"@downloader_action_resume_all": {},
"downloader_action_cancel_all": "全部取消",
"@downloader_action_cancel_all": {},
"downloader_info_no_download_tasks": "无下载任务",
"@downloader_info_no_download_tasks": {},
"downloader_info_total_size": "总大小:{v1}",
"@downloader_info_total_size": {},
"downloader_info_verifying": "校验中...{v2}",
"@downloader_info_verifying": {},
"downloader_info_downloading": "下载中... ({v0}%)",
"@downloader_info_downloading": {},
"downloader_info_status": "状态:{v0}",
"@downloader_info_status": {},
"downloader_info_uploaded": "已上传:{v0}",
"@downloader_info_uploaded": {},
"downloader_info_downloaded": "已下载:{v0}",
"@downloader_info_downloaded": {},
"downloader_action_options": "选项",
"@downloader_action_options": {},
"downloader_action_continue_download": "继续下载",
"@downloader_action_continue_download": {},
"downloader_action_pause_download": "暂停下载",
"@downloader_action_pause_download": {},
"downloader_action_cancel_download": "取消下载",
"@downloader_action_cancel_download": {},
"action_open_folder": "打开文件夹",
"@action_open_folder": {},
"downloader_info_download_upload_speed": "下载: {v0}/s 上传:{v1}/s",
"@downloader_info_download_upload_speed": {},
"downloader_info_downloading_status": "下载中...",
"@downloader_info_downloading_status": {},
"downloader_info_waiting": "等待中",
"@downloader_info_waiting": {},
"downloader_info_paused": "已暂停",
"@downloader_info_paused": {},
"downloader_info_download_failed": "下载失败",
"@downloader_info_download_failed": {},
"downloader_info_download_completed": "下载完成",
"@downloader_info_download_completed": {},
"downloader_info_deleted": "已删除",
"@downloader_info_deleted": {},
"downloader_title_downloading": "下载中",
"@downloader_title_downloading": {},
"downloader_title_ended": "已结束",
"@downloader_title_ended": {},
"downloader_action_confirm_cancel_all_tasks": "确认取消全部任务?",
"@downloader_action_confirm_cancel_all_tasks": {},
"downloader_info_manual_file_deletion_note": "如果文件不再需要,你可能需要手动删除下载文件。",
"@downloader_info_manual_file_deletion_note": {},
"downloader_action_confirm_cancel_download": "确认取消下载?",
"@downloader_action_confirm_cancel_download": {},
"downloader_info_p2p_network_note": "SC 汉化盒子使用 p2p 网络来加速文件下载,如果您流量有限,可在此处将上传带宽设置为 1(byte)。",
"@downloader_info_p2p_network_note": {},
"downloader_info_download_unit_input_prompt": "请输入下载单位1、100k、10m 0或留空为不限速。",
"@downloader_info_download_unit_input_prompt": {},
"downloader_input_upload_speed_limit": "上传限速:",
"@downloader_input_upload_speed_limit": {},
"downloader_input_download_speed_limit": "下载限速:",
"@downloader_input_download_speed_limit": {},
"downloader_input_info_p2p_upload_note": "* P2P 上传仅在下载文件时进行,下载完成后会关闭 p2p 连接。如您想参与做种,请通过关于页面联系我们。",
"@downloader_input_info_p2p_upload_note": {},
"doctor_title_one_click_diagnosis": "一键诊断 -> {v0}",
"@doctor_title_one_click_diagnosis": {},
"doctor_action_rsi_launcher_log": "RSI启动器log",
"@doctor_action_rsi_launcher_log": {},
"doctor_action_game_run_log": "游戏运行log",
"@doctor_action_game_run_log": {},
"doctor_info_scan_complete_no_issues": "扫描完毕,没有找到问题!",
"@doctor_info_scan_complete_no_issues": {},
"doctor_info_processing": "正在处理...",
"@doctor_info_processing": {},
"doctor_info_game_rescue_service_note": "您即将前往由 深空治疗中心QQ群号536454632 提供的游戏异常救援服务,主要解决游戏安装失败与频繁闪退,如游戏玩法问题,请勿加群。",
"@doctor_info_game_rescue_service_note": {},
"doctor_info_need_help": "需要帮助? 点击加群寻求免费人工支援!",
"@doctor_info_need_help": {},
"doctor_info_tool_check_result_note": "注意:本工具检测结果仅供参考,若您不理解以下操作,请提供截图给有经验的玩家!",
"@doctor_info_tool_check_result_note": {},
"doctor_info_result_unsupported_os": "不支持的操作系统,游戏可能无法运行",
"@doctor_info_result_unsupported_os": {},
"doctor_info_result_upgrade_system": "请升级您的系统 ({v0})",
"@doctor_info_result_upgrade_system": {},
"doctor_info_result_missing_live_folder": "安装目录缺少LIVE文件夹可能导致安装失败",
"@doctor_info_result_missing_live_folder": {},
"doctor_info_result_create_live_folder": "点击修复为您创建 LIVE 文件夹,完成后重试安装。({v0})",
"@doctor_info_result_create_live_folder": {},
"doctor_info_result_incompatible_nvme_device": "新型 NVME 设备,与 RSI 启动器暂不兼容,可能导致安装失败",
"@doctor_info_result_incompatible_nvme_device": {},
"doctor_info_result_add_registry_value": "为注册表项添加 ForcedPhysicalSectorSizeInBytes 值 模拟旧设备。硬盘分区({v0})",
"@doctor_info_result_add_registry_value": {},
"doctor_info_result_missing_easyanticheat_files": "EasyAntiCheat 文件丢失",
"@doctor_info_result_missing_easyanticheat_files": {},
"doctor_info_result_verify_files_with_rsi_launcher": "未在 LIVE 文件夹找到 EasyAntiCheat 文件 或 文件不完整,请使用 RSI 启动器校验文件",
"@doctor_info_result_verify_files_with_rsi_launcher": {},
"doctor_info_result_easyanticheat_not_installed": "EasyAntiCheat 未安装 或 未正常退出",
"@doctor_info_result_easyanticheat_not_installed": {},
"doctor_info_result_install_easyanticheat": "EasyAntiCheat 未安装,请点击修复为您一键安装。(在游戏正常启动并结束前,该问题会一直出现,若您因为其他原因游戏闪退,可忽略此条目)",
"@doctor_info_result_install_easyanticheat": {},
"doctor_info_result_chinese_username": "中文用户名!",
"@doctor_info_result_chinese_username": {},
"doctor_info_result_chinese_username_error": "中文用户名可能会导致游戏启动/安装错误! 点击修复按钮查看修改教程!",
"@doctor_info_result_chinese_username_error": {},
"doctor_info_result_chinese_install_path": "中文安装路径!",
"@doctor_info_result_chinese_install_path": {},
"doctor_info_result_chinese_install_path_error": "中文安装路径!这可能会导致游戏 启动/安装 错误!({v0}请在RSI启动器更换安装路径。",
"@doctor_info_result_chinese_install_path_error": {},
"doctor_info_result_low_physical_memory": "物理内存过低",
"@doctor_info_result_low_physical_memory": {},
"doctor_info_result_memory_requirement": "您至少需要 16GB 的物理内存Memory才可运行此游戏。当前大小{v0}",
"@doctor_info_result_memory_requirement": {},
"doctor_info_result_fix_suggestion": "修复建议: {v0}",
"@doctor_info_result_fix_suggestion": {},
"doctor_info_result_no_solution": "暂无解决方法,请截图反馈",
"@doctor_info_result_no_solution": {},
"doctor_info_action_fix": "修复",
"@doctor_info_action_fix": {},
"doctor_action_view_solution": "查看解决方案",
"@doctor_action_view_solution": {},
"doctor_tip_title_select_game_directory": "请在首页选择游戏安装目录。",
"@doctor_tip_title_select_game_directory": {},
"doctor_action_result_try_latest_windows": "若您的硬件达标,请尝试安装最新的 Windows 系统。",
"@doctor_action_result_try_latest_windows": {},
"doctor_action_result_create_folder_success": "创建文件夹成功,请尝试继续下载游戏!",
"@doctor_action_result_create_folder_success": {},
"doctor_action_result_create_folder_fail": "创建文件夹失败,请尝试手动创建。\n目录{v0} \n错误{v1}",
"@doctor_action_result_create_folder_fail": {},
"doctor_action_result_fix_success": "修复成功,请尝试重启后继续安装游戏! 若注册表修改操作导致其他软件出现兼容问题,请使用 工具 中的 NVME 注册表清理。",
"@doctor_action_result_fix_success": {},
"doctor_action_result_fix_fail": "修复失败,{v0}",
"@doctor_action_result_fix_fail": {},
"doctor_action_result_game_start_success": "修复成功,请尝试启动游戏。(若问题无法解决,请使用工具箱的 《重装 EAC》",
"@doctor_action_result_game_start_success": {},
"doctor_action_result_redirect_warning": "即将跳转,教程来自互联网,请谨慎操作...",
"@doctor_action_result_redirect_warning": {},
"doctor_action_result_issue_not_supported": "该问题暂不支持自动处理,请提供截图寻求帮助",
"@doctor_action_result_issue_not_supported": {},
"doctor_action_analyzing": "正在分析...",
"@doctor_action_analyzing": {},
"doctor_action_result_analysis_no_issue": "分析完毕,没有发现问题",
"@doctor_action_result_analysis_no_issue": {},
"doctor_action_result_analysis_issues_found": "分析完毕,发现 {v0} 个问题",
"@doctor_action_result_analysis_issues_found": {},
"doctor_action_result_toast_scan_no_issue": "扫描完毕,没有发现问题,若仍然安装失败,请尝试使用工具箱中的 RSI启动器管理员模式。",
"@doctor_action_result_toast_scan_no_issue": {},
"doctor_action_tip_checking_game_log": "正在检查Game.log",
"@doctor_action_tip_checking_game_log": {},
"doctor_action_info_game_abnormal_exit": "游戏异常退出:{v0}",
"@doctor_action_info_game_abnormal_exit": {},
"doctor_action_info_game_abnormal_exit_unknown": "游戏异常退出:未知异常",
"@doctor_action_info_game_abnormal_exit_unknown": {},
"doctor_action_info_info_feedback": "info:{v0},请点击右下角加群反馈。",
"@doctor_action_info_info_feedback": {},
"doctor_action_info_checking_eac": "正在检查EAC",
"@doctor_action_info_checking_eac": {},
"doctor_action_info_checking_runtime": "正在检查:运行环境",
"@doctor_action_info_checking_runtime": {},
"doctor_action_result_info_unsupported_os": "不支持的操作系统:{v0}",
"@doctor_action_result_info_unsupported_os": {},
"doctor_action_info_checking_install_info": "正在检查:安装信息",
"@doctor_action_info_checking_install_info": {},
"doctor_action_view_details": "查看详情",
"@doctor_action_view_details": {},
"home_install_location": "安装位置:",
"@home_install_location": {},
"home_not_installed_or_failed": "未安装 或 安装失败",
"@home_not_installed_or_failed": {},
"home_action_star_citizen_website_localization": "星际公民官网汉化",
"@home_action_star_citizen_website_localization": {},
"home_action_info_roberts_space_industries_origin": "罗伯茨航天工业公司,万物的起源",
"@home_action_info_roberts_space_industries_origin": {},
"home_action_uex_localization": "UEX 汉化",
"@home_action_uex_localization": {},
"home_action_info_mining_refining_trade_calculator": "采矿、精炼、贸易计算器、价格、船信息",
"@home_action_info_mining_refining_trade_calculator": {},
"home_action_dps_calculator_localization": "DPS计算器汉化",
"@home_action_dps_calculator_localization": {},
"home_action_info_ship_upgrade_damage_value_query": "在线改船,查询伤害数值和配件购买地点",
"@home_action_info_ship_upgrade_damage_value_query": {},
"home_action_external_browser_extension": "外部浏览器拓展:",
"@home_action_external_browser_extension": {},
"home_action_one_click_diagnosis": "一键诊断",
"@home_action_one_click_diagnosis": {},
"home_action_info_one_click_diagnosis_star_citizen": "一键诊断星际公民常见问题",
"@home_action_info_one_click_diagnosis_star_citizen": {},
"home_action_localization_management": "汉化管理",
"@home_action_localization_management": {},
"home_action_info_quick_install_localization_resources": "快捷安装汉化资源",
"@home_action_info_quick_install_localization_resources": {},
"home_action_performance_optimization": "性能优化",
"@home_action_performance_optimization": {},
"home_action_info_engine_config_optimization": "调整引擎配置文件,优化游戏性能",
"@home_action_info_engine_config_optimization": {},
"home_action_rsi_status_platform": "平台",
"@home_action_rsi_status_platform": {},
"home_action_rsi_status_persistent_universe": "持续宇宙",
"@home_action_rsi_status_persistent_universe": {},
"home_action_rsi_status_electronic_access": "电子访问",
"@home_action_rsi_status_electronic_access": {},
"home_action_rsi_status_arena_commander": "竞技场指挥官",
"@home_action_rsi_status_arena_commander": {},
"home_action_rsi_status_rsi_server_status": "RSI 服务器状态",
"@home_action_rsi_status_rsi_server_status": {},
"home_action_rsi_status_status": "状态:",
"@home_action_rsi_status_status": {},
"home_announcement_details": "公告详情",
"@home_announcement_details": {},
"home_action_info_valid_install_location_required": "该功能需要一个有效的安装位置\n\n如果您的游戏未下载完成请等待下载完毕后使用此功能。\n\n如果您的游戏已下载完毕但未识别请启动一次游戏后重新打开盒子 或 在设置选项中手动设置安装位置。",
"@home_action_info_valid_install_location_required": {},
"home_action_info_scanning": "正在扫描 ...",
"@home_action_info_scanning": {},
"home_action_info_scan_complete_valid_directories_found": "扫描完毕,共找到 {v0} 个有效安装目录",
"@home_action_info_scan_complete_valid_directories_found": {},
"home_action_info_log_file_parse_fail": "解析 log 文件失败!",
"@home_action_info_log_file_parse_fail": {},
"home_action_title_star_citizen_website_localization": "星际公民网站汉化",
"@home_action_title_star_citizen_website_localization": {},
"home_action_info_web_localization_plugin_disclaimer": "本插功能件仅供大致浏览使用,不对任何有关本功能产生的问题负责!在涉及账号操作前请注意确认网站的原本内容!\n\n\n使用此功能登录账号时请确保您的 SC汉化盒子 是从可信任的来源下载。",
"@home_action_info_web_localization_plugin_disclaimer": {},
"home_action_info_initializing_resources": "正在初始化汉化资源...",
"@home_action_info_initializing_resources": {},
"home_action_info_initialization_failed": "初始化网页汉化资源失败!{v0}",
"@home_action_info_initialization_failed": {},
"home_title_app_name": "SC汉化盒子",
"@home_title_app_name": {},
"home_localization_new_version_available": "汉化有新版本!",
"@home_localization_new_version_available": {},
"home_localization_new_version_installed": "您在 {v0} 安装的汉化有新版本啦!",
"@home_localization_new_version_installed": {},
"home_info_valid_installation_required": "该功能需要一个有效的安装位置",
"@home_info_valid_installation_required": {},
"home_info_one_click_launch_warning": "一键启动功能提示",
"@home_info_one_click_launch_warning": {},
"home_info_account_security_warning": "为确保账户安全,一键启动功能已在开发版中禁用,我们将在微软商店版本中提供此功能。\n\n微软商店版由微软提供可靠的分发下载与数字签名可有效防止软件被恶意篡改。\n\n提示您无需使用盒子启动游戏也可使用汉化。",
"@home_info_account_security_warning": {},
"home_action_install_microsoft_store_version": "安装微软商店版本",
"@home_action_install_microsoft_store_version": {},
"home_action_cancel": "取消",
"@home_action_cancel": {},
"home_action_info_abnormal_game_exit": "游戏非正常退出\nexitCode={v0}\nstdout={v1}\nstderr={v2}\n\n诊断信息{v3} \n{v4}",
"@home_action_info_abnormal_game_exit": {},
"home_action_info_unknown_error": "未知错误,请通过一键诊断加群反馈。",
"@home_action_info_unknown_error": {},
"home_action_info_check_web_link": "请查看弹出的网页链接获得详细信息。",
"@home_action_info_check_web_link": {},
"home_action_info_game_built_in": "游戏内置",
"@home_action_info_game_built_in": {},
"home_action_info_warning": "警告",
"@home_action_info_warning": {},
"localization_info_machine_translation_warning": "您正在使用游戏内置文本官方文本目前为机器翻译截至3.21.0),建议您在下方安装社区汉化。",
"@localization_info_machine_translation_warning": {},
"localization_info_translation": "游戏汉化",
"@localization_info_translation": {},
"localization_info_enabled": "启用({v0}",
"@localization_info_enabled": {},
"localization_info_installed_version": "已安装版本:{v0}",
"@localization_info_installed_version": {},
"localization_action_translation_feedback": "汉化反馈",
"@localization_action_translation_feedback": {},
"localization_action_uninstall_translation": "卸载汉化",
"@localization_action_uninstall_translation": {},
"localization_info_note": "备注:",
"@localization_info_note": {},
"localization_info_community_translation": "社区汉化",
"@localization_info_community_translation": {},
"localization_info_no_translation_available": "该语言/版本 暂无可用汉化,敬请期待!",
"@localization_info_no_translation_available": {},
"localization_action_install": "安装",
"@localization_action_install": {},
"localization_info_version_number": "版本号:{v0}",
"@localization_info_version_number": {},
"localization_info_channel": "通道:{v0}",
"@localization_info_channel": {},
"localization_info_update_time": "更新时间:{v0}",
"@localization_info_update_time": {},
"localization_info_installed": "已安装",
"@localization_info_installed": {},
"localization_info_unavailable": "不可用",
"@localization_info_unavailable": {},
"localization_info_language": "语言: ",
"@localization_info_language": {},
"localization_info_remove_incompatible_translation_params": "是否移除不兼容的汉化参数",
"@localization_info_remove_incompatible_translation_params": {},
"localization_info_incompatible_translation_params_warning": "USER.cfg 包含不兼容的汉化参数,这可能是以前的汉化文件的残留信息。\n\n这将可能导致汉化无效或乱码点击确认为您一键移除不会影响其他配置。",
"@localization_info_incompatible_translation_params_warning": {},
"localization_info_corrupted_file": "文件受损,请重新下载",
"@localization_info_corrupted_file": {},
"localization_info_installation_error": "安装出错!\n\n {v0}",
"@localization_info_installation_error": {},
"localization_info_custom_files": "自定义文件",
"@localization_info_custom_files": {},
"performance_info_graphic_optimization_hint": "图形优化提示",
"@performance_info_graphic_optimization_hint": {},
"performance_info_graphic_optimization_warning": "该功能对优化显卡瓶颈有很大帮助,但对 CPU 瓶颈可能起反效果,如果您显卡性能强劲,可以尝试使用更好的画质来获得更高的显卡利用率。",
"@performance_info_graphic_optimization_warning": {},
"performance_info_current_status": "当前状态:{v0}",
"@performance_info_current_status": {},
"performance_info_applied": "已应用",
"@performance_info_applied": {},
"performance_info_not_applied": "未应用",
"@performance_info_not_applied": {},
"performance_action_preset": "预设:",
"@performance_action_preset": {},
"performance_action_low": "低",
"@performance_action_low": {},
"performance_action_medium": "中",
"@performance_action_medium": {},
"performance_action_high": "高",
"@performance_action_high": {},
"performance_action_super": "超级",
"@performance_action_super": {},
"performance_action_info_preset_only_changes_graphics": "(预设只修改图形设置)",
"@performance_action_info_preset_only_changes_graphics": {},
"performance_action_reset_to_default": " 恢复默认 ",
"@performance_action_reset_to_default": {},
"performance_action_apply": "应用",
"@performance_action_apply": {},
"performance_action_apply_and_clear_shaders": "应用并清理着色器(推荐)",
"@performance_action_apply_and_clear_shaders": {},
"performance_title_performance_optimization": "性能优化 -> {v0}",
"@performance_title_performance_optimization": {},
"performance_action_custom_parameters_input": "您可以在这里输入未收录进盒子的自定义参数。配置示例:\n\nr_displayinfo=0\nr_VSync=0",
"@performance_action_custom_parameters_input": {},
"performance_info_min_max_values": "{v0} 最小值: {v1} / 最大值: {v2}",
"@performance_info_min_max_values": {},
"performance_info_graphics": "图形",
"@performance_info_graphics": {},
"performance_info_delete_config_file": "删除配置文件...",
"@performance_info_delete_config_file": {},
"performance_action_clear_shaders": "清理着色器",
"@performance_action_clear_shaders": {},
"performance_info_done": "完成...",
"@performance_info_done": {},
"performance_info_shader_clearing_warning": "清理着色器后首次进入游戏可能会出现卡顿,请耐心等待游戏初始化完毕。",
"@performance_info_shader_clearing_warning": {},
"performance_info_generate_config_file": "生成配置文件",
"@performance_info_generate_config_file": {},
"performance_info_write_out_config_file": "写出配置文件",
"@performance_info_write_out_config_file": {},
"app_index_menu_home": "首页",
"@app_index_menu_home": {},
"app_index_menu_lobby": "大厅",
"@app_index_menu_lobby": {},
"app_index_menu_tools": "工具",
"@app_index_menu_tools": {},
"app_index_menu_settings": "设置",
"@app_index_menu_settings": {},
"app_index_menu_about": "关于",
"@app_index_menu_about": {},
"lobby_online_lobby_coming_soon": "联机大厅,敬请期待 ",
"@lobby_online_lobby_coming_soon": {},
"lobby_invitation_to_participate": "诚邀您参与 ",
"@lobby_invitation_to_participate": {},
"lobby_survey": "问卷调查。",
"@lobby_survey": {},
"setting_action_create_settings_shortcut": "创建设置快捷方式",
"@setting_action_create_settings_shortcut": {},
"setting_action_create_desktop_shortcut": "在桌面创建《SC汉化盒子》快捷方式",
"@setting_action_create_desktop_shortcut": {},
"setting_action_reset_auto_password_fill": "重置自动密码填充",
"@setting_action_reset_auto_password_fill": {},
"setting_action_ignore_efficiency_cores_on_launch": "启动游戏时忽略能效核心( 适用于Intel 12th+ 处理器 ",
"@setting_action_ignore_efficiency_cores_on_launch": {},
"setting_action_set_core_count": "已设置的核心数量:{v0} (此功能适用于首页的盒子一键启动 或 工具中的RSI启动器管理员模式当为 0 时不启用此功能 ",
"@setting_action_set_core_count": {},
"setting_action_set_launcher_file": "设置启动器文件RSI Launcher.exe",
"@setting_action_set_launcher_file": {},
"setting_action_info_manual_launcher_location_setting": "手动设置启动器位置,建议仅在无法自动扫描安装位置时使用",
"@setting_action_info_manual_launcher_location_setting": {},
"setting_action_set_game_file": "设置游戏文件 StarCitizen.exe",
"@setting_action_set_game_file": {},
"setting_action_info_manual_game_location_setting": "手动设置游戏安装位置,建议仅在无法自动扫描安装位置时使用",
"@setting_action_info_manual_game_location_setting": {},
"setting_action_clear_translation_file_cache": "清理汉化文件缓存",
"@setting_action_clear_translation_file_cache": {},
"setting_action_info_cache_clearing_info": "缓存大小 {v0}MB清理盒子下载的汉化文件缓存不会影响已安装的汉化",
"@setting_action_info_cache_clearing_info": {},
"setting_action_tool_site_access_acceleration": "工具站访问加速",
"@setting_action_tool_site_access_acceleration": {},
"setting_action_info_mirror_server_info": "使用镜像服务器加速访问 Dps Uex 等工具网站,若访问异常请关闭该功能。 为保护账户安全任何情况下都不会加速RSI官网。",
"@setting_action_info_mirror_server_info": {},
"setting_action_view_log": "查看log",
"@setting_action_view_log": {},
"setting_action_info_view_log_file": "查看汉化盒子的 log 文件,以定位盒子的 bug",
"@setting_action_info_view_log_file": {},
"setting_action_info_confirm_reset_autofill": "确认重置自动填充?",
"@setting_action_info_confirm_reset_autofill": {},
"setting_action_info_delete_local_account_warning": "这将会删除本地的账号记录,或在下次启动游戏时将自动填充选择 ‘否’ 以禁用自动填充。",
"@setting_action_info_delete_local_account_warning": {},
"setting_action_info_autofill_data_cleared": "已清理自动填充数据",
"@setting_action_info_autofill_data_cleared": {},
"setting_action_info_enter_cpu_core_to_ignore": "请输入要忽略的 CPU 核心数",
"@setting_action_info_enter_cpu_core_to_ignore": {},
"setting_action_info_cpu_core_tip": "Tip您的设备拥有几个能效核心就输入几非大小核设备请保持 0\n\n此功能适用于首页的盒子一键启动 或 工具中的 RSI启动器管理员模式当为 0 时不启用此功能。",
"@setting_action_info_cpu_core_tip": {},
"setting_action_info_select_rsi_launcher_location": "请选择RSI启动器位置RSI Launcher.exe",
"@setting_action_info_select_rsi_launcher_location": {},
"setting_action_info_setting_success": "设置成功,在对应页面点击刷新即可扫描出新路径",
"@setting_action_info_setting_success": {},
"setting_action_info_file_error": "文件有误!",
"@setting_action_info_file_error": {},
"setting_action_info_select_game_install_location": "请选择游戏安装位置StarCitizen.exe",
"@setting_action_info_select_game_install_location": {},
"setting_action_info_confirm_clear_cache": "确认清理汉化缓存?",
"@setting_action_info_confirm_clear_cache": {},
"setting_action_info_clear_cache_warning": "这不会影响已安装的汉化。",
"@setting_action_info_clear_cache_warning": {},
"setting_action_info_microsoft_version_limitation": "因微软版功能限制,请在接下来打开的窗口中 手动将《SC汉化盒子》拖动到桌面即可创建快捷方式。",
"@setting_action_info_microsoft_version_limitation": {},
"setting_action_info_shortcut_created": "创建完毕,请返回桌面查看",
"@setting_action_info_shortcut_created": {},
"app_upgrade_title_new_version_found": "发现新版本 -> {v0}",
"@app_upgrade_title_new_version_found": {},
"app_upgrade_info_getting_new_version_details": "正在获取新版本详情...",
"@app_upgrade_info_getting_new_version_details": {},
"app_upgrade_info_update_server_tip": "提示:当前正在使用分流服务器进行更新,可能会出现下载速度下降,但有助于我们进行成本控制,若下载异常请点击这里跳转手动安装。",
"@app_upgrade_info_update_server_tip": {},
"app_upgrade_info_installing": "正在安装: ",
"@app_upgrade_info_installing": {},
"app_upgrade_info_downloading": "正在下载: {v0}% ",
"@app_upgrade_info_downloading": {},
"app_upgrade_action_update_now": "立即更新",
"@app_upgrade_action_update_now": {},
"app_upgrade_action_next_time": "下次吧",
"@app_upgrade_action_next_time": {},
"app_upgrade_info_download_failed": "下载失败,请尝试手动安装!",
"@app_upgrade_info_download_failed": {},
"app_upgrade_info_run_failed": "运行失败,请尝试手动安装!",
"@app_upgrade_info_run_failed": {},
"app_splash_checking_availability": "正在检测可用性,这可能需要一点时间...",
"@app_splash_checking_availability": {},
"app_splash_checking_for_updates": "正在检查更新...",
"@app_splash_checking_for_updates": {},
"app_splash_almost_done": "即将完成…",
"@app_splash_almost_done": {},
"tools_hosts_info_rsi_official_website": "RSI 官网",
"@tools_hosts_info_rsi_official_website": {},
"tools_hosts_info_rsi_customer_service": "RSI 客服站",
"@tools_hosts_info_rsi_customer_service": {},
"tools_hosts_info_dns_query_and_test": "正在查询 DNS 并测试可访问性 请耐心等待...",
"@tools_hosts_info_dns_query_and_test": {},
"tools_hosts_info_writing_hosts": "正在写入 Hosts ...",
"@tools_hosts_info_writing_hosts": {},
"tools_hosts_info_reading_config": "读取配置 ...",
"@tools_hosts_info_reading_config": {},
"tools_hosts_info_hosts_acceleration": "Hosts 加速",
"@tools_hosts_info_hosts_acceleration": {},
"tools_hosts_info_open_hosts_file": "打开 Hosts 文件",
"@tools_hosts_info_open_hosts_file": {},
"tools_hosts_info_status": "状态",
"@tools_hosts_info_status": {},
"tools_hosts_info_site": "站点",
"@tools_hosts_info_site": {},
"tools_hosts_info_enable": "是否启用",
"@tools_hosts_info_enable": {},
"tools_hosts_action_one_click_acceleration": "一键加速",
"@tools_hosts_action_one_click_acceleration": {},
"tools_info_scanning": "正在扫描...",
"@tools_info_scanning": {},
"tools_info_processing_failed": "处理失败!:{v0}",
"@tools_info_processing_failed": {},
"tools_info_game_install_location": "游戏安装位置: ",
"@tools_info_game_install_location": {},
"tools_info_rsi_launcher_location": "RSI启动器位置",
"@tools_info_rsi_launcher_location": {},
"tools_action_view_system_info": "查看系统信息",
"@tools_action_view_system_info": {},
"tools_action_info_view_critical_system_info": "查看系统关键信息,用于快速问诊 \n\n耗时操作请耐心等待。",
"@tools_action_info_view_critical_system_info": {},
"tools_action_p4k_download_repair": "P4K 分流下载 / 修复",
"@tools_action_p4k_download_repair": {},
"tools_action_info_p4k_download_repair_tip": "使用星际公民中文百科提供的分流下载服务,可用于下载或修复 p4k。 \n资源有限请勿滥用。",
"@tools_action_info_p4k_download_repair_tip": {},
"tools_action_hosts_acceleration_experimental": "Hosts 加速(实验性)",
"@tools_action_hosts_acceleration_experimental": {},
"tools_action_info_hosts_acceleration_experimental_tip": "将 IP 信息写入 Hosts 文件,解决部分地区的 DNS 污染导致无法登录官网等问题。\n该功能正在进行第一阶段测试遇到问题请及时反馈。",
"@tools_action_info_hosts_acceleration_experimental_tip": {},
"tools_action_reinstall_easyanticheat": "重装 EasyAntiCheat 反作弊",
"@tools_action_reinstall_easyanticheat": {},
"tools_action_info_reinstall_eac": "若您遇到 EAC 错误,且自动修复无效,请尝试使用此功能重装 EAC。",
"@tools_action_info_reinstall_eac": {},
"tools_action_rsi_launcher_admin_mode": "RSI Launcher 管理员模式",
"@tools_action_rsi_launcher_admin_mode": {},
"tools_action_info_run_rsi_as_admin": "以管理员身份运行RSI启动器可能会解决一些问题。\n\n若设置了能效核心屏蔽参数也会在此应用。",
"@tools_action_info_run_rsi_as_admin": {},
"tools_action_info_init_failed": "初始化失败,请截图报告给开发者。{v0}",
"@tools_action_info_init_failed": {},
"tools_action_rsi_launcher_log_fix": "RSI Launcher Log 修复",
"@tools_action_rsi_launcher_log_fix": {},
"tools_action_info_rsi_launcher_log_issue": "在某些情况下 RSI启动器 的 log 文件会损坏,导致无法完成问题扫描,使用此工具清理损坏的 log 文件。\n\n当前日志文件大小{v0} MB",
"@tools_action_info_rsi_launcher_log_issue": {},
"tools_action_remove_nvme_registry_patch": "移除 nvme 注册表补丁",
"@tools_action_remove_nvme_registry_patch": {},
"tools_action_info_nvme_patch_issue": "若您使用 nvme 补丁出现问题,请运行此工具。(可能导致游戏 安装/更新 不可用。)\n\n当前补丁状态{v0}",
"@tools_action_info_nvme_patch_issue": {},
"tools_action_info_not_installed": "未安装",
"@tools_action_info_not_installed": {},
"tools_action_info_removed_restart_effective": "已移除,重启电脑生效!",
"@tools_action_info_removed_restart_effective": {},
"tools_action_write_nvme_registry_patch": "写入 nvme 注册表补丁",
"@tools_action_write_nvme_registry_patch": {},
"tools_action_info_manual_nvme_patch": "手动写入NVM补丁该功能仅在您知道自己在作什么的情况下使用",
"@tools_action_info_manual_nvme_patch": {},
"tools_action_info_fix_success_restart": "修复成功,请尝试重启电脑后继续安装游戏! 若注册表修改操作导致其他软件出现兼容问题,请使用 工具 中的 NVME 注册表清理。",
"@tools_action_info_fix_success_restart": {},
"tools_action_clear_shader_cache": "清理着色器缓存",
"@tools_action_clear_shader_cache": {},
"tools_action_info_shader_cache_issue": "若游戏画面出现异常或版本更新后可使用本工具清理过期的着色器当大于500M时建议清理 \n\n缓存大小{v0} MB",
"@tools_action_info_shader_cache_issue": {},
"tools_action_close_photography_mode": "关闭摄影模式",
"@tools_action_close_photography_mode": {},
"tools_action_open_photography_mode": "开启摄影模式",
"@tools_action_open_photography_mode": {},
"tools_action_info_restore_lens_shake": "还原镜头摇晃效果。\n\n@拉邦那 Lapernum 提供参数信息。",
"@tools_action_info_restore_lens_shake": {},
"tools_action_info_one_key_close_lens_shake": "一键关闭游戏内镜头晃动以便于摄影操作。\n\n @拉邦那 Lapernum 提供参数信息。",
"@tools_action_info_one_key_close_lens_shake": {},
"tools_action_info_log_file_parse_failed": "解析 log 文件失败!\n请尝试使用 RSI Launcher log 修复 工具!",
"@tools_action_info_log_file_parse_failed": {},
"tools_action_info_rsi_launcher_not_found": "未找到 RSI 启动器,请尝试重新安装,或在设置中手动添加。",
"@tools_action_info_rsi_launcher_not_found": {},
"tools_action_info_star_citizen_not_found": "未找到星际公民游戏安装位置,请至少完成一次游戏启动操作 或在设置中手动添加。",
"@tools_action_info_star_citizen_not_found": {},
"tools_action_info_valid_game_directory_needed": "该功能需要一个有效的游戏安装目录",
"@tools_action_info_valid_game_directory_needed": {},
"tools_action_info_eac_file_removed": "已为您移除 EAC 文件,接下来将为您打开 RSI 启动器,请您前往 SETTINGS -> VERIFY 重装 EAC。",
"@tools_action_info_eac_file_removed": {},
"tools_action_info_error_occurred": "出现错误:{v0}",
"@tools_action_info_error_occurred": {},
"tools_action_info_system_info_content": "系统:{v0}\n\n处理器{v1}\n\n内存大小{v2}GB\n\n显卡信息\n{v3}\n\n硬盘信息\n{v4}\n\n",
"@tools_action_info_system_info_content": {},
"tools_action_info_rsi_launcher_directory_not_found": "未找到 RSI 启动器目录,请您尝试手动操作。",
"@tools_action_info_rsi_launcher_directory_not_found": {},
"tools_action_info_log_file_not_exist": "日志文件不存在,请尝试进行一次游戏启动或游戏安装,并退出启动器,若无法解决问题,请尝试将启动器更新至最新版本!",
"@tools_action_info_log_file_not_exist": {},
"tools_action_info_cleanup_complete": "清理完毕,请完成一次安装 / 游戏启动 操作。",
"@tools_action_info_cleanup_complete": {},
"tools_action_info_cleanup_failed": "清理失败,请手动移除,文件位置:{v0}",
"@tools_action_info_cleanup_failed": {},
"tools_action_info_system_info_title": "系统信息",
"@tools_action_info_system_info_title": {},
"tools_action_info_rsi_launcher_running_warning": "RSI启动器正在运行请先关闭启动器再使用此功能",
"@tools_action_info_rsi_launcher_running_warning": {},
"tools_action_info_p4k_file_description": "P4k 是星际公民的核心游戏文件,高达 100GB+盒子提供的离线下载是为了帮助一些p4k文件下载超级慢的用户 或用于修复官方启动器无法修复的 p4k 文件。\n\n接下来会弹窗询问您保存位置可以选择星际公民文件夹也可以选择别处下载完成后请确保 P4K 文件夹位于 LIVE 文件夹内,之后使用星际公民启动器校验更新即可。",
"@tools_action_info_p4k_file_description": {},
"tools_action_info_p4k_download_in_progress": "已经有一个p4k下载任务正在进行中请前往下载管理器查看",
"@tools_action_info_p4k_download_in_progress": {},
"tools_action_info_function_under_maintenance": "功能维护中,请稍后重试!",
"@tools_action_info_function_under_maintenance": {},
"tools_action_info_config_file_not_exist": "配置文件不存在,请尝试运行一次游戏",
"@tools_action_info_config_file_not_exist": {},
"webview_localization_name_member": "名成员",
"@webview_localization_name_member": {},
"webview_localization_total_invitations": "总邀请数:",
"@webview_localization_total_invitations": {},
"webview_localization_unfinished_invitations": "未完成的邀请",
"@webview_localization_unfinished_invitations": {},
"webview_localization_finished_invitations": "已完成的邀请",
"@webview_localization_finished_invitations": {},
"app_init_failed_with_reason": "初始化失败:{v0}",
"@app_init_failed_with_reason": {},
"settings_app_language": "语言",
"settings_app_language_auto": "自动",
"app_common_network_error": "网络异常!\n这可能是您的网络环境存在DNS污染请尝试更换DNS。\n或服务器正在维护或遭受攻击稍后再试。 \n进入离线模式... \n\n请谨慎在离线模式中使用。 \n当前版本构建日期{v0}\n QQ群940696487 \n错误信息{v1}",
"app_common_upgrade_info_error": "获取更新信息失败,请稍后重试。",
"doctor_game_error_low_memory": "可用内存不足",
"doctor_game_error_low_memory_info": "请尝试增加虚拟内存( 1080p 下, 物理可用+虚拟内存需 > 64G ",
"doctor_game_error_generic_info": "游戏触发了最为广泛的崩溃问题,请查看排障指南",
"doctor_game_error_gpu_crash": "您的显卡崩溃啦!请查看排障指南",
"doctor_game_error_socket_error": "检测到 socket 异常",
"doctor_game_error_socket_error_info": "如使用 X黑盒 加速器,请尝试更换加速模式",
"doctor_game_error_permissions_error": "权限不足",
"doctor_game_error_permissions_error_info": "请尝试以管理员权限运行启动器,或使用盒子(微软商店版)启动。",
"doctor_game_error_game_process_error": "游戏进程被占用",
"doctor_game_error_game_process_error_info": "请尝试重启启动器,或直接重启电脑",
"doctor_game_error_game_damaged_file": "游戏程序文件损坏",
"doctor_game_error_game_damaged_file_info": "请尝试删除 Bin64 文件夹 并在启动器校验。",
"doctor_game_error_game_damaged_p4k_file": "P4K文件损坏",
"doctor_game_error_game_damaged_p4k_file_info": "请尝试删除 Data.p4k 文件 并在启动器校验 或 使用盒子分流。",
"doctor_game_error_low_gpu_memory": "可用显存不足",
"doctor_game_error_low_gpu_memory_info": "请不要在后台运行其他高显卡占用的 游戏/应用,或更换显卡。",
"doctor_game_error_gpu_vulkan_crash": "GPU Vulkan 崩溃",
"doctor_game_error_gpu_vulkan_crash_info": "Vulkan 崩溃!这可能是驱动版本或游戏引擎问题,请尝试更新 GPU 驱动 或 使用清理着色器功能为您回退到 DX11",
"app_common_error_info": "出现错误: {v0}",
"app_common_tip": "提示",
"app_common_tip_i_know": "我知道了",
"app_common_tip_confirm": "确认",
"app_common_tip_cancel": "取消",
"settings_app_language_switch_info": "切换应用显示语言",
"home_holiday_countdown_days": "{v0}天 ",
"home_holiday_countdown_in_progress": "正在进行中",
"app_common_loading_images": "加载图片...",
"app_splash_dialog_u_a_p_p": "用户协议与隐私政策",
"app_splash_dialog_u_a_p_p_content": "感谢您选择 SC汉化盒子 ,我们致力于为您提供 安全、便捷、可靠的使用体验,在您开始使用应用前,请先阅读并同意以下内容:\n\n 1. 本应用 为 GNU 通用公共许可证 v3.0 协议下的开源软件,您可以在遵守协议的前提下自由使用、修改、分发本软件。我们的源代码位于:[Github.com/StarCitizenToolBox/app](https://github.com/StarCitizenToolBox/app)。 \n2. 本应用中的互联网内容(包括但不限于 本地化文件、工具网站、新闻、视频 等)版权由其作者创作所有,不属于 GPL 的一部分,请在遵守对应的授权协议下使用。\n3. 本应用的官方免费发布渠道为:[微软应用商店](https://apps.microsoft.com/detail/9NF3SWFWNKL1) 与 [星际公民汉化组官网](https://www.starcitizenzw.com/) ,若您从其他第三方处获得,请仔细甄别,以免遭受财产损失。\n4. 本应用在使用过程中会向我们的服务器发送匿名的统计数据,用于改进软件质量,我们不会收集您的任何个人隐私信息。 \n5. 本应用由社区提供支持,与 Cloud Imperium Games 或 其他第三方商业公司 无直接关联。\n6. 我们提供有限的社区支持,如有需要,请前往关于页面了解如何联系我们。",
"tools_unp4k_msg_init": "初始化中...",
"tools_unp4k_msg_reading": "正在读取P4K 文件 ...",
"tools_unp4k_msg_reading2": "正在处理文件 ...",
"tools_unp4k_msg_reading3": "正在处理文件 ({v0}/{v1}) ...",
"tools_unp4k_msg_read_completed": "加载完毕:{v0} 个文件,用时:{v1} ms",
"tools_unp4k_msg_open_file": "打开文件:{v0}",
"tools_unp4k_msg_read_file": "读取文件:{v0} ...",
"home_localization_advanced_title": "高级汉化 -> {v0}",
"home_localization_advanced_msg_version": "已加载汉化版本:{v0}",
"home_localization_advanced_title_msg": "汉化文本行数:{v0} P4K文本行数{v1}",
"home_localization_advanced_action_install": "安装汉化",
"home_localization_advanced_action_mod_change": "正在重新生成文本...",
"home_localization_advanced_action_mode": "模式",
"home_localization_advanced_title_preview": "预览:{v0}",
"home_localization_advanced_json_text_location_other": "地点-其他",
"home_localization_advanced_json_text_location_used": "地点-常用",
"home_localization_advanced_json_text_things_other": "物品-其他",
"home_localization_advanced_json_text_things_used": "物品-常用",
"home_localization_advanced_json_text_vehicle_other": "载具-其他",
"home_localization_advanced_json_text_vehicle_used": "载具-常用",
"home_localization_advanced_json_text_mission_or_logs": "任务/日志",
"home_localization_advanced_json_text_subtitle": "字幕",
"home_localization_advanced_json_text_ui_or_hud_or_menu": "UI/HUD/菜单",
"home_localization_advanced_json_text_un_localization": "未汉化",
"home_localization_advanced_json_text_others": "其他",
"home_localization_advanced_action_mod_change_localization": "汉化",
"home_localization_advanced_action_mod_change_un_localization": "英文原文",
"home_localization_advanced_action_mod_change_mixed": "双语",
"home_localization_advanced_action_mod_change_mixed_newline": "双语(换行)",
"home_localization_advanced_msg_classifying": "正在分类 ...",
"home_localization_advanced_msg_reading_p4k": "读取 p4k 文件 ...",
"home_localization_advanced_msg_reading_server_localization_text": "获取汉化文本 ...",
"home_localization_advanced_msg_gen_localization_text": "生成汉化文件...",
"home_localization_advanced_msg_gen_localization_install": "安装汉化文件...",
"home_localization_msg_version_advanced": " (高级汉化)",
"home_localization_msg_no_note": "该版本没有提供描述",
"home_localization_action_rsi_launcher_localization": "RSI 启动器汉化",
"home_localization_action_rsi_launcher_no_game_path_msg": "您当前未安装游戏本体或未选择游戏安装目录,只可使用启动器汉化功能。请确保游戏安装完毕或在盒子设置中添加游戏安装目录后重试。",
"home_localization_action_advanced": "高级汉化",
"home_localization_action_install_customize": "安装自定义文件",
"home_localization_title_localization_tools": "汉化工具",
"performance_json_text_ssdo": "屏幕光线后处理",
"performance_json_text_ssdo_info": "调整光线后处理等级",
"performance_json_text_title_graphics": "图形(修改后建议清理着色器)",
"performance_json_text_antialiasing": "抗锯齿",
"performance_json_text_antialiasing_info": "0 关闭1 SMAA2 时间过滤+SMAA3 时间滤波和投影矩阵抖动的 SMAA",
"performance_json_text_game_effects": "特效等级",
"performance_json_text_game_effects_info": "游戏特效等级",
"performance_json_text_texture": "纹理等级",
"performance_json_text_texture_info": "模型纹理细节",
"performance_json_text_volumetric_effects": "体积效果",
"performance_json_text_volumetric_effects_info": "体积云、体积光照等",
"performance_json_text_water": "水体效果",
"performance_json_text_water_info": "各种水的等级",
"performance_json_text_object_detail": "对象细节",
"performance_json_text_object_detail_info": "模型对象细节影响LOD等..",
"performance_json_text_particles": "粒子细节",
"performance_json_text_physics": "物理细节",
"performance_json_text_physics_info": "物理效果范围",
"performance_json_text_shading": "着色器细节",
"performance_json_text_shading_info": "着色器相关",
"performance_json_text_shadows": "阴影细节",
"performance_json_text_shadows_info": "阴影效果",
"performance_json_text_postprocessing": "后处理细节",
"performance_json_text_postprocessing_info": "后处理着色器,动态模糊效果 等",
"performance_json_text_renderer": "渲染器质量",
"performance_json_text_renderer_info": "cryengine 渲染器质量",
"performance_json_text_shader_decal": "贴花质量",
"performance_json_text_shader_decal_info": "LOGO、标志等",
"performance_json_text_shader_post_process": "着色器质量",
"performance_json_text_shader_fx": "FX 质量",
"performance_json_text_shader_general": "常规质量",
"performance_json_text_shader_general_info": "整体模型质量",
"performance_json_text_shader_glass": "玻璃质量",
"performance_json_text_shader_glass_info": "窗、镜子等",
"performance_json_text_shader_hdr": "HDR质量",
"performance_json_text_shader_hdr_info": "HDR色差亮度层级 处理 等",
"performance_json_text_shader_particle": "粒子质量",
"performance_json_text_shader_particle_info": "粒子效果质量",
"performance_json_text_shader_terrain": "地面质量",
"performance_json_text_shader_shadow": "阴影质量",
"performance_json_text_shader_sky": "天空质量",
"performance_json_text_particles_object_collisions": "粒子碰撞",
"performance_json_text_particles_object_collisions_info": "1 仅静态粒子 2 包括动态粒子",
"performance_json_text_displayinfo": "屏幕信息(展示帧率)",
"performance_json_text_displayinfo_info": "在屏幕右上角展示帧率,服务器信息等",
"performance_json_text_max_fps": "最大帧率",
"performance_json_text_max_fps_info": "调整游戏最高帧率0为不限制",
"performance_json_text_display_session": "显示会话信息",
"performance_json_text_display_session_info": "开启后在屏幕上显示一个二维码,用于反馈时让 CIG 快速定位相关信息",
"performance_json_text_vsync": "垂直同步",
"performance_json_text_vsync_info": "开启以防止撕裂,关闭以提高帧率",
"performance_json_text_motion_blur": "动态模糊",
"performance_json_text_motion_blur_info": "开启以提高运动感,关闭提升观感",
"performance_json_text_fov": "设置视角FOV",
"performance_json_text_ui_animation": "UI 淡入淡出动画",
"performance_json_text_custom_parameters": "自定义参数",
"performance_json_text_title_custom": "自定义",
"tools_rsi_launcher_enhance_init_msg1": "读取启动器信息...",
"tools_rsi_launcher_enhance_init_msg2": "正在从网络获取增强数据...",
"tools_rsi_launcher_enhance_working_msg1": "生成补丁 ...",
"tools_rsi_launcher_enhance_working_msg2": "安装补丁,这需要一点时间,取决于您的计算机性能 ...",
"tools_rsi_launcher_enhance_title": "RSI 启动器增强",
"tools_rsi_launcher_enhance_msg_version": "启动器内部版本信息:{v0}",
"tools_rsi_launcher_enhance_msg_patch_status": "补丁状态:{v0}",
"tools_rsi_launcher_enhance_msg_error": "获取增强数据失败,可能是网络问题或当前版本不支持",
"tools_rsi_launcher_enhance_title_localization": "RSI 启动器本地化",
"tools_rsi_launcher_enhance_subtitle_localization": "为 RSI 启动器增加多语言支持。",
"tools_rsi_launcher_enhance_title_download_booster": "RSI 启动器下载增强",
"tools_rsi_launcher_enhance_subtitle_download_booster": "下载游戏时可使用更多线程以提升下载速度,启用后请在启动器设置修改线程数。",
"tools_rsi_launcher_enhance_action_install": "安装增强补丁",
"tools_rsi_launcher_enhance_msg_uninstall": "* 如需卸载增强补丁,请覆盖安装 RSI 启动器。",
"tools_rsi_launcher_enhance_msg_error_launcher_notfound": "未找到 RSI 启动器",
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error": "读取启动器信息失败!",
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error_with_args": "读取启动器信息失败:{v0}",
"tools_action_rsi_launcher_enhance_info": "启动器汉化,下载线程增强",
"tools_rsi_launcher_enhance_note_title": "RSI 启动器增强使用须知",
"tools_rsi_launcher_enhance_note_msg": "RSI 启动器增强是一项社区功能,它会在您的电脑上解包 \"RSI Launcher\" 并加入额外的增强功能,具体使用哪些功能由您决定。\n\n目前官方CIG仅许可我们进行多语言操作启动器下载增强是我们认为有用的额外功能违反cig用户协议https://robertsspaceindustries.com/eula可能导致账号被封禁等严重后果是否启用由您自己决定我们不对可能产生的后果游戏损坏账号封禁等承担任何责任。\n\n对于启动器的修改内容我们开源于https://github.com/StarCitizenToolBox/RSILauncherEnhance如有需要您可自行查阅。\n\n如果您因为任何原因需要取消此增强补丁请直接覆盖安装官方启动器。",
"tools_action_unp4k": "P4K 查看器",
"tools_action_unp4k_info": "解包星际公民 p4k 文件",
"tools_unp4k_title": "P4K 查看器 -> {v0}",
"tools_unp4k_view_file": "单击文件以预览",
"tools_unp4k_msg_unknown_file_type": "未知文件类型\n{v0}",
"home_localization_select_customize_file_ini": "请选择 ini 文件",
"home_localization_select_customize_file": "请选择自定义汉化文件",
"home_localization_action_select_customize_file": "点击选择 ini 文件",
"home_localization_ptu_advanced_localization_tip_title": "推荐使用高级汉化",
"home_localization_ptu_advanced_localization_tip_title_info": "在 PTU/EPTU 等测试频道 ,当前汉化文本可能与游戏不同步,使用高级汉化可以减少乱码产生。",
"tools_rsi_launcher_enhance_action_fold": "收起额外功能",
"tools_rsi_launcher_enhance_action_expand": "展开额外功能",
"tools_unp4k_missing_runtime": "缺少运行库",
"tools_unp4k_missing_runtime_info": "使用此功能需安装 .NET8 运行库,请点击下方按钮下载安装,安装成功后重新打开此页面即可继续使用。",
"tools_unp4k_missing_runtime_action_install": "安装运行库"
}

801
lib/l10n/intl_zh_TW.arb Normal file
View File

@ -0,0 +1,801 @@
{
"@@locale": "zh_TW",
"@@auto_translate_locale": "zh-tw",
"app_language_name": "繁體中文",
"@app_language_name": {},
"app_language_code": "zh_TW",
"app_index_version_info": "SC工具箱 V{v0} {v1}",
"@app_index_version_info": {},
"app_shortcut_name": "SC工具箱DEV.lnk",
"@app_shortcut_name": {},
"about_check_update": "檢查更新",
"@about_check_update": {},
"about_app_description": "這個工具能做的不僅僅是翻譯!\n\nSC工具箱是你探索宇宙的好幫手我們致力於為各位公民解決遊戲中的常見問題並為社群翻譯、性能改善、常用網站翻譯 等操作提供便利。",
"@about_app_description": {},
"about_online_feedback": "意見反饋",
"@about_online_feedback": {},
"about_action_qq_group": "QQ群組",
"@about_action_qq_group": {},
"about_action_email": "電子信箱",
"@about_action_email": {},
"about_action_open_source": "專案開源 (Github)",
"@about_action_open_source": {},
"about_disclaimer": "SC工具箱非官方的星際公民工具不隸屬於 Cloud Imperium 公司集團。 本軟體中非由其主機或使用者創作的所有內容均為其各自所有者的財產。 \nStar Citizen®、Roberts Space Industries® 和 Cloud Imperium® 是 Cloud Imperium Rights LLC 的註冊商標。",
"@about_disclaimer": {},
"about_analytics_launch": "啟動",
"@about_analytics_launch": {},
"about_analytics_launch_game": "啟動遊戲",
"@about_analytics_launch_game": {},
"about_analytics_total_users": "使用者總計",
"@about_analytics_total_users": {},
"about_analytics_install_translation": "翻譯安裝",
"@about_analytics_install_translation": {},
"about_analytics_performance_optimization": "畫面與性能改善",
"@about_analytics_performance_optimization": {},
"about_analytics_p4k_redirection": "P4K分流",
"@about_analytics_p4k_redirection": {},
"about_analytics_units_user": "位",
"@about_analytics_units_user": {},
"about_analytics_units_times": "次",
"@about_analytics_units_times": {},
"about_info_latest_version": "已經更新至最新版本",
"@about_info_latest_version": {},
"home_holiday_countdown": "遊戲節慶倒數計時",
"@home_holiday_countdown": {},
"home_holiday_countdown_disclaimer": "* 以上節慶日期由人工收錄與維護,可能存在部分偏誤,歡迎進行反饋!",
"@home_holiday_countdown_disclaimer": {},
"home_action_one_click_launch": "快速啟動",
"@home_action_one_click_launch": {},
"home_title_logging_in": "正在登入...",
"@home_title_logging_in": {},
"home_login_title_welcome_back": "歡迎回來!",
"@home_login_title_welcome_back": {},
"home_login_title_launching_game": "正在為您啟動遊戲...",
"@home_login_title_launching_game": {},
"home_action_login_rsi_account": "登入 RSI 帳戶",
"@home_action_login_rsi_account": {},
"home_login_info_game_version_outdated": "遊戲版本過舊",
"@home_login_info_game_version_outdated": {},
"home_login_info_rsi_server_report": "RSI 伺服器報告版本號:{v1} \n\n本機版本號{v2} \n\n建議使用 RSI Launcher 更新遊戲!",
"@home_login_info_rsi_server_report": {},
"home_login_info_action_ignore": "忽略",
"@home_login_info_action_ignore": {},
"home_login_action_title_box_one_click_launch": "工具箱快速啟動",
"@home_login_action_title_box_one_click_launch": {},
"home_login_info_one_click_launch_description": "本功能可以幫您更加便利的啟動遊戲。\n\n為確保帳戶安全 ,本功能使用中文翻譯瀏覽器保留登入狀態,且不會儲存您的密碼資訊(除非你啟用了自動輸入功能)。\n\n使用此功能登入帳號時請確保您的 SC工具箱 是從可信任的來源下載。",
"@home_login_info_one_click_launch_description": {},
"home_login_action_title_need_webview2_runtime": "需要安裝 WebView2 Runtime",
"@home_login_action_title_need_webview2_runtime": {},
"action_close": "關閉",
"@action_close": {},
"downloader_speed_limit_settings": "下載設定",
"@downloader_speed_limit_settings": {},
"downloader_action_pause_all": "全部暫停",
"@downloader_action_pause_all": {},
"downloader_action_resume_all": "全部繼續",
"@downloader_action_resume_all": {},
"downloader_action_cancel_all": "全部取消",
"@downloader_action_cancel_all": {},
"downloader_info_no_download_tasks": "無下載任務",
"@downloader_info_no_download_tasks": {},
"downloader_info_total_size": "總大小:{v1}",
"@downloader_info_total_size": {},
"downloader_info_verifying": "校驗中...{v2}",
"@downloader_info_verifying": {},
"downloader_info_downloading": "下載中... ({v0}%)",
"@downloader_info_downloading": {},
"downloader_info_status": "狀態:{v0}",
"@downloader_info_status": {},
"downloader_info_uploaded": "已上傳:{v0}",
"@downloader_info_uploaded": {},
"downloader_info_downloaded": "已下載:{v0}",
"@downloader_info_downloaded": {},
"downloader_action_options": "選項",
"@downloader_action_options": {},
"downloader_action_continue_download": "繼續下載",
"@downloader_action_continue_download": {},
"downloader_action_pause_download": "暫停下載",
"@downloader_action_pause_download": {},
"downloader_action_cancel_download": "取消下載",
"@downloader_action_cancel_download": {},
"action_open_folder": "打開資料夾",
"@action_open_folder": {},
"downloader_info_download_upload_speed": "下載: {v0}/s 上傳:{v1}/s",
"@downloader_info_download_upload_speed": {},
"downloader_info_downloading_status": "下載中...",
"@downloader_info_downloading_status": {},
"downloader_info_waiting": "等待中",
"@downloader_info_waiting": {},
"downloader_info_paused": "已暫停",
"@downloader_info_paused": {},
"downloader_info_download_failed": "下載失敗",
"@downloader_info_download_failed": {},
"downloader_info_download_completed": "下載完成",
"@downloader_info_download_completed": {},
"downloader_info_deleted": "已刪除",
"@downloader_info_deleted": {},
"downloader_title_downloading": "下載中",
"@downloader_title_downloading": {},
"downloader_title_ended": "已結束",
"@downloader_title_ended": {},
"downloader_action_confirm_cancel_all_tasks": "確認取消全部任務?",
"@downloader_action_confirm_cancel_all_tasks": {},
"downloader_info_manual_file_deletion_note": "如果文件不再需要,你可能需要手動刪除下載文件。",
"@downloader_info_manual_file_deletion_note": {},
"downloader_action_confirm_cancel_download": "確認取消下載?",
"@downloader_action_confirm_cancel_download": {},
"downloader_info_p2p_network_note": "SC 工具箱使用 p2p 網路來加速文件下載,如果您流量有限,可在此處將上傳頻寬設定為 1(byte)。",
"@downloader_info_p2p_network_note": {},
"downloader_info_download_unit_input_prompt": "請輸入下載單位1、100k、10m 0或留空為不限速。",
"@downloader_info_download_unit_input_prompt": {},
"downloader_input_upload_speed_limit": "上傳限制:",
"@downloader_input_upload_speed_limit": {},
"downloader_input_download_speed_limit": "下載限制:",
"@downloader_input_download_speed_limit": {},
"downloader_input_info_p2p_upload_note": "* P2P 上傳僅在下載文件時進行,下載完成後會關閉 p2p 連接。如您想參與製作種子文件,請透過關於頁面聯絡我們。",
"@downloader_input_info_p2p_upload_note": {},
"doctor_title_one_click_diagnosis": "疑難排解 -> {v0}",
"@doctor_title_one_click_diagnosis": {},
"doctor_action_rsi_launcher_log": "RSI啟動器log",
"@doctor_action_rsi_launcher_log": {},
"doctor_action_game_run_log": "遊戲執行log",
"@doctor_action_game_run_log": {},
"doctor_info_scan_complete_no_issues": "掃描完畢,沒有找到問題!",
"@doctor_info_scan_complete_no_issues": {},
"doctor_info_processing": "正在處理...",
"@doctor_info_processing": {},
"doctor_info_game_rescue_service_note": "您即將前往由 深空治療中心QQ群號536454632 提供的遊戲異常救援服務,主要解決遊戲安裝失敗與頻繁閃退,如遊戲玩法問題,請勿加群。",
"@doctor_info_game_rescue_service_note": {},
"doctor_info_need_help": "需要幫助? 點擊加群尋求免費人工支援!",
"@doctor_info_need_help": {},
"doctor_info_tool_check_result_note": "注意:本工具檢測結果僅供參考,若您不理解以下操作,請提供截圖給有經驗的玩家!",
"@doctor_info_tool_check_result_note": {},
"doctor_info_result_unsupported_os": "不支援的作業系統,遊戲可能無法執行",
"@doctor_info_result_unsupported_os": {},
"doctor_info_result_upgrade_system": "請更新您的系統 ({v0})",
"@doctor_info_result_upgrade_system": {},
"doctor_info_result_missing_live_folder": "安裝目錄缺少LIVE資料夾可能導致安裝失敗",
"@doctor_info_result_missing_live_folder": {},
"doctor_info_result_create_live_folder": "點擊修復為您新增 LIVE 資料夾,完成後重試安裝。({v0})",
"@doctor_info_result_create_live_folder": {},
"doctor_info_result_incompatible_nvme_device": "新型 NVME 裝置,與 RSI 啟動器暫不相容,可能導致安裝失敗",
"@doctor_info_result_incompatible_nvme_device": {},
"doctor_info_result_add_registry_value": "為登錄鍵值添加 ForcedPhysicalSectorSizeInBytes 值 模擬舊裝置。硬碟分區({v0})",
"@doctor_info_result_add_registry_value": {},
"doctor_info_result_missing_easyanticheat_files": "EasyAntiCheat 檔案遺失",
"@doctor_info_result_missing_easyanticheat_files": {},
"doctor_info_result_verify_files_with_rsi_launcher": "未在 LIVE 資料夾找到 EasyAntiCheat 文件 或 文件不完整,請使用 RSI 啟動器校驗文件",
"@doctor_info_result_verify_files_with_rsi_launcher": {},
"doctor_info_result_easyanticheat_not_installed": "EasyAntiCheat 未安裝 或 未正常退出",
"@doctor_info_result_easyanticheat_not_installed": {},
"doctor_info_result_install_easyanticheat": "EasyAntiCheat 未安裝,請點擊修復為您快速安裝。(在遊戲正常啟動並結束前,該問題會一直出現,若您因為其他原因遊戲閃退,可忽略此條目)",
"@doctor_info_result_install_easyanticheat": {},
"doctor_info_result_chinese_username": "中文使用者名稱!",
"@doctor_info_result_chinese_username": {},
"doctor_info_result_chinese_username_error": "中文使用者名稱可能會導致遊戲啟動/安裝錯誤! 點擊修復按鈕查看修改教學!",
"@doctor_info_result_chinese_username_error": {},
"doctor_info_result_chinese_install_path": "中文安裝路徑!",
"@doctor_info_result_chinese_install_path": {},
"doctor_info_result_chinese_install_path_error": "中文安裝路徑!這可能會導致遊戲 啟動/安裝 錯誤!({v0}請在RSI啟動器更換安裝路徑。",
"@doctor_info_result_chinese_install_path_error": {},
"doctor_info_result_low_physical_memory": "物理記憶體過低",
"@doctor_info_result_low_physical_memory": {},
"doctor_info_result_memory_requirement": "您至少需要 16GB 的物理記憶體Memory才可執行此遊戲。目前大小{v0}",
"@doctor_info_result_memory_requirement": {},
"doctor_info_result_fix_suggestion": "修復建議: {v0}",
"@doctor_info_result_fix_suggestion": {},
"doctor_info_result_no_solution": "暫無解決方法,請截圖回饋",
"@doctor_info_result_no_solution": {},
"doctor_info_action_fix": "修復",
"@doctor_info_action_fix": {},
"doctor_action_view_solution": "查看解決方案",
"@doctor_action_view_solution": {},
"doctor_tip_title_select_game_directory": "請在首頁選擇遊戲安裝目錄。",
"@doctor_tip_title_select_game_directory": {},
"doctor_action_result_try_latest_windows": "若您的硬體達標,請嘗試安裝最新的 Windows 系統。",
"@doctor_action_result_try_latest_windows": {},
"doctor_action_result_create_folder_success": "建立資料夾成功,請嘗試繼續下載遊戲!",
"@doctor_action_result_create_folder_success": {},
"doctor_action_result_create_folder_fail": "建立資料夾失敗,請嘗試手動建立。\n目錄{v0} \n錯誤{v1}",
"@doctor_action_result_create_folder_fail": {},
"doctor_action_result_fix_success": "修復成功,請嘗試重啟後繼續安裝遊戲! 若登錄檔修改操作導致其他軟體出現相容問題,請使用 工具 中的 NVME 登錄檔清理。",
"@doctor_action_result_fix_success": {},
"doctor_action_result_fix_fail": "修復失敗,{v0}",
"@doctor_action_result_fix_fail": {},
"doctor_action_result_game_start_success": "修復成功,請嘗試啟動遊戲。(若問題無法解決,請使用工具箱的 《重裝 EAC》",
"@doctor_action_result_game_start_success": {},
"doctor_action_result_redirect_warning": "即將前往,教學來自網路,請謹慎操作...",
"@doctor_action_result_redirect_warning": {},
"doctor_action_result_issue_not_supported": "該問題暫不支援自動處理,請提供截圖尋求幫助",
"@doctor_action_result_issue_not_supported": {},
"doctor_action_analyzing": "正在分析...",
"@doctor_action_analyzing": {},
"doctor_action_result_analysis_no_issue": "分析完畢,沒有發現問題",
"@doctor_action_result_analysis_no_issue": {},
"doctor_action_result_analysis_issues_found": "分析完畢,發現 {v0} 個問題",
"@doctor_action_result_analysis_issues_found": {},
"doctor_action_result_toast_scan_no_issue": "掃描完畢,沒有發現問題,若仍然安裝失敗,請嘗試使用工具箱中的 RSI啟動器管理員模式。",
"@doctor_action_result_toast_scan_no_issue": {},
"doctor_action_tip_checking_game_log": "正在檢查Game.log",
"@doctor_action_tip_checking_game_log": {},
"doctor_action_info_game_abnormal_exit": "遊戲錯誤退出:{v0}",
"@doctor_action_info_game_abnormal_exit": {},
"doctor_action_info_game_abnormal_exit_unknown": "遊戲錯誤退出:未知錯誤",
"@doctor_action_info_game_abnormal_exit_unknown": {},
"doctor_action_info_info_feedback": "info:{v0},請點擊右下角加群回饋。",
"@doctor_action_info_info_feedback": {},
"doctor_action_info_checking_eac": "正在檢查EAC",
"@doctor_action_info_checking_eac": {},
"doctor_action_info_checking_runtime": "正在檢查:執行環境",
"@doctor_action_info_checking_runtime": {},
"doctor_action_result_info_unsupported_os": "不支援的作業系統:{v0}",
"@doctor_action_result_info_unsupported_os": {},
"doctor_action_info_checking_install_info": "正在檢查:安裝資訊",
"@doctor_action_info_checking_install_info": {},
"doctor_action_view_details": "查看詳情",
"@doctor_action_view_details": {},
"home_install_location": "安裝位置:",
"@home_install_location": {},
"home_not_installed_or_failed": "未安裝 或 安裝失敗",
"@home_not_installed_or_failed": {},
"home_action_star_citizen_website_localization": "星際公民官網",
"@home_action_star_citizen_website_localization": {},
"home_action_info_roberts_space_industries_origin": "羅伯茨航天工業公司,萬物的起源",
"@home_action_info_roberts_space_industries_origin": {},
"home_action_uex_localization": "UEX",
"@home_action_uex_localization": {},
"home_action_info_mining_refining_trade_calculator": "採礦、精煉、貿易計算器、價格、載具資訊",
"@home_action_info_mining_refining_trade_calculator": {},
"home_action_dps_calculator_localization": "DPS計算器",
"@home_action_dps_calculator_localization": {},
"home_action_info_ship_upgrade_damage_value_query": "在線上進行改裝、查詢傷害數值和配件購買地點",
"@home_action_info_ship_upgrade_damage_value_query": {},
"home_action_external_browser_extension": "瀏覽器擴充套件:",
"@home_action_external_browser_extension": {},
"home_action_one_click_diagnosis": "疑難排解",
"@home_action_one_click_diagnosis": {},
"home_action_info_one_click_diagnosis_star_citizen": "快速解決星際公民的常見問題",
"@home_action_info_one_click_diagnosis_star_citizen": {},
"home_action_localization_management": "翻譯管理",
"@home_action_localization_management": {},
"home_action_info_quick_install_localization_resources": "快速安裝翻譯文件",
"@home_action_info_quick_install_localization_resources": {},
"home_action_performance_optimization": "畫面調整",
"@home_action_performance_optimization": {},
"home_action_info_engine_config_optimization": "調整引擎配置檔案,改善遊戲性能",
"@home_action_info_engine_config_optimization": {},
"home_action_rsi_status_platform": "平台",
"@home_action_rsi_status_platform": {},
"home_action_rsi_status_persistent_universe": "恆久宇宙",
"@home_action_rsi_status_persistent_universe": {},
"home_action_rsi_status_electronic_access": "電子訪問",
"@home_action_rsi_status_electronic_access": {},
"home_action_rsi_status_arena_commander": "競技場指揮官",
"@home_action_rsi_status_arena_commander": {},
"home_action_rsi_status_rsi_server_status": "RSI 伺服器狀態",
"@home_action_rsi_status_rsi_server_status": {},
"home_action_rsi_status_status": "狀態:",
"@home_action_rsi_status_status": {},
"home_announcement_details": "公告詳情",
"@home_announcement_details": {},
"home_action_info_valid_install_location_required": "該功能需要一個有效的安裝位置\n\n如果您的遊戲未下載完成請等待下載完畢後使用此功能。\n\n如果您的遊戲已下載完畢但未識別請啟動一次遊戲後重新打開工具箱 或 在設定選項中手動設定安裝位置。",
"@home_action_info_valid_install_location_required": {},
"home_action_info_scanning": "正在掃描 ...",
"@home_action_info_scanning": {},
"home_action_info_scan_complete_valid_directories_found": "掃描完畢,共找到 {v0} 個有效安裝目錄",
"@home_action_info_scan_complete_valid_directories_found": {},
"home_action_info_log_file_parse_fail": "解析 log 文件失敗!",
"@home_action_info_log_file_parse_fail": {},
"home_action_title_star_citizen_website_localization": "星際公民網站翻譯",
"@home_action_title_star_citizen_website_localization": {},
"home_action_info_web_localization_plugin_disclaimer": "本插件功能僅供大致瀏覽使用,不對任何有關本功能產生的問題負責!在涉及帳號操作前請注意確認網站的原本內容!\n\n\n使用此功能登入帳號時請確保您的 SC工具箱 是從可信任的來源下載。",
"@home_action_info_web_localization_plugin_disclaimer": {},
"home_action_info_initializing_resources": "正在初始化翻譯文件...",
"@home_action_info_initializing_resources": {},
"home_action_info_initialization_failed": "初始化網頁翻譯文件失敗!{v0}",
"@home_action_info_initialization_failed": {},
"home_title_app_name": "SC工具箱",
"@home_title_app_name": {},
"home_localization_new_version_available": "社群翻譯有新的版本",
"@home_localization_new_version_available": {},
"home_localization_new_version_installed": "您在 {v0} 安裝的社群翻譯有新的版本",
"@home_localization_new_version_installed": {},
"home_info_valid_installation_required": "該功能需要一個有效的安裝位置",
"@home_info_valid_installation_required": {},
"home_info_one_click_launch_warning": "快速啟動功能提示",
"@home_info_one_click_launch_warning": {},
"home_info_account_security_warning": "為確保帳戶安全快速啟動功能已在Dev版本中禁用我們將在Microsoft Store版本中提供此功能。\n\nMicrosoft Store版由Microsoft提供可靠的分發下載與數位簽章可有效防止軟體被惡意篡改。\n\n提示您無需使用工具箱啟動遊戲也可使用社群翻譯。",
"@home_info_account_security_warning": {},
"home_action_install_microsoft_store_version": "安裝Microsoft Store版本",
"@home_action_install_microsoft_store_version": {},
"home_action_cancel": "取消",
"@home_action_cancel": {},
"home_action_info_abnormal_game_exit": "遊戲非正常退出\nexitCode={v0}\nstdout={v1}\nstderr={v2}\n\n診斷資訊{v3} \n{v4}",
"@home_action_info_abnormal_game_exit": {},
"home_action_info_unknown_error": "未知錯誤,請透過疑難排解加入群組反應。",
"@home_action_info_unknown_error": {},
"home_action_info_check_web_link": "請查看彈出式網頁連結獲得詳細資訊。",
"@home_action_info_check_web_link": {},
"home_action_info_game_built_in": "內建翻譯文件",
"@home_action_info_game_built_in": {},
"home_action_info_warning": "翻譯警告",
"@home_action_info_warning": {},
"localization_info_machine_translation_warning": "您目前正在使用遊戲內建翻譯文件,官方內建文件截止至 3.21.0 都是機器翻譯,建議安裝下方提供的社群翻譯或是來自其他來源的社群翻譯文件。",
"@localization_info_machine_translation_warning": {},
"localization_info_translation": "遊戲翻譯",
"@localization_info_translation": {},
"localization_info_enabled": "啟用({v0}",
"@localization_info_enabled": {},
"localization_info_installed_version": "已安裝:{v0}",
"@localization_info_installed_version": {},
"localization_action_translation_feedback": "意見反饋",
"@localization_action_translation_feedback": {},
"localization_action_uninstall_translation": "解除安裝",
"@localization_action_uninstall_translation": {},
"localization_info_note": "備註:",
"@localization_info_note": {},
"localization_info_community_translation": "社群翻譯",
"@localization_info_community_translation": {},
"localization_info_no_translation_available": "該語言/版本可能因為較新而暫時沒有可安裝的社群翻譯,可以使用進階功能安裝其他來源的社群翻譯",
"@localization_info_no_translation_available": {},
"localization_action_install": "安裝",
"@localization_action_install": {},
"localization_info_version_number": "版本:{v0}",
"@localization_info_version_number": {},
"localization_info_channel": "遊戲通道:{v0}",
"@localization_info_channel": {},
"localization_info_update_time": "更新時間:{v0}",
"@localization_info_update_time": {},
"localization_info_installed": "已安裝",
"@localization_info_installed": {},
"localization_info_unavailable": "無法使用",
"@localization_info_unavailable": {},
"localization_info_language": "語言: ",
"@localization_info_language": {},
"localization_info_remove_incompatible_translation_params": "是否移除不相容的翻譯參數",
"@localization_info_remove_incompatible_translation_params": {},
"localization_info_incompatible_translation_params_warning": "USER.cfg 包含不相容的翻譯參數,這可能是以前的翻譯文件的殘留信息。\n\n這將可能導致翻譯無效或亂碼點擊確認進行快速刪除不會影響其他配置。",
"@localization_info_incompatible_translation_params_warning": {},
"localization_info_corrupted_file": "文件已損毀,請重新下載",
"@localization_info_corrupted_file": {},
"localization_info_installation_error": "安裝錯誤!\n\n {v0}",
"@localization_info_installation_error": {},
"localization_info_custom_files": "自訂文件",
"@localization_info_custom_files": {},
"performance_info_graphic_optimization_hint": "畫面改善提示",
"@performance_info_graphic_optimization_hint": {},
"performance_info_graphic_optimization_warning": "此功能對改善因 GPU 造成的瓶頸,但對於因 CPU 造成瓶頸的裝置可能引發負面效果,如果您 GPU 性能強勁,可以嘗試更改為更高的畫質來獲得更高的 GPU 使用率並改善畫面表現。",
"@performance_info_graphic_optimization_warning": {},
"performance_info_current_status": "目前狀態:{v0}",
"@performance_info_current_status": {},
"performance_info_applied": "已套用",
"@performance_info_applied": {},
"performance_info_not_applied": "未套用",
"@performance_info_not_applied": {},
"performance_action_preset": "預設:",
"@performance_action_preset": {},
"performance_action_low": "低",
"@performance_action_low": {},
"performance_action_medium": "中",
"@performance_action_medium": {},
"performance_action_high": "高",
"@performance_action_high": {},
"performance_action_super": "極高",
"@performance_action_super": {},
"performance_action_info_preset_only_changes_graphics": "(預設只修改圖形設定)",
"@performance_action_info_preset_only_changes_graphics": {},
"performance_action_reset_to_default": " 回復預設 ",
"@performance_action_reset_to_default": {},
"performance_action_apply": "套用設定",
"@performance_action_apply": {},
"performance_action_apply_and_clear_shaders": "套用設定並清除著色器快取(建議)",
"@performance_action_apply_and_clear_shaders": {},
"performance_title_performance_optimization": "畫面調整 -> {v0}",
"@performance_title_performance_optimization": {},
"performance_action_custom_parameters_input": "您可以在這裡輸入未收錄進工具箱的自訂參數。配置範例:\n\nr_displayinfo=0\nr_VSync=0",
"@performance_action_custom_parameters_input": {},
"performance_info_min_max_values": "{v0} 最小值: {v1} / 最大值: {v2}",
"@performance_info_min_max_values": {},
"performance_info_graphics": "圖形",
"@performance_info_graphics": {},
"performance_info_delete_config_file": "刪除配置檔案...",
"@performance_info_delete_config_file": {},
"performance_action_clear_shaders": "清理著色器",
"@performance_action_clear_shaders": {},
"performance_info_done": "完成...",
"@performance_info_done": {},
"performance_info_shader_clearing_warning": "清理著色器後首次進入遊戲可能會出現卡頓,請耐心等待著色器載入完畢。",
"@performance_info_shader_clearing_warning": {},
"performance_info_generate_config_file": "生成配置檔案",
"@performance_info_generate_config_file": {},
"performance_info_write_out_config_file": "寫出配置檔案",
"@performance_info_write_out_config_file": {},
"app_index_menu_home": "首頁",
"@app_index_menu_home": {},
"app_index_menu_lobby": "大廳",
"@app_index_menu_lobby": {},
"app_index_menu_tools": "工具",
"@app_index_menu_tools": {},
"app_index_menu_settings": "設定",
"@app_index_menu_settings": {},
"app_index_menu_about": "關於",
"@app_index_menu_about": {},
"lobby_online_lobby_coming_soon": "多人大廳,敬請期待 ",
"@lobby_online_lobby_coming_soon": {},
"lobby_invitation_to_participate": "誠邀您參與 ",
"@lobby_invitation_to_participate": {},
"lobby_survey": "問卷調查。",
"@lobby_survey": {},
"setting_action_create_settings_shortcut": "新增桌面捷徑",
"@setting_action_create_settings_shortcut": {},
"setting_action_create_desktop_shortcut": "在桌面新增《SC工具箱》捷徑",
"@setting_action_create_desktop_shortcut": {},
"setting_action_reset_auto_password_fill": "重設自動密碼輸入",
"@setting_action_reset_auto_password_fill": {},
"setting_action_ignore_efficiency_cores_on_launch": "啟動遊戲時忽略 E-Core (適用於Intel 12代以上的處理器)",
"@setting_action_ignore_efficiency_cores_on_launch": {},
"setting_action_set_core_count": "已設定的核心數量:{v0} (此功能適用於首頁的工具箱快速啟動 或 工具中的RSI啟動器管理員模式當為 0 時不啟用此功能 ",
"@setting_action_set_core_count": {},
"setting_action_set_launcher_file": "變更啟動器文件RSI Launcher.exe",
"@setting_action_set_launcher_file": {},
"setting_action_info_manual_launcher_location_setting": "手動選擇啟動器位置,建議僅在無法自動掃描安裝位置時使用",
"@setting_action_info_manual_launcher_location_setting": {},
"setting_action_set_game_file": "變更遊戲文件 StarCitizen.exe",
"@setting_action_set_game_file": {},
"setting_action_info_manual_game_location_setting": "手動選擇遊戲安裝位置,建議僅在無法自動掃描安裝位置時使用",
"@setting_action_info_manual_game_location_setting": {},
"setting_action_clear_translation_file_cache": "清理翻譯文件快取",
"@setting_action_clear_translation_file_cache": {},
"setting_action_info_cache_clearing_info": "快取大小 {v0}MB清理工具箱下載的翻譯文件快取不會影響已安裝的社群翻譯",
"@setting_action_info_cache_clearing_info": {},
"setting_action_tool_site_access_acceleration": "網站加速",
"@setting_action_tool_site_access_acceleration": {},
"setting_action_info_mirror_server_info": "使用鏡像伺服器加速訪問 DPS、UEX 等工具網站,若出現錯誤請關閉此功能。 (RSI 官方網站除外)",
"@setting_action_info_mirror_server_info": {},
"setting_action_view_log": "查看log",
"@setting_action_view_log": {},
"setting_action_info_view_log_file": "查看工具箱的 log 文件,用於定位工具箱的 bug",
"@setting_action_info_view_log_file": {},
"setting_action_info_confirm_reset_autofill": "確認重設自動輸入?",
"@setting_action_info_confirm_reset_autofill": {},
"setting_action_info_delete_local_account_warning": "這將會刪除本機的帳號記錄,或在下次啟動遊戲時將自動輸入選擇 ‘否’ 以禁用自動輸入。",
"@setting_action_info_delete_local_account_warning": {},
"setting_action_info_autofill_data_cleared": "已清理自動輸入資料",
"@setting_action_info_autofill_data_cleared": {},
"setting_action_info_enter_cpu_core_to_ignore": "請輸入要忽略的 CPU 核心數",
"@setting_action_info_enter_cpu_core_to_ignore": {},
"setting_action_info_cpu_core_tip": "Tip您的裝置擁有幾個 E-Core 就輸入幾個,非大小核裝置請保持 0\n\n此功能適用於首頁的工具箱快速啟動 或 工具中的 RSI啟動器管理員模式當為 0 時不啟用此功能。",
"@setting_action_info_cpu_core_tip": {},
"setting_action_info_select_rsi_launcher_location": "請選擇RSI啟動器位置RSI Launcher.exe",
"@setting_action_info_select_rsi_launcher_location": {},
"setting_action_info_setting_success": "設定成功,在對應頁面點擊重新整理即可掃描出新路徑",
"@setting_action_info_setting_success": {},
"setting_action_info_file_error": "文件錯誤!",
"@setting_action_info_file_error": {},
"setting_action_info_select_game_install_location": "請選擇遊戲安裝位置StarCitizen.exe",
"@setting_action_info_select_game_install_location": {},
"setting_action_info_confirm_clear_cache": "確認清理翻譯快取?",
"@setting_action_info_confirm_clear_cache": {},
"setting_action_info_clear_cache_warning": "這不會影響已安裝的社群翻譯。",
"@setting_action_info_clear_cache_warning": {},
"setting_action_info_microsoft_version_limitation": "因Microsoft Store版本功能限制請在接下來打開的視窗中 手動將《SC工具箱》拖動到桌面即可建立捷徑。",
"@setting_action_info_microsoft_version_limitation": {},
"setting_action_info_shortcut_created": "建立完畢,請返回桌面查看",
"@setting_action_info_shortcut_created": {},
"app_upgrade_title_new_version_found": "發現新版本 -> {v0}",
"@app_upgrade_title_new_version_found": {},
"app_upgrade_info_getting_new_version_details": "正在取得新版本詳情...",
"@app_upgrade_info_getting_new_version_details": {},
"app_upgrade_info_update_server_tip": "提示:目前正在使用分流伺服器進行更新,可能會出現下載速度下降,但有助於我們進行成本控制,若下載錯誤請點擊這裡前往手動安裝。",
"@app_upgrade_info_update_server_tip": {},
"app_upgrade_info_installing": "正在安裝: ",
"@app_upgrade_info_installing": {},
"app_upgrade_info_downloading": "正在下載: {v0}% ",
"@app_upgrade_info_downloading": {},
"app_upgrade_action_update_now": "立即更新",
"@app_upgrade_action_update_now": {},
"app_upgrade_action_next_time": "稍後提醒",
"@app_upgrade_action_next_time": {},
"app_upgrade_info_download_failed": "下載失敗,請嘗試手動安裝!",
"@app_upgrade_info_download_failed": {},
"app_upgrade_info_run_failed": "執行失敗,請嘗試手動安裝!",
"@app_upgrade_info_run_failed": {},
"app_splash_checking_availability": "正在檢測可用性,這可能需要一點時間...",
"@app_splash_checking_availability": {},
"app_splash_checking_for_updates": "正在檢查更新...",
"@app_splash_checking_for_updates": {},
"app_splash_almost_done": "即將完成…",
"@app_splash_almost_done": {},
"tools_hosts_info_rsi_official_website": "RSI 官方網站",
"@tools_hosts_info_rsi_official_website": {},
"tools_hosts_info_rsi_customer_service": "RSI 客服站",
"@tools_hosts_info_rsi_customer_service": {},
"tools_hosts_info_dns_query_and_test": "正在查詢 DNS 並測試可瀏覽性 請耐心等待...",
"@tools_hosts_info_dns_query_and_test": {},
"tools_hosts_info_writing_hosts": "正在寫入 Hosts ...",
"@tools_hosts_info_writing_hosts": {},
"tools_hosts_info_reading_config": "讀取配置 ...",
"@tools_hosts_info_reading_config": {},
"tools_hosts_info_hosts_acceleration": "Hosts 加速",
"@tools_hosts_info_hosts_acceleration": {},
"tools_hosts_info_open_hosts_file": "打開 Hosts 文件",
"@tools_hosts_info_open_hosts_file": {},
"tools_hosts_info_status": "狀態",
"@tools_hosts_info_status": {},
"tools_hosts_info_site": "站點",
"@tools_hosts_info_site": {},
"tools_hosts_info_enable": "是否啟用",
"@tools_hosts_info_enable": {},
"tools_hosts_action_one_click_acceleration": "快速加速",
"@tools_hosts_action_one_click_acceleration": {},
"tools_info_scanning": "正在掃描...",
"@tools_info_scanning": {},
"tools_info_processing_failed": "處理失敗!:{v0}",
"@tools_info_processing_failed": {},
"tools_info_game_install_location": "遊戲安裝位置: ",
"@tools_info_game_install_location": {},
"tools_info_rsi_launcher_location": "RSI啟動器位置",
"@tools_info_rsi_launcher_location": {},
"tools_action_view_system_info": "系統資訊",
"@tools_action_view_system_info": {},
"tools_action_info_view_critical_system_info": "查看系統關鍵資訊,用於快速診斷 \n\n此功能較為耗時請耐心等待。",
"@tools_action_info_view_critical_system_info": {},
"tools_action_p4k_download_repair": "P4K 分流下載 / 修復",
"@tools_action_p4k_download_repair": {},
"tools_action_info_p4k_download_repair_tip": "使用星際公民中文百科提供的分流下載服務,可用於下載或修復 p4k。 \n資源有限請勿濫用。",
"@tools_action_info_p4k_download_repair_tip": {},
"tools_action_hosts_acceleration_experimental": "Hosts 加速Beta",
"@tools_action_hosts_acceleration_experimental": {},
"tools_action_info_hosts_acceleration_experimental_tip": "將 IP 資訊寫入 Hosts 文件,解決部分地區的 DNS 汙染導致無法登入官網等問題。\n該功能正在進行第一階段測試遇到問題請及時回饋。",
"@tools_action_info_hosts_acceleration_experimental_tip": {},
"tools_action_reinstall_easyanticheat": "重新安裝 EAC",
"@tools_action_reinstall_easyanticheat": {},
"tools_action_info_reinstall_eac": "若您遇到 EAC 錯誤,且自動修復無效,請嘗試使用此功能重裝 EAC。",
"@tools_action_info_reinstall_eac": {},
"tools_action_rsi_launcher_admin_mode": "管理員模式",
"@tools_action_rsi_launcher_admin_mode": {},
"tools_action_info_run_rsi_as_admin": "以管理員身份執行RSI啟動器可能會解決一些問題。\n\n若設定了 E-Core 核心忽略參數,也會在此套用。",
"@tools_action_info_run_rsi_as_admin": {},
"tools_action_info_init_failed": "初始化失敗,請截圖報告給開發者。{v0}",
"@tools_action_info_init_failed": {},
"tools_action_rsi_launcher_log_fix": "啟動器日誌修復",
"@tools_action_rsi_launcher_log_fix": {},
"tools_action_info_rsi_launcher_log_issue": "在某些情況下 RSI啟動器 的 log 文件會損壞,導致無法完成問題掃描,使用此工具清理損壞的 log 文件。\n\n目前日誌檔案大小{v0} MB",
"@tools_action_info_rsi_launcher_log_issue": {},
"tools_action_remove_nvme_registry_patch": "移除 nvme 登錄檔補丁",
"@tools_action_remove_nvme_registry_patch": {},
"tools_action_info_nvme_patch_issue": "若您使用 nvme 補丁出現問題,請執行此工具。(可能導致遊戲 安裝/更新 無法使用。)\n\n目前補丁狀態{v0}",
"@tools_action_info_nvme_patch_issue": {},
"tools_action_info_not_installed": "未安裝",
"@tools_action_info_not_installed": {},
"tools_action_info_removed_restart_effective": "已移除登錄檔補丁,重新啟動後電腦生效",
"@tools_action_info_removed_restart_effective": {},
"tools_action_write_nvme_registry_patch": "寫入 nvme 登錄檔補丁",
"@tools_action_write_nvme_registry_patch": {},
"tools_action_info_manual_nvme_patch": "此功能將手動寫入NVME補丁該功能僅在您知道自己在做什麼的情況下使用",
"@tools_action_info_manual_nvme_patch": {},
"tools_action_info_fix_success_restart": "修復成功,請嘗試重新啟動電腦後繼續安裝遊戲! 若登錄檔修改操作導致其他軟體出現相容問題,請使用 工具 中的 NVME 登錄檔清理。",
"@tools_action_info_fix_success_restart": {},
"tools_action_clear_shader_cache": "刪除著色器快取",
"@tools_action_clear_shader_cache": {},
"tools_action_info_shader_cache_issue": "若遊戲畫面出現異常或版本更新後可使用此工具清除著色器快取 \n\n建議清理快取大於 500 MB\n快取大小{v0} MB",
"@tools_action_info_shader_cache_issue": {},
"tools_action_close_photography_mode": "攝影模式",
"@tools_action_close_photography_mode": {},
"tools_action_open_photography_mode": "攝影模式",
"@tools_action_open_photography_mode": {},
"tools_action_info_restore_lens_shake": "已開啟攝影模式,再次點擊來關閉並還原鏡頭晃動效果。\n\n@拉邦那 Lapernum 提供參數資訊。",
"@tools_action_info_restore_lens_shake": {},
"tools_action_info_one_key_close_lens_shake": "關閉遊戲內鏡頭晃動效果以便進行攝影。\n\n @拉邦那 Lapernum 提供參數資訊。",
"@tools_action_info_one_key_close_lens_shake": {},
"tools_action_info_log_file_parse_failed": "解析 log 文件失敗!\n請嘗試使用 啟動器日誌修復 工具!",
"@tools_action_info_log_file_parse_failed": {},
"tools_action_info_rsi_launcher_not_found": "未找到 RSI 啟動器,請嘗試重新安裝,或在設定中手動新增。",
"@tools_action_info_rsi_launcher_not_found": {},
"tools_action_info_star_citizen_not_found": "未找到星際公民遊戲安裝位置,請至少完成一次遊戲啟動操作 或在設定中手動新增。",
"@tools_action_info_star_citizen_not_found": {},
"tools_action_info_valid_game_directory_needed": "該功能需要一個有效的遊戲安裝目錄",
"@tools_action_info_valid_game_directory_needed": {},
"tools_action_info_eac_file_removed": "已為您移除 EAC 文件,接下來將為您打開 RSI 啟動器,請您前往 SETTINGS -> VERIFY 重新安裝 EAC。",
"@tools_action_info_eac_file_removed": {},
"tools_action_info_error_occurred": "出現錯誤:{v0}",
"@tools_action_info_error_occurred": {},
"tools_action_info_system_info_content": "系統:{v0}\n\n處理器{v1}\n\n記憶體{v2}GB\n\n顯示卡\n{v3}\n\n硬碟\n{v4}\n\n",
"@tools_action_info_system_info_content": {},
"tools_action_info_rsi_launcher_directory_not_found": "未找到 RSI 啟動器目錄,請您嘗試手動操作。",
"@tools_action_info_rsi_launcher_directory_not_found": {},
"tools_action_info_log_file_not_exist": "日誌檔案不存在,請嘗試進行一次遊戲啟動或遊戲安裝,並退出啟動器,若無法解決問題,請嘗試將啟動器更新至最新版本!",
"@tools_action_info_log_file_not_exist": {},
"tools_action_info_cleanup_complete": "清理完畢,請完成一次安裝 / 遊戲啟動 操作。",
"@tools_action_info_cleanup_complete": {},
"tools_action_info_cleanup_failed": "清理失敗,請手動移除,檔案位置:{v0}",
"@tools_action_info_cleanup_failed": {},
"tools_action_info_system_info_title": "系統資訊",
"@tools_action_info_system_info_title": {},
"tools_action_info_rsi_launcher_running_warning": "RSI啟動器正在執行請先關閉啟動器再使用此功能",
"@tools_action_info_rsi_launcher_running_warning": {},
"tools_action_info_p4k_file_description": "P4k 是星際公民的核心遊戲文件,高達 100GB+工具箱提供的離線下載是為了幫助一些p4k文件下載慢到不行的使用者 或用於修復官方啟動器無法修復的 p4k 文件。\n\n接下來會跳出視窗詢問您儲存位置可以選擇星際公民資料夾也可以選擇別處下載完成後請確保 P4K 資料夾位於 LIVE 資料夾內,之後使用星際公民啟動器校驗更新即可。",
"@tools_action_info_p4k_file_description": {},
"tools_action_info_p4k_download_in_progress": "已經有一個p4k下載任務正在進行中請前往下載管理器查看",
"@tools_action_info_p4k_download_in_progress": {},
"tools_action_info_function_under_maintenance": "功能維護中,請稍後重試!",
"@tools_action_info_function_under_maintenance": {},
"tools_action_info_config_file_not_exist": "配置檔案不存在,請嘗試執行一次遊戲",
"@tools_action_info_config_file_not_exist": {},
"webview_localization_name_member": "名成員",
"@webview_localization_name_member": {},
"webview_localization_total_invitations": "總邀請數:",
"@webview_localization_total_invitations": {},
"webview_localization_unfinished_invitations": "未完成的邀請",
"@webview_localization_unfinished_invitations": {},
"webview_localization_finished_invitations": "已完成的邀請",
"@webview_localization_finished_invitations": {},
"app_init_failed_with_reason": "初始化失敗:{v0}",
"@app_init_failed_with_reason": {},
"settings_app_language": "語言",
"settings_app_language_auto": "自動",
"app_common_network_error": "網路異常!\n這可能是您的網路環境存在DNS汙染請嘗試更換DNS。\n或伺服器正在維護或遭受攻擊稍後再試。 \n進入離線模式... \n\n請謹慎在離線模式中使用。 \n目前版本構建日期{v0}\n QQ群940696487 \n錯誤資訊{v1}",
"app_common_upgrade_info_error": "獲取更新資訊失敗,請稍後重試。",
"doctor_game_error_low_memory": "可用記憶體不足",
"doctor_game_error_low_memory_info": "請嘗試增加虛擬記憶體( 1080p 下, 物理可用+虛擬記憶體需 > 64G ",
"doctor_game_error_generic_info": "遊戲觸發了最為廣泛的崩潰問題,請查看除錯指南",
"doctor_game_error_gpu_crash": "您的顯示卡已崩潰,請查看除錯指南",
"doctor_game_error_socket_error": "檢測到 socket 異常",
"doctor_game_error_socket_error_info": "如使用 X黑盒 加速器,請嘗試更換加速模式",
"doctor_game_error_permissions_error": "權限不足",
"doctor_game_error_permissions_error_info": "請嘗試以管理員權限執行啟動器或使用工具箱Microsoft Store版啟動。",
"doctor_game_error_game_process_error": "遊戲行程被占用",
"doctor_game_error_game_process_error_info": "請嘗試重啟啟動器,或直接重啟電腦",
"doctor_game_error_game_damaged_file": "遊戲程式文件損壞",
"doctor_game_error_game_damaged_file_info": "請嘗試刪除 Bin64 資料夾 並在啟動器校驗。",
"doctor_game_error_game_damaged_p4k_file": "P4K文件損壞",
"doctor_game_error_game_damaged_p4k_file_info": "請嘗試刪除 Data.p4k 文件 並在啟動器校驗 或 使用工具箱分流。",
"doctor_game_error_low_gpu_memory": "可用 VRAM 不足",
"doctor_game_error_low_gpu_memory_info": "請勿在背景執行其他高GPU占用的 遊戲/應用程式,或更換顯示卡。",
"app_common_error_info": "出現錯誤: {v0}",
"app_common_tip": "提示",
"app_common_tip_i_know": "了解",
"app_common_tip_confirm": "確認",
"app_common_tip_cancel": "取消",
"settings_app_language_switch_info": "切換應用程式的顯示語言",
"home_holiday_countdown_days": "{v0}天 ",
"home_holiday_countdown_in_progress": "正在進行中",
"app_common_loading_images": "載入圖片...",
"app_splash_dialog_u_a_p_p": "使用者協議與隱私政策",
"app_splash_dialog_u_a_p_p_content": "感謝使用 SC工具箱 ,我們致力於為您提供 安全、便捷、可靠的使用體驗,在您開始使用此應用程式前,請先閱讀並同意以下內容:\n\n 1. 本應用程式 為 GNU 通用公共許可證 v3.0 協議下的開源軟體,您可以在遵守協議的前提下自由使用、修改、分發本軟體。我們的源代碼位於:[Github.com/StarCitizenToolBox/app](https://github.com/StarCitizenToolBox/app)。\n2. 本應用程式中的網路內容(包括但不限於 本地化文件、工具網站、新聞、影片 等)版權由其作者創作所有,不屬於 GPL 的一部分,請在遵守對應的授權協議下使用。\n3. 本應用程式的官方免費發布渠道為:[Microsoft Store](https://apps.microsoft.com/detail/9NF3SWFWNKL1) 與[星際公民翻譯組官方網站](https://www.starcitizenzw.com/ ) ,若您從其他第三方處獲得,請仔細甄別,以免遭受財產損失。\n4. 本應用程式在使用過程中會向我們的伺服器發送匿名的統計數據,用於改進軟體服務品質,我們不會收集您的任何個人隱私資訊。\n5. 本應用程式由社群提供支援,與 Cloud Imperium Games 或 其他第三方商業公司 無直接關聯。\n6. 我們提供有限的社群支援,如有需要,請前往關於頁面了解如何聯絡我們。",
"tools_unp4k_msg_init": "初始化中...",
"tools_unp4k_msg_reading": "正在讀取P4K 文件 ...",
"tools_unp4k_msg_reading2": "正在處理文件 ...",
"tools_unp4k_msg_reading3": "正在處理文件 ({v0}/{v1}) ...",
"tools_unp4k_msg_read_completed": "載入完畢:{v0} 個文件,用時:{v1} ms",
"tools_unp4k_msg_open_file": "打開文件:{v0}",
"tools_unp4k_msg_read_file": "讀取文件:{v0} ...",
"home_localization_advanced_title": "進階翻譯 -> {v0}",
"home_localization_advanced_msg_version": "已載入翻譯版本:{v0}",
"home_localization_advanced_title_msg": "翻譯文字行數:{v0} P4K文字行數{v1}",
"home_localization_advanced_action_install": "安裝翻譯",
"home_localization_advanced_action_mod_change": "正在重新生成文字...",
"home_localization_advanced_action_mode": "模式",
"home_localization_advanced_title_preview": "預覽:{v0}",
"home_localization_advanced_json_text_location_other": "地點-其他",
"home_localization_advanced_json_text_location_used": "地點-常用",
"home_localization_advanced_json_text_things_other": "物品-其他",
"home_localization_advanced_json_text_things_used": "物品-常用",
"home_localization_advanced_json_text_vehicle_other": "載具-其他",
"home_localization_advanced_json_text_vehicle_used": "載具-常用",
"home_localization_advanced_json_text_mission_or_logs": "任務/日誌",
"home_localization_advanced_json_text_subtitle": "字幕",
"home_localization_advanced_json_text_ui_or_hud_or_menu": "UI/HUD/選單",
"home_localization_advanced_json_text_un_localization": "未翻譯",
"home_localization_advanced_json_text_others": "其他",
"home_localization_advanced_action_mod_change_localization": "翻譯",
"home_localization_advanced_action_mod_change_un_localization": "英文原文",
"home_localization_advanced_action_mod_change_mixed": "雙語",
"home_localization_advanced_action_mod_change_mixed_newline": "雙語(換行)",
"home_localization_advanced_msg_classifying": "正在分類 ...",
"home_localization_advanced_msg_reading_p4k": "讀取 p4k 文件 ...",
"home_localization_advanced_msg_reading_server_localization_text": "獲取翻譯文字 ...",
"home_localization_advanced_msg_gen_localization_text": "生成翻譯文件...",
"home_localization_advanced_msg_gen_localization_install": "安裝翻譯文件...",
"home_localization_msg_version_advanced": " (進階翻譯)",
"home_localization_msg_no_note": "該版本沒有提供描述",
"home_localization_action_rsi_launcher_localization": "RSI 啟動器翻譯",
"home_localization_action_advanced": "進階翻譯",
"home_localization_action_install_customize": "安裝自訂文件",
"home_localization_title_localization_tools": "翻譯工具",
"performance_json_text_ssdo": "螢幕光線後處理",
"performance_json_text_ssdo_info": "調整光線後處理等級",
"performance_json_text_title_graphics": "圖形(修改後建議刪除著色器快取)",
"performance_json_text_antialiasing": "反鋸齒",
"performance_json_text_antialiasing_info": "0 關閉1 SMAA2 時間過濾+SMAA3 時間濾波和投影矩陣抖動的 SMAA",
"performance_json_text_game_effects": "特效等級",
"performance_json_text_game_effects_info": "遊戲特效等級",
"performance_json_text_texture": "紋理等級",
"performance_json_text_texture_info": "模型紋理細節",
"performance_json_text_volumetric_effects": "體積效果",
"performance_json_text_volumetric_effects_info": "體積雲、體積光照等",
"performance_json_text_water": "水體效果",
"performance_json_text_water_info": "各種水的等級",
"performance_json_text_object_detail": "物件細節",
"performance_json_text_object_detail_info": "模型物件細節影響LOD等..",
"performance_json_text_particles": "粒子細節",
"performance_json_text_physics": "物理細節",
"performance_json_text_physics_info": "物理效果範圍",
"performance_json_text_shading": "著色器細節",
"performance_json_text_shading_info": "著色器相關",
"performance_json_text_shadows": "陰影細節",
"performance_json_text_shadows_info": "陰影效果",
"performance_json_text_postprocessing": "後處理細節",
"performance_json_text_postprocessing_info": "後處理著色器,動態模糊效果 等",
"performance_json_text_renderer": "繪製器品質",
"performance_json_text_renderer_info": "cryengine 繪製器品質",
"performance_json_text_shader_decal": "貼花品質",
"performance_json_text_shader_decal_info": "LOGO、標誌等",
"performance_json_text_shader_post_process": "著色器品質",
"performance_json_text_shader_fx": "FX 品質",
"performance_json_text_shader_general": "一般品質",
"performance_json_text_shader_general_info": "整體模型品質",
"performance_json_text_shader_glass": "玻璃品質",
"performance_json_text_shader_glass_info": "窗、鏡子等",
"performance_json_text_shader_hdr": "HDR品質",
"performance_json_text_shader_hdr_info": "HDR色差亮度層級 處理 等",
"performance_json_text_shader_particle": "粒子品質",
"performance_json_text_shader_particle_info": "粒子效果品質",
"performance_json_text_shader_terrain": "地面品質",
"performance_json_text_shader_shadow": "陰影品質",
"performance_json_text_shader_sky": "天空品質",
"performance_json_text_particles_object_collisions": "粒子碰撞",
"performance_json_text_particles_object_collisions_info": "1 僅靜態粒子 2 包括動態粒子",
"performance_json_text_displayinfo": "螢幕資訊(顯示幀率)",
"performance_json_text_displayinfo_info": "在螢幕右上角展示幀率,伺服器資訊等",
"performance_json_text_max_fps": "最大幀率",
"performance_json_text_max_fps_info": "調整遊戲最高幀率0為不限制",
"performance_json_text_display_session": "顯示工作階段資訊",
"performance_json_text_display_session_info": "開啟後在螢幕上顯示一個二維碼,用於回饋時讓 CIG 快速定位相關資訊",
"performance_json_text_vsync": "垂直同步",
"performance_json_text_vsync_info": "開啟以防止撕裂,關閉以提高幀率",
"performance_json_text_motion_blur": "動態模糊",
"performance_json_text_motion_blur_info": "開啟以提高運動感,關閉提升觀感",
"performance_json_text_fov": "設定視角FOV",
"performance_json_text_ui_animation": "UI 淡入淡出動畫",
"performance_json_text_custom_parameters": "自訂參數",
"performance_json_text_title_custom": "自訂",
"tools_rsi_launcher_enhance_init_msg1": "讀取啟動器資訊...",
"tools_rsi_launcher_enhance_init_msg2": "正在從網路取得增強資料...",
"tools_rsi_launcher_enhance_working_msg1": "生成補丁 ...",
"tools_rsi_launcher_enhance_working_msg2": "安裝補丁,這需要一點時間,取決於您的電腦性能 ...",
"tools_rsi_launcher_enhance_title": "RSI 啟動器增強",
"tools_rsi_launcher_enhance_msg_version": "啟動器內部版本資訊:{v0}",
"tools_rsi_launcher_enhance_msg_patch_status": "補丁狀態:{v0}",
"tools_rsi_launcher_enhance_msg_error": "增強資料取得失敗,可能是網路問題或目前版本不支援",
"tools_rsi_launcher_enhance_title_localization": "RSI 啟動器本地化",
"tools_rsi_launcher_enhance_subtitle_localization": "為 RSI 啟動器增加多語言支援。",
"tools_rsi_launcher_enhance_title_download_booster": "RSI 啟動器下載增強",
"tools_rsi_launcher_enhance_subtitle_download_booster": "下載遊戲時可使用更多執行緒以提升下載速度,啟用後請在啟動器設定修改執行緒數。",
"tools_rsi_launcher_enhance_action_install": "安裝增強補丁",
"tools_rsi_launcher_enhance_msg_uninstall": "* 如需移除增強補丁,請覆蓋安裝 RSI 啟動器。",
"tools_rsi_launcher_enhance_msg_error_launcher_notfound": "未找到 RSI 啟動器",
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error": "讀取啟動器資訊失敗!",
"tools_rsi_launcher_enhance_msg_error_get_launcher_info_error_with_args": "讀取啟動器資訊失敗:{v0}",
"tools_action_rsi_launcher_enhance_info": "啟動器翻譯,下載執行緒增強",
"tools_rsi_launcher_enhance_note_title": "RSI 啟動器增強使用須知",
"tools_rsi_launcher_enhance_note_msg": "RSI 啟動器增強是一項社群功能,它會在您的電腦上解包 \"RSI Launcher\" 並加入額外的增強功能,具體使用哪些功能由您決定。\n\n目前官方CIG僅許可我們進行多語言操作啟動器下載增強是我們認為有用的額外功能違反cig使用者協議https://robertsspaceindustries.com/eula可能導致帳號被封禁等嚴重後果是否啟用由您自己決定我們不對可能產生的後果遊戲損壞帳號封禁等承擔任何責任。\n\n對於啟動器的修改內容我們開源於https://github.com/StarCitizenToolBox/RSILauncherEnhance如有需要您可自行查閱。\n\n如果您因為任何原因需要取消此增強補丁請直接覆蓋安裝官方啟動器。",
"tools_action_unp4k": "P4K 查看器",
"tools_action_unp4k_info": "解包星際公民 p4k 文件",
"tools_unp4k_title": "P4K 查看器 -> {v0}",
"tools_unp4k_view_file": "單擊文件以預覽",
"tools_unp4k_msg_unknown_file_type": "未知文件類型\n{v0}",
"home_localization_action_rsi_launcher_no_game_path_msg": "您當前未安裝遊戲本體或未選擇遊戲安裝目錄,只可使用啟動器翻譯功能。請確保遊戲安裝完畢或在工具箱設置中添加遊戲安裝目錄後重試。",
"home_localization_select_customize_file_ini": "請選擇 ini 文件",
"home_localization_select_customize_file": "請選擇自定義翻譯文件",
"home_localization_action_select_customize_file": "點擊選擇 ini 文件",
"home_localization_ptu_advanced_localization_tip_title": "推薦使用高級翻譯",
"home_localization_ptu_advanced_localization_tip_title_info": "在 PTU/EPTU 等測試頻道 ,當前翻譯文本可能與遊戲不同步,使用高級翻譯可以減少亂碼產生。",
"tools_rsi_launcher_enhance_action_fold": "收起額外功能",
"tools_rsi_launcher_enhance_action_expand": "展開額外功能",
"tools_unp4k_missing_runtime": "缺少運行庫",
"tools_unp4k_missing_runtime_info": "使用此功能需安裝 .NET8 運行庫,請點擊下方按鈕下載安裝,安裝成功後重新打開此頁面即可繼續使用。",
"tools_unp4k_missing_runtime_action_install": "安裝運行庫",
"doctor_game_error_gpu_vulkan_crash": "GPU Vulkan 崩潰",
"doctor_game_error_gpu_vulkan_crash_info": "Vulkan 崩潰!這可能是驅動版本或遊戲引擎問題,請嘗試更新 GPU 驅動 或 使用清理著色器功能為您回退到 DX11"
}

View File

@ -1,35 +1,56 @@
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/generated/l10n.dart';
import 'package:window_manager/window_manager.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'base/ui_model.dart';
import 'common/conf/app_conf.dart';
import 'global_ui_model.dart';
import 'ui/splash_ui.dart';
import 'ui/splash_ui_model.dart';
import 'app.dart';
void main(List<String> args) async {
// webview window
if (runWebViewTitleBarWidget(args,
backgroundColor: const Color.fromRGBO(19, 36, 49, 1),
builder: _defaultWebviewTitleBar)) {
return;
}
await AppConf.init(args);
runApp(ProviderScope(
child: BaseUIContainer(
uiCreate: () => AppUI(),
modelCreate: () => globalUIModelProvider,
),
));
WidgetsFlutterBinding.ensureInitialized();
await _initWindow();
// run app
runApp(const ProviderScope(child: App()));
}
class AppUI extends BaseUI {
_initWindow() async {
await windowManager.ensureInitialized();
await windowManager.setTitleBarStyle(
TitleBarStyle.hidden,
windowButtonVisibility: false,
);
await windowManager.setSize(const Size(1280, 810));
await windowManager.setMinimumSize(const Size(1280, 810));
await windowManager.center(animate: true);
}
class App extends HookConsumerWidget {
const App({super.key});
@override
Widget? buildBody(BuildContext context, BaseUIModel model) {
return FluentApp(
title: "StarCitizen Doctor",
restorationScopeId: "Doctor",
Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider);
final appState = ref.watch(appGlobalModelProvider);
return FluentApp.router(
title: "StarCitizenToolBox",
restorationScopeId: "StarCitizenToolBox",
themeMode: ThemeMode.dark,
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
FluentLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
builder: (context, child) {
return MediaQuery(
data:
@ -41,39 +62,21 @@ class AppUI extends BaseUI {
brightness: Brightness.dark,
fontFamily: "SourceHanSansCN-Regular",
navigationPaneTheme: NavigationPaneThemeData(
backgroundColor: AppConf.colorBackground,
backgroundColor: appState.themeConf.backgroundColor,
),
menuColor: AppConf.colorMenu,
micaBackgroundColor: AppConf.colorMica,
menuColor: appState.themeConf.menuColor,
micaBackgroundColor: appState.themeConf.micaColor,
buttonTheme: ButtonThemeData(
defaultButtonStyle: ButtonStyle(
shape: ButtonState.all(RoundedRectangleBorder(
shape: WidgetStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
side: BorderSide(color: Colors.white.withOpacity(.01)))),
))),
locale: appState.appLocale,
debugShowCheckedModeBanner: false,
home: BaseUIContainer(
uiCreate: () => SplashUI(), modelCreate: () => SplashUIModel()),
);
}
@override
String getUITitle(BuildContext context, BaseUIModel model) => "";
}
class WindowButtons extends StatelessWidget {
const WindowButtons({super.key});
@override
Widget build(BuildContext context) {
final FluentThemeData theme = FluentTheme.of(context);
return SizedBox(
width: 138,
height: 50,
child: WindowCaption(
brightness: theme.brightness,
backgroundColor: Colors.transparent,
),
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
routeInformationProvider: router.routeInformationProvider,
);
}
}
@ -86,6 +89,7 @@ Widget _defaultWebviewTitleBar(BuildContext context) {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (Platform.isMacOS) const SizedBox(width: 96),
IconButton(
onPressed: !state.canGoBack ? null : controller.back,
icon: const Icon(FluentIcons.chevron_left),

216
lib/provider/aria2c.dart Normal file
View File

@ -0,0 +1,216 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/conf/binary_conf.dart';
import 'dart:io';
import 'dart:math';
import 'package:aria2/aria2.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:starcitizen_doctor/api/api.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/rust/api/rs_process.dart'
as rs_process;
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
part 'aria2c.g.dart';
part 'aria2c.freezed.dart';
@freezed
class Aria2cModelState with _$Aria2cModelState {
const factory Aria2cModelState({
required String aria2cDir,
Aria2c? aria2c,
Aria2GlobalStat? aria2globalStat,
}) = _Aria2cModelState;
}
extension Aria2cModelExt on Aria2cModelState {
bool get isRunning => aria2c != null;
bool get hasDownloadTask => aria2globalStat != null && aria2TotalTaskNum > 0;
int get aria2TotalTaskNum => aria2globalStat == null
? 0
: ((aria2globalStat!.numActive ?? 0) +
(aria2globalStat!.numWaiting ?? 0));
}
@riverpod
class Aria2cModel extends _$Aria2cModel {
bool _disposed = false;
@override
Aria2cModelState build() {
if (appGlobalState.applicationBinaryModuleDir == null) {
throw Exception("applicationBinaryModuleDir is null");
}
ref.onDispose(() {
_disposed = true;
});
ref.keepAlive();
final aria2cDir = "${appGlobalState.applicationBinaryModuleDir}\\aria2c";
// LazyLoad init
() async {
try {
final sessionFile = File("$aria2cDir\\aria2.session");
//
if (await sessionFile.exists() &&
(await sessionFile.readAsString()).trim().isNotEmpty) {
dPrint("launch Aria2c daemon");
await launchDaemon(appGlobalState.applicationBinaryModuleDir!);
} else {
dPrint("LazyLoad Aria2c daemon");
}
} catch (e) {
dPrint("Aria2cManager.checkLazyLoad Error:$e");
}
}();
return Aria2cModelState(aria2cDir: aria2cDir);
}
Future launchDaemon(String applicationBinaryModuleDir) async {
if (state.aria2c != null) return;
await BinaryModuleConf.extractModule(
["aria2c"], applicationBinaryModuleDir);
/// skip for debug hot reload
if (kDebugMode) {
if ((await SystemHelper.getPID("aria2c")).isNotEmpty) {
dPrint("[Aria2cManager] debug skip for hot reload");
return;
}
}
final sessionFile = File("${state.aria2cDir}\\aria2.session");
if (!await sessionFile.exists()) {
await sessionFile.create(recursive: true);
}
final exePath = "${state.aria2cDir}\\aria2c.exe";
final port = await getFreePort();
final pwd = generateRandomPassword(16);
dPrint("pwd === $pwd");
final trackerList = await Api.getTorrentTrackerList();
dPrint("trackerList === $trackerList");
dPrint("Aria2cManager .----- aria2c start $port------");
final stream = rs_process.start(
executable: exePath,
arguments: [
"-V",
"-c",
"-x 16",
"--dir=${state.aria2cDir}\\downloads",
"--disable-ipv6",
"--enable-rpc",
"--pause",
"--rpc-listen-port=$port",
"--rpc-secret=$pwd",
"--input-file=${sessionFile.absolute.path.trim()}",
"--save-session=${sessionFile.absolute.path.trim()}",
"--save-session-interval=60",
"--file-allocation=trunc",
"--seed-time=0",
],
workingDirectory: state.aria2cDir);
String launchError = "";
stream.listen((event) {
dPrint("Aria2cManager.rs_process event === $event");
switch (event.dataType) {
case rs_process.RsProcessStreamDataType.output:
if (event.data.contains("IPv4 RPC: listening on TCP port")) {
_onLaunch(port, pwd, trackerList);
}
break;
case rs_process.RsProcessStreamDataType.error:
launchError = event.data;
state = state.copyWith(aria2c: null);
break;
case rs_process.RsProcessStreamDataType.exit:
launchError = event.data;
state = state.copyWith(aria2c: null);
break;
}
});
while (true) {
if (state.aria2c != null) return;
if (launchError.isNotEmpty) throw launchError;
await Future.delayed(const Duration(milliseconds: 100));
}
}
Future<int> getFreePort() async {
final serverSocket = await ServerSocket.bind("127.0.0.1", 0);
final port = serverSocket.port;
await serverSocket.close();
return port;
}
String generateRandomPassword(int length) {
const String charset =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = Random();
StringBuffer buffer = StringBuffer();
for (int i = 0; i < length; i++) {
int randomIndex = random.nextInt(charset.length);
buffer.write(charset[randomIndex]);
}
return buffer.toString();
}
int textToByte(String text) {
if (text.length == 1) {
return 0;
}
if (int.tryParse(text) != null) {
return int.parse(text);
}
if (text.endsWith("k")) {
return int.parse(text.substring(0, text.length - 1)) * 1024;
}
if (text.endsWith("m")) {
return int.parse(text.substring(0, text.length - 1)) * 1024 * 1024;
}
return 0;
}
Future<void> _onLaunch(int port, String pwd, String trackerList) async {
final aria2c = Aria2c("ws://127.0.0.1:$port/jsonrpc", "websocket", pwd);
state = state.copyWith(aria2c: aria2c);
aria2c.getVersion().then((value) {
dPrint("Aria2cManager.connected! version == ${value.version}");
_listenState(aria2c);
});
final box = await Hive.openBox("app_conf");
aria2c.changeGlobalOption(Aria2Option()
..maxOverallUploadLimit =
textToByte(box.get("downloader_up_limit", defaultValue: "0"))
..maxOverallDownloadLimit =
textToByte(box.get("downloader_down_limit", defaultValue: "0"))
..btTracker = trackerList);
}
Future<void> _listenState(Aria2c aria2c) async {
dPrint("Aria2cModel._listenState start");
while (true) {
if (_disposed || state.aria2c == null) {
dPrint("Aria2cModel._listenState end");
return;
}
try {
final aria2globalStat = await aria2c.getGlobalStat();
state = state.copyWith(aria2globalStat: aria2globalStat);
} catch (e) {
dPrint("aria2globalStat update error:$e");
}
await Future.delayed(const Duration(seconds: 1));
}
}
}

View File

@ -0,0 +1,197 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'aria2c.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$Aria2cModelState {
String get aria2cDir => throw _privateConstructorUsedError;
Aria2c? get aria2c => throw _privateConstructorUsedError;
Aria2GlobalStat? get aria2globalStat => throw _privateConstructorUsedError;
/// Create a copy of Aria2cModelState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$Aria2cModelStateCopyWith<Aria2cModelState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $Aria2cModelStateCopyWith<$Res> {
factory $Aria2cModelStateCopyWith(
Aria2cModelState value, $Res Function(Aria2cModelState) then) =
_$Aria2cModelStateCopyWithImpl<$Res, Aria2cModelState>;
@useResult
$Res call(
{String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat});
}
/// @nodoc
class _$Aria2cModelStateCopyWithImpl<$Res, $Val extends Aria2cModelState>
implements $Aria2cModelStateCopyWith<$Res> {
_$Aria2cModelStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Aria2cModelState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? aria2cDir = null,
Object? aria2c = freezed,
Object? aria2globalStat = freezed,
}) {
return _then(_value.copyWith(
aria2cDir: null == aria2cDir
? _value.aria2cDir
: aria2cDir // ignore: cast_nullable_to_non_nullable
as String,
aria2c: freezed == aria2c
? _value.aria2c
: aria2c // ignore: cast_nullable_to_non_nullable
as Aria2c?,
aria2globalStat: freezed == aria2globalStat
? _value.aria2globalStat
: aria2globalStat // ignore: cast_nullable_to_non_nullable
as Aria2GlobalStat?,
) as $Val);
}
}
/// @nodoc
abstract class _$$Aria2cModelStateImplCopyWith<$Res>
implements $Aria2cModelStateCopyWith<$Res> {
factory _$$Aria2cModelStateImplCopyWith(_$Aria2cModelStateImpl value,
$Res Function(_$Aria2cModelStateImpl) then) =
__$$Aria2cModelStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat});
}
/// @nodoc
class __$$Aria2cModelStateImplCopyWithImpl<$Res>
extends _$Aria2cModelStateCopyWithImpl<$Res, _$Aria2cModelStateImpl>
implements _$$Aria2cModelStateImplCopyWith<$Res> {
__$$Aria2cModelStateImplCopyWithImpl(_$Aria2cModelStateImpl _value,
$Res Function(_$Aria2cModelStateImpl) _then)
: super(_value, _then);
/// Create a copy of Aria2cModelState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? aria2cDir = null,
Object? aria2c = freezed,
Object? aria2globalStat = freezed,
}) {
return _then(_$Aria2cModelStateImpl(
aria2cDir: null == aria2cDir
? _value.aria2cDir
: aria2cDir // ignore: cast_nullable_to_non_nullable
as String,
aria2c: freezed == aria2c
? _value.aria2c
: aria2c // ignore: cast_nullable_to_non_nullable
as Aria2c?,
aria2globalStat: freezed == aria2globalStat
? _value.aria2globalStat
: aria2globalStat // ignore: cast_nullable_to_non_nullable
as Aria2GlobalStat?,
));
}
}
/// @nodoc
class _$Aria2cModelStateImpl
with DiagnosticableTreeMixin
implements _Aria2cModelState {
const _$Aria2cModelStateImpl(
{required this.aria2cDir, this.aria2c, this.aria2globalStat});
@override
final String aria2cDir;
@override
final Aria2c? aria2c;
@override
final Aria2GlobalStat? aria2globalStat;
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'Aria2cModelState(aria2cDir: $aria2cDir, aria2c: $aria2c, aria2globalStat: $aria2globalStat)';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('type', 'Aria2cModelState'))
..add(DiagnosticsProperty('aria2cDir', aria2cDir))
..add(DiagnosticsProperty('aria2c', aria2c))
..add(DiagnosticsProperty('aria2globalStat', aria2globalStat));
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$Aria2cModelStateImpl &&
(identical(other.aria2cDir, aria2cDir) ||
other.aria2cDir == aria2cDir) &&
(identical(other.aria2c, aria2c) || other.aria2c == aria2c) &&
(identical(other.aria2globalStat, aria2globalStat) ||
other.aria2globalStat == aria2globalStat));
}
@override
int get hashCode =>
Object.hash(runtimeType, aria2cDir, aria2c, aria2globalStat);
/// Create a copy of Aria2cModelState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$Aria2cModelStateImplCopyWith<_$Aria2cModelStateImpl> get copyWith =>
__$$Aria2cModelStateImplCopyWithImpl<_$Aria2cModelStateImpl>(
this, _$identity);
}
abstract class _Aria2cModelState implements Aria2cModelState {
const factory _Aria2cModelState(
{required final String aria2cDir,
final Aria2c? aria2c,
final Aria2GlobalStat? aria2globalStat}) = _$Aria2cModelStateImpl;
@override
String get aria2cDir;
@override
Aria2c? get aria2c;
@override
Aria2GlobalStat? get aria2globalStat;
/// Create a copy of Aria2cModelState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$Aria2cModelStateImplCopyWith<_$Aria2cModelStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'aria2c.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$aria2cModelHash() => r'55dea5bd2e1c81fec0ef8ef1a10f41179775d7ee';
/// See also [Aria2cModel].
@ProviderFor(Aria2cModel)
final aria2cModelProvider =
AutoDisposeNotifierProvider<Aria2cModel, Aria2cModelState>.internal(
Aria2cModel.new,
name: r'aria2cModelProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$aria2cModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$Aria2cModel = AutoDisposeNotifier<Aria2cModelState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

278
lib/provider/unp4kc.dart Normal file
View File

@ -0,0 +1,278 @@
import 'dart:convert';
import 'dart:io';
import 'package:file/memory.dart';
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/common/conf/binary_conf.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
import 'package:starcitizen_doctor/common/rust/api/rs_process.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/data/app_unp4k_p4k_item_data.dart';
import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart';
import 'package:starcitizen_doctor/common/rust/api/rs_process.dart'
as rs_process;
part 'unp4kc.freezed.dart';
part 'unp4kc.g.dart';
@freezed
class Unp4kcState with _$Unp4kcState {
const factory Unp4kcState({
required bool startUp,
Map<String, AppUnp4kP4kItemData>? files,
MemoryFileSystem? fs,
required String curPath,
String? endMessage,
MapEntry<String, String>? tempOpenFile,
@Default("") String errorMessage,
}) = _Unp4kcState;
}
@riverpod
class Unp4kCModel extends _$Unp4kCModel {
int? _rsPid;
@override
Unp4kcState build() {
state = Unp4kcState(
startUp: false,
curPath: '\\',
endMessage: S.current.tools_unp4k_msg_init);
_init();
return state;
}
ToolsUIState get _toolsState => ref.read(toolsUIModelProvider);
String getGamePath() => _toolsState.scInstalledPath;
bool _hasUnp4kRunTimeError = false;
void _init() async {
final execDir = "${appGlobalState.applicationBinaryModuleDir}\\unp4kc";
await BinaryModuleConf.extractModule(
["unp4kc"], appGlobalState.applicationBinaryModuleDir!);
final exec = "$execDir\\unp4kc.exe";
final stream = rs_process.start(
executable: exec, arguments: [], workingDirectory: execDir);
stream.listen((event) async {
switch (event.dataType) {
case RsProcessStreamDataType.output:
_rsPid = event.rsPid;
try {
final eventJson = await compute(json.decode, event.data);
_handleMessage(eventJson, event.rsPid);
} catch (e) {
dPrint("[unp4kc] json error: $e");
}
break;
case RsProcessStreamDataType.error:
dPrint("[unp4kc] stderr: ${event.data}");
if (state.errorMessage.isEmpty) {
state = state.copyWith(errorMessage: event.data);
} else {
state = state.copyWith(
errorMessage: "${state.errorMessage}\n${event.data}");
}
if (!_hasUnp4kRunTimeError) {
if (checkRunTimeError(state.errorMessage)) {
_hasUnp4kRunTimeError = true;
AnalyticsApi.touch("unp4k_no_runtime");
}
}
break;
case RsProcessStreamDataType.exit:
dPrint("[unp4kc] exit: ${event.data}");
break;
}
});
ref.onDispose(() {
state = state.copyWith(fs: null);
if (_rsPid != null) {
Process.killPid(_rsPid!);
dPrint("[unp4kc] kill ...");
}
});
}
DateTime? _loadStartTime;
void _handleMessage(Map<String, dynamic> eventJson, int rsPid) async {
final action = eventJson["action"];
final data = eventJson["data"];
final gamePath = getGamePath();
final gameP4kPath = "$gamePath\\Data.p4k";
switch (action.toString().trim()) {
case "info: startup":
rs_process.write(rsPid: rsPid, data: "$gameP4kPath\n");
break;
case "info: Reading_p4k_file":
_loadStartTime = DateTime.now();
state = state.copyWith(endMessage: S.current.tools_unp4k_msg_reading);
break;
case "info: All Ready":
state = state.copyWith(endMessage: S.current.tools_unp4k_msg_reading2);
break;
case "data: P4K_Files":
final p4kFiles = (data as List<dynamic>);
final files = <String, AppUnp4kP4kItemData>{};
final fs = MemoryFileSystem(style: FileSystemStyle.posix);
var nextAwait = 0;
for (var i = 0; i < p4kFiles.length; i++) {
final item = AppUnp4kP4kItemData.fromJson(p4kFiles[i]);
item.name = "${item.name}";
files["\\${item.name}"] = item;
await fs
.file(item.name?.replaceAll("\\", "/") ?? "")
.create(recursive: true);
if (i == nextAwait) {
state = state.copyWith(
endMessage:
S.current.tools_unp4k_msg_reading3(i, p4kFiles.length));
await Future.delayed(Duration.zero);
nextAwait += 20000;
}
}
final endTime = DateTime.now();
state = state.copyWith(
files: files,
fs: fs,
endMessage: S.current.tools_unp4k_msg_read_completed(files.length,
endTime.difference(_loadStartTime!).inMilliseconds));
_loadStartTime = null;
break;
case "info: Extracted_Open":
final filePath = data.toString();
dPrint("[unp4kc] Extracted_Open file: $filePath");
const textExt = [".txt", ".xml", ".json", ".lua", ".cfg", ".ini"];
const imgExt = [".png"];
String openType = "unknown";
for (var element in textExt) {
if (filePath.toLowerCase().endsWith(element)) {
openType = "text";
}
}
for (var element in imgExt) {
if (filePath.endsWith(element)) {
openType = "image";
}
}
state = state.copyWith(
tempOpenFile: MapEntry(openType, filePath),
endMessage: S.current.tools_unp4k_msg_open_file(filePath));
break;
default:
dPrint("[unp4kc] unknown action: $action");
break;
}
}
List<AppUnp4kP4kItemData>? getFiles() {
final path = state.curPath.replaceAll("\\", "/");
final fs = state.fs;
if (fs == null) return null;
final dir = fs.directory(path);
if (!dir.existsSync()) return [];
final files = dir.listSync(recursive: false, followLinks: false);
files.sort((a, b) {
if (a is Directory && b is File) {
return -1;
} else if (a is File && b is Directory) {
return 1;
} else {
return a.path.compareTo(b.path);
}
});
final result = <AppUnp4kP4kItemData>[];
for (var file in files) {
if (file is File) {
final f = state.files?[file.path.replaceAll("/", "\\")];
if (f != null) {
if (!(f.name?.startsWith("\\") ?? true)) {
f.name = "\\${f.name}";
}
result.add(f);
}
} else {
result.add(AppUnp4kP4kItemData(
name: file.path.replaceAll("/", "\\"), isDirectory: true));
}
}
return result;
}
void changeDir(String name, {bool fullPath = false}) {
if (fullPath) {
state = state.copyWith(curPath: name);
} else {
state = state.copyWith(curPath: "${state.curPath}$name\\");
}
}
openFile(String filePath) async {
final tempDir = await getTemporaryDirectory();
final tempPath =
"${tempDir.absolute.path}\\SCToolbox_unp4kc\\${SCLoggerHelper.getGameChannelID(getGamePath())}\\";
state = state.copyWith(
tempOpenFile: const MapEntry("loading", ""),
endMessage: S.current.tools_unp4k_msg_open_file(filePath));
extractFile(filePath, tempPath, mode: "extract_open");
}
extractFile(String filePath, String outputPath,
{String mode = "extract"}) async {
// remove first \\
if (filePath.startsWith("\\")) {
filePath = filePath.substring(1);
}
outputPath = "$outputPath$filePath";
dPrint("extractFile .... $filePath");
if (_rsPid != null) {
rs_process.write(
rsPid: _rsPid!, data: "$mode<:,:>$filePath<:,:>$outputPath\n");
}
}
static bool checkRunTimeError(String errorMessage) {
if (errorMessage
.contains("You must install .NET to run this application") ||
errorMessage.contains(
"You must install or update .NET to run this application") ||
errorMessage.contains(
"It was not possible to find any compatible framework version")) {
AnalyticsApi.touch("unp4k_no_runtime");
return true;
}
return false;
}
static Future<Uint8List> unp4kTools(
String applicationBinaryModuleDir, List<String> args) async {
await BinaryModuleConf.extractModule(
["unp4kc"], applicationBinaryModuleDir);
final execDir = "$applicationBinaryModuleDir\\unp4kc";
final exec = "$execDir\\unp4kc.exe";
final r = await Process.run(exec, args);
if (r.exitCode != 0) {
Process.killPid(r.pid);
throw Exception(
"error: ${r.exitCode} , info= ${r.stdout} , err= ${r.stderr}");
}
final eventJson = await compute(json.decode, r.stdout.toString());
if (eventJson["action"] == "data: Uint8List") {
final data = eventJson["data"];
return Uint8List.fromList((data as List).cast<int>());
}
throw Exception("error: data error");
}
}

View File

@ -0,0 +1,304 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'unp4kc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$Unp4kcState {
bool get startUp => throw _privateConstructorUsedError;
Map<String, AppUnp4kP4kItemData>? get files =>
throw _privateConstructorUsedError;
MemoryFileSystem? get fs => throw _privateConstructorUsedError;
String get curPath => throw _privateConstructorUsedError;
String? get endMessage => throw _privateConstructorUsedError;
MapEntry<String, String>? get tempOpenFile =>
throw _privateConstructorUsedError;
String get errorMessage => throw _privateConstructorUsedError;
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$Unp4kcStateCopyWith<Unp4kcState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $Unp4kcStateCopyWith<$Res> {
factory $Unp4kcStateCopyWith(
Unp4kcState value, $Res Function(Unp4kcState) then) =
_$Unp4kcStateCopyWithImpl<$Res, Unp4kcState>;
@useResult
$Res call(
{bool startUp,
Map<String, AppUnp4kP4kItemData>? files,
MemoryFileSystem? fs,
String curPath,
String? endMessage,
MapEntry<String, String>? tempOpenFile,
String errorMessage});
}
/// @nodoc
class _$Unp4kcStateCopyWithImpl<$Res, $Val extends Unp4kcState>
implements $Unp4kcStateCopyWith<$Res> {
_$Unp4kcStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startUp = null,
Object? files = freezed,
Object? fs = freezed,
Object? curPath = null,
Object? endMessage = freezed,
Object? tempOpenFile = freezed,
Object? errorMessage = null,
}) {
return _then(_value.copyWith(
startUp: null == startUp
? _value.startUp
: startUp // ignore: cast_nullable_to_non_nullable
as bool,
files: freezed == files
? _value.files
: files // ignore: cast_nullable_to_non_nullable
as Map<String, AppUnp4kP4kItemData>?,
fs: freezed == fs
? _value.fs
: fs // ignore: cast_nullable_to_non_nullable
as MemoryFileSystem?,
curPath: null == curPath
? _value.curPath
: curPath // ignore: cast_nullable_to_non_nullable
as String,
endMessage: freezed == endMessage
? _value.endMessage
: endMessage // ignore: cast_nullable_to_non_nullable
as String?,
tempOpenFile: freezed == tempOpenFile
? _value.tempOpenFile
: tempOpenFile // ignore: cast_nullable_to_non_nullable
as MapEntry<String, String>?,
errorMessage: null == errorMessage
? _value.errorMessage
: errorMessage // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$Unp4kcStateImplCopyWith<$Res>
implements $Unp4kcStateCopyWith<$Res> {
factory _$$Unp4kcStateImplCopyWith(
_$Unp4kcStateImpl value, $Res Function(_$Unp4kcStateImpl) then) =
__$$Unp4kcStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{bool startUp,
Map<String, AppUnp4kP4kItemData>? files,
MemoryFileSystem? fs,
String curPath,
String? endMessage,
MapEntry<String, String>? tempOpenFile,
String errorMessage});
}
/// @nodoc
class __$$Unp4kcStateImplCopyWithImpl<$Res>
extends _$Unp4kcStateCopyWithImpl<$Res, _$Unp4kcStateImpl>
implements _$$Unp4kcStateImplCopyWith<$Res> {
__$$Unp4kcStateImplCopyWithImpl(
_$Unp4kcStateImpl _value, $Res Function(_$Unp4kcStateImpl) _then)
: super(_value, _then);
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startUp = null,
Object? files = freezed,
Object? fs = freezed,
Object? curPath = null,
Object? endMessage = freezed,
Object? tempOpenFile = freezed,
Object? errorMessage = null,
}) {
return _then(_$Unp4kcStateImpl(
startUp: null == startUp
? _value.startUp
: startUp // ignore: cast_nullable_to_non_nullable
as bool,
files: freezed == files
? _value._files
: files // ignore: cast_nullable_to_non_nullable
as Map<String, AppUnp4kP4kItemData>?,
fs: freezed == fs
? _value.fs
: fs // ignore: cast_nullable_to_non_nullable
as MemoryFileSystem?,
curPath: null == curPath
? _value.curPath
: curPath // ignore: cast_nullable_to_non_nullable
as String,
endMessage: freezed == endMessage
? _value.endMessage
: endMessage // ignore: cast_nullable_to_non_nullable
as String?,
tempOpenFile: freezed == tempOpenFile
? _value.tempOpenFile
: tempOpenFile // ignore: cast_nullable_to_non_nullable
as MapEntry<String, String>?,
errorMessage: null == errorMessage
? _value.errorMessage
: errorMessage // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$Unp4kcStateImpl with DiagnosticableTreeMixin implements _Unp4kcState {
const _$Unp4kcStateImpl(
{required this.startUp,
final Map<String, AppUnp4kP4kItemData>? files,
this.fs,
required this.curPath,
this.endMessage,
this.tempOpenFile,
this.errorMessage = ""})
: _files = files;
@override
final bool startUp;
final Map<String, AppUnp4kP4kItemData>? _files;
@override
Map<String, AppUnp4kP4kItemData>? get files {
final value = _files;
if (value == null) return null;
if (_files is EqualUnmodifiableMapView) return _files;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
final MemoryFileSystem? fs;
@override
final String curPath;
@override
final String? endMessage;
@override
final MapEntry<String, String>? tempOpenFile;
@override
@JsonKey()
final String errorMessage;
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile, errorMessage: $errorMessage)';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('type', 'Unp4kcState'))
..add(DiagnosticsProperty('startUp', startUp))
..add(DiagnosticsProperty('files', files))
..add(DiagnosticsProperty('fs', fs))
..add(DiagnosticsProperty('curPath', curPath))
..add(DiagnosticsProperty('endMessage', endMessage))
..add(DiagnosticsProperty('tempOpenFile', tempOpenFile))
..add(DiagnosticsProperty('errorMessage', errorMessage));
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$Unp4kcStateImpl &&
(identical(other.startUp, startUp) || other.startUp == startUp) &&
const DeepCollectionEquality().equals(other._files, _files) &&
(identical(other.fs, fs) || other.fs == fs) &&
(identical(other.curPath, curPath) || other.curPath == curPath) &&
(identical(other.endMessage, endMessage) ||
other.endMessage == endMessage) &&
(identical(other.tempOpenFile, tempOpenFile) ||
other.tempOpenFile == tempOpenFile) &&
(identical(other.errorMessage, errorMessage) ||
other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(
runtimeType,
startUp,
const DeepCollectionEquality().hash(_files),
fs,
curPath,
endMessage,
tempOpenFile,
errorMessage);
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$Unp4kcStateImplCopyWith<_$Unp4kcStateImpl> get copyWith =>
__$$Unp4kcStateImplCopyWithImpl<_$Unp4kcStateImpl>(this, _$identity);
}
abstract class _Unp4kcState implements Unp4kcState {
const factory _Unp4kcState(
{required final bool startUp,
final Map<String, AppUnp4kP4kItemData>? files,
final MemoryFileSystem? fs,
required final String curPath,
final String? endMessage,
final MapEntry<String, String>? tempOpenFile,
final String errorMessage}) = _$Unp4kcStateImpl;
@override
bool get startUp;
@override
Map<String, AppUnp4kP4kItemData>? get files;
@override
MemoryFileSystem? get fs;
@override
String get curPath;
@override
String? get endMessage;
@override
MapEntry<String, String>? get tempOpenFile;
@override
String get errorMessage;
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$Unp4kcStateImplCopyWith<_$Unp4kcStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'unp4kc.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$unp4kCModelHash() => r'636da3fe20d1fa94917dd63934f08f8dbffc8a9d';
/// See also [Unp4kCModel].
@ProviderFor(Unp4kCModel)
final unp4kCModelProvider =
AutoDisposeNotifierProvider<Unp4kCModel, Unp4kcState>.internal(
Unp4kCModel.new,
name: r'unp4kCModelProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$unp4kCModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$Unp4kCModel = AutoDisposeNotifier<Unp4kcState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@ -1,146 +1,89 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/common/conf/app_conf.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/app.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/widgets/src/flow_number_text.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'about_ui_model.dart';
class AboutUI extends BaseUI<AboutUIModel> {
bool isTipTextCn = false;
class AboutUI extends HookConsumerWidget {
const AboutUI({super.key});
@override
Widget? buildBody(BuildContext context, AboutUIModel model) {
Widget build(BuildContext context, WidgetRef ref) {
final isTipTextCn = useState(false);
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Spacer(),
const SizedBox(height: 64),
const SizedBox(height: 32),
Image.asset("assets/app_logo.png", width: 128, height: 128),
const SizedBox(height: 6),
const Text(
"SC汉化盒子 V${AppConf.appVersion} ${AppConf.isMSE ? "" : " +Dev"}",
style: TextStyle(fontSize: 18)),
Text(
S.current.app_index_version_info(
ConstConf.appVersion, ConstConf.isMSE ? "" : " Dev"),
style: const TextStyle(fontSize: 18)),
const SizedBox(height: 12),
Button(
onPressed: model.checkUpdate,
child: const Padding(
padding: EdgeInsets.all(4),
child: Text("检查更新"),
onPressed: () => _onCheckUpdate(context, ref),
child: Padding(
padding: const EdgeInsets.all(4),
child: Text(S.current.about_check_update),
)),
const SizedBox(height: 32),
Container(
margin: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(24),
child: Text(
"不仅仅是汉化!\n\nSC汉化盒子是你探索宇宙的好帮手我们致力于为各位公民解决游戏中的常见问题并为社区汉化、性能调优、常用网站汉化 等操作提供便利。",
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.9)),
child: Column(
children: [
Text(
S.current.about_app_description,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.9)),
),
],
),
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.link),
const SizedBox(width: 8),
Text(
"在线反馈",
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString(URLConf.feedbackUrl);
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.qq),
const SizedBox(width: 8),
Text(
"QQ群: 940696487",
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString(
"https://qm.qq.com/cgi-bin/qm/qr?k=TdyR3QU-x77OeD0NQ5w--F0uiNxPq-Tn&jump_from=webapi&authKey=m8s5GhF/7bRCvm5vI4aNl7RQEx5KOViwkzzIl54K+u9w2hzFpr9N/3avG4W/HaVS");
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.envelope),
const SizedBox(width: 8),
Text(
"邮箱: scbox@xkeyc.com",
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString("mailto:scbox@xkeyc.com");
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.github),
const SizedBox(width: 8),
Text(
"开源",
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString("https://github.com/StarCitizenToolBox/app");
},
),
],
),
makeAnalyticsWidget(context),
const SizedBox(height: 24),
makeLinksRow(),
const Spacer(),
Row(
children: [
const Spacer(),
Container(
width: MediaQuery.of(context).size.width * .35,
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor.withOpacity(.03),
borderRadius: BorderRadius.circular(12)),
child: IconButton(
icon: Padding(
padding: const EdgeInsets.all(3),
child: Text(
isTipTextCn ? tipTextCN : tipTextEN,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12, color: Colors.white.withOpacity(.9)),
AnimatedSize(
duration: const Duration(milliseconds: 200),
child: Container(
width: MediaQuery.of(context).size.width * .35,
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor.withOpacity(.06),
borderRadius: BorderRadius.circular(12)),
child: IconButton(
icon: Padding(
padding: const EdgeInsets.all(3),
child: Text(
isTipTextCn.value ? tipTextCN : tipTextEN,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12, color: Colors.white.withOpacity(.9)),
),
),
onPressed: () {
isTipTextCn.value = !isTipTextCn.value;
},
),
onPressed: () {
isTipTextCn = !isTipTextCn;
setState(() {});
},
),
),
const SizedBox(width: 12),
@ -152,12 +95,171 @@ class AboutUI extends BaseUI<AboutUIModel> {
);
}
Widget makeLinksRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.link),
const SizedBox(width: 8),
Text(
S.current.about_online_feedback,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString(URLConf.feedbackUrl);
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.qq),
const SizedBox(width: 8),
Text(
S.current.about_action_qq_group,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString(
"https://qm.qq.com/cgi-bin/qm/qr?k=TdyR3QU-x77OeD0NQ5w--F0uiNxPq-Tn&jump_from=webapi&authKey=m8s5GhF/7bRCvm5vI4aNl7RQEx5KOViwkzzIl54K+u9w2hzFpr9N/3avG4W/HaVS");
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.envelope),
const SizedBox(width: 8),
Text(
S.current.about_action_email,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString("mailto:xkeyc@qq.com");
},
),
const SizedBox(width: 24),
IconButton(
icon: Row(
children: [
const Icon(FontAwesomeIcons.github),
const SizedBox(width: 8),
Text(
S.current.about_action_open_source,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
],
),
onPressed: () {
launchUrlString("https://github.com/StarCitizenToolBox/app");
},
),
],
);
}
static const tipTextEN =
"This is an unofficial Star Citizen fan-made tools, not affiliated with the Cloud Imperium group of companies. All content on this Software not authored by its host or users are property of their respective owners. \nStar Citizen®, Roberts Space Industries® and Cloud Imperium® are registered trademarks of Cloud Imperium Rights LLC.";
static const tipTextCN =
"这是一个非官方的星际公民工具,不隶属于 Cloud Imperium 公司集团。 本软件中非由其主机或用户创作的所有内容均为其各自所有者的财产。 \nStar Citizen®、Roberts Space Industries® 和 Cloud Imperium® 是 Cloud Imperium Rights LLC 的注册商标。";
static String get tipTextCN => S.current.about_disclaimer;
@override
String getUITitle(BuildContext context, AboutUIModel model) => "";
Widget makeAnalyticsWidget(BuildContext context) {
return LoadingWidget(
onLoadData: AnalyticsApi.getAnalyticsData,
autoRefreshDuration: const Duration(seconds: 60),
childBuilder: (BuildContext context, Map<String, dynamic> data) {
return Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (data["total"] is List)
for (var item in data["total"])
if (item is Map)
if ([
"launch",
"gameLaunch",
"firstLaunch",
"install_localization",
"performance_apply",
"p4k_download",
].contains(item["Type"]))
makeAnalyticsItem(
context: context,
name: item["Type"] as String,
value: item["Count"] as int)
],
);
},
);
}
Widget makeAnalyticsItem(
{required BuildContext context,
required String name,
required int value}) {
final names = {
"launch": S.current.about_analytics_launch,
"gameLaunch": S.current.about_analytics_launch_game,
"firstLaunch": S.current.about_analytics_total_users,
"install_localization": S.current.about_analytics_install_translation,
"performance_apply": S.current.about_analytics_performance_optimization,
"p4k_download": S.current.about_analytics_p4k_redirection
};
return Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(left: 18, right: 18),
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor.withOpacity(.06),
borderRadius: BorderRadius.circular(12)),
child: Column(
children: [
Text(
names[name] ?? name,
style: TextStyle(fontSize: 13, color: Colors.white.withOpacity(.6)),
),
const SizedBox(height: 4),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FlowNumberText(
targetValue: value,
style: const TextStyle(
fontSize: 20,
),
),
Text(
" ${name == "firstLaunch" ? S.current.about_analytics_units_user : S.current.about_analytics_units_times}"),
],
),
],
),
);
}
_onCheckUpdate(BuildContext context, WidgetRef ref) async {
if (ConstConf.isMSE) {
launchUrlString("ms-windows-store://pdp/?productid=9NF3SWFWNKL1");
return;
} else {
final hasUpdate =
await ref.read(appGlobalModelProvider.notifier).checkUpdate(context);
if (!hasUpdate) {
if (!context.mounted) return;
showToast(context, S.current.about_info_latest_version);
}
}
}
}

View File

@ -1,17 +0,0 @@
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/conf/app_conf.dart';
import 'package:starcitizen_doctor/global_ui_model.dart';
import 'package:url_launcher/url_launcher_string.dart';
class AboutUIModel extends BaseUIModel {
Future<void> checkUpdate() async {
if (AppConf.isMSE) {
launchUrlString("ms-windows-store://pdp/?productid=9NF3SWFWNKL1");
return;
}
final hasUpdate = await globalUIModel.doCheckUpdate(context!);
if (!hasUpdate) {
if (mounted) showToast(context!, "已是最新版本");
}
}
}

View File

@ -1,92 +0,0 @@
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/widgets/countdown_time_text.dart';
import 'countdown_dialog_ui_model.dart';
class CountdownDialogUI extends BaseUI<CountdownDialogUIModel> {
@override
Widget? buildBody(BuildContext context, CountdownDialogUIModel model) {
return ContentDialog(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .65),
title: Row(
children: [
IconButton(
icon: const Icon(
FluentIcons.back,
size: 22,
),
onPressed: model.onBack),
const SizedBox(width: 12),
const Text("节日倒计时"),
],
),
content: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: Column(
children: [
AlignedGridView.count(
crossAxisCount: 3,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
itemCount: model.countdownFestivalListData.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
final item = model.countdownFestivalListData[index];
return Container(
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
if (item.icon != null && item.icon != "") ...[
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Image.asset(
"assets/countdown/${item.icon}",
width: 38,
height: 38,
),
),
const SizedBox(width: 12),
] else
const SizedBox(width: 50),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${item.name}",
),
CountdownTimeText(
targetTime: DateTime.fromMillisecondsSinceEpoch(
item.time ?? 0),
)
],
)
],
),
),
);
},
),
const SizedBox(height: 12),
Text(
"* 以上节日日期由人工收录、维护,可能存在错误,欢迎反馈!",
style: TextStyle(
fontSize: 13, color: Colors.white.withOpacity(.3)),
)
],
),
),
),
);
}
@override
String getUITitle(BuildContext context, CountdownDialogUIModel model) => "";
}

View File

@ -1,12 +0,0 @@
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart';
class CountdownDialogUIModel extends BaseUIModel {
final List<CountdownFestivalItemData> countdownFestivalListData;
CountdownDialogUIModel(this.countdownFestivalListData);
onBack() {
Navigator.pop(context!);
}
}

View File

@ -0,0 +1,98 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
class HomeCountdownDialogUI extends HookConsumerWidget {
const HomeCountdownDialogUI({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final homeState = ref.watch(homeUIModelProvider);
return ContentDialog(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .65),
title: Row(
children: [
IconButton(
icon: const Icon(
FluentIcons.back,
size: 22,
),
onPressed: () {
Navigator.of(context).pop();
}),
const SizedBox(width: 12),
Text(S.current.home_holiday_countdown),
],
),
content: homeState.countdownFestivalListData == null
? makeLoading(context)
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: Column(
children: [
AlignedGridView.count(
crossAxisCount: 3,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
itemCount: homeState.countdownFestivalListData!.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
final item =
homeState.countdownFestivalListData![index];
return Container(
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
if (item.icon != null && item.icon != "") ...[
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Image.asset(
"assets/countdown/${item.icon}",
width: 38,
height: 38,
),
),
const SizedBox(width: 12),
] else
const SizedBox(width: 50),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${item.name}",
),
CountdownTimeText(
targetTime:
DateTime.fromMillisecondsSinceEpoch(
item.time ?? 0),
)
],
)
],
),
),
);
},
),
const SizedBox(height: 12),
Text(
S.current.home_holiday_countdown_disclaimer,
style: TextStyle(
fontSize: 13, color: Colors.white.withOpacity(.3)),
)
],
),
),
),
);
}
}

View File

@ -0,0 +1,121 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'home_game_login_dialog_ui_model.dart';
class HomeGameLoginDialogUI extends HookConsumerWidget {
final BuildContext launchContext;
const HomeGameLoginDialogUI(this.launchContext, {super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final loginState = ref.watch(homeGameLoginUIModelProvider);
useEffect(() {
ref
.read(homeGameLoginUIModelProvider.notifier)
.launchWebLogin(launchContext);
return null;
}, []);
return ContentDialog(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .56,
),
title: (loginState.loginStatus == 2)
? null
: Text(S.current.home_action_one_click_launch),
content: AnimatedSize(
duration: const Duration(milliseconds: 230),
child: Padding(
padding: const EdgeInsets.only(top: 12, bottom: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Row(),
if (loginState.loginStatus == 0) ...[
Center(
child: Column(
children: [
Text(S.current.home_title_logging_in),
const SizedBox(height: 12),
const ProgressRing(),
],
),
),
] else if (loginState.loginStatus == 2 ||
loginState.loginStatus == 3) ...[
Center(
child: Column(
children: [
const SizedBox(height: 12),
Text(
S.current.home_login_title_welcome_back,
style: const TextStyle(fontSize: 20),
),
const SizedBox(height: 24),
if (loginState.avatarUrl != null)
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: CacheNetImage(
url: loginState.avatarUrl!,
width: 128,
height: 128,
fit: BoxFit.fill,
),
),
const SizedBox(height: 12),
Text(
loginState.nickname ?? "",
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
if (loginState.libraryData?.games != null) ...[
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
for (final game in loginState.libraryData!.games!)
Padding(
padding: const EdgeInsets.only(
left: 12, right: 12),
child: Row(
children: [
Icon(
FluentIcons.skype_circle_check,
color: Colors.green,
),
const SizedBox(width: 6),
Text("${game.name}"),
],
),
)
],
),
),
const SizedBox(height: 24)
],
const SizedBox(height: 12),
Text(S.current.home_login_title_launching_game),
const SizedBox(height: 12),
const ProgressRing(),
const SizedBox(height: 12),
],
),
)
]
],
),
),
),
);
}
}

View File

@ -0,0 +1,230 @@
import 'dart:convert';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/data/rsi_game_library_data.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/ui/webview/webview.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:uuid/uuid.dart';
part 'home_game_login_dialog_ui_model.freezed.dart';
part 'home_game_login_dialog_ui_model.g.dart';
@freezed
class HomeGameLoginState with _$HomeGameLoginState {
factory HomeGameLoginState({
required int loginStatus,
String? nickname,
String? avatarUrl,
String? authToken,
String? webToken,
Map? releaseInfo,
RsiGameLibraryData? libraryData,
String? installPath,
bool? isDeviceSupportWinHello,
}) = _LoginStatus;
}
@riverpod
class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
@override
HomeGameLoginState build() {
return HomeGameLoginState(loginStatus: 0);
}
// ignore: avoid_build_context_in_providers
Future<void> launchWebLogin(BuildContext context) async {
final homeState = ref.read(homeUIModelProvider);
if (!context.mounted) return;
goWebView(context, S.current.home_action_login_rsi_account,
"https://robertsspaceindustries.com/connect?jumpto=/connect",
loginMode: true, rsiLoginCallback: (message, ok) async {
// dPrint(
// "======rsiLoginCallback=== $ok ===== data==\n${json.encode(message)}");
if (message == null || !ok) {
Navigator.pop(context);
return;
}
// final emailBox = await Hive.openBox("quick_login_email");
final data = message["data"];
final authToken = data["authToken"];
final webToken = data["webToken"];
final releaseInfo = data["releaseInfo"];
final libraryData = RsiGameLibraryData.fromJson(data["libraryData"]);
var avatarUrl = data["avatar"]
?.toString()
.replaceAll("url(\"", "")
.replaceAll("\")", "");
if (avatarUrl?.startsWith("/") ?? false) {
avatarUrl = "https://robertsspaceindustries.com$avatarUrl";
}
final Map<String, dynamic> payload = Jwt.parseJwt(authToken!);
final nickname = payload["nickname"] ?? "";
state = state.copyWith(
nickname: nickname,
avatarUrl: avatarUrl,
authToken: authToken,
webToken: webToken,
releaseInfo: releaseInfo,
libraryData: libraryData,
);
final buildInfoFile =
File("${homeState.scInstalledPath}\\build_manifest.id");
if (await buildInfoFile.exists()) {
final buildInfo =
json.decode(await buildInfoFile.readAsString())["Data"];
if (releaseInfo?["versionLabel"] != null &&
buildInfo["RequestedP4ChangeNum"] != null) {
if (!(releaseInfo!["versionLabel"]!
.toString()
.endsWith(buildInfo["RequestedP4ChangeNum"]!.toString()))) {
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context,
S.current.home_login_info_game_version_outdated,
Text(S.current.home_login_info_rsi_server_report(
releaseInfo?["versionLabel"],
buildInfo["RequestedP4ChangeNum"])),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .4),
cancel: S.current.home_login_info_action_ignore);
if (ok == true) {
if (!context.mounted) return;
Navigator.pop(context);
return;
}
}
}
}
if (!context.mounted) return;
_readyForLaunch(homeState, context);
}, useLocalization: true, homeState: homeState);
}
// ignore: avoid_build_context_in_providers
goWebView(BuildContext context, String title, String url,
{bool useLocalization = false,
bool loginMode = false,
RsiLoginCallback? rsiLoginCallback,
required HomeUIModelState homeState}) async {
if (useLocalization) {
const tipVersion = 2;
final box = await Hive.openBox("app_conf");
final skip = await box.get("skip_web_login_version", defaultValue: 0);
if (skip != tipVersion) {
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context,
S.current.home_login_action_title_box_one_click_launch,
Text(
S.current.home_login_info_one_click_launch_description,
style: const TextStyle(fontSize: 16),
),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .6));
if (!ok) {
if (loginMode) {
rsiLoginCallback?.call(null, false);
}
return;
}
await box.put("skip_web_login_version", tipVersion);
}
}
if (!await WebviewWindow.isWebviewAvailable()) {
if (!context.mounted) return;
await showToast(
context, S.current.home_login_action_title_need_webview2_runtime);
if (!context.mounted) return;
await launchUrlString(
"https://developer.microsoft.com/en-us/microsoft-edge/webview2/");
if (!context.mounted) return;
Navigator.pop(context);
return;
}
if (!context.mounted) return;
final webViewModel = WebViewModel(context,
loginMode: loginMode,
loginCallback: rsiLoginCallback,
loginChannel: getChannelID(homeState.scInstalledPath!));
if (useLocalization) {
try {
await webViewModel
.initLocalization(homeState.webLocalizationVersionsData!);
} catch (_) {}
}
await Future.delayed(const Duration(milliseconds: 500));
await webViewModel.initWebView(
title: title,
applicationSupportDir: appGlobalState.applicationSupportDir!,
appVersionData: appGlobalState.networkVersionData!,
);
await webViewModel.launch(url, appGlobalState.networkVersionData!);
}
Future<void> _readyForLaunch(
HomeUIModelState homeState,
// ignore: avoid_build_context_in_providers
BuildContext context) async {
final userBox = await Hive.openBox("rsi_account_data");
state = state.copyWith(loginStatus: 2);
final launchData = {
"username": userBox.get("account_email", defaultValue: ""),
"token": state.webToken,
"auth_token": state.authToken,
"star_network": {
"services_endpoint": state.releaseInfo?["servicesEndpoint"],
"hostname": state.releaseInfo?["universeHost"],
"port": state.releaseInfo?["universePort"],
},
"TMid": const Uuid().v4(),
};
final executable = state.releaseInfo?["executable"];
final launchOptions = state.releaseInfo?["launchOptions"];
// dPrint("----------launch data ====== -----------\n$launchData");
// dPrint(
// "----------executable data ====== -----------\n${homeState.scInstalledPath}\\$executable $launchOptions");
final launchFile = File("${homeState.scInstalledPath}\\loginData.json");
if (await launchFile.exists()) {
await launchFile.delete();
}
await launchFile.create();
await launchFile.writeAsString(json.encode(launchData));
final processorAffinity = await SystemHelper.getCpuAffinity();
final homeUIModel = ref.read(homeUIModelProvider.notifier);
if (!context.mounted) return;
homeUIModel.doLaunchGame(
context,
'${homeState.scInstalledPath}\\$executable',
["-no_login_dialog", ...launchOptions.toString().split(" ")],
homeState.scInstalledPath!,
processorAffinity);
await Future.delayed(const Duration(seconds: 1));
if (!context.mounted) return;
Navigator.pop(context);
}
String getChannelID(String installPath) {
if (installPath.endsWith("\\LIVE")) {
return "LIVE";
}
return "PTU";
}
}

View File

@ -0,0 +1,336 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'home_game_login_dialog_ui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$HomeGameLoginState {
int get loginStatus => throw _privateConstructorUsedError;
String? get nickname => throw _privateConstructorUsedError;
String? get avatarUrl => throw _privateConstructorUsedError;
String? get authToken => throw _privateConstructorUsedError;
String? get webToken => throw _privateConstructorUsedError;
Map<dynamic, dynamic>? get releaseInfo => throw _privateConstructorUsedError;
RsiGameLibraryData? get libraryData => throw _privateConstructorUsedError;
String? get installPath => throw _privateConstructorUsedError;
bool? get isDeviceSupportWinHello => throw _privateConstructorUsedError;
/// Create a copy of HomeGameLoginState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$HomeGameLoginStateCopyWith<HomeGameLoginState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeGameLoginStateCopyWith<$Res> {
factory $HomeGameLoginStateCopyWith(
HomeGameLoginState value, $Res Function(HomeGameLoginState) then) =
_$HomeGameLoginStateCopyWithImpl<$Res, HomeGameLoginState>;
@useResult
$Res call(
{int loginStatus,
String? nickname,
String? avatarUrl,
String? authToken,
String? webToken,
Map<dynamic, dynamic>? releaseInfo,
RsiGameLibraryData? libraryData,
String? installPath,
bool? isDeviceSupportWinHello});
}
/// @nodoc
class _$HomeGameLoginStateCopyWithImpl<$Res, $Val extends HomeGameLoginState>
implements $HomeGameLoginStateCopyWith<$Res> {
_$HomeGameLoginStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of HomeGameLoginState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? loginStatus = null,
Object? nickname = freezed,
Object? avatarUrl = freezed,
Object? authToken = freezed,
Object? webToken = freezed,
Object? releaseInfo = freezed,
Object? libraryData = freezed,
Object? installPath = freezed,
Object? isDeviceSupportWinHello = freezed,
}) {
return _then(_value.copyWith(
loginStatus: null == loginStatus
? _value.loginStatus
: loginStatus // ignore: cast_nullable_to_non_nullable
as int,
nickname: freezed == nickname
? _value.nickname
: nickname // ignore: cast_nullable_to_non_nullable
as String?,
avatarUrl: freezed == avatarUrl
? _value.avatarUrl
: avatarUrl // ignore: cast_nullable_to_non_nullable
as String?,
authToken: freezed == authToken
? _value.authToken
: authToken // ignore: cast_nullable_to_non_nullable
as String?,
webToken: freezed == webToken
? _value.webToken
: webToken // ignore: cast_nullable_to_non_nullable
as String?,
releaseInfo: freezed == releaseInfo
? _value.releaseInfo
: releaseInfo // ignore: cast_nullable_to_non_nullable
as Map<dynamic, dynamic>?,
libraryData: freezed == libraryData
? _value.libraryData
: libraryData // ignore: cast_nullable_to_non_nullable
as RsiGameLibraryData?,
installPath: freezed == installPath
? _value.installPath
: installPath // ignore: cast_nullable_to_non_nullable
as String?,
isDeviceSupportWinHello: freezed == isDeviceSupportWinHello
? _value.isDeviceSupportWinHello
: isDeviceSupportWinHello // ignore: cast_nullable_to_non_nullable
as bool?,
) as $Val);
}
}
/// @nodoc
abstract class _$$LoginStatusImplCopyWith<$Res>
implements $HomeGameLoginStateCopyWith<$Res> {
factory _$$LoginStatusImplCopyWith(
_$LoginStatusImpl value, $Res Function(_$LoginStatusImpl) then) =
__$$LoginStatusImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int loginStatus,
String? nickname,
String? avatarUrl,
String? authToken,
String? webToken,
Map<dynamic, dynamic>? releaseInfo,
RsiGameLibraryData? libraryData,
String? installPath,
bool? isDeviceSupportWinHello});
}
/// @nodoc
class __$$LoginStatusImplCopyWithImpl<$Res>
extends _$HomeGameLoginStateCopyWithImpl<$Res, _$LoginStatusImpl>
implements _$$LoginStatusImplCopyWith<$Res> {
__$$LoginStatusImplCopyWithImpl(
_$LoginStatusImpl _value, $Res Function(_$LoginStatusImpl) _then)
: super(_value, _then);
/// Create a copy of HomeGameLoginState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? loginStatus = null,
Object? nickname = freezed,
Object? avatarUrl = freezed,
Object? authToken = freezed,
Object? webToken = freezed,
Object? releaseInfo = freezed,
Object? libraryData = freezed,
Object? installPath = freezed,
Object? isDeviceSupportWinHello = freezed,
}) {
return _then(_$LoginStatusImpl(
loginStatus: null == loginStatus
? _value.loginStatus
: loginStatus // ignore: cast_nullable_to_non_nullable
as int,
nickname: freezed == nickname
? _value.nickname
: nickname // ignore: cast_nullable_to_non_nullable
as String?,
avatarUrl: freezed == avatarUrl
? _value.avatarUrl
: avatarUrl // ignore: cast_nullable_to_non_nullable
as String?,
authToken: freezed == authToken
? _value.authToken
: authToken // ignore: cast_nullable_to_non_nullable
as String?,
webToken: freezed == webToken
? _value.webToken
: webToken // ignore: cast_nullable_to_non_nullable
as String?,
releaseInfo: freezed == releaseInfo
? _value._releaseInfo
: releaseInfo // ignore: cast_nullable_to_non_nullable
as Map<dynamic, dynamic>?,
libraryData: freezed == libraryData
? _value.libraryData
: libraryData // ignore: cast_nullable_to_non_nullable
as RsiGameLibraryData?,
installPath: freezed == installPath
? _value.installPath
: installPath // ignore: cast_nullable_to_non_nullable
as String?,
isDeviceSupportWinHello: freezed == isDeviceSupportWinHello
? _value.isDeviceSupportWinHello
: isDeviceSupportWinHello // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
/// @nodoc
class _$LoginStatusImpl implements _LoginStatus {
_$LoginStatusImpl(
{required this.loginStatus,
this.nickname,
this.avatarUrl,
this.authToken,
this.webToken,
final Map<dynamic, dynamic>? releaseInfo,
this.libraryData,
this.installPath,
this.isDeviceSupportWinHello})
: _releaseInfo = releaseInfo;
@override
final int loginStatus;
@override
final String? nickname;
@override
final String? avatarUrl;
@override
final String? authToken;
@override
final String? webToken;
final Map<dynamic, dynamic>? _releaseInfo;
@override
Map<dynamic, dynamic>? get releaseInfo {
final value = _releaseInfo;
if (value == null) return null;
if (_releaseInfo is EqualUnmodifiableMapView) return _releaseInfo;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
final RsiGameLibraryData? libraryData;
@override
final String? installPath;
@override
final bool? isDeviceSupportWinHello;
@override
String toString() {
return 'HomeGameLoginState(loginStatus: $loginStatus, nickname: $nickname, avatarUrl: $avatarUrl, authToken: $authToken, webToken: $webToken, releaseInfo: $releaseInfo, libraryData: $libraryData, installPath: $installPath, isDeviceSupportWinHello: $isDeviceSupportWinHello)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoginStatusImpl &&
(identical(other.loginStatus, loginStatus) ||
other.loginStatus == loginStatus) &&
(identical(other.nickname, nickname) ||
other.nickname == nickname) &&
(identical(other.avatarUrl, avatarUrl) ||
other.avatarUrl == avatarUrl) &&
(identical(other.authToken, authToken) ||
other.authToken == authToken) &&
(identical(other.webToken, webToken) ||
other.webToken == webToken) &&
const DeepCollectionEquality()
.equals(other._releaseInfo, _releaseInfo) &&
(identical(other.libraryData, libraryData) ||
other.libraryData == libraryData) &&
(identical(other.installPath, installPath) ||
other.installPath == installPath) &&
(identical(
other.isDeviceSupportWinHello, isDeviceSupportWinHello) ||
other.isDeviceSupportWinHello == isDeviceSupportWinHello));
}
@override
int get hashCode => Object.hash(
runtimeType,
loginStatus,
nickname,
avatarUrl,
authToken,
webToken,
const DeepCollectionEquality().hash(_releaseInfo),
libraryData,
installPath,
isDeviceSupportWinHello);
/// Create a copy of HomeGameLoginState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoginStatusImplCopyWith<_$LoginStatusImpl> get copyWith =>
__$$LoginStatusImplCopyWithImpl<_$LoginStatusImpl>(this, _$identity);
}
abstract class _LoginStatus implements HomeGameLoginState {
factory _LoginStatus(
{required final int loginStatus,
final String? nickname,
final String? avatarUrl,
final String? authToken,
final String? webToken,
final Map<dynamic, dynamic>? releaseInfo,
final RsiGameLibraryData? libraryData,
final String? installPath,
final bool? isDeviceSupportWinHello}) = _$LoginStatusImpl;
@override
int get loginStatus;
@override
String? get nickname;
@override
String? get avatarUrl;
@override
String? get authToken;
@override
String? get webToken;
@override
Map<dynamic, dynamic>? get releaseInfo;
@override
RsiGameLibraryData? get libraryData;
@override
String? get installPath;
@override
bool? get isDeviceSupportWinHello;
/// Create a copy of HomeGameLoginState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoginStatusImplCopyWith<_$LoginStatusImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'home_game_login_dialog_ui_model.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$homeGameLoginUIModelHash() =>
r'e8afccb7bba7c79e766e30a27f64128918a63dd7';
/// See also [HomeGameLoginUIModel].
@ProviderFor(HomeGameLoginUIModel)
final homeGameLoginUIModelProvider = AutoDisposeNotifierProvider<
HomeGameLoginUIModel, HomeGameLoginState>.internal(
HomeGameLoginUIModel.new,
name: r'homeGameLoginUIModelProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$homeGameLoginUIModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$HomeGameLoginUIModel = AutoDisposeNotifier<HomeGameLoginState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@ -0,0 +1,55 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/material.dart' show Material;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
class HomeMdContentDialogUI extends HookConsumerWidget {
final String title;
final String url;
const HomeMdContentDialogUI(
{super.key, required this.title, required this.url});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Material(
child: ContentDialog(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .6,
),
title: Text(title),
content: LoadingWidget(
onLoadData: _getContent,
childBuilder: (BuildContext context, String data) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: makeMarkdownView(data),
),
),
);
},
),
actions: [
FilledButton(
child: Padding(
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
child: Text(S.current.action_close),
),
onPressed: () {
Navigator.pop(context);
})
],
),
);
}
Future<String> _getContent() async {
final r = await RSHttp.getText(url);
return r;
}
}

View File

@ -1,43 +0,0 @@
import 'package:flutter/material.dart' show Material;
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/ui/home/dialogs/md_content_dialog_ui_model.dart';
class MDContentDialogUI extends BaseUI<MDContentDialogUIModel> {
@override
Widget? buildBody(BuildContext context, MDContentDialogUIModel model) {
return Material(
child: ContentDialog(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .6,
),
title: Text(getUITitle(context, model)),
content: model.data == null
? makeLoading(context)
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: makeMarkdownView(model.data ?? ""),
),
),
),
actions: [
FilledButton(
child: const Padding(
padding: EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
child: Text("关闭"),
),
onPressed: () {
Navigator.pop(context);
})
],
),
);
}
@override
String getUITitle(BuildContext context, MDContentDialogUIModel model) =>
model.title;
}

View File

@ -1,19 +0,0 @@
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
class MDContentDialogUIModel extends BaseUIModel {
String title;
String url;
MDContentDialogUIModel(this.title, this.url);
String? data;
@override
Future loadData() async {
final r = await handleError(() => RSHttp.getText(url));
if (r == null) return;
data = r;
notifyListeners();
}
}

View File

@ -0,0 +1,260 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:file_sizes/file_sizes.dart';
import 'home_downloader_ui_model.dart';
class HomeDownloaderUI extends HookConsumerWidget {
const HomeDownloaderUI({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(homeDownloaderUIModelProvider);
final model = ref.read(homeDownloaderUIModelProvider.notifier);
return makeDefaultPage(context,
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12),
Row(
children: [
const Spacer(),
const SizedBox(width: 24),
const SizedBox(width: 12),
for (final item in <MapEntry<String, IconData>, String>{
const MapEntry("settings", FluentIcons.settings):
S.current.downloader_speed_limit_settings,
if (state.tasks.isNotEmpty)
const MapEntry("pause_all", FluentIcons.pause):
S.current.downloader_action_pause_all,
if (state.waitingTasks.isNotEmpty)
const MapEntry("resume_all", FluentIcons.download):
S.current.downloader_action_resume_all,
if (state.tasks.isNotEmpty || state.waitingTasks.isNotEmpty)
const MapEntry("cancel_all", FluentIcons.cancel):
S.current.downloader_action_cancel_all,
}.entries)
Padding(
padding: const EdgeInsets.only(left: 6, right: 6),
child: Button(
child: Padding(
padding: const EdgeInsets.all(4),
child: Row(
children: [
Icon(item.key.value),
const SizedBox(width: 6),
Text(item.value),
],
),
),
onPressed: () =>
model.onTapButton(context, item.key.key)),
),
const SizedBox(width: 12),
],
),
if (model.getTasksLen() == 0)
Expanded(
child: Center(
child: Text(S.current.downloader_info_no_download_tasks),
))
else
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
final (task, type, isFirstType) = model.getTaskAndType(index);
final nt = HomeDownloaderUIModel.getTaskTypeAndName(task);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isFirstType)
Column(
children: [
Container(
padding: EdgeInsets.only(
left: 24,
right: 24,
top: index == 0 ? 0 : 12,
bottom: 12),
margin: const EdgeInsets.only(top: 6, bottom: 6),
child: Row(
children: [
Expanded(
child: Row(
children: [
Text(
"${model.listHeaderStatusMap[type]}",
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold),
),
],
)),
],
),
),
],
),
Container(
padding: const EdgeInsets.only(
left: 12, right: 12, top: 12, bottom: 12),
margin: const EdgeInsets.only(
left: 12, right: 12, top: 6, bottom: 6),
decoration: BoxDecoration(
color: FluentTheme.of(context)
.cardColor
.withOpacity(.06),
borderRadius: BorderRadius.circular(7),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
nt.value,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
),
const SizedBox(height: 6),
Row(
children: [
Text(
S.current.downloader_info_total_size(
FileSize.getSize(
task.totalLength ?? 0)),
style: const TextStyle(fontSize: 14),
),
const SizedBox(width: 12),
if (nt.key == "torrent" &&
task.verifiedLength != null &&
task.verifiedLength != 0)
Text(
S.current.downloader_info_verifying(
FileSize.getSize(
task.verifiedLength)),
style: const TextStyle(fontSize: 14),
)
else if (task.status == "active")
Text(S.current
.downloader_info_downloading(
((task.completedLength ?? 0) *
100 /
(task.totalLength ?? 1))
.toStringAsFixed(4)))
else
Text(S.current.downloader_info_status(
model.statusMap[task.status] ??
"Unknown")),
const SizedBox(width: 24),
if (task.status == "active" &&
task.verifiedLength == null)
Text(
"ETA: ${model.formatter.format(DateTime.now().add(Duration(seconds: model.getETA(task))))}"),
],
),
],
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.current.downloader_info_uploaded(
FileSize.getSize(task.uploadLength))),
Text(S.current.downloader_info_downloaded(
FileSize.getSize(task.completedLength))),
],
),
const SizedBox(width: 18),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"↑:${FileSize.getSize(task.uploadSpeed)}/s"),
Text(
"↓:${FileSize.getSize(task.downloadSpeed)}/s"),
],
),
const SizedBox(width: 32),
if (type != "stopped")
DropDownButton(
closeAfterClick: false,
title: Padding(
padding: const EdgeInsets.all(3),
child:
Text(S.current.downloader_action_options),
),
items: [
if (task.status == "paused")
MenuFlyoutItem(
leading:
const Icon(FluentIcons.download),
text: Text(S.current
.downloader_action_continue_download),
onPressed: () =>
model.resumeTask(task.gid))
else if (task.status == "active")
MenuFlyoutItem(
leading: const Icon(FluentIcons.pause),
text: Text(S.current
.downloader_action_pause_download),
onPressed: () =>
model.pauseTask(task.gid)),
const MenuFlyoutSeparator(),
MenuFlyoutItem(
leading: const Icon(
FluentIcons.chrome_close,
size: 14,
),
text: Text(S.current
.downloader_action_cancel_download),
onPressed: () =>
model.cancelTask(context, task.gid)),
MenuFlyoutItem(
leading: const Icon(
FluentIcons.folder_open,
size: 14,
),
text: Text(S.current.action_open_folder),
onPressed: () => model.openFolder(task)),
],
),
const SizedBox(width: 12),
],
),
),
],
);
},
itemCount: model.getTasksLen(),
)),
Container(
color: FluentTheme.of(context).cardColor.withOpacity(.06),
child: Padding(
padding: const EdgeInsets.only(left: 12, bottom: 3, top: 3),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: state.isAvailable ? Colors.green : Colors.white,
borderRadius: BorderRadius.circular(1000),
),
),
const SizedBox(width: 12),
Text(S.current.downloader_info_download_upload_speed(
FileSize.getSize(state.globalStat?.downloadSpeed ?? 0),
FileSize.getSize(state.globalStat?.uploadSpeed ?? 0)))
],
),
),
),
],
),
useBodyContainer: true);
}
}

View File

@ -0,0 +1,310 @@
// ignore_for_file: avoid_build_context_in_providers, avoid_public_notifier_properties
import 'dart:io';
import 'package:aria2/aria2.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/services.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:intl/intl.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/provider/aria2c.dart';
import '../../../widgets/widgets.dart';
part 'home_downloader_ui_model.g.dart';
part 'home_downloader_ui_model.freezed.dart';
@freezed
class HomeDownloaderUIState with _$HomeDownloaderUIState {
factory HomeDownloaderUIState({
@Default([]) List<Aria2Task> tasks,
@Default([]) List<Aria2Task> waitingTasks,
@Default([]) List<Aria2Task> stoppedTasks,
Aria2GlobalStat? globalStat,
}) = _HomeDownloaderUIState;
}
extension HomeDownloaderUIStateExtension on HomeDownloaderUIState {
bool get isAvailable => globalStat != null;
}
@riverpod
class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
final DateFormat formatter = DateFormat('yyyy-MM-dd HH:mm:ss');
bool _disposed = false;
final statusMap = {
"active": S.current.downloader_info_downloading_status,
"waiting": S.current.downloader_info_waiting,
"paused": S.current.downloader_info_paused,
"error": S.current.downloader_info_download_failed,
"complete": S.current.downloader_info_download_completed,
"removed": S.current.downloader_info_deleted,
};
final listHeaderStatusMap = {
"active": S.current.downloader_title_downloading,
"waiting": S.current.downloader_info_waiting,
"stopped": S.current.downloader_title_ended,
};
@override
HomeDownloaderUIState build() {
state = HomeDownloaderUIState();
_listenDownloader();
ref.onDispose(() {
_disposed = true;
});
return state;
}
onTapButton(BuildContext context, String key) async {
final aria2cState = ref.read(aria2cModelProvider);
switch (key) {
case "pause_all":
if (!aria2cState.isRunning) return;
await aria2cState.aria2c?.pauseAll();
await aria2cState.aria2c?.saveSession();
return;
case "resume_all":
if (!aria2cState.isRunning) return;
await aria2cState.aria2c?.unpauseAll();
await aria2cState.aria2c?.saveSession();
return;
case "cancel_all":
final userOK = await showConfirmDialogs(
context,
S.current.downloader_action_confirm_cancel_all_tasks,
Text(S.current.downloader_info_manual_file_deletion_note));
if (userOK == true) {
if (!aria2cState.isRunning) return;
try {
for (var value in [...state.tasks, ...state.waitingTasks]) {
await aria2cState.aria2c?.remove(value.gid!);
}
await aria2cState.aria2c?.saveSession();
} catch (e) {
dPrint("DownloadsUIModel cancel_all Error: $e");
}
}
return;
case "settings":
_showDownloadSpeedSettings(context);
return;
}
}
int getTasksLen() {
return state.tasks.length +
state.waitingTasks.length +
state.stoppedTasks.length;
}
(Aria2Task, String, bool) getTaskAndType(int index) {
final tempList = <Aria2Task>[
...state.tasks,
...state.waitingTasks,
...state.stoppedTasks
];
if (index >= 0 && index < state.tasks.length) {
return (tempList[index], "active", index == 0);
}
if (index >= state.tasks.length &&
index < state.tasks.length + state.waitingTasks.length) {
return (tempList[index], "waiting", index == state.tasks.length);
}
if (index >= state.tasks.length + state.waitingTasks.length &&
index < tempList.length) {
return (
tempList[index],
"stopped",
index == state.tasks.length + state.waitingTasks.length
);
}
throw Exception("Index out of range or element is null");
}
static MapEntry<String, String> getTaskTypeAndName(Aria2Task task) {
if (task.bittorrent == null) {
String uri = task.files?[0]['uris'][0]['uri'] as String;
return MapEntry("url", uri.split('/').last);
} else if (task.bittorrent != null) {
if (task.bittorrent!.containsKey('info')) {
var btName = task.bittorrent?["info"]["name"];
return MapEntry("torrent", btName ?? 'torrent');
} else {
return MapEntry("magnet", '[METADATA]${task.infoHash}');
}
} else {
return const MapEntry("metaLink", '==========metaLink============');
}
}
int getETA(Aria2Task task) {
if (task.downloadSpeed == null || task.downloadSpeed == 0) return 0;
final remainingBytes =
(task.totalLength ?? 0) - (task.completedLength ?? 0);
return remainingBytes ~/ (task.downloadSpeed!);
}
Future<void> resumeTask(String? gid) async {
final aria2c = ref.read(aria2cModelProvider).aria2c;
if (gid != null) {
await aria2c?.unpause(gid);
}
}
Future<void> pauseTask(String? gid) async {
final aria2c = ref.read(aria2cModelProvider).aria2c;
if (gid != null) {
await aria2c?.pause(gid);
}
}
Future<void> cancelTask(BuildContext context, String? gid) async {
await Future.delayed(const Duration(milliseconds: 300));
if (gid != null) {
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context,
S.current.downloader_action_confirm_cancel_download,
Text(S.current.downloader_info_manual_file_deletion_note));
if (ok == true) {
final aria2c = ref.read(aria2cModelProvider).aria2c;
await aria2c?.remove(gid);
await aria2c?.saveSession();
}
}
}
List<Aria2File> getFilesFormTask(Aria2Task task) {
List<Aria2File> l = [];
if (task.files != null) {
for (var element in task.files!) {
final f = Aria2File.fromJson(element);
l.add(f);
}
}
return l;
}
openFolder(Aria2Task task) {
final f = getFilesFormTask(task).firstOrNull;
if (f != null) {
SystemHelper.openDir(File(f.path!).absolute.path.replaceAll("/", "\\"));
}
}
_listenDownloader() async {
try {
while (true) {
final aria2cState = ref.read(aria2cModelProvider);
if (_disposed) return;
if (aria2cState.isRunning) {
final aria2c = aria2cState.aria2c!;
final tasks = await aria2c.tellActive();
final waitingTasks = await aria2c.tellWaiting(0, 1000000);
final stoppedTasks = await aria2c.tellStopped(0, 1000000);
final globalStat = await aria2c.getGlobalStat();
state = state.copyWith(
tasks: tasks,
waitingTasks: waitingTasks,
stoppedTasks: stoppedTasks,
globalStat: globalStat,
);
} else {
state = state.copyWith(
tasks: [],
waitingTasks: [],
stoppedTasks: [],
globalStat: null,
);
}
await Future.delayed(const Duration(seconds: 1));
}
} catch (e) {
dPrint("[DownloadsUIModel]._listenDownloader Error: $e");
}
}
Future<void> _showDownloadSpeedSettings(BuildContext context) async {
final box = await Hive.openBox("app_conf");
final upCtrl = TextEditingController(
text: box.get("downloader_up_limit", defaultValue: ""));
final downCtrl = TextEditingController(
text: box.get("downloader_down_limit", defaultValue: ""));
final ifr = FilteringTextInputFormatter.allow(RegExp(r'^\d*[km]?$'));
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context,
S.current.downloader_speed_limit_settings,
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.current.downloader_info_p2p_network_note,
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(.6),
),
),
const SizedBox(height: 24),
Text(S.current.downloader_info_download_unit_input_prompt),
const SizedBox(height: 12),
Text(S.current.downloader_input_upload_speed_limit),
const SizedBox(height: 6),
TextFormBox(
placeholder: "1、100k、10m、0",
controller: upCtrl,
placeholderStyle: TextStyle(color: Colors.white.withOpacity(.6)),
inputFormatters: [ifr],
),
const SizedBox(height: 12),
Text(S.current.downloader_input_download_speed_limit),
const SizedBox(height: 6),
TextFormBox(
placeholder: "1、100k、10m、0",
controller: downCtrl,
placeholderStyle: TextStyle(color: Colors.white.withOpacity(.6)),
inputFormatters: [ifr],
),
const SizedBox(height: 24),
Text(
S.current.downloader_input_info_p2p_upload_note,
style: TextStyle(
fontSize: 13,
color: Colors.white.withOpacity(.6),
),
)
],
));
if (ok == true) {
final aria2cState = ref.read(aria2cModelProvider);
final aria2cModel = ref.read(aria2cModelProvider.notifier);
await aria2cModel
.launchDaemon(appGlobalState.applicationBinaryModuleDir!);
final aria2c = aria2cState.aria2c!;
final upByte = aria2cModel.textToByte(upCtrl.text.trim());
final downByte = aria2cModel.textToByte(downCtrl.text.trim());
final r = await aria2c
.changeGlobalOption(Aria2Option()
..maxOverallUploadLimit = upByte
..maxOverallDownloadLimit = downByte)
.unwrap();
if (r != null) {
await box.put('downloader_up_limit', upCtrl.text.trim());
await box.put('downloader_down_limit', downCtrl.text.trim());
}
}
}
}

View File

@ -0,0 +1,243 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'home_downloader_ui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$HomeDownloaderUIState {
List<Aria2Task> get tasks => throw _privateConstructorUsedError;
List<Aria2Task> get waitingTasks => throw _privateConstructorUsedError;
List<Aria2Task> get stoppedTasks => throw _privateConstructorUsedError;
Aria2GlobalStat? get globalStat => throw _privateConstructorUsedError;
/// Create a copy of HomeDownloaderUIState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$HomeDownloaderUIStateCopyWith<HomeDownloaderUIState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeDownloaderUIStateCopyWith<$Res> {
factory $HomeDownloaderUIStateCopyWith(HomeDownloaderUIState value,
$Res Function(HomeDownloaderUIState) then) =
_$HomeDownloaderUIStateCopyWithImpl<$Res, HomeDownloaderUIState>;
@useResult
$Res call(
{List<Aria2Task> tasks,
List<Aria2Task> waitingTasks,
List<Aria2Task> stoppedTasks,
Aria2GlobalStat? globalStat});
}
/// @nodoc
class _$HomeDownloaderUIStateCopyWithImpl<$Res,
$Val extends HomeDownloaderUIState>
implements $HomeDownloaderUIStateCopyWith<$Res> {
_$HomeDownloaderUIStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of HomeDownloaderUIState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tasks = null,
Object? waitingTasks = null,
Object? stoppedTasks = null,
Object? globalStat = freezed,
}) {
return _then(_value.copyWith(
tasks: null == tasks
? _value.tasks
: tasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
waitingTasks: null == waitingTasks
? _value.waitingTasks
: waitingTasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
stoppedTasks: null == stoppedTasks
? _value.stoppedTasks
: stoppedTasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
globalStat: freezed == globalStat
? _value.globalStat
: globalStat // ignore: cast_nullable_to_non_nullable
as Aria2GlobalStat?,
) as $Val);
}
}
/// @nodoc
abstract class _$$HomeDownloaderUIStateImplCopyWith<$Res>
implements $HomeDownloaderUIStateCopyWith<$Res> {
factory _$$HomeDownloaderUIStateImplCopyWith(
_$HomeDownloaderUIStateImpl value,
$Res Function(_$HomeDownloaderUIStateImpl) then) =
__$$HomeDownloaderUIStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{List<Aria2Task> tasks,
List<Aria2Task> waitingTasks,
List<Aria2Task> stoppedTasks,
Aria2GlobalStat? globalStat});
}
/// @nodoc
class __$$HomeDownloaderUIStateImplCopyWithImpl<$Res>
extends _$HomeDownloaderUIStateCopyWithImpl<$Res,
_$HomeDownloaderUIStateImpl>
implements _$$HomeDownloaderUIStateImplCopyWith<$Res> {
__$$HomeDownloaderUIStateImplCopyWithImpl(_$HomeDownloaderUIStateImpl _value,
$Res Function(_$HomeDownloaderUIStateImpl) _then)
: super(_value, _then);
/// Create a copy of HomeDownloaderUIState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tasks = null,
Object? waitingTasks = null,
Object? stoppedTasks = null,
Object? globalStat = freezed,
}) {
return _then(_$HomeDownloaderUIStateImpl(
tasks: null == tasks
? _value._tasks
: tasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
waitingTasks: null == waitingTasks
? _value._waitingTasks
: waitingTasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
stoppedTasks: null == stoppedTasks
? _value._stoppedTasks
: stoppedTasks // ignore: cast_nullable_to_non_nullable
as List<Aria2Task>,
globalStat: freezed == globalStat
? _value.globalStat
: globalStat // ignore: cast_nullable_to_non_nullable
as Aria2GlobalStat?,
));
}
}
/// @nodoc
class _$HomeDownloaderUIStateImpl implements _HomeDownloaderUIState {
_$HomeDownloaderUIStateImpl(
{final List<Aria2Task> tasks = const [],
final List<Aria2Task> waitingTasks = const [],
final List<Aria2Task> stoppedTasks = const [],
this.globalStat})
: _tasks = tasks,
_waitingTasks = waitingTasks,
_stoppedTasks = stoppedTasks;
final List<Aria2Task> _tasks;
@override
@JsonKey()
List<Aria2Task> get tasks {
if (_tasks is EqualUnmodifiableListView) return _tasks;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_tasks);
}
final List<Aria2Task> _waitingTasks;
@override
@JsonKey()
List<Aria2Task> get waitingTasks {
if (_waitingTasks is EqualUnmodifiableListView) return _waitingTasks;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_waitingTasks);
}
final List<Aria2Task> _stoppedTasks;
@override
@JsonKey()
List<Aria2Task> get stoppedTasks {
if (_stoppedTasks is EqualUnmodifiableListView) return _stoppedTasks;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_stoppedTasks);
}
@override
final Aria2GlobalStat? globalStat;
@override
String toString() {
return 'HomeDownloaderUIState(tasks: $tasks, waitingTasks: $waitingTasks, stoppedTasks: $stoppedTasks, globalStat: $globalStat)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$HomeDownloaderUIStateImpl &&
const DeepCollectionEquality().equals(other._tasks, _tasks) &&
const DeepCollectionEquality()
.equals(other._waitingTasks, _waitingTasks) &&
const DeepCollectionEquality()
.equals(other._stoppedTasks, _stoppedTasks) &&
(identical(other.globalStat, globalStat) ||
other.globalStat == globalStat));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(_tasks),
const DeepCollectionEquality().hash(_waitingTasks),
const DeepCollectionEquality().hash(_stoppedTasks),
globalStat);
/// Create a copy of HomeDownloaderUIState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$HomeDownloaderUIStateImplCopyWith<_$HomeDownloaderUIStateImpl>
get copyWith => __$$HomeDownloaderUIStateImplCopyWithImpl<
_$HomeDownloaderUIStateImpl>(this, _$identity);
}
abstract class _HomeDownloaderUIState implements HomeDownloaderUIState {
factory _HomeDownloaderUIState(
{final List<Aria2Task> tasks,
final List<Aria2Task> waitingTasks,
final List<Aria2Task> stoppedTasks,
final Aria2GlobalStat? globalStat}) = _$HomeDownloaderUIStateImpl;
@override
List<Aria2Task> get tasks;
@override
List<Aria2Task> get waitingTasks;
@override
List<Aria2Task> get stoppedTasks;
@override
Aria2GlobalStat? get globalStat;
/// Create a copy of HomeDownloaderUIState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$HomeDownloaderUIStateImplCopyWith<_$HomeDownloaderUIStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'home_downloader_ui_model.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$homeDownloaderUIModelHash() =>
r'ece2e6da4576b945ead5767aea2ccacf5e3e17aa';
/// See also [HomeDownloaderUIModel].
@ProviderFor(HomeDownloaderUIModel)
final homeDownloaderUIModelProvider = AutoDisposeNotifierProvider<
HomeDownloaderUIModel, HomeDownloaderUIState>.internal(
HomeDownloaderUIModel.new,
name: r'homeDownloaderUIModelProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$homeDownloaderUIModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$HomeDownloaderUIModel = AutoDisposeNotifier<HomeDownloaderUIState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@ -1,18 +1,71 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'game_doctor_ui_model.dart';
class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
class HomeGameDoctorUI extends HookConsumerWidget {
const HomeGameDoctorUI({super.key});
@override
Widget? buildBody(BuildContext context, GameDoctorUIModel model) {
return makeDefaultPage(context, model,
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(homeGameDoctorUIModelProvider);
final homeState = ref.watch(homeUIModelProvider);
final model = ref.read(homeGameDoctorUIModelProvider.notifier);
useEffect(() {
AnalyticsApi.touch("auto_scan_issues");
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
dPrint("HomeGameDoctorUI useEffect doCheck timeStamp === $timeStamp");
model.doCheck(context);
});
return null;
}, []);
return makeDefaultPage(context,
title: S.current
.doctor_title_one_click_diagnosis(homeState.scInstalledPath ?? ""),
useBodyContainer: true,
content: Stack(
children: [
Column(
children: [
if (model.isChecking)
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
for (final item in {
"rsi_log": S.current.doctor_action_rsi_launcher_log,
"game_log": S.current.doctor_action_game_run_log,
}.entries)
Padding(
padding: const EdgeInsets.only(left: 6, right: 6),
child: Button(
child: Padding(
padding: const EdgeInsets.all(4),
child: Row(
children: [
const Icon(FluentIcons.folder_open),
const SizedBox(width: 6),
Text(item.value),
],
),
),
onPressed: () =>
_onTapButton(context, item.key, homeState)),
),
],
),
if (state.isChecking)
Expanded(
child: Center(
child: Column(
@ -20,28 +73,29 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
children: [
const ProgressRing(),
const SizedBox(height: 12),
Text(model.lastScreenInfo)
Text(state.lastScreenInfo)
],
),
))
else if (model.checkResult == null ||
model.checkResult!.isEmpty) ...[
const Expanded(
else if (state.checkResult == null ||
state.checkResult!.isEmpty) ...[
Expanded(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 12),
Text("扫描完毕,没有找到问题!", maxLines: 1),
SizedBox(height: 64),
const SizedBox(height: 12),
Text(S.current.doctor_info_scan_complete_no_issues,
maxLines: 1),
const SizedBox(height: 64),
],
),
))
] else
...makeResult(context, model),
...makeResult(context, state, model),
],
),
if (model.isFixing)
if (state.isFixing)
Container(
decoration: BoxDecoration(
color: Colors.black.withAlpha(150),
@ -52,9 +106,9 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
children: [
const ProgressRing(),
const SizedBox(height: 12),
Text(model.isFixingString.isNotEmpty
? model.isFixingString
: "正在处理..."),
Text(state.isFixingString.isNotEmpty
? state.isFixingString
: S.current.doctor_info_processing),
],
),
),
@ -68,34 +122,11 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
));
}
List<Widget> makeResult(BuildContext context, GameDoctorUIModel model) {
return [
const SizedBox(height: 24),
Text(model.lastScreenInfo, maxLines: 1),
const SizedBox(height: 12),
Text(
"注意:本工具检测结果仅供参考,若您不理解以下操作,请提供截图给有经验的玩家!",
style: TextStyle(color: Colors.red, fontSize: 16),
),
const SizedBox(height: 24),
ListView.builder(
itemCount: model.checkResult!.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
final item = model.checkResult![index];
return makeResultItem(item, model);
},
),
const SizedBox(height: 64),
];
}
Widget makeRescueBanner(BuildContext context) {
return GestureDetector(
onTap: () async {
await showToast(context,
"您即将前往由 深空治疗中心QQ群号536454632 提供的游戏异常救援服务,主要解决游戏安装失败与频繁闪退,如游戏玩法问题,请勿加群。");
await showToast(
context, S.current.doctor_info_game_rescue_service_note);
launchUrlString(
"https://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=-M4wEme_bCXbUGT4LFKLH0bAYTFt70Ad&authKey=vHVr0TNgRmKu%2BHwywoJV6EiLa7La2VX74Vkyixr05KA0H9TqB6qWlCdY%2B9jLQ4Ha&noverify=0&group_code=536454632");
},
@ -113,7 +144,7 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
children: [
Image.asset("assets/rescue.png", width: 24, height: 24),
const SizedBox(width: 12),
const Text("需要帮助? 点击加群寻求免费人工支援!"),
Text(S.current.doctor_info_need_help),
],
),
)),
@ -121,25 +152,53 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
);
}
Widget makeResultItem(
MapEntry<String, String> item, GameDoctorUIModel model) {
List<Widget> makeResult(BuildContext context, HomeGameDoctorState state,
HomeGameDoctorUIModel model) {
return [
const SizedBox(height: 24),
Text(state.lastScreenInfo, maxLines: 1),
const SizedBox(height: 12),
Text(
S.current.doctor_info_tool_check_result_note,
style: TextStyle(color: Colors.red, fontSize: 16),
),
const SizedBox(height: 24),
ListView.builder(
itemCount: state.checkResult!.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
final item = state.checkResult![index];
return makeResultItem(context, item, state, model);
},
),
const SizedBox(height: 64),
];
}
Widget makeResultItem(BuildContext context, MapEntry<String, String> item,
HomeGameDoctorState state, HomeGameDoctorUIModel model) {
final errorNames = {
"unSupport_system":
MapEntry("不支持的操作系统,游戏可能无法运行", "请升级您的系统 (${item.value})"),
"no_live_path": MapEntry("安装目录缺少LIVE文件夹可能导致安装失败",
"点击修复为您创建 LIVE 文件夹,完成后重试安装。(${item.value})"),
"nvme_PhysicalBytes": MapEntry("新型 NVME 设备,与 RSI 启动器暂不兼容,可能导致安装失败",
"为注册表项添加 ForcedPhysicalSectorSizeInBytes 值 模拟旧设备。硬盘分区(${item.value})"),
"eac_file_miss": const MapEntry("EasyAntiCheat 文件丢失",
"未在 LIVE 文件夹找到 EasyAntiCheat 文件 或 文件不完整,请使用 RSI 启动器校验文件"),
"eac_not_install": const MapEntry("EasyAntiCheat 未安装 或 未正常退出",
"EasyAntiCheat 未安装,请点击修复为您一键安装。(在游戏正常启动并结束前,该问题会一直出现,若您因为其他原因游戏闪退,可忽略此条目)"),
"cn_user_name":
const MapEntry("中文用户名!", "中文用户名可能会导致游戏启动/安装错误! 点击修复按钮查看修改教程!"),
"cn_install_path": MapEntry("中文安装路径!",
"中文安装路径!这可能会导致游戏 启动/安装 错误!(${item.value}请在RSI启动器更换安装路径。"),
"low_ram": MapEntry(
"物理内存过低", "您至少需要 16GB 的物理内存Memory才可运行此游戏。当前大小${item.value}"),
"unSupport_system": MapEntry(S.current.doctor_info_result_unsupported_os,
S.current.doctor_info_result_upgrade_system(item.value)),
"no_live_path": MapEntry(S.current.doctor_info_result_missing_live_folder,
S.current.doctor_info_result_create_live_folder(item.value)),
"nvme_PhysicalBytes": MapEntry(
S.current.doctor_info_result_incompatible_nvme_device,
S.current.doctor_info_result_add_registry_value(item.value)),
"eac_file_miss": MapEntry(
S.current.doctor_info_result_missing_easyanticheat_files,
S.current.doctor_info_result_verify_files_with_rsi_launcher),
"eac_not_install": MapEntry(
S.current.doctor_info_result_easyanticheat_not_installed,
S.current.doctor_info_result_install_easyanticheat),
"cn_user_name": MapEntry(S.current.doctor_info_result_chinese_username,
S.current.doctor_info_result_chinese_username_error),
"cn_install_path": MapEntry(
S.current.doctor_info_result_chinese_install_path,
S.current.doctor_info_result_chinese_install_path_error(item.value)),
"low_ram": MapEntry(S.current.doctor_info_result_low_physical_memory,
S.current.doctor_info_result_memory_requirement(item.value)),
};
bool isCheckedError = errorNames.containsKey(item.key);
@ -160,7 +219,9 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
children: [
const SizedBox(height: 4),
Text(
"修复建议: ${errorNames[item.key]?.value ?? "暂无解决方法,请截图反馈"}",
S.current.doctor_info_result_fix_suggestion(
errorNames[item.key]?.value ??
S.current.doctor_info_result_no_solution),
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.7)),
),
@ -168,16 +229,15 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
),
),
trailing: Button(
onPressed: (errorNames[item.key]?.value == null || model.isFixing)
onPressed: (errorNames[item.key]?.value == null || state.isFixing)
? null
: () async {
await model.doFix(item);
model.isFixing = false;
model.notifyListeners();
await model.doFix(context, item);
},
child: const Padding(
padding: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
child: Text("修复"),
child: Padding(
padding:
const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
child: Text(S.current.doctor_info_action_fix),
),
),
),
@ -213,10 +273,10 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
onPressed: () {
launchUrlString(item.value);
},
child: const Padding(
padding:
EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
child: Text("查看解决方案"),
child: Padding(
padding: const EdgeInsets.only(
left: 8, right: 8, top: 4, bottom: 4),
child: Text(S.current.doctor_action_view_solution),
),
)
: null,
@ -224,7 +284,22 @@ class GameDoctorUI extends BaseUI<GameDoctorUIModel> {
);
}
@override
String getUITitle(BuildContext context, GameDoctorUIModel model) =>
"一键诊断 > ${model.scInstalledPath}";
_onTapButton(
BuildContext context, String key, HomeUIModelState homeState) async {
switch (key) {
case "rsi_log":
final path = await SCLoggerHelper.getLogFilePath();
if (path == null) return;
SystemHelper.openDir(path);
return;
case "game_log":
if (homeState.scInstalledPath == "not_install" ||
homeState.scInstalledPath == null) {
showToast(context, S.current.doctor_tip_title_select_game_directory);
return;
}
SystemHelper.openDir("${homeState.scInstalledPath}\\Game.log");
return;
}
}
}

View File

@ -1,99 +1,196 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:url_launcher/url_launcher_string.dart';
class GameDoctorUIModel extends BaseUIModel {
String scInstalledPath = "";
part 'game_doctor_ui_model.g.dart';
GameDoctorUIModel(this.scInstalledPath);
part 'game_doctor_ui_model.freezed.dart';
String _lastScreenInfo = "";
String get lastScreenInfo => _lastScreenInfo;
List<MapEntry<String, String>>? checkResult;
set lastScreenInfo(String info) {
_lastScreenInfo = info;
notifyListeners();
}
bool isChecking = false;
bool isFixing = false;
String isFixingString = "";
final cnExp = RegExp(r"[^\x00-\xff]");
@freezed
class HomeGameDoctorState with _$HomeGameDoctorState {
factory HomeGameDoctorState({
@Default(false) bool isChecking,
@Default(false) bool isFixing,
@Default("") String lastScreenInfo,
@Default("") String isFixingString,
List<MapEntry<String, String>>? checkResult,
}) = _HomeGameDoctorState;
}
@riverpod
class HomeGameDoctorUIModel extends _$HomeGameDoctorUIModel {
@override
void initModel() {
doCheck()?.call();
super.initModel();
HomeGameDoctorState build() {
state = HomeGameDoctorState();
return state;
}
VoidCallback? doCheck() {
if (isChecking) return null;
return () async {
isChecking = true;
lastScreenInfo = "正在分析...";
await _statCheck();
isChecking = false;
notifyListeners();
};
Future<void> doFix(
// ignore: avoid_build_context_in_providers
BuildContext context,
MapEntry<String, String> item) async {
final checkResult =
List<MapEntry<String, String>>.from(state.checkResult ?? []);
state = state.copyWith(isFixing: true, isFixingString: "");
switch (item.key) {
case "unSupport_system":
showToast(context, S.current.doctor_action_result_try_latest_windows);
break;
case "no_live_path":
try {
await Directory(item.value).create(recursive: true);
if (!context.mounted) break;
showToast(
context, S.current.doctor_action_result_create_folder_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} catch (e) {
showToast(context,
S.current.doctor_action_result_create_folder_fail(item.value, e));
}
break;
case "nvme_PhysicalBytes":
final r = await SystemHelper.addNvmePatch();
if (r == "") {
if (!context.mounted) break;
showToast(context, S.current.doctor_action_result_fix_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} else {
if (!context.mounted) break;
showToast(context, S.current.doctor_action_result_fix_fail(r));
}
break;
case "eac_file_miss":
showToast(context,
S.current.doctor_info_result_verify_files_with_rsi_launcher);
break;
case "eac_not_install":
final eacJsonPath = "${item.value}\\Settings.json";
final eacJsonData = await File(eacJsonPath).readAsBytes();
final Map eacJson = json.decode(utf8.decode(eacJsonData));
final eacID = eacJson["productid"];
try {
var result = await Process.run(
"${item.value}\\EasyAntiCheat_EOS_Setup.exe", ["install", eacID]);
dPrint("${item.value}\\EasyAntiCheat_EOS_Setup.exe install $eacID");
if (result.stderr == "") {
if (!context.mounted) break;
showToast(
context, S.current.doctor_action_result_game_start_success);
checkResult.remove(item);
state = state.copyWith(checkResult: checkResult);
} else {
if (!context.mounted) break;
showToast(context,
S.current.doctor_action_result_fix_fail(result.stderr));
}
} catch (e) {
if (!context.mounted) break;
showToast(context, S.current.doctor_action_result_fix_fail(e));
}
break;
case "cn_user_name":
showToast(context, S.current.doctor_action_result_redirect_warning);
await Future.delayed(const Duration(milliseconds: 300));
launchUrlString(
"https://jingyan.baidu.com/article/59703552a318a08fc0074021.html");
break;
default:
showToast(context, S.current.doctor_action_result_issue_not_supported);
break;
}
state = state.copyWith(isFixing: false, isFixingString: "");
}
Future _statCheck() async {
checkResult = [];
// ignore: avoid_build_context_in_providers
doCheck(BuildContext context) async {
if (state.isChecking) return;
state = state.copyWith(
isChecking: true, lastScreenInfo: S.current.doctor_action_analyzing);
dPrint("-------- start docker check -----");
if (!context.mounted) return;
await _statCheck(context);
state = state.copyWith(isChecking: false);
}
// ignore: avoid_build_context_in_providers
_statCheck(BuildContext context) async {
final homeState = ref.read(homeUIModelProvider);
final scInstalledPath = homeState.scInstalledPath!;
final checkResult = <MapEntry<String, String>>[];
// TODO for debug
// checkResult?.add(const MapEntry("unSupport_system", "android"));
// checkResult?.add(const MapEntry("nvme_PhysicalBytes", "C"));
// checkResult?.add(const MapEntry("no_live_path", ""));
// checkResult?.add(MapEntry("unSupport_system", "android"));
// checkResult?.add(MapEntry("nvme_PhysicalBytes", "C"));
// checkResult?.add(MapEntry("no_live_path", ""));
await _checkPreInstall();
await _checkEAC();
await _checkGameRunningLog();
await _checkPreInstall(context, scInstalledPath, checkResult);
if (!context.mounted) return;
await _checkEAC(context, scInstalledPath, checkResult);
if (!context.mounted) return;
await _checkGameRunningLog(context, scInstalledPath, checkResult);
if (checkResult!.isEmpty) {
checkResult = null;
lastScreenInfo = "分析完毕,没有发现问题";
if (checkResult.isEmpty) {
final lastScreenInfo = S.current.doctor_action_result_analysis_no_issue;
state = state.copyWith(checkResult: null, lastScreenInfo: lastScreenInfo);
} else {
lastScreenInfo = "分析完毕,发现 ${checkResult!.length} 个问题";
final lastScreenInfo = S.current
.doctor_action_result_analysis_issues_found(
checkResult.length.toString());
state = state.copyWith(
checkResult: checkResult, lastScreenInfo: lastScreenInfo);
}
if (scInstalledPath == "not_install" && (checkResult?.isEmpty ?? true)) {
showToast(context!, "扫描完毕,没有发现问题,若仍然安装失败,请尝试使用工具箱中的 RSI启动器管理员模式。");
if (scInstalledPath == "not_install" && (checkResult.isEmpty)) {
if (!context.mounted) return;
showToast(context, S.current.doctor_action_result_toast_scan_no_issue);
}
}
Future _checkGameRunningLog() async {
// ignore: avoid_build_context_in_providers
Future _checkGameRunningLog(BuildContext context, String scInstalledPath,
List<MapEntry<String, String>> checkResult) async {
if (scInstalledPath == "not_install") return;
lastScreenInfo = "正在检查Game.log";
final lastScreenInfo = S.current.doctor_action_tip_checking_game_log;
state = state.copyWith(lastScreenInfo: lastScreenInfo);
final logs = await SCLoggerHelper.getGameRunningLogs(scInstalledPath);
if (logs == null) return;
final info = SCLoggerHelper.getGameRunningLogInfo(logs);
if (info != null) {
if (info.key != "_") {
checkResult?.add(MapEntry("游戏异常退出:${info.key}", info.value));
checkResult.add(MapEntry(
S.current.doctor_action_info_game_abnormal_exit(info.key),
info.value));
} else {
checkResult
?.add(MapEntry("游戏异常退出:未知异常", "info:${info.value},请点击右下角加群反馈。"));
checkResult.add(MapEntry(
S.current.doctor_action_info_game_abnormal_exit_unknown,
S.current.doctor_action_info_info_feedback(info.value)));
}
}
}
Future _checkEAC() async {
// ignore: avoid_build_context_in_providers
Future _checkEAC(BuildContext context, String scInstalledPath,
List<MapEntry<String, String>> checkResult) async {
if (scInstalledPath == "not_install") return;
lastScreenInfo = "正在检查EAC";
final lastScreenInfo = S.current.doctor_action_info_checking_eac;
state = state.copyWith(lastScreenInfo: lastScreenInfo);
final eacPath = "$scInstalledPath\\EasyAntiCheat";
final eacJsonPath = "$eacPath\\Settings.json";
if (!await Directory(eacPath).exists() ||
!await File(eacJsonPath).exists()) {
checkResult?.add(const MapEntry("eac_file_miss", ""));
checkResult.add(const MapEntry("eac_file_miss", ""));
return;
}
final eacJsonData = await File(eacJsonPath).readAsBytes();
@ -101,38 +198,46 @@ class GameDoctorUIModel extends BaseUIModel {
final eacID = eacJson["productid"];
final eacDeploymentId = eacJson["deploymentid"];
if (eacID == null || eacDeploymentId == null) {
checkResult?.add(const MapEntry("eac_file_miss", ""));
checkResult.add(const MapEntry("eac_file_miss", ""));
return;
}
final eacFilePath =
"${Platform.environment["appdata"]}\\EasyAntiCheat\\$eacID\\$eacDeploymentId\\anticheatlauncher.log";
if (!await File(eacFilePath).exists()) {
checkResult?.add(MapEntry("eac_not_install", eacPath));
checkResult.add(MapEntry("eac_not_install", eacPath));
return;
}
}
Future _checkPreInstall() async {
lastScreenInfo = "正在检查:运行环境";
final _cnExp = RegExp(r"[^\x00-\xff]");
// ignore: avoid_build_context_in_providers
Future _checkPreInstall(BuildContext context, String scInstalledPath,
List<MapEntry<String, String>> checkResult) async {
final lastScreenInfo = S.current.doctor_action_info_checking_runtime;
state = state.copyWith(lastScreenInfo: lastScreenInfo);
if (!(Platform.operatingSystemVersion.contains("Windows 10") ||
Platform.operatingSystemVersion.contains("Windows 11"))) {
checkResult
?.add(MapEntry("unSupport_system", Platform.operatingSystemVersion));
lastScreenInfo = "不支持的操作系统:${Platform.operatingSystemVersion}";
await showToast(context!, lastScreenInfo);
.add(MapEntry("unSupport_system", Platform.operatingSystemVersion));
final lastScreenInfo = S.current.doctor_action_result_info_unsupported_os(
Platform.operatingSystemVersion);
state = state.copyWith(lastScreenInfo: lastScreenInfo);
await showToast(context, lastScreenInfo);
}
if (cnExp.hasMatch(await SCLoggerHelper.getLogFilePath() ?? "")) {
checkResult?.add(const MapEntry("cn_user_name", ""));
if (_cnExp.hasMatch(await SCLoggerHelper.getLogFilePath() ?? "")) {
checkResult.add(const MapEntry("cn_user_name", ""));
}
// RAM
final ramSize = await SystemHelper.getSystemMemorySizeGB();
if (ramSize < 16) {
checkResult?.add(MapEntry("low_ram", "$ramSize"));
checkResult.add(MapEntry("low_ram", "$ramSize"));
}
lastScreenInfo = "正在检查:安装信息";
state = state.copyWith(
lastScreenInfo: S.current.doctor_action_info_checking_install_info);
//
try {
final listData = await SCLoggerHelper.getGameInstallPath(
@ -141,13 +246,13 @@ class GameDoctorUIModel extends BaseUIModel {
final checkedPath = [];
for (var installPath in listData) {
if (!checkedPath.contains(installPath)) {
if (cnExp.hasMatch(installPath)) {
checkResult?.add(MapEntry("cn_install_path", installPath));
if (_cnExp.hasMatch(installPath)) {
checkResult.add(MapEntry("cn_install_path", installPath));
}
if (scInstalledPath == "not_install") {
checkedPath.add(installPath);
if (!await Directory(installPath).exists()) {
checkResult?.add(MapEntry("no_live_path", installPath));
checkResult.add(MapEntry("no_live_path", installPath));
}
}
final tp = installPath.split(":")[0];
@ -162,12 +267,13 @@ class GameDoctorUIModel extends BaseUIModel {
var result = await Process.run('powershell', [
"(fsutil fsinfo sectorinfo $element: | Select-String 'PhysicalBytesPerSectorForPerformance').ToString().Split(':')[1].Trim()"
]);
dPrint(result.stdout);
dPrint(
"fsutil info sector info: ->>> ${result.stdout.toString().trim()}");
if (result.stderr == "") {
final rs = result.stdout.toString();
final rs = result.stdout.toString().trim();
final physicalBytesPerSectorForPerformance = (int.tryParse(rs) ?? 0);
if (physicalBytesPerSectorForPerformance > 4096) {
checkResult?.add(MapEntry("nvme_PhysicalBytes", element));
checkResult.add(MapEntry("nvme_PhysicalBytes", element));
}
}
}
@ -175,68 +281,4 @@ class GameDoctorUIModel extends BaseUIModel {
dPrint(e);
}
}
Future<void> doFix(MapEntry<String, String> item) async {
isFixing = true;
notifyListeners();
switch (item.key) {
case "unSupport_system":
showToast(context!, "若您的硬件达标,请尝试安装最新的 Windows 系统。");
return;
case "no_live_path":
try {
await Directory(item.value).create(recursive: true);
showToast(context!, "创建文件夹成功,请尝试继续下载游戏!");
checkResult?.remove(item);
notifyListeners();
} catch (e) {
showToast(context!, "创建文件夹失败,请尝试手动创建。\n目录:${item.value} \n错误:$e");
}
return;
case "nvme_PhysicalBytes":
final r = await SystemHelper.addNvmePatch();
if (r == "") {
showToast(context!,
"修复成功,请尝试重启后继续安装游戏! 若注册表修改操作导致其他软件出现兼容问题,请使用 工具 中的 NVME 注册表清理。");
checkResult?.remove(item);
notifyListeners();
} else {
showToast(context!, "修复失败,$r");
}
return;
case "eac_file_miss":
showToast(
context!, "未在 LIVE 文件夹找到 EasyAntiCheat 文件 或 文件不完整,请使用 RSI 启动器校验文件");
return;
case "eac_not_install":
final eacJsonPath = "${item.value}\\Settings.json";
final eacJsonData = await File(eacJsonPath).readAsBytes();
final Map eacJson = json.decode(utf8.decode(eacJsonData));
final eacID = eacJson["productid"];
try {
var result = await Process.run(
"${item.value}\\EasyAntiCheat_EOS_Setup.exe", ["install", eacID]);
dPrint("${item.value}\\EasyAntiCheat_EOS_Setup.exe install $eacID");
if (result.stderr == "") {
showToast(context!, "修复成功,请尝试启动游戏。(若问题无法解决,请使用工具箱的 《重装 EAC》");
checkResult?.remove(item);
notifyListeners();
} else {
showToast(context!, "修复失败,${result.stderr}");
}
} catch (e) {
showToast(context!, "修复失败,$e");
}
return;
case "cn_user_name":
showToast(context!, "即将跳转,教程来自互联网,请谨慎操作...");
await Future.delayed(const Duration(milliseconds: 300));
launchUrlString(
"https://btfy.eu.org/?q=5L+u5pS5d2luZG93c+eUqOaIt+WQjeS7juS4reaWh+WIsOiLseaWhw==");
return;
default:
showToast(context!, "该问题暂不支持自动处理,请提供截图寻求帮助");
return;
}
}
}

View File

@ -0,0 +1,253 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'game_doctor_ui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$HomeGameDoctorState {
bool get isChecking => throw _privateConstructorUsedError;
bool get isFixing => throw _privateConstructorUsedError;
String get lastScreenInfo => throw _privateConstructorUsedError;
String get isFixingString => throw _privateConstructorUsedError;
List<MapEntry<String, String>>? get checkResult =>
throw _privateConstructorUsedError;
/// Create a copy of HomeGameDoctorState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$HomeGameDoctorStateCopyWith<HomeGameDoctorState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeGameDoctorStateCopyWith<$Res> {
factory $HomeGameDoctorStateCopyWith(
HomeGameDoctorState value, $Res Function(HomeGameDoctorState) then) =
_$HomeGameDoctorStateCopyWithImpl<$Res, HomeGameDoctorState>;
@useResult
$Res call(
{bool isChecking,
bool isFixing,
String lastScreenInfo,
String isFixingString,
List<MapEntry<String, String>>? checkResult});
}
/// @nodoc
class _$HomeGameDoctorStateCopyWithImpl<$Res, $Val extends HomeGameDoctorState>
implements $HomeGameDoctorStateCopyWith<$Res> {
_$HomeGameDoctorStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of HomeGameDoctorState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? isChecking = null,
Object? isFixing = null,
Object? lastScreenInfo = null,
Object? isFixingString = null,
Object? checkResult = freezed,
}) {
return _then(_value.copyWith(
isChecking: null == isChecking
? _value.isChecking
: isChecking // ignore: cast_nullable_to_non_nullable
as bool,
isFixing: null == isFixing
? _value.isFixing
: isFixing // ignore: cast_nullable_to_non_nullable
as bool,
lastScreenInfo: null == lastScreenInfo
? _value.lastScreenInfo
: lastScreenInfo // ignore: cast_nullable_to_non_nullable
as String,
isFixingString: null == isFixingString
? _value.isFixingString
: isFixingString // ignore: cast_nullable_to_non_nullable
as String,
checkResult: freezed == checkResult
? _value.checkResult
: checkResult // ignore: cast_nullable_to_non_nullable
as List<MapEntry<String, String>>?,
) as $Val);
}
}
/// @nodoc
abstract class _$$HomeGameDoctorStateImplCopyWith<$Res>
implements $HomeGameDoctorStateCopyWith<$Res> {
factory _$$HomeGameDoctorStateImplCopyWith(_$HomeGameDoctorStateImpl value,
$Res Function(_$HomeGameDoctorStateImpl) then) =
__$$HomeGameDoctorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{bool isChecking,
bool isFixing,
String lastScreenInfo,
String isFixingString,
List<MapEntry<String, String>>? checkResult});
}
/// @nodoc
class __$$HomeGameDoctorStateImplCopyWithImpl<$Res>
extends _$HomeGameDoctorStateCopyWithImpl<$Res, _$HomeGameDoctorStateImpl>
implements _$$HomeGameDoctorStateImplCopyWith<$Res> {
__$$HomeGameDoctorStateImplCopyWithImpl(_$HomeGameDoctorStateImpl _value,
$Res Function(_$HomeGameDoctorStateImpl) _then)
: super(_value, _then);
/// Create a copy of HomeGameDoctorState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? isChecking = null,
Object? isFixing = null,
Object? lastScreenInfo = null,
Object? isFixingString = null,
Object? checkResult = freezed,
}) {
return _then(_$HomeGameDoctorStateImpl(
isChecking: null == isChecking
? _value.isChecking
: isChecking // ignore: cast_nullable_to_non_nullable
as bool,
isFixing: null == isFixing
? _value.isFixing
: isFixing // ignore: cast_nullable_to_non_nullable
as bool,
lastScreenInfo: null == lastScreenInfo
? _value.lastScreenInfo
: lastScreenInfo // ignore: cast_nullable_to_non_nullable
as String,
isFixingString: null == isFixingString
? _value.isFixingString
: isFixingString // ignore: cast_nullable_to_non_nullable
as String,
checkResult: freezed == checkResult
? _value._checkResult
: checkResult // ignore: cast_nullable_to_non_nullable
as List<MapEntry<String, String>>?,
));
}
}
/// @nodoc
class _$HomeGameDoctorStateImpl implements _HomeGameDoctorState {
_$HomeGameDoctorStateImpl(
{this.isChecking = false,
this.isFixing = false,
this.lastScreenInfo = "",
this.isFixingString = "",
final List<MapEntry<String, String>>? checkResult})
: _checkResult = checkResult;
@override
@JsonKey()
final bool isChecking;
@override
@JsonKey()
final bool isFixing;
@override
@JsonKey()
final String lastScreenInfo;
@override
@JsonKey()
final String isFixingString;
final List<MapEntry<String, String>>? _checkResult;
@override
List<MapEntry<String, String>>? get checkResult {
final value = _checkResult;
if (value == null) return null;
if (_checkResult is EqualUnmodifiableListView) return _checkResult;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override
String toString() {
return 'HomeGameDoctorState(isChecking: $isChecking, isFixing: $isFixing, lastScreenInfo: $lastScreenInfo, isFixingString: $isFixingString, checkResult: $checkResult)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$HomeGameDoctorStateImpl &&
(identical(other.isChecking, isChecking) ||
other.isChecking == isChecking) &&
(identical(other.isFixing, isFixing) ||
other.isFixing == isFixing) &&
(identical(other.lastScreenInfo, lastScreenInfo) ||
other.lastScreenInfo == lastScreenInfo) &&
(identical(other.isFixingString, isFixingString) ||
other.isFixingString == isFixingString) &&
const DeepCollectionEquality()
.equals(other._checkResult, _checkResult));
}
@override
int get hashCode => Object.hash(
runtimeType,
isChecking,
isFixing,
lastScreenInfo,
isFixingString,
const DeepCollectionEquality().hash(_checkResult));
/// Create a copy of HomeGameDoctorState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$HomeGameDoctorStateImplCopyWith<_$HomeGameDoctorStateImpl> get copyWith =>
__$$HomeGameDoctorStateImplCopyWithImpl<_$HomeGameDoctorStateImpl>(
this, _$identity);
}
abstract class _HomeGameDoctorState implements HomeGameDoctorState {
factory _HomeGameDoctorState(
{final bool isChecking,
final bool isFixing,
final String lastScreenInfo,
final String isFixingString,
final List<MapEntry<String, String>>? checkResult}) =
_$HomeGameDoctorStateImpl;
@override
bool get isChecking;
@override
bool get isFixing;
@override
String get lastScreenInfo;
@override
String get isFixingString;
@override
List<MapEntry<String, String>>? get checkResult;
/// Create a copy of HomeGameDoctorState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$HomeGameDoctorStateImplCopyWith<_$HomeGameDoctorStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'game_doctor_ui_model.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$homeGameDoctorUIModelHash() =>
r'b69a19a937ca375214a7c7e73b8288f577265625';
/// See also [HomeGameDoctorUIModel].
@ProviderFor(HomeGameDoctorUIModel)
final homeGameDoctorUIModelProvider = AutoDisposeNotifierProvider<
HomeGameDoctorUIModel, HomeGameDoctorState>.internal(
HomeGameDoctorUIModel.new,
name: r'homeGameDoctorUIModelProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$homeGameDoctorUIModelHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$HomeGameDoctorUIModel = AutoDisposeNotifier<HomeGameDoctorState>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@ -1,19 +1,30 @@
import 'package:card_swiper/card_swiper.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/widgets/cache_image.dart';
import 'package:starcitizen_doctor/widgets/countdown_time_text.dart';
import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'dialogs/home_countdown_dialog_ui.dart';
import 'dialogs/home_md_content_dialog_ui.dart';
import 'home_ui_model.dart';
import 'localization/localization_dialog_ui.dart';
import 'localization/localization_ui_model.dart';
class HomeUI extends HookConsumerWidget {
const HomeUI({super.key});
class HomeUI extends BaseUI<HomeUIModel> {
@override
Widget? buildBody(BuildContext context, HomeUIModel model) {
Widget build(BuildContext context, WidgetRef ref) {
final homeState = ref.watch(homeUIModelProvider);
final model = ref.watch(homeUIModelProvider.notifier);
ref.watch(localizationUIModelProvider);
return Stack(
children: [
Center(
@ -22,29 +33,29 @@ class HomeUI extends BaseUI<HomeUIModel> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (model.appPlacardData != null) ...[
if (homeState.appPlacardData != null) ...[
InfoBar(
title: Text("${model.appPlacardData?.title}"),
content: Text("${model.appPlacardData?.content}"),
title: Text("${homeState.appPlacardData?.title}"),
content: Text("${homeState.appPlacardData?.content}"),
severity: InfoBarSeverity.info,
action: model.appPlacardData?.link == null
action: homeState.appPlacardData?.link == null
? null
: Button(
child: const Text('查看详情'),
onPressed: () => model.showPlacard(),
child: Text(S.current.doctor_action_view_details),
onPressed: () => _showPlacard(context, homeState),
),
onClose: model.appPlacardData?.alwaysShow == true
onClose: homeState.appPlacardData?.alwaysShow == true
? null
: () => model.closePlacard(),
),
const SizedBox(height: 6),
],
...makeIndex(context, model)
...makeIndex(context, model, homeState, ref)
],
),
),
),
if (model.isFixing)
if (homeState.isFixing)
Container(
decoration: BoxDecoration(
color: Colors.black.withAlpha(150),
@ -55,9 +66,9 @@ class HomeUI extends BaseUI<HomeUIModel> {
children: [
const ProgressRing(),
const SizedBox(height: 12),
Text(model.isFixingString.isNotEmpty
? model.isFixingString
: "正在处理..."),
Text(homeState.isFixingString.isNotEmpty
? homeState.isFixingString
: S.current.doctor_info_processing),
],
),
),
@ -66,8 +77,9 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
List<Widget> makeIndex(BuildContext context, HomeUIModel model) {
const double width = 280;
List<Widget> makeIndex(BuildContext context, HomeUIModel model,
HomeUIModelState homeState, WidgetRef ref) {
double width = 280;
return [
Stack(
children: [
@ -86,7 +98,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
height: 260,
),
),
makeGameStatusCard(context, model, 340)
makeGameStatusCard(context, model, 340, homeState)
],
),
),
@ -95,12 +107,12 @@ class HomeUI extends BaseUI<HomeUIModel> {
Positioned(
top: 0,
left: 24,
child: makeLeftColumn(context, model, width),
child: makeLeftColumn(context, model, width, homeState),
),
Positioned(
right: 24,
top: 0,
child: makeNewsCard(context, model),
child: makeNewsCard(context, model, homeState),
),
],
),
@ -110,56 +122,50 @@ class HomeUI extends BaseUI<HomeUIModel> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text("安装位置:"),
Text(S.current.home_install_location),
const SizedBox(width: 6),
Expanded(
child: ComboBox<String>(
value: model.scInstalledPath,
value: homeState.scInstalledPath,
isExpanded: true,
items: [
const ComboBoxItem(
ComboBoxItem(
value: "not_install",
child: Text("未安装 或 安装失败"),
child: Text(S.current.home_not_installed_or_failed),
),
for (final path in model.scInstallPaths)
for (final path in homeState.scInstallPaths)
ComboBoxItem(
value: path,
child: Text(path),
child: Row(
children: [Text(path)],
),
)
],
onChanged: (v) {
model.scInstalledPath = v!;
model.notifyListeners();
},
onChanged: model.onChangeInstallPath,
),
),
const SizedBox(width: 12),
AnimatedSize(
duration: const Duration(milliseconds: 130),
child: model.isRsiLauncherStarting
? const ProgressRing()
: Button(
onPressed: model.appWebLocalizationVersionsData == null
? null
: () => model.launchRSI(),
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(
model.isCurGameRunning
? FluentIcons.stop_solid
: FluentIcons.play,
color: model.isCurGameRunning
? Colors.red.withOpacity(.8)
: null,
),
)),
),
const SizedBox(width: 12),
Button(
child: const Padding(
padding: EdgeInsets.all(6),
child: Icon(FluentIcons.folder_open),
),
onPressed: () => model.openDir(model.scInstalledPath)),
onPressed: homeState.webLocalizationVersionsData == null
? null
: () => model.launchRSI(context),
style: homeState.isCurGameRunning
? null
: ButtonStyle(
backgroundColor:
WidgetStateProperty.resolveWith(_getRunButtonColor),
),
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(
homeState.isCurGameRunning
? FluentIcons.stop_solid
: FluentIcons.play_solid,
color: homeState.isCurGameRunning
? Colors.red.withOpacity(.8)
: Colors.white,
),
)),
const SizedBox(width: 12),
Button(
onPressed: model.reScanPath,
@ -172,12 +178,13 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
),
const SizedBox(height: 8),
Text(model.lastScreenInfo, maxLines: 1),
makeIndexActionLists(context, model),
Text(homeState.lastScreenInfo, maxLines: 1),
makeIndexActionLists(context, model, homeState, ref),
];
}
Widget makeLeftColumn(BuildContext context, HomeUIModel model, double width) {
Widget makeLeftColumn(BuildContext context, HomeUIModel model, double width,
HomeUIModelState homeState) {
return Stack(
children: [
Column(
@ -192,21 +199,24 @@ class HomeUI extends BaseUI<HomeUIModel> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
makeWebViewButton(model,
makeWebViewButton(context, model,
icon: SvgPicture.asset(
"assets/rsi.svg",
colorFilter: makeSvgColor(Colors.white),
height: 18,
),
name: "星际公民官网汉化",
webTitle: "星际公民官网汉化",
name: S.current
.home_action_star_citizen_website_localization,
webTitle: S.current
.home_action_star_citizen_website_localization,
webURL: "https://robertsspaceindustries.com",
info: "罗伯茨航天工业公司,万物的起源",
info: S.current
.home_action_info_roberts_space_industries_origin,
useLocalization: true,
width: width,
touchKey: "webLocalization_rsi"),
const SizedBox(height: 12),
makeWebViewButton(model,
makeWebViewButton(context, model,
icon: Row(
children: [
SvgPicture.asset(
@ -216,15 +226,16 @@ class HomeUI extends BaseUI<HomeUIModel> {
const SizedBox(width: 12),
],
),
name: "UEX 汉化",
webTitle: "UEX 汉化",
name: S.current.home_action_uex_localization,
webTitle: S.current.home_action_uex_localization,
webURL: "https://uexcorp.space/",
info: "采矿、精炼、贸易计算器、价格、船信息",
info: S.current
.home_action_info_mining_refining_trade_calculator,
useLocalization: true,
width: width,
touchKey: "webLocalization_uex"),
const SizedBox(height: 12),
makeWebViewButton(model,
makeWebViewButton(context, model,
icon: Row(
children: [
Image.asset(
@ -234,15 +245,17 @@ class HomeUI extends BaseUI<HomeUIModel> {
const SizedBox(width: 12),
],
),
name: "DPS计算器汉化",
webTitle: "DPS计算器汉化",
name: S.current.home_action_dps_calculator_localization,
webTitle:
S.current.home_action_dps_calculator_localization,
webURL: "https://www.erkul.games/live/calculator",
info: "在线改船,查询伤害数值和配件购买地点",
info: S.current
.home_action_info_ship_upgrade_damage_value_query,
useLocalization: true,
width: width,
touchKey: "webLocalization_dps"),
const SizedBox(height: 12),
const Text("外部浏览器拓展:"),
Text(S.current.home_action_external_browser_extension),
const SizedBox(height: 12),
Row(
children: [
@ -288,10 +301,10 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
),
const SizedBox(height: 16),
makeActivityBanner(context, model, width),
makeActivityBanner(context, model, width, homeState),
],
),
if (model.appWebLocalizationVersionsData == null)
if (homeState.webLocalizationVersionsData == null)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
@ -305,7 +318,8 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
Widget makeNewsCard(BuildContext context, HomeUIModel model) {
Widget makeNewsCard(
BuildContext context, HomeUIModel model, HomeUIModelState homeState) {
return ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: Container(
@ -326,16 +340,17 @@ class HomeUI extends BaseUI<HomeUIModel> {
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
child: model.rssVideoItems == null
child: homeState.rssVideoItems == null
? Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(.1)),
child: makeLoading(context),
)
: Swiper(
itemCount: model.rssVideoItems?.length ?? 0,
itemCount: getMinNumber(
[homeState.rssVideoItems?.length ?? 0, 6]),
itemBuilder: (context, index) {
final item = model.rssVideoItems![index];
final item = homeState.rssVideoItems![index];
return GestureDetector(
onTap: () {
if (item.link != null) {
@ -352,14 +367,14 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
)),
const SizedBox(height: 1),
if (model.rssTextItems == null)
if (homeState.rssTextItems == null)
makeLoading(context)
else
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
final item = model.rssTextItems![index];
final item = homeState.rssTextItems![index];
return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12),
@ -378,7 +393,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
const SizedBox(width: 6),
Expanded(
child: Text(
"${model.handleTitle(item.title)}",
model.handleTitle(item.title),
textAlign: TextAlign.start,
maxLines: 1,
overflow: TextOverflow.ellipsis,
@ -396,7 +411,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
));
},
itemCount: model.rssTextItems?.length,
itemCount: homeState.rssTextItems?.length,
),
const SizedBox(height: 12),
],
@ -421,13 +436,23 @@ class HomeUI extends BaseUI<HomeUIModel> {
return const FaIcon(FontAwesomeIcons.rss, size: 14);
}
Widget makeIndexActionLists(BuildContext context, HomeUIModel model) {
Widget makeIndexActionLists(BuildContext context, HomeUIModel model,
HomeUIModelState homeState, WidgetRef ref) {
final items = [
_HomeItemData("auto_check", "一键诊断", "一键诊断星际公民常见问题",
_HomeItemData(
"game_doctor",
S.current.home_action_one_click_diagnosis,
S.current.home_action_info_one_click_diagnosis_star_citizen,
FluentIcons.auto_deploy_settings),
_HomeItemData(
"localization", "汉化管理", "快捷安装汉化资源", FluentIcons.locale_language),
_HomeItemData("performance", "性能优化", "调整引擎配置文件,优化游戏性能",
"localization",
S.current.home_action_localization_management,
S.current.home_action_info_quick_install_localization_resources,
FluentIcons.locale_language),
_HomeItemData(
"performance",
S.current.home_action_performance_optimization,
S.current.home_action_info_engine_config_optimization,
FluentIcons.process_meta_task),
];
return Padding(
@ -441,14 +466,14 @@ class HomeUI extends BaseUI<HomeUIModel> {
itemBuilder: (context, index) {
final item = items.elementAt(index);
return HoverButton(
onPressed: () => model.onMenuTap(item.key),
builder: (BuildContext context, Set<ButtonStates> states) {
onPressed: () => _onMenuTap(context, item.key, homeState, ref),
builder: (BuildContext context, Set<WidgetState> states) {
return Container(
width: 300,
height: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: states.isHovering
color: states.isHovered
? FluentTheme.of(context).cardColor.withOpacity(.1)
: FluentTheme.of(context).cardColor,
),
@ -461,10 +486,10 @@ class HomeUI extends BaseUI<HomeUIModel> {
color: Colors.white.withOpacity(.2),
borderRadius: BorderRadius.circular(1000)),
child: Padding(
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(12),
child: Icon(
item.icon,
size: 26,
size: 24,
),
),
),
@ -479,19 +504,24 @@ class HomeUI extends BaseUI<HomeUIModel> {
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 4),
Text(item.infoString),
Text(
item.infoString,
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(.6)),
),
],
)),
if (item.key == "localization" &&
model.localizationUpdateInfo != null)
homeState.localizationUpdateInfo != null)
Container(
padding: const EdgeInsets.only(
top: 3, bottom: 3, left: 8, right: 8),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(12)),
child:
Text(model.localizationUpdateInfo?.key ?? " "),
child: Text(
homeState.localizationUpdateInfo?.key ?? " "),
),
const SizedBox(width: 12),
const Icon(
@ -508,10 +538,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
@override
String getUITitle(BuildContext context, HomeUIModel model) => "HOME";
Widget makeWebViewButton(HomeUIModel model,
Widget makeWebViewButton(BuildContext context, HomeUIModel model,
{required Widget icon,
required String name,
required String webTitle,
@ -528,7 +555,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
if (touchKey != null) {
AnalyticsApi.touch(touchKey);
}
model.goWebView(webTitle, webURL, useLocalization: true);
model.goWebView(context, webTitle, webURL, useLocalization: true);
},
child: Container(
width: width,
@ -557,6 +584,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
padding: const EdgeInsets.only(top: 4),
child: Text(
info,
maxLines: 1,
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(.6)),
@ -579,15 +607,25 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
Widget makeGameStatusCard(
BuildContext context, HomeUIModel model, double width) {
Widget makeGameStatusCard(BuildContext context, HomeUIModel model,
double width, HomeUIModelState homeState) {
final statusCnName = {
"Platform": S.current.home_action_rsi_status_platform,
"Persistent Universe":
S.current.home_action_rsi_status_persistent_universe,
"Electronic Access": S.current.home_action_rsi_status_electronic_access,
"Arena Commander": S.current.home_action_rsi_status_arena_commander
};
return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .2),
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
model.goWebView(
"RSI 服务器状态", "https://status.robertsspaceindustries.com/",
context,
S.current.home_action_rsi_status_rsi_server_status,
"https://status.robertsspaceindustries.com/",
useLocalization: true);
},
child: Container(
@ -598,14 +636,14 @@ class HomeUI extends BaseUI<HomeUIModel> {
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(children: [
if (model.scServerStatus == null)
if (homeState.scServerStatus == null)
makeLoading(context, width: 20)
else
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("状态:"),
for (final item in model.scServerStatus ?? [])
Text(S.current.home_action_rsi_status_status),
for (final item in homeState.scServerStatus ?? [])
Row(
children: [
SizedBox(
@ -622,7 +660,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
const SizedBox(width: 5),
Text(
"${model.statusCnName[item["name"]] ?? item["name"]}",
"${statusCnName[item["name"]] ?? item["name"]}",
style: const TextStyle(fontSize: 13),
),
],
@ -641,20 +679,20 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
Widget makeActivityBanner(
BuildContext context, HomeUIModel model, double width) {
Widget makeActivityBanner(BuildContext context, HomeUIModel model,
double width, HomeUIModelState homeState) {
return Tilt(
borderRadius: BorderRadius.circular(12),
shadowConfig: const ShadowConfig(disable: true),
child: GestureDetector(
onTap: () => model.onTapFestival(),
onTap: () => _onTapFestival(context),
child: Container(
width: width + 24,
decoration: BoxDecoration(color: FluentTheme.of(context).cardColor),
child: Padding(
padding:
const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 8),
child: (model.countdownFestivalListData == null)
child: (homeState.countdownFestivalListData == null)
? SizedBox(
width: width,
height: 62,
@ -666,11 +704,13 @@ class HomeUI extends BaseUI<HomeUIModel> {
width: width,
height: 62,
child: Swiper(
itemCount: model.countdownFestivalListData!.length,
itemCount: getMinNumber(
[homeState.countdownFestivalListData!.length, 6]),
autoplay: true,
autoplayDelay: 5000,
itemBuilder: (context, index) {
final item = model.countdownFestivalListData![index];
final item =
homeState.countdownFestivalListData![index];
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
@ -714,6 +754,71 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
);
}
_showPlacard(BuildContext context, HomeUIModelState homeState) {
switch (homeState.appPlacardData?.linkType) {
case "external":
launchUrlString(homeState.appPlacardData?.link);
return;
case "doc":
showDialog(
context: context,
builder: (context) {
return HomeMdContentDialogUI(
title: homeState.appPlacardData?.title ??
S.current.home_announcement_details,
url: homeState.appPlacardData?.link,
);
});
return;
}
}
_onTapFestival(BuildContext context) {
showDialog(
context: context, builder: (context) => const HomeCountdownDialogUI());
}
_onMenuTap(BuildContext context, String key, HomeUIModelState homeState,
WidgetRef ref) async {
String gameInstallReqInfo =
S.current.home_action_info_valid_install_location_required;
switch (key) {
case "localization":
if (homeState.scInstalledPath == "not_install") {
ToolsUIModel.rsiEnhance(context, showNotGameInstallMsg: true);
break;
}
final model = ref.watch(homeUIModelProvider.notifier);
model.checkLocalizationUpdate();
await showDialog(
context: context,
dismissWithEsc: false,
builder: (BuildContext context) => const LocalizationDialogUI(),
);
model.checkLocalizationUpdate(skipReload: true);
break;
case "performance":
if (homeState.scInstalledPath == "not_install") {
showToast(context, gameInstallReqInfo);
break;
}
context.push("/index/$key");
break;
default:
context.push("/index/$key");
}
}
Color? _getRunButtonColor(Set<WidgetState> states) {
if (states.isPressed) {
return const Color.fromRGBO(49, 227, 88, .5);
}
if (states.isPressed) {
return const Color.fromRGBO(47, 213, 84, 1.0);
}
return const Color.fromRGBO(49, 227, 88, .8);
}
}
class _HomeItemData {

Some files were not shown because too many files have changed in this diff Show More