Compare commits

..

530 Commits

Author SHA1 Message Date
dependabot[bot]
8f85d96488
build(deps): bump ndarray from 0.17.1 to 0.17.2 in /rust (#183)
Bumps [ndarray](https://github.com/rust-ndarray/ndarray) from 0.17.1 to 0.17.2.
- [Release notes](https://github.com/rust-ndarray/ndarray/releases)
- [Changelog](https://github.com/rust-ndarray/ndarray/blob/master/RELEASES.md)
- [Commits](https://github.com/rust-ndarray/ndarray/compare/0.17.1...0.17.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:14:31 +08:00
dependabot[bot]
c8a382c08f
build(deps): bump serde_json from 1.0.148 to 1.0.149 in /rust (#182)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.148 to 1.0.149.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.148...v1.0.149)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:12:58 +08:00
dependabot[bot]
0f131203f2
build(deps): bump url from 2.5.7 to 2.5.8 in /rust (#184)
Bumps [url](https://github.com/servo/rust-url) from 2.5.7 to 2.5.8.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.5.7...v2.5.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:12:45 +08:00
dependabot[bot]
bfbad50772
build(deps): bump ort from 2.0.0-rc.10 to 2.0.0-rc.11 in /rust (#185)
Bumps [ort](https://github.com/pykeio/ort) from 2.0.0-rc.10 to 2.0.0-rc.11.
- [Release notes](https://github.com/pykeio/ort/releases)
- [Commits](https://github.com/pykeio/ort/compare/v2.0.0-rc.10...v2.0.0-rc.11)

---
updated-dependencies:
- dependency-name: ort
  dependency-version: 2.0.0-rc.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:11:39 +08:00
dependabot[bot]
dc9816eb9e
build(deps): bump ffi from 2.1.4 to 2.1.5 (#186)
Bumps [ffi](https://github.com/dart-lang/native/tree/main/pkgs) from 2.1.4 to 2.1.5.
- [Release notes](https://github.com/dart-lang/native/releases)
- [Commits](https://github.com/dart-lang/native/commits/ffi-v2.1.5/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:11:28 +08:00
dependabot[bot]
c6a0f5b8c0
build(deps): bump watcher from 1.2.0 to 1.2.1 (#187)
Bumps [watcher](https://github.com/dart-lang/tools/tree/main/pkgs) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/dart-lang/tools/releases)
- [Commits](https://github.com/dart-lang/tools/commits/watcher-v1.2.1/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 18:11:16 +08:00
xkeyC
91046e7f5e bump: librqbit
feat: add user_agent
2026-01-05 11:58:24 +08:00
dependabot[bot]
678f8d8cd7
build(deps): bump tokio from 1.48.0 to 1.49.0 in /rust (#181)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.48.0 to 1.49.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.48.0...tokio-1.49.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 11:45:34 +08:00
xkeyC
6263a0a5e6 feat: bump deps
fix: Acrylic background Color
2025-12-30 18:16:26 +08:00
dependabot[bot]
45c0476636
build(deps): bump serde_json from 1.0.146 to 1.0.148 in /rust (#179)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.146 to 1.0.148.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.146...v1.0.148)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 10:05:19 +08:00
dependabot[bot]
d86d454f52
build(deps): bump riverpod_annotation, riverpod_lint, riverpod_generator, hooks_riverpod and flutter_riverpod (#180)
Bumps [riverpod_annotation](https://github.com/rrousselGit/riverpod), [riverpod_lint](https://github.com/rrousselGit/river_pod), [riverpod_generator](https://github.com/rrousselGit/riverpod), [hooks_riverpod](https://github.com/rrousselGit/riverpod) and [flutter_riverpod](https://github.com/rrousselGit/riverpod). These dependencies needed to be updated together.

Updates `riverpod_annotation` from 3.0.3 to 4.0.0
- [Commits](https://github.com/rrousselGit/riverpod/compare/riverpod_annotation-v3.0.3...riverpod_annotation-v4.0.0)

Updates `riverpod_lint` from 3.0.3 to 3.1.0
- [Commits](https://github.com/rrousselGit/river_pod/compare/riverpod_lint-v3.0.3...riverpod_lint-v3.1.0)

Updates `riverpod_generator` from 3.0.3 to 4.0.0+1
- [Commits](https://github.com/rrousselGit/riverpod/compare/riverpod_generator-v3.0.3...riverpod_generator-v4.0.0)

Updates `hooks_riverpod` from 3.0.3 to 3.1.0
- [Commits](https://github.com/rrousselGit/riverpod/compare/hooks_riverpod-v3.0.3...hooks_riverpod-v3.1.0)

Updates `flutter_riverpod` from 3.0.3 to 3.1.0
- [Commits](https://github.com/rrousselGit/riverpod/compare/flutter_riverpod-v3.0.3...flutter_riverpod-v3.1.0)

---
updated-dependencies:
- dependency-name: riverpod_annotation
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: riverpod_lint
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: riverpod_generator
  dependency-version: 4.0.0+1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: hooks_riverpod
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: flutter_riverpod
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 10:05:05 +08:00
xkeyC
2be5441cf4 feat: translate-manager Beta 2025-12-27 11:47:25 +08:00
xkeyC
a673f70862 feat: update app_links 2025-12-26 23:03:41 +08:00
xkeyC
1d59acff2d feat: Add user profile refresh 2025-12-26 17:07:25 +08:00
xkeyC
724f7d8242 feat: oidc support 2025-12-26 16:39:12 +08:00
xkeyC
3135edad8e
Add Linux Nightly Build badge to README 2025-12-24 16:33:44 +08:00
xkeyC
bba2dbd360 feat: linux support 2025-12-23 22:40:05 +08:00
xkeyC
66ead87d47 feat: Introduce shader cache cleaning options ('Keep Latest', 'Clean All') via a new dialog and refactor cleaning logic with new localization.
close: https://github.com/StarCitizenToolBox/app/issues/173
2025-12-23 17:54:15 +08:00
xkeyC
1a1f72a596 feat: Linux Path Basic Support
modified:   lib/ui/settings/settings_ui_model.dart
2025-12-23 16:45:22 +08:00
Copilot
062014f24a
Add Linux Nightly Build workflow configuration (#178)
* Initial plan

* Add Linux Nightly Build workflow configuration

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Add explicit permissions and comments to Linux workflow

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Add NASM dependency and verify Linux build

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
2025-12-23 12:52:26 +08:00
xkeyC
4078395a89 Release: 3.0.0 Beta9 2025-12-22 21:00:55 +08:00
xkeyC
dd762d53b2 feat: WebView optimization 2025-12-22 20:55:34 +08:00
dependabot[bot]
eb42c7101d
build(deps): bump hive_ce from 2.15.1 to 2.16.0 (#176)
Bumps [hive_ce](https://github.com/IO-Design-Team/hive_ce) from 2.15.1 to 2.16.0.
- [Commits](https://github.com/IO-Design-Team/hive_ce/compare/hive_ce-2.15.1...hive_ce-2.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 11:55:25 +08:00
dependabot[bot]
9ec72c29ca
build(deps): bump file_picker from 10.3.7 to 10.3.8 (#175)
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 10.3.7 to 10.3.8.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/compare/v10.3.7...v10.3.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 11:54:52 +08:00
dependabot[bot]
bb6d63efe2
build(deps): bump reqwest from 0.12.25 to 0.12.26 in /rust (#174)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.25 to 0.12.26.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.25...v0.12.26)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 11:54:36 +08:00
xkeyC
380eb1e77f
Update README_en.md 2025-12-20 18:27:02 +08:00
xkeyC
e9021117ff
Update README_en.md 2025-12-20 18:05:13 +08:00
xkeyC
e56f7c5294
Update README_en.md 2025-12-20 18:02:49 +08:00
kerbcat-bot
32cffea018
Translations update from 42Kit Translate (#172)
* Translated using Weblate (Japanese)

Currently translated at 90.0% (861 of 956 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ja/

* Translated using Weblate (Russian)

Currently translated at 90.0% (861 of 956 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ru/

---------

Co-authored-by: Anonymous <noreply@weblate.org>
2025-12-20 13:42:19 +08:00
xkeyC
4b2ac25c1f fix: YearlyReportData error 2025-12-18 11:14:22 +08:00
xkeyC
00e8b0c303 Release: 3.0.0 Beta8 2025-12-17 22:29:17 +08:00
xkeyC
dc163d790c fix: username 2025-12-17 22:28:12 +08:00
xkeyC
750f3b1fee fix: l10n 2025-12-17 20:26:29 +08:00
xkeyC
e3bdf33eec bump: 3.0.0 Beta7 2025-12-17 20:21:01 +08:00
xkeyC
c5f54e04b5 fix: update self-kill logic in yearly report analyzer 2025-12-17 20:15:54 +08:00
xkeyC
b62c603b01 feat: l10n 2025-12-17 17:47:47 +08:00
xkeyC
0186b5f9f0 feat: YearlyReportUI 2025-12-17 17:42:33 +08:00
xkeyC
70c47a8b85 feat: YearlyReportUI Update 2025-12-17 16:49:58 +08:00
xkeyC
6ec973144e feat: init YearlyReportUI 2025-12-17 12:26:57 +08:00
xkeyC
9a28257f4a feat: init YearlyReportUI 2025-12-17 12:25:36 +08:00
dependabot[bot]
07f476e324
build(deps): bump reqwest from 0.12.24 to 0.12.25 in /rust (#167)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.24 to 0.12.25.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.24...v0.12.25)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:55:15 +08:00
dependabot[bot]
28efaf0685
build(deps): bump protobuf from 5.1.0 to 6.0.0 (#168)
Bumps [protobuf](https://github.com/google/protobuf.dart) from 5.1.0 to 6.0.0.
- [Release notes](https://github.com/google/protobuf.dart/releases)
- [Commits](https://github.com/google/protobuf.dart/compare/protobuf-v5.1.0...protobuf-v6.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:54:56 +08:00
dependabot[bot]
f69b65f233
build(deps): bump watcher from 1.1.4 to 1.2.0 (#169)
Bumps [watcher](https://github.com/dart-lang/tools/tree/main/pkgs) from 1.1.4 to 1.2.0.
- [Release notes](https://github.com/dart-lang/tools/releases)
- [Commits](https://github.com/dart-lang/tools/commits/watcher-v1.2.0/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:54:48 +08:00
dependabot[bot]
56c1ec98c5
build(deps): bump go_router from 17.0.0 to 17.0.1 (#170)
Bumps [go_router](https://github.com/flutter/packages/tree/main/packages) from 17.0.0 to 17.0.1.
- [Commits](https://github.com/flutter/packages/commits/go_router-v17.0.1/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:54:35 +08:00
xkeyC
a05737a4f4 feat: update uex url 2025-12-13 18:31:25 +08:00
xkeyC
f37208a383 fix 2025-12-13 17:20:45 +08:00
xkeyC
3f6a9f44d4 fix: shader clean 2025-12-13 17:19:05 +08:00
xkeyC
13875f850f fix: l10n 2025-12-13 17:16:19 +08:00
xkeyC
b787898e1f Release: 3.0.0 Beta6 76 2025-12-13 17:05:39 +08:00
xkeyC
50c8d294f9 feat: To avoid PTU information becoming outdated 2025-12-13 16:54:26 +08:00
xkeyC
cf3e67838d fix: values 2025-12-13 16:19:45 +08:00
xkeyC
c8962d509c fix: webview 2025-12-13 16:14:12 +08:00
xkeyC
39d571960b update: l10n 2025-12-13 15:57:32 +08:00
xkeyC
a132c85b8c fix: webview 2025-12-13 15:57:09 +08:00
kerbcat-bot
f68b7a4380
Translations update from 42Kit Translate (#166)
* Translated using Weblate (English)

Currently translated at 99.5% (865 of 869 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 90.4% (786 of 869 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/zh_Hant/

* Translated using Weblate (Japanese)

Currently translated at 89.1% (775 of 869 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ja/

* Translated using Weblate (Russian)

Currently translated at 89.1% (775 of 869 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ru/

---------

Co-authored-by: Anonymous <noreply@weblate.org>
2025-12-13 12:16:30 +08:00
xkeyC
138be64c0d feat: Add OpenXR setting, track default values, and optimize config file writing by skipping default entries. 2025-12-12 10:06:21 +08:00
xkeyC
3fd020b8b0 feat: unp4k supper search support 2025-12-11 00:54:30 +08:00
xkeyC
83c0fa6a26 feat: unp4k data forge support 2025-12-11 00:31:16 +08:00
xkeyC
0126ae811e feat: unp4k data forge support 2025-12-11 00:19:13 +08:00
xkeyC
23e909e330 feat: unp4k update 2025-12-10 21:04:47 +08:00
xkeyC
c172b623d7 fix: ToolsLogAnalyze 2025-12-10 17:21:28 +08:00
xkeyC
da0bf8f4e7 fix: win com call 2025-12-10 16:05:38 +08:00
dependabot[bot]
df025319aa
build(deps): bump wmi from 0.15.2 to 0.18.0 in /rust (#165)
Bumps [wmi](https://github.com/ohadravid/wmi-rs) from 0.15.2 to 0.18.0.
- [Release notes](https://github.com/ohadravid/wmi-rs/releases)
- [Commits](https://github.com/ohadravid/wmi-rs/compare/v0.15.2...v0.18.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 09:41:27 +08:00
xkeyC
c456a2ac47 fix: deps 2025-12-06 15:55:55 +08:00
xkeyC
a813617689 Release: 3.0.0 Beta5 2025-12-06 15:54:52 +08:00
xkeyC
9872823aff Release: 3.0.0 Beta5 2025-12-06 15:53:30 +08:00
xkeyC
8c4c11df6a feat: add NASM for ci 2025-12-06 15:38:29 +08:00
xkeyC
fddaa99779
Merge pull request #163 from StarCitizenToolBox/feat/rqbit
Feat/rqbit
2025-12-06 15:31:45 +08:00
xkeyC
fbf40580cf feat: downloader update 2025-12-06 15:31:11 +08:00
xkeyC
8ea5373dec feat: rm aria2c.zip 2025-12-05 22:11:42 +08:00
xkeyC
8898569067 feat: AdaptiveConcurrencyController 2025-12-05 22:06:55 +08:00
xkeyC
3c60b5a2c1 fix: webseed_config 2025-12-05 18:19:44 +08:00
xkeyC
c77684ddb8 frat: add webseed config
modified:   src/api/downloader_api.rs
2025-12-05 18:19:19 +08:00
xkeyC
d750b91f61 fix: net speed 2025-12-05 18:10:01 +08:00
xkeyC
3f5aaaecd9 fix: downloader display 2025-12-05 18:03:56 +08:00
xkeyC
53ffab783f fix: download status 2025-12-05 17:40:45 +08:00
xkeyC
39ddea7254 fix: async runtime error 2025-12-05 17:24:52 +08:00
xkeyC
289691896d feat: downloader update 2025-12-05 17:12:40 +08:00
xkeyC
4315e36cbe feat: use rust rqbit to replace aria2c 2025-12-05 16:32:53 +08:00
xkeyC
c5de9e2252
Merge pull request #162 from StarCitizenToolBox/feat/move_powershell_to_rust_impl
Feat/move powershell to rust impl
2025-12-05 11:34:24 +08:00
xkeyC
fe141d98c2 fix: macos build 2025-12-05 11:29:35 +08:00
xkeyC
62b8718dbd feat: Migrate more PowerShell calls to Rust implementation 2025-12-05 11:06:54 +08:00
xkeyC
f6676ed3d8 feat: Migrate PowerShell calls to Rust implementation 2025-12-05 10:52:03 +08:00
xkeyC
855ea1fe8f
Merge pull request #161 from StarCitizenToolBox/feat-wry_webview
feat: Replace desktop_webview_window with tao&wry , from tauri
2025-12-05 10:29:33 +08:00
xkeyC
dcb288597f feat: web nav update 2025-12-05 10:28:12 +08:00
xkeyC
79e1256759 feat: Optimize structure 2025-12-05 10:12:06 +08:00
xkeyC
b11603d68c feat: web nav update 2025-12-05 09:59:05 +08:00
xkeyC
6f0c760ab4 feat: Replace desktop_webview_window with tao&wry , from tauri 2025-12-05 01:29:48 +08:00
xkeyC
125fedbc84 fix: nextAwait 2025-12-04 22:18:43 +08:00
xkeyC
19488507b0 feat: GraphicsRendererDialog 2025-12-04 19:34:53 +08:00
xkeyC
bf246e469f
Merge pull request #160 from StarCitizenToolBox/feat/unp4k_rs
Feat: unp4k rs
2025-12-04 17:56:32 +08:00
xkeyC
1c4eafccca feat: unp4k UI update 2025-12-04 17:43:12 +08:00
xkeyC
aaa97429b9 feat: update file read 2025-12-04 16:27:43 +08:00
xkeyC
f3fab62291 fix: p4k close 2025-12-04 16:18:51 +08:00
xkeyC
e1ed30b6e6 feat: update unp4k 2025-12-04 16:06:49 +08:00
xkeyC
e3c3986379 feat: use unp4k_rs 2025-12-04 15:28:56 +08:00
xkeyC
a0290cf28a fix: view handle URL 2025-12-03 18:02:31 +08:00
Copilot
6c3d9d05be
feat: L10n for party room
* Initial plan

* Fix l10n_gen multi-line string bug and add localization strings for party_room and splash modules

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Fix const/import issues in l10n_replace output

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Fix comment issues found in code review

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
2025-12-02 12:23:10 +08:00
xkeyC
0f24b506fa fix: typo 2025-12-01 10:44:55 +08:00
dependabot[bot]
9704ddc211
build(deps): bump device_info_plus from 12.2.0 to 12.3.0 (#156)
Bumps [device_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus) from 12.2.0 to 12.3.0.
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/device_info_plus-v12.3.0/packages/device_info_plus)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 09:39:23 +08:00
dependabot[bot]
fc6063866c
build(deps): bump ffigen from 20.1.0 to 20.1.1 (#158)
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 20.1.0 to 20.1.1.
- [Release notes](https://github.com/dart-lang/native/releases)
- [Commits](https://github.com/dart-lang/native/commits/ffigen-v20.1.1/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 09:39:09 +08:00
Copilot
db89100402
Add XNN Pack toggle switch for ONNX inference acceleration (#155)
* Initial plan

* Add XNN Pack switch for ONNX inference acceleration

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Refactor Rust ONNX session creation to reduce code duplication

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
2025-11-28 21:23:31 +08:00
xkeyC
db024f19bd fix: avatar 2025-11-28 19:13:26 +08:00
xkeyC
5ccd2def37 feat: add Server ping 2025-11-26 17:22:27 +08:00
xkeyC
28789792ce bump: 3.0.0 Beta3 74 2025-11-26 16:25:21 +08:00
xkeyC
7d6f7879c4 feat: UI fix 2025-11-26 13:23:35 +08:00
xkeyC
9959ae8c8f feat: 诊断模式 2025-11-26 13:16:20 +08:00
xkeyC
f744acbad5 fix: UI 2025-11-25 21:25:27 +08:00
xkeyC
da7c4b958d feat: use rust impl checkHost 2025-11-25 21:19:36 +08:00
xkeyC
3c07d12ee9 fix: default avatar url 2025-11-25 19:39:50 +08:00
xkeyC
825b399ab1 feat: bump MSE 2025-11-24 15:45:09 +08:00
xkeyC
509f65b165 bump: version 2025-11-24 14:48:58 +08:00
xkeyC
f9c06c0980 fix: room logic 2025-11-24 14:48:08 +08:00
xkeyC
4718b4627b feat: update messages 2025-11-24 12:25:32 +08:00
xkeyC
078eae8e52 bump: deps 2025-11-24 09:48:29 +08:00
xkeyC
2f680b98e9
Revert "build(deps): bump fluent_ui from 4.11.3 to 4.12.0 (#134)" (#153)
This reverts commit c26d9cdc42.
2025-11-24 09:43:07 +08:00
dependabot[bot]
c26d9cdc42
build(deps): bump fluent_ui from 4.11.3 to 4.12.0 (#134)
Bumps [fluent_ui](https://github.com/bdlukaa/fluent_ui) from 4.11.3 to 4.12.0.
- [Release notes](https://github.com/bdlukaa/fluent_ui/releases)
- [Changelog](https://github.com/bdlukaa/fluent_ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bdlukaa/fluent_ui/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:35:21 +08:00
dependabot[bot]
69b87620d6
build(deps): bump json_serializable from 6.11.1 to 6.11.2 (#149)
Bumps [json_serializable](https://github.com/google/json_serializable.dart) from 6.11.1 to 6.11.2.
- [Release notes](https://github.com/google/json_serializable.dart/releases)
- [Commits](https://github.com/google/json_serializable.dart/compare/json_serializable-v6.11.1...json_serializable-v6.11.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:35:04 +08:00
dependabot[bot]
c1c8bebec7
build(deps): bump flutter_svg from 2.2.2 to 2.2.3 (#150)
Bumps [flutter_svg](https://github.com/flutter/packages/tree/main/third_party/packages) from 2.2.2 to 2.2.3.
- [Commits](https://github.com/flutter/packages/commits/flutter_svg-v2.2.3/third_party/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:35:00 +08:00
dependabot[bot]
7db8f01009
build(deps): bump file_picker from 10.3.6 to 10.3.7 (#151)
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 10.3.6 to 10.3.7.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/compare/v10.3.6...v10.3.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:34:41 +08:00
dependabot[bot]
967c46e6eb
build(deps): bump ffigen from 20.0.0 to 20.1.0 (#152)
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 20.0.0 to 20.1.0.
- [Release notes](https://github.com/dart-lang/native/releases)
- [Commits](https://github.com/dart-lang/native/commits/ffigen-v20.1.0/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:34:29 +08:00
kerbcat-bot
5d1443b472
Merge pull request #148 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2025-11-23 13:37:11 +08:00
xkeyC
a0382a1d2a fix: fps down 2025-11-23 13:06:40 +08:00
xkeyC
5c668cba2c bump: 3.0.0 Beta 72 2025-11-21 00:01:22 +08:00
xkeyC
19034a04d5
Merge pull request #147 from StarCitizenToolBox/feat/party_room
Feat/party room
2025-11-20 23:59:23 +08:00
xkeyC
3e9f82ecdf feat: PartyRoomGameLogTrackerProvider 2025-11-20 23:58:31 +08:00
xkeyC
f551ccfbde Merge remote-tracking branch 'origin/feat/party_room' into feat/party_room 2025-11-20 21:10:37 +08:00
xkeyC
1c40fac522 Merge remote-tracking branch 'refs/remotes/origin/main' into feat/party_room 2025-11-20 21:04:12 +08:00
xkeyC
a199ba745a feat: use CDN url 2025-11-20 11:32:14 +08:00
xkeyC
7a38d0d386 fix: MEMBER_STATUS_UPDATED 2025-11-20 09:54:06 +08:00
xkeyC
d1f19bae4e fix: party room provider 2025-11-20 09:28:46 +08:00
xkeyC
b65187d4f0 feat: 增加基础的游戏进程监听 2025-11-20 00:27:20 +08:00
xkeyC
f6340337db feat: 增加游客模式 2025-11-19 21:37:32 +08:00
xkeyC
6fda5628ff feat: UI update 2025-11-19 21:14:36 +08:00
xkeyC
2ffb02e62d feat: ui update 2025-11-19 18:19:55 +08:00
xkeyC
a6a5a117bc feat: update UI 2025-11-19 17:18:04 +08:00
xkeyC
0983ebe21f fix: macos Support 2025-11-19 11:53:45 +08:00
xkeyC
aaaee30368 feat: init Party Room 2025-11-18 23:10:04 +08:00
kerbcat-bot
fd2291a85d
Merge pull request #146 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2025-11-17 09:30:58 +08:00
xkeyC
f98235f2f3 feat: model l10n 2025-11-16 20:13:23 +08:00
xkeyC
77c1b4f51a feat: use Opus-MT-StarCitizen-zh-en model 2025-11-16 15:09:56 +08:00
xkeyC
af15d106f0
Merge pull request #145 from StarCitizenToolBox/feat/ort_translate
Feat/ort translate
2025-11-15 22:28:13 +08:00
xkeyC
31d867bf3b fix: windows close 2025-11-15 22:27:44 +08:00
xkeyC
3f660c7d5e feat: desktop_multi_window: ^0.3.0 2025-11-15 22:06:56 +08:00
xkeyC
d82cfb41aa fix: improve Aria2c session handling and adjust translation timer 2025-11-15 20:57:52 +08:00
xkeyC
3219129094 feat: ORT Local Translate 2025-11-15 20:49:53 +08:00
xkeyC
58da84c0a6 feat: [rust] add Opus-MT 2025-11-15 17:56:58 +08:00
dependabot[bot]
028660cbba
build(deps): bump ffigen from 19.1.0 to 20.0.0 (#140)
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 19.1.0 to 20.0.0.
- [Release notes](https://github.com/dart-lang/native/releases)
- [Commits](https://github.com/dart-lang/native/commits/ffigen-v20.0.0/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 11:12:34 +08:00
dependabot[bot]
857e471f28
build(deps): bump go_router from 16.3.0 to 17.0.0 (#141)
Bumps [go_router](https://github.com/flutter/packages/tree/main/packages) from 16.3.0 to 17.0.0.
- [Commits](https://github.com/flutter/packages/commits/go_router-v17.0.0/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 11:12:16 +08:00
dependabot[bot]
fba1e49600
build(deps): bump crypto from 3.0.6 to 3.0.7 (#142)
Bumps [crypto](https://github.com/dart-lang/core/tree/main/pkgs) from 3.0.6 to 3.0.7.
- [Release notes](https://github.com/dart-lang/core/releases)
- [Commits](https://github.com/dart-lang/core/commits/crypto-v3.0.7/pkgs)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 11:12:01 +08:00
dependabot[bot]
fc4b5c590b
build(deps): bump flutter_svg from 2.2.1 to 2.2.2 (#143)
Bumps [flutter_svg](https://github.com/flutter/packages/tree/main/third_party/packages) from 2.2.1 to 2.2.2.
- [Commits](https://github.com/flutter/packages/commits/flutter_svg-v2.2.2/third_party/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 11:11:40 +08:00
xkeyC
90fef6bcba bump: 2.15.0 70 2025-11-08 17:53:33 +08:00
xkeyC
cabe05eb03 feat: web request_interceptor 2025-11-08 17:51:36 +08:00
Copilot
e212928f57
Fix countdown festival list not sorted after date advancement (#138)
* Initial plan

* Fix: Sort countdown festivals by updated timestamps

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* fix: Api

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
Co-authored-by: xkeyC <3334969096@qq.com>
2025-11-08 15:22:19 +08:00
xkeyC
95f1cc6481
Revert "build(deps): bump desktop_multi_window from 0.2.1 to 0.3.0 (#136)" (#137)
This reverts commit 4c7f7c5b2e.
2025-11-07 09:26:33 +08:00
dependabot[bot]
4c7f7c5b2e
build(deps): bump desktop_multi_window from 0.2.1 to 0.3.0 (#136)
Bumps [desktop_multi_window](https://github.com/MixinNetwork/flutter-plugins/tree/main/packages) from 0.2.1 to 0.3.0.
- [Release notes](https://github.com/MixinNetwork/flutter-plugins/releases)
- [Commits](https://github.com/MixinNetwork/flutter-plugins/commits/HEAD/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-06 17:10:05 +08:00
xkeyC
a6942ca396 bump: 2.14.5 69 2025-10-30 20:52:12 +08:00
xkeyC
88dd4bdf8b feat: 高级汉化支持载具排序 2025-10-30 20:49:33 +08:00
xkeyC
64d5e27a72 fix: 高级汉化,性能优化 页面故障 2025-10-30 20:43:09 +08:00
xkeyC
80f87a8337 feat: bump 2.14.4 2025-10-26 18:05:02 +08:00
xkeyC
6c940ce6f3 feat: remove Google Translate functionality and related UI elements 2025-10-26 18:04:38 +08:00
xkeyC
c2a512699c feat: citizen news support 2025-10-26 17:44:55 +08:00
xkeyC
8d635827c4 feat: add FPS Support 2025-10-25 18:48:34 +08:00
xkeyC
2f2a3c3889 feat: add FPS Support 2025-10-25 18:36:09 +08:00
Copilot
df437b222d
Add settings icon button to home page for easy game path reconfiguration (#129)
* Initial plan

* Add settings icon button to home UI for reopening path guidance

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Add path rescan after returning from guide page

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* build(deps): bump windows from 0.62.1 to 0.62.2 in /rust (#130)

Bumps [windows](https://github.com/microsoft/windows-rs) from 0.62.1 to 0.62.2.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump tokio from 1.47.1 to 1.48.0 in /rust (#132)

Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.47.1 to 1.48.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.47.1...tokio-1.48.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump reqwest from 0.12.23 to 0.12.24 in /rust (#131)

Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.23 to 0.12.24.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.23...v0.12.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Initial plan

* Add settings icon button to home UI for reopening path guidance

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* Add path rescan after returning from guide page

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

* feat: game path settings icon And bump deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: xkeyC <3334969096@qq.com>
2025-10-25 18:11:12 +08:00
dependabot[bot]
4822d0c76d
build(deps): bump reqwest from 0.12.23 to 0.12.24 in /rust (#131)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.23 to 0.12.24.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.23...v0.12.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 09:29:34 +08:00
dependabot[bot]
04e06c18c9
build(deps): bump tokio from 1.47.1 to 1.48.0 in /rust (#132)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.47.1 to 1.48.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.47.1...tokio-1.48.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 09:29:07 +08:00
dependabot[bot]
e70edb7bab
build(deps): bump windows from 0.62.1 to 0.62.2 in /rust (#130)
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.62.1 to 0.62.2.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-14 09:11:18 +08:00
dependabot[bot]
d8af51db28
build(deps): bump windows from 0.62.0 to 0.62.1 in /rust (#128)
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.62.0 to 0.62.1.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-09 09:37:44 +08:00
dependabot[bot]
bafcf42dbc
build(deps): bump anyhow from 1.0.99 to 1.0.100 in /rust (#126)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.99 to 1.0.100.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.99...1.0.100)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-22 11:52:47 +08:00
dependabot[bot]
bb96740607
build(deps): bump windows from 0.61.3 to 0.62.0 in /rust (#125)
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.61.3 to 0.62.0.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits/0.62.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-13 13:49:09 +08:00
xkeyC
5412382a59 feat: bump dependencies 2025-09-05 16:03:15 +08:00
xkeyC
31626efa9f feat: _fixFestivalCountdownListDateTime 节日已过7天时,更新为下一年的时间 2025-09-05 16:02:43 +08:00
dependabot[bot]
44b4c4be82
build(deps): bump tracing-subscriber from 0.3.19 to 0.3.20 in /rust (#124)
Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.19 to 0.3.20.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.19...tracing-subscriber-0.3.20)

---
updated-dependencies:
- dependency-name: tracing-subscriber
  dependency-version: 0.3.20
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-01 11:36:43 +08:00
Copilot
5e1a9750f8
Add comprehensive GitHub Copilot instructions for StarCitizenToolBox development (#119)
* Initial plan

* Create comprehensive copilot-instructions.md for StarCitizenToolBox

Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: xkeyC <39891083+xkeyC@users.noreply.github.com>
2025-08-21 12:16:02 +08:00
dependabot[bot]
9ea6e09846
build(deps): bump anyhow from 1.0.98 to 1.0.99 in /rust (#115)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.98 to 1.0.99.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.98...1.0.99)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 09:45:21 +08:00
dependabot[bot]
830ac75f08
build(deps): bump reqwest from 0.12.22 to 0.12.23 in /rust (#116)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.22 to 0.12.23.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.22...v0.12.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 09:44:22 +08:00
kerbcat-bot
107ad46a53
Translations update from 42Kit Translate (#114)
* Translated using Weblate (English)

Currently translated at 99.6% (584 of 586 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/

* Translated using Weblate (Japanese)

Currently translated at 98.1% (575 of 586 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ja/

* Translated using Weblate (Russian)

Currently translated at 98.1% (575 of 586 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/ru/

---------

Co-authored-by: Anonymous <noreply@weblate.org>
2025-08-17 20:21:48 +08:00
xkeyC
e26ea0d7d9 fix: about_disclaimer 2025-08-17 15:36:04 +08:00
xkeyC
a6dc5a659e Release: 2.14.3 67 2025-08-15 23:27:54 +08:00
xkeyC
f9466dc3a1 Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2025-08-15 23:18:46 +08:00
xkeyC
ca2e971c6d fix: game login 2025-08-15 23:18:26 +08:00
xkeyC
99104527d4 dart: fix 2025-08-15 22:52:13 +08:00
xkeyC
44bf771f4c bump: flutter 3.35.1 2025-08-15 22:48:16 +08:00
dependabot[bot]
6119505426
build(deps): bump tokio from 1.47.0 to 1.47.1 in /rust (#112)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.47.0 to 1.47.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.47.0...tokio-1.47.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 11:45:53 +08:00
dependabot[bot]
998213bc69
build(deps): bump tokio from 1.46.1 to 1.47.0 in /rust (#111)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.46.1 to 1.47.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.46.1...tokio-1.47.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-28 11:25:42 +08:00
dependabot[bot]
8bfea81ee6
build(deps): bump tokio from 1.45.1 to 1.46.1 in /rust (#108)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.1 to 1.46.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.1...tokio-1.46.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-07 09:57:29 +08:00
dependabot[bot]
3c1e71891b
build(deps): bump flutter_rust_bridge from 2.10.0 to 2.11.1 in /rust (#109)
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.10.0 to 2.11.1.
- [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.10.0...v2.11.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-07 09:57:20 +08:00
dependabot[bot]
92d65e69da
build(deps): bump reqwest from 0.12.20 to 0.12.22 in /rust (#110)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.20 to 0.12.22.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.20...v0.12.22)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-07 09:57:10 +08:00
xkeyC
86b2411fe6 bump: frb 2025-06-20 23:29:52 +08:00
xkeyC
c39412b099
Revert "Merge pull request #106 from kerbcat-bot/weblate-sctoolbox-CoreApp" (#107)
This reverts commit 7ebfb5e39d.
2025-06-20 23:23:09 +08:00
kerbcat-bot
7ebfb5e39d
Merge pull request #106 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2025-06-20 23:22:24 +08:00
xkeyC
4e89578695 fix: VehicleSorting
close: https://github.com/StarCitizenToolBox/app/issues/100
2025-06-20 23:20:53 +08:00
xkeyC
7a921e6d38 feat: font update
close: https://github.com/StarCitizenToolBox/app/issues/105
2025-06-20 23:20:09 +08:00
xkeyC
34ea335b3f
Merge pull request #102 from StarCitizenToolBox/dependabot/cargo/rust/windows-0.61.3
build(deps): bump windows from 0.61.1 to 0.61.3 in /rust
2025-06-16 09:17:57 +08:00
xkeyC
07ca125c5b
Merge pull request #103 from StarCitizenToolBox/dependabot/cargo/rust/reqwest-0.12.20
build(deps): bump reqwest from 0.12.19 to 0.12.20 in /rust
2025-06-16 09:17:45 +08:00
dependabot[bot]
301c002c90
build(deps): bump reqwest from 0.12.19 to 0.12.20 in /rust
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.19 to 0.12.20.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.19...v0.12.20)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 00:36:39 +00:00
dependabot[bot]
ea0e046bee
build(deps): bump windows from 0.61.1 to 0.61.3 in /rust
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.61.1 to 0.61.3.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 00:36:28 +00:00
xkeyC
277c193d73
Merge pull request #101 from StarCitizenToolBox/dependabot/cargo/rust/reqwest-0.12.19
build(deps): bump reqwest from 0.12.18 to 0.12.19 in /rust
2025-06-09 09:23:31 +08:00
dependabot[bot]
0df2fe7580
build(deps): bump reqwest from 0.12.18 to 0.12.19 in /rust
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.18 to 0.12.19.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.18...v0.12.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 00:36:32 +00:00
xkeyC
f63a2f833a
Merge pull request #98 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-2.10.0
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0 in /rust
2025-06-02 12:36:55 +08:00
xkeyC
b1b6b358f5
Merge pull request #99 from StarCitizenToolBox/dependabot/cargo/rust/reqwest-0.12.18
build(deps): bump reqwest from 0.12.15 to 0.12.18 in /rust
2025-06-02 12:36:46 +08:00
dependabot[bot]
4e37b87d59
build(deps): bump reqwest from 0.12.15 to 0.12.18 in /rust
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.15 to 0.12.18.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.15...v0.12.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 00:16:18 +00:00
dependabot[bot]
2463bb1560
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0 in /rust
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.9.0 to 2.10.0.
- [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.9.0...v2.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 00:16:07 +00:00
xkeyC
f328d981c8 feat: VehicleSorting l10
fix: _short name
2025-06-01 16:55:33 +08:00
xkeyC
488ad2a485 feat: VehicleSorting 2025-06-01 16:36:10 +08:00
xkeyC
4679d559d9 fix: UI 2025-06-01 14:08:11 +08:00
xkeyC
d257663b27 fix: launchSubWindow game install path 2025-05-31 19:53:01 +08:00
xkeyC
5d735632bf bump: Flutter 3.32.1 Rust 1.87.0
fix: rsi launcher patch 2.4.0
2025-05-31 17:27:21 +08:00
xkeyC
2139bfb652 fix: intl dependency 2025-05-26 09:39:44 +08:00
xkeyC
4d4c9db816
Merge pull request #97 from StarCitizenToolBox/dependabot/cargo/rust/tokio-1.45.1
build(deps): bump tokio from 1.45.0 to 1.45.1 in /rust
2025-05-26 09:05:26 +08:00
dependabot[bot]
2d7e309395
build(deps): bump tokio from 1.45.0 to 1.45.1 in /rust
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.0 to 1.45.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.45.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 00:35:59 +00:00
xkeyC
b4dc6e34eb
fix: intl 2025-05-23 10:02:36 +08:00
xkeyC
f958edc5c7
Merge pull request #92 from StarCitizenToolBox/dependabot/cargo/rust/win32job-2.0.3
build(deps): bump win32job from 2.0.2 to 2.0.3 in /rust
2025-05-19 10:06:38 +08:00
xkeyC
2f74fef969
Merge pull request #91 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-2.10.0
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0 in /rust
2025-05-19 10:06:30 +08:00
xkeyC
b276043c31
Merge pull request #94 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.10.0
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0
2025-05-19 10:05:59 +08:00
xkeyC
9cc7a7684c
Merge pull request #93 from StarCitizenToolBox/dependabot/pub/fluent_ui-4.11.5
build(deps): bump fluent_ui from 4.11.4 to 4.11.5
2025-05-19 10:05:51 +08:00
xkeyC
3479d09ba5
Merge pull request #95 from StarCitizenToolBox/dependabot/pub/hive_ce-2.11.2
build(deps): bump hive_ce from 2.11.1 to 2.11.2
2025-05-19 10:05:44 +08:00
xkeyC
27a05414b8
Merge pull request #96 from StarCitizenToolBox/dependabot/pub/file_picker-10.1.9
build(deps): bump file_picker from 10.1.7 to 10.1.9
2025-05-19 10:05:36 +08:00
dependabot[bot]
af7074b37b
build(deps): bump file_picker from 10.1.7 to 10.1.9
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 10.1.7 to 10.1.9.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 01:02:47 +00:00
dependabot[bot]
05a1b62b8a
build(deps): bump hive_ce from 2.11.1 to 2.11.2
Bumps [hive_ce](https://github.com/IO-Design-Team/hive_ce) from 2.11.1 to 2.11.2.
- [Commits](https://github.com/IO-Design-Team/hive_ce/compare/hive_ce-2.11.1...hive_ce-2.11.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 01:02:43 +00:00
dependabot[bot]
db1b8141d3
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.9.0 to 2.10.0.
- [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.9.0...v2.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 01:02:37 +00:00
dependabot[bot]
8a7ac8eb8d
build(deps): bump fluent_ui from 4.11.4 to 4.11.5
Bumps [fluent_ui](https://github.com/bdlukaa/fluent_ui) from 4.11.4 to 4.11.5.
- [Release notes](https://github.com/bdlukaa/fluent_ui/releases)
- [Changelog](https://github.com/bdlukaa/fluent_ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bdlukaa/fluent_ui/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 01:02:30 +00:00
dependabot[bot]
80456079a3
build(deps): bump win32job from 2.0.2 to 2.0.3 in /rust
Bumps [win32job](https://github.com/ohadravid/win32job-rs) from 2.0.2 to 2.0.3.
- [Release notes](https://github.com/ohadravid/win32job-rs/releases)
- [Commits](https://github.com/ohadravid/win32job-rs/compare/v2.0.2...v2.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 00:50:59 +00:00
dependabot[bot]
86b35ebd3d
build(deps): bump flutter_rust_bridge from 2.9.0 to 2.10.0 in /rust
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.9.0 to 2.10.0.
- [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.9.0...v2.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 00:50:48 +00:00
xkeyC
c4d3d099cd
Merge pull request #89 from StarCitizenToolBox/dependabot/pub/go_router-15.1.2
build(deps): bump go_router from 15.1.1 to 15.1.2
2025-05-12 09:08:42 +08:00
xkeyC
e887986854
Merge pull request #88 from StarCitizenToolBox/dependabot/pub/fluent_ui-4.11.4
build(deps): bump fluent_ui from 4.11.3 to 4.11.4
2025-05-12 09:08:32 +08:00
xkeyC
debc31a6ed
Merge pull request #87 from StarCitizenToolBox/dependabot/pub/file_picker-10.1.7
build(deps): bump file_picker from 10.1.2 to 10.1.7
2025-05-12 09:08:20 +08:00
xkeyC
08ddaa897e
Merge pull request #86 from StarCitizenToolBox/dependabot/cargo/rust/tokio-1.45.0
build(deps): bump tokio from 1.44.2 to 1.45.0 in /rust
2025-05-12 09:08:09 +08:00
dependabot[bot]
edd49cb55f
build(deps): bump go_router from 15.1.1 to 15.1.2
Bumps [go_router](https://github.com/flutter/packages/tree/main/packages) from 15.1.1 to 15.1.2.
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/go_router-v15.1.2/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 00:54:10 +00:00
dependabot[bot]
b181d918bd
build(deps): bump fluent_ui from 4.11.3 to 4.11.4
Bumps [fluent_ui](https://github.com/bdlukaa/fluent_ui) from 4.11.3 to 4.11.4.
- [Release notes](https://github.com/bdlukaa/fluent_ui/releases)
- [Changelog](https://github.com/bdlukaa/fluent_ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bdlukaa/fluent_ui/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 00:54:03 +00:00
dependabot[bot]
df225b9850
build(deps): bump file_picker from 10.1.2 to 10.1.7
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 10.1.2 to 10.1.7.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 00:53:59 +00:00
dependabot[bot]
055421f22f
build(deps): bump tokio from 1.44.2 to 1.45.0 in /rust
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.44.2 to 1.45.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.2...tokio-1.45.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 00:24:09 +00:00
xkeyC
184290aaf4 Release: 2.14.1 65 2025-05-08 23:51:59 +08:00
xkeyC
14b16f3a78 feat: NavUI l10n 2025-05-08 23:35:21 +08:00
xkeyC
b2ec1e93a8 refactor: update Hive package to hive_ce across multiple files 2025-05-08 23:22:35 +08:00
xkeyC
cb35c400f9 feat: add listSortReverse option to ToolsLogAnalyze provider 2025-05-08 23:16:27 +08:00
xkeyC
3c061f995c feat: 42kit Nav Support network config 2025-05-08 22:44:22 +08:00
xkeyC
03c941c970 feat: 42kit Nav
feat: Animation Optimization
2025-05-04 14:07:56 +08:00
xkeyC
a2de310d84 fix: subWindow close 2025-05-04 10:46:31 +08:00
xkeyC
85bc6e487b feat: Disable game launch tools when not in zh_CN
fix: https://github.com/StarCitizenToolBox/app/issues/82
2025-05-04 10:07:07 +08:00
xkeyC
033e2824a4 feat: restore .lock 2025-05-04 09:55:28 +08:00
xkeyC
3b940ead08 fix: https://github.com/StarCitizenToolBox/app/issues/81 2025-05-04 09:45:45 +08:00
xkeyC
01f16201a9
Merge pull request #83 from everland-3769/main
更新 README_zh-TW.md 內容
2025-05-04 09:27:19 +08:00
everland.3769
251fe08139
Update README_zh-TW.md 2025-05-03 00:26:53 +08:00
everland.3769
88f9a6eccc
Update README_zh-TW.md 2025-05-01 22:06:00 +08:00
everland.3769
404b0ec958
Update README_zh-TW.md 2025-05-01 22:02:05 +08:00
xkeyC
fc59eb3879
Update README.md 2025-04-27 10:02:57 +08:00
xkeyC
fef65f6c2a
Merge pull request #80 from StarCitizenToolBox/dependabot/pub/go_router-15.0.0
build(deps): bump go_router from 14.8.1 to 15.0.0
2025-04-21 09:53:13 +08:00
dependabot[bot]
5728ed8379
build(deps): bump go_router from 14.8.1 to 15.0.0
Bumps [go_router](https://github.com/flutter/packages/tree/main/packages) from 14.8.1 to 15.0.0.
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/go_router-v15.0.0/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 00:56:53 +00:00
xkeyC
368bf04a9a
Merge pull request #79 from StarCitizenToolBox/dependabot/pub/file_picker-10.0.0
build(deps): bump file_picker from 9.2.3 to 10.0.0
2025-04-07 17:09:15 +08:00
xkeyC
48ab2e28b2
Merge pull request #78 from StarCitizenToolBox/dependabot/pub/protobuf-4.0.0
build(deps): bump protobuf from 3.1.0 to 4.0.0
2025-04-07 17:09:02 +08:00
dependabot[bot]
1343ac650f
build(deps): bump file_picker from 9.2.3 to 10.0.0
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 9.2.3 to 10.0.0.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 00:57:13 +00:00
dependabot[bot]
16dab8236b
build(deps): bump protobuf from 3.1.0 to 4.0.0
Bumps [protobuf](https://github.com/google/protobuf.dart) from 3.1.0 to 4.0.0.
- [Release notes](https://github.com/google/protobuf.dart/releases)
- [Commits](https://github.com/google/protobuf.dart/compare/protobuf-v3.1.0...protobuf-v4.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 00:57:07 +00:00
xkeyC
72f3cbd2d7 chore: update app version to 2.14.0 and version code to 64 2025-04-06 02:39:49 +08:00
xkeyC
a75a580b2d feat: enhance log analyzer to include vehicle destruction details 2025-04-06 02:37:23 +08:00
xkeyC
320ce177b9 feat: Russian language support 2025-04-06 02:12:55 +08:00
xkeyC
a6de0364c1 fix: ToolsLogAnalyze _getLogLineDateTime time 2025-04-06 02:12:55 +08:00
xkeyC
5b8314411b
Update README.md 2025-04-06 01:51:51 +08:00
xkeyC
ac72bcb554 feat: l10n update 2025-04-06 01:36:39 +08:00
xkeyC
71844945f2 feat: update log analyzer localization 2025-04-06 00:23:42 +08:00
xkeyC
fdc4060ac0 feat: log 分析器 2025-04-06 00:00:35 +08:00
xkeyC
8dd7ef53a1 fix: homeUI performance 2025-04-05 16:44:00 +08:00
xkeyC
c02c98a19e bump: hickory_resolver 0.25 2025-04-05 14:34:56 +08:00
xkeyC
4b875b7898
feat: update ci 2025-03-26 09:22:08 +08:00
xkeyC
ac959a9faa
Merge pull request #76 from StarCitizenToolBox/dependabot/cargo/rust/windows-0.61.1
build(deps): update windows requirement from 0.60.0 to 0.61.1 in /rust
2025-03-25 09:29:30 +08:00
xkeyC
26e4908101
Merge pull request #77 from StarCitizenToolBox/dependabot/cargo/rust/hickory-resolver-0.25
build(deps): update hickory-resolver requirement from 0.24 to 0.25 in /rust
2025-03-25 09:29:21 +08:00
dependabot[bot]
41b66ca33f
build(deps): update hickory-resolver requirement in /rust
Updates the requirements on [hickory-resolver](https://github.com/hickory-dns/hickory-dns) to permit the latest version.
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/OLD-CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.24.0...v0.25.1)

---
updated-dependencies:
- dependency-name: hickory-resolver
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 00:24:45 +00:00
dependabot[bot]
bea907b817
build(deps): update windows requirement from 0.60.0 to 0.61.1 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/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 00:24:34 +00:00
xkeyC
f5f3e4753c feat: desktop_multi_window Support 2025-03-16 17:14:45 +08:00
xkeyC
b18024a8ce bump: frb 2025-03-16 15:51:53 +08:00
xkeyC
b830b2b863 feat: performance r_DepthOfField support 2025-03-15 13:42:14 +08:00
xkeyC
cb77b69fa1
Merge pull request #75 from StarCitizenToolBox/dependabot/pub/re_editor-0.7.0
build(deps): bump re_editor from 0.6.0 to 0.7.0
2025-03-10 09:12:18 +08:00
dependabot[bot]
722b0693fd
build(deps): bump re_editor from 0.6.0 to 0.7.0
Bumps [re_editor](https://github.com/reqable/re-editor) from 0.6.0 to 0.7.0.
- [Changelog](https://github.com/reqable/re-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/reqable/re-editor/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 00:57:10 +00:00
xkeyC
6a90930bca
Merge pull request #74 from StarCitizenToolBox/dependabot/pub/extended_image-10.0.0
build(deps): bump extended_image from 9.1.0 to 10.0.0
2025-03-03 14:58:03 +08:00
dependabot[bot]
d747294662
build(deps): bump extended_image from 9.1.0 to 10.0.0
Bumps [extended_image](https://github.com/fluttercandies/extended_image) from 9.1.0 to 10.0.0.
- [Release notes](https://github.com/fluttercandies/extended_image/releases)
- [Changelog](https://github.com/fluttercandies/extended_image/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercandies/extended_image/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-03 00:52:22 +00:00
xkeyC
ebc469f3c1 fix: MSE version 2025-03-01 14:03:55 +08:00
xkeyC
6a8614406c Release: 2.13.5 63 2025-03-01 13:52:04 +08:00
xkeyC
dd8325e78b fix: Donation sort 2025-03-01 13:47:36 +08:00
xkeyC
721ba6a3c2 feat: Donation page 2025-03-01 13:42:30 +08:00
xkeyC
d65eb82ece feat: p4k 分流使提示使用外部浏览器打开 2025-03-01 11:39:34 +08:00
xkeyC
a902bf82a0 feat: remove JetBrains 2025-02-27 21:25:04 +08:00
xkeyC
b091022799 bump: deps 2025-02-27 21:14:56 +08:00
xkeyC
0afa8c0386 fix: web login 2025-02-27 20:59:41 +08:00
xkeyC
53e28d7272
Merge pull request #72 from StarCitizenToolBox/dependabot/cargo/rust/windows-0.60.0
build(deps): update windows requirement from 0.59.0 to 0.60.0 in /rust
2025-02-24 11:59:10 +08:00
xkeyC
d2f21661b8
Merge pull request #73 from StarCitizenToolBox/dependabot/pub/flutter_hooks-0.21.2
build(deps): bump flutter_hooks from 0.20.5 to 0.21.2
2025-02-24 11:58:55 +08:00
dependabot[bot]
580498a71a
build(deps): bump flutter_hooks from 0.20.5 to 0.21.2
Bumps [flutter_hooks](https://github.com/rrousselGit/flutter_hooks/tree/master/packages) from 0.20.5 to 0.21.2.
- [Commits](https://github.com/rrousselGit/flutter_hooks/commits/flutter_hooks-v0.21.2/packages)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 00:41:54 +00:00
dependabot[bot]
69ee1bcc9e
build(deps): update windows requirement from 0.59.0 to 0.60.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.59.0...0.60.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 00:40:58 +00:00
xkeyC
258405bcf5
Merge pull request #71 from StarCitizenToolBox/dependabot/pub/file_picker-9.0.0
build(deps): bump file_picker from 8.3.7 to 9.0.0
2025-02-17 09:20:00 +08:00
xkeyC
026933c25f
Merge pull request #70 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.8.0
build(deps): update flutter_rust_bridge requirement from =2.7.1 to =2.8.0 in /rust
2025-02-17 09:19:44 +08:00
dependabot[bot]
3b50830dab
build(deps): bump file_picker from 8.3.7 to 9.0.0
Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 8.3.7 to 9.0.0.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 00:33:28 +00:00
dependabot[bot]
73ad2ad023
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.7.1...v2.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 00:08:32 +00:00
xkeyC
96aea196a6
fix: web login 2025-02-12 09:13:56 +08:00
xkeyC
f45e9849a0
Merge pull request #67 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.7.1
build(deps): update flutter_rust_bridge requirement from =2.7.0 to =2.7.1 in /rust
2025-02-04 16:37:39 +08:00
dependabot[bot]
b881e825a9
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.7.0...v2.7.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 00:19:40 +00:00
xkeyC
ac36c0c248
Merge pull request #66 from StarCitizenToolBox/dependabot/cargo/rust/windows-0.59.0
build(deps): update windows requirement from 0.58.0 to 0.59.0 in /rust
2025-01-13 09:14:30 +08:00
dependabot[bot]
8a679a0a66
build(deps): update windows requirement from 0.58.0 to 0.59.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.58.0...0.59.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 00:27:22 +00:00
xkeyC
7be9bdf7c3 bugfix 2024-12-20 19:38:12 +08:00
xkeyC
cfa6f18a58 Release: 2.13.4 2024-12-20 19:29:16 +08:00
xkeyC
43d0d8454c feat: networkGameChannels Support 2024-12-20 19:17:30 +08:00
xkeyC
33f8866bb9
feat: Support 4.0_PREVIEW channel 2024-12-20 13:03:58 +08:00
xkeyC
a0d4d8b32d Merge branch 'main' of https://github.com/StarCitizenToolBox/app 2024-12-14 13:48:49 +08:00
xkeyC
c112a920ec bump: flutter:3.27.0 rust:1.83.0 2024-12-14 13:48:24 +08:00
xkeyC
f415ee3469
rollback: workflows 2024-12-02 09:40:06 +08:00
xkeyC
fe4f330e5e
Merge pull request #64 from StarCitizenToolBox/revert-63-feat/golang
Revert "Feat/golang"
2024-12-02 09:09:58 +08:00
xkeyC
ddcd6d8f16
Revert "Feat/golang" 2024-11-29 18:25:42 +08:00
xkeyC
16e50e6d75
feat: rust2go-cli 2024-11-29 18:13:36 +08:00
xkeyC
3ce485df5c
Merge pull request #63 from StarCitizenToolBox/feat/golang
Feat/golang
2024-11-29 18:04:02 +08:00
xkeyC
61ee05f5b2
feat: ci golang support 2024-11-29 18:03:24 +08:00
xkeyC
8249d577be feat: golang support 2024-11-29 17:23:38 +08:00
xkeyC
5ebe438584
Merge pull request #62 from StarCitizenToolBox/dependabot/pub/ffigen-16.0.0
build(deps): bump ffigen from 15.0.0 to 16.0.0
2024-11-26 09:09:45 +08:00
dependabot[bot]
2a009a1a51
build(deps): bump ffigen from 15.0.0 to 16.0.0
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 15.0.0 to 16.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-11-25 00:52:51 +00:00
xkeyC
4b70ec1914 bugfix 2024-11-23 22:45:25 +08:00
xkeyC
4c6a5f7565 fix: 翻译禁用换行符 2024-11-23 22:04:55 +08:00
xkeyC
82943020f7 Release: 2.13.2 60 2024-11-23 21:59:51 +08:00
xkeyC
4297b2f530 feat: 优化首字母大写 2024-11-23 21:59:00 +08:00
xkeyC
772f329407 feat: 弃用兔小巢 2024-11-23 21:55:23 +08:00
xkeyC
f8a846e706 feat: input_method_auto_translate 2024-11-23 21:51:36 +08:00
xkeyC
cd788b6fe5 bump: flutter_rust_bridge: 2.6.0 once_cell = "1.20" 2024-11-15 20:16:15 +08:00
xkeyC
9e4523c891
Merge pull request #61 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.6.0
build(deps): update flutter_rust_bridge requirement from =2.5.1 to =2.6.0 in /rust
2024-11-11 09:33:57 +08:00
dependabot[bot]
3dd68c7c87
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.5.1...v2.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 00:56:16 +00:00
xkeyC
a9a85607b0 Release: 2.13.1 2024-11-07 21:34:51 +08:00
xkeyC
11738da6a5 feat: l10n 2024-11-07 21:33:30 +08:00
xkeyC
9789b9e1a9 optimization 2024-11-07 20:16:08 +08:00
xkeyC
56208e1909 fix 2024-11-07 00:43:05 +08:00
xkeyC
472fdb08fb feat: web 输入支持 2024-11-07 00:34:11 +08:00
xkeyC
1681e2407b feat: 自定义文件,高级汉化 社区输入法支持 2024-11-06 20:15:49 +08:00
xkeyC
49cef9ed90 feat: 优化指引 2024-11-06 19:39:59 +08:00
xkeyC
9f7e0dad52 feat: CommunityInputMethod 2024-11-05 22:55:00 +08:00
xkeyC
281f6ee995 feat: CommunityInputMethod Install 2024-11-05 20:42:02 +08:00
xkeyC
8d07af2253 Release: 2.13.0 58 2024-11-03 18:33:47 +08:00
xkeyC
8a58719908 feat: Guide UI 2024-11-03 18:32:12 +08:00
xkeyC
0577b54f9c feat: l10n 2024-11-03 16:55:44 +08:00
xkeyC
3c59a2ca57 feat: InternalDNS switch 2024-11-03 16:42:39 +08:00
xkeyC
0c03050f5c feat: rust/rsHttp Option with_custom_dns 2024-11-03 15:57:37 +08:00
xkeyC
7e1e96707c bump: flutter_riverpod: ^2.6.1 2024-11-03 15:41:51 +08:00
xkeyC
c6ced405ef bump: Flutter 3.24.4 && Rust 1.82.0 2024-11-03 15:33:52 +08:00
xkeyC
11a54501c0
Merge pull request #59 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.5.1
build(deps): bump flutter_rust_bridge from 2.5.0 to 2.5.1
2024-10-28 09:16:15 +08:00
xkeyC
74527178b7
Merge pull request #58 from StarCitizenToolBox/dependabot/pub/ffigen-15.0.0
build(deps): bump ffigen from 14.0.1 to 15.0.0
2024-10-28 09:15:45 +08:00
xkeyC
1dec934d6a
Merge pull request #57 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.5.1
build(deps): update flutter_rust_bridge requirement from =2.5.0 to =2.5.1 in /rust
2024-10-28 09:15:31 +08:00
xkeyC
94ffcb8118
Merge pull request #60 from StarCitizenToolBox/dependabot/pub/re_editor-0.5.0
build(deps): bump re_editor from 0.4.0 to 0.5.0
2024-10-28 09:14:32 +08:00
dependabot[bot]
e9708827df
build(deps): bump re_editor from 0.4.0 to 0.5.0
Bumps [re_editor](https://github.com/reqable/re-editor) from 0.4.0 to 0.5.0.
- [Changelog](https://github.com/reqable/re-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/reqable/re-editor/commits)

---
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-10-28 00:51:02 +00:00
dependabot[bot]
75d9fc7e5e
build(deps): bump flutter_rust_bridge from 2.5.0 to 2.5.1
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.5.0 to 2.5.1.
- [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.5.0...v2.5.1)

---
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-10-28 00:50:59 +00:00
dependabot[bot]
eb1ee49085
build(deps): bump ffigen from 14.0.1 to 15.0.0
Bumps [ffigen](https://github.com/dart-lang/native/tree/main/pkgs) from 14.0.1 to 15.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-10-28 00:50:52 +00:00
dependabot[bot]
5fb0df38b0
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.5.0...v2.5.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-28 00:30:44 +00:00
xkeyC
5cb9e931c7
Merge pull request #56 from StarCitizenToolBox/dependabot/pub/extended_image-9.0.4
build(deps): bump extended_image from 8.3.1 to 9.0.4
2024-10-21 09:45:58 +08:00
dependabot[bot]
57c6dd7fd1
build(deps): bump extended_image from 8.3.1 to 9.0.4
Bumps [extended_image](https://github.com/fluttercandies/extended_image) from 8.3.1 to 9.0.4.
- [Release notes](https://github.com/fluttercandies/extended_image/releases)
- [Changelog](https://github.com/fluttercandies/extended_image/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercandies/extended_image/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 00:50:31 +00:00
xkeyC
f969a084ae
Merge pull request #55 from StarCitizenToolBox/dependabot/pub/device_info_plus-11.0.0
build(deps): bump device_info_plus from 10.1.2 to 11.0.0
2024-10-14 09:11:01 +08:00
xkeyC
15773e6639
Merge pull request #54 from StarCitizenToolBox/dependabot/pub/flutter_rust_bridge-2.5.0
build(deps): bump flutter_rust_bridge from 2.4.0 to 2.5.0
2024-10-14 09:10:42 +08:00
xkeyC
c9114bb202
Merge pull request #53 from StarCitizenToolBox/dependabot/cargo/rust/flutter_rust_bridge-eq-2.5.0
build(deps): update flutter_rust_bridge requirement from =2.4.0 to =2.5.0 in /rust
2024-10-14 09:10:22 +08:00
dependabot[bot]
9713c62c46
build(deps): bump device_info_plus from 10.1.2 to 11.0.0
Bumps [device_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus) from 10.1.2 to 11.0.0.
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/device_info_plus-v11.0.0/packages/device_info_plus)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 01:07:08 +00:00
dependabot[bot]
5822dec69e
build(deps): bump flutter_rust_bridge from 2.4.0 to 2.5.0
Bumps [flutter_rust_bridge](https://github.com/fzyzcjy/flutter_rust_bridge) from 2.4.0 to 2.5.0.
- [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.4.0...v2.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 01:07:02 +00:00
dependabot[bot]
ae920fca8f
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.4.0...v2.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 01:04:18 +00:00
xkeyC
bbca12e3a2
Merge pull request #52 from kerbcat-bot/weblate-sctoolbox-CoreApp
Translations update from 42Kit Translate
2024-10-08 14:03:13 +08:00
Anonymous
e31902d67e Translated using Weblate (English)
Currently translated at 99.7% (481 of 482 strings)

Translation: SCToolBox/CoreApp
Translate-URL: http://translate.42kit.com/projects/sctoolbox/CoreApp/en/
2024-10-08 05:16:36 +00:00
xkeyC
e37acfdaed Release: 2.12.3 2024-10-07 12:58:50 +08:00
xkeyC
f81aae82ab feat: 更新着色器清理描述 2024-10-07 12:56:50 +08:00
xkeyC
72cdf77a74 feat: 汉化缓存支持清理启动器汉化缓存 2024-10-07 12:48:31 +08:00
xkeyC
6df16058ac fix: Aria2cModel logs 2024-10-07 12:40:41 +08:00
xkeyC
abfd31e001 feat: 使用内置浏览器打开教程 2024-10-07 12:36:39 +08:00
xkeyC
53087306a8 feat: p4k 分流增加版本信息 2024-10-07 12:29:57 +08:00
xkeyC
197053380d Merge remote-tracking branch 'origin/main' 2024-10-07 11:25:14 +08:00
xkeyC
495dfd2c94 bugfix: https://github.com/StarCitizenToolBox/StarCitizenBoxBrowserEx/issues/2 2024-10-07 11:24:56 +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
314 changed files with 102902 additions and 11788 deletions

3
.fvmrc Normal file
View File

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

258
.github/copilot-instructions.md vendored Normal file
View File

@ -0,0 +1,258 @@
# StarCitizenToolBox Flutter/Rust Desktop Application
StarCitizenToolBox is a Flutter desktop application with Rust native bindings designed for Star Citizen players. It provides localization management, game diagnostics, website translations, performance optimization, and various tools for the Star Citizen gaming experience. The app supports Windows, macOS, and Linux platforms using Fluent UI design.
Always reference these instructions first and fallback to additional search or context gathering only when information in these instructions is incomplete or found to be in error.
## Working Effectively
### Initial Setup and Dependencies
Install required dependencies in this exact order:
1. **Install Rust toolchain:**
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
```
2. **Install Flutter SDK (stable channel):**
```bash
# Clone Flutter repository
cd /tmp
git clone https://github.com/flutter/flutter.git -b stable --depth 1
export PATH="/tmp/flutter/bin:$PATH"
flutter --version
```
Note: If Flutter download fails due to network issues, the build can still proceed with existing generated code.
3. **Install essential Rust tools:**
```bash
cargo install cargo-expand
cargo install 'flutter_rust_bridge_codegen@^2.0.0-dev.0'
```
### Build Process - NEVER CANCEL LONG-RUNNING COMMANDS
Execute these commands in sequence. **NEVER CANCEL** - builds can take 45+ minutes:
1. **Install Flutter dependencies:** (2-3 minutes)
```bash
flutter pub get
```
2. **Generate Dart code:** (3-5 minutes)
```bash
dart run build_runner build --delete-conflicting-outputs
```
3. **Update Rust dependencies:** (10-15 minutes first time, 2-3 minutes subsequent)
```bash
cd rust && cargo update
```
4. **Generate Rust-Dart bridge code:** (5-8 minutes)
```bash
flutter_rust_bridge_codegen generate
```
5. **Generate localization files:** (1-2 minutes)
```bash
flutter pub global activate intl_utils
flutter pub global run intl_utils:generate
```
6. **Build Rust components:** (60-90 seconds debug, 110-120 seconds release)
```bash
cd rust
cargo build --release # NEVER CANCEL: Takes ~2 minutes
```
7. **Build Flutter application:** (15-25 minutes - NEVER CANCEL)
```bash
flutter build windows -v # Set timeout to 30+ minutes minimum
```
**CRITICAL BUILD TIMING:**
- Complete full build from scratch: **45-60 minutes** - NEVER CANCEL
- Rust release build: **2 minutes** - NEVER CANCEL
- Flutter application build: **15-25 minutes** - NEVER CANCEL
- Code generation steps: **10-15 minutes total** - NEVER CANCEL
### Platform-Specific Build Requirements
**Windows (Primary Platform):**
- MSBuild tools
- Visual Studio Build Tools or Visual Studio Community
- Windows SDK
- LLVM/Clang (version 18+ recommended)
**Linux (Development/Testing):**
- Basic build tools: `build-essential`, `cmake`, `ninja-build`
- GTK development libraries
- Limited functionality (desktop app designed primarily for Windows)
**macOS:**
- Xcode Command Line Tools
- CMake
### Testing and Validation
**Rust Component Testing:**
```bash
cd rust
cargo check # Fast syntax check (1-2 minutes)
cargo test # Run Rust unit tests (5-10 minutes - NEVER CANCEL)
```
**Flutter Testing:**
```bash
flutter test # Run Flutter widget tests (2-5 minutes)
```
**Linting and Code Quality:**
```bash
flutter analyze # Dart/Flutter linting (30-60 seconds)
cd rust && cargo clippy # Rust linting (2-3 minutes)
```
### Manual Validation Requirements
After building, always perform these validation steps:
1. **Verify application starts:**
```bash
# Windows
./build/windows/x64/runner/Release/starcitizen_doctor.exe
# Linux (limited functionality)
./build/linux/x64/release/bundle/starcitizen_doctor
```
2. **Test core functionality:**
- Application launches without crashes
- Main navigation works
- Settings panel accessible
- Localization switching functional
**Note:** Full UI testing requires Windows environment. Linux builds have limited functionality.
## Project Structure and Key Files
### Entry Points and Main Code
- **Main application:** `lib/main.dart` - Flutter app entry point with multi-window support
- **App configuration:** `lib/app.dart` - Application state, routing, theming, and localization
- **Rust bridge:** `lib/common/rust/` - Generated Rust-Dart interop code
- **UI modules:** `lib/ui/` - All user interface components organized by feature
### Build Configuration
- **Flutter config:** `pubspec.yaml` - Dependencies, assets, build settings
- **Rust config:** `rust/Cargo.toml` - Native dependencies and build settings
- **Rust bridge:** `flutter_rust_bridge.yaml` - Bridge code generation settings
- **Analysis:** `analysis_options.yaml` - Dart/Flutter linting rules
### Build System Files
- **Rust builder:** `rust_builder/` - Custom Rust compilation integration with cargokit
- **Platform builds:** `windows/`, `linux/`, `macos/` - Platform-specific build configurations
- **CI/CD:** `.github/workflows/windows_nightly.yml` - Automated build pipeline
### Generated Code (DO NOT EDIT)
- `lib/generated/` - Auto-generated localization files
- `lib/**/*.g.dart` - Generated JSON serialization code
- `lib/**/*.freezed.dart` - Generated immutable data classes
- `lib/common/rust/` - Generated Rust-Dart bridge code
## Development Workflow
### Making Changes
1. **For Dart/Flutter changes:**
```bash
# After UI or logic changes
dart run build_runner build --delete-conflicting-outputs
flutter analyze
```
2. **For Rust changes:**
```bash
cd rust
cargo check # Quick validation
flutter_rust_bridge_codegen generate # Regenerate bridge if API changed
```
3. **For localization changes:**
```bash
flutter pub global run intl_utils:generate
```
### Pre-commit Validation
Always run before committing changes:
```bash
flutter analyze # Dart linting (required for CI)
cd rust && cargo clippy # Rust linting
flutter test # Widget tests
cd rust && cargo test # Rust tests
```
**CI Pipeline will fail if:**
- Flutter analyze reports errors
- Rust clippy reports errors
- Any tests fail
- Build process fails
## Common Issues and Solutions
### Flutter/Dart Issues
- **Build runner conflicts:** Delete generated files and rebuild with `--delete-conflicting-outputs`
- **Dependency conflicts:** Run `flutter pub deps` to check for version conflicts
- **Localization missing:** Ensure `flutter pub global run intl_utils:generate` completed successfully
### Rust Issues
- **Bridge generation fails:** Verify flutter_rust_bridge_codegen is installed and Rust code compiles
- **Link errors:** Ensure all required system libraries are installed for target platform
- **API changes:** Regenerate bridge code after modifying Rust API signatures
### Build Performance
- Use `cargo check` instead of `cargo build` for quick Rust validation
- Use `flutter analyze` instead of full build for quick Dart validation
- Clean build artifacts if experiencing issues: `flutter clean && cd rust && cargo clean`
## Application Architecture
**UI Framework:** Flutter with Fluent UI design system for Windows-native appearance
**State Management:** Riverpod with code generation for type-safe state management
**Routing:** GoRouter for navigation with nested routes
**Localization:** Flutter i18n with custom tooling for community translations
**Data Layer:** Hive for local storage, HTTP client for network requests
**Native Integration:** Rust via flutter_rust_bridge for system operations and performance-critical code
## Key Development Commands Reference
```bash
# Quick development validation (5-10 minutes total)
flutter analyze && cd rust && cargo check
# Full build validation (45-60 minutes - NEVER CANCEL)
flutter pub get && \
dart run build_runner build --delete-conflicting-outputs && \
cd rust && cargo update && cd .. && \
flutter_rust_bridge_codegen generate && \
flutter pub global run intl_utils:generate && \
flutter build windows -v
# Code generation only (5-10 minutes)
dart run build_runner build --delete-conflicting-outputs && \
flutter_rust_bridge_codegen generate && \
flutter pub global run intl_utils:generate
# Test execution (10-15 minutes total - NEVER CANCEL)
flutter test && cd rust && cargo test
```
**CRITICAL REMINDERS:**
- NEVER CANCEL builds or long-running commands - they can take 45+ minutes
- Always set command timeouts to 60+ minutes for build operations
- Always set command timeouts to 30+ minutes for test operations
- Validate changes with both quick checks and full builds before committing
- Use Windows environment for complete functionality testing

77
.github/workflows/linux_nightly.yml vendored Normal file
View File

@ -0,0 +1,77 @@
name: "Linux Nightly Build"
on:
schedule:
- cron: "0 0 * * *" # every day at midnight
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Linux dependencies
run: |
sudo apt-get update
# libwebkit2gtk-4.1-dev is required for wry webview (4.0 is not available in Ubuntu 24.04+)
sudo apt-get install -y \
clang cmake ninja-build pkg-config nasm \
libgtk-3-dev liblzma-dev \
libsecret-1-dev libjsoncpp-dev \
libnotify-dev libayatana-appindicator3-dev \
libwebkit2gtk-4.1-dev
- 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: 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 Linux
run: flutter build linux -v
- name: Archive build
uses: actions/upload-artifact@v4
with:
name: linux
path: build/linux/x64/release/bundle

View File

@ -14,7 +14,7 @@ jobs:
uses: microsoft/setup-msbuild@v2
- name: Set up Flutter
uses: subosito/flutter-action@v2.12.0
uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
@ -37,10 +37,11 @@ jobs:
cache-all-crates: true
- name: Set up LLVM
uses: KyleMayes/install-llvm-action@v1
uses: KyleMayes/install-llvm-action@v2
with:
version: "17.0.2"
version: "18"
- name: Set up NASM
uses: ilammy/setup-nasm@v1
- name: Flutter pub get
run: flutter pub get
- name: Flutter build runner
@ -61,11 +62,10 @@ jobs:
flutter pub global activate intl_utils
flutter pub global run intl_utils:generate
- name: Flutter build Windows
run: flutter build windows
run: flutter build windows -v
- name: Archive build
uses: actions/upload-artifact@v4
with:
name: windows
path: build/windows/x64/runner/Release

7
.gitignore vendored
View File

@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
@ -42,8 +44,9 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
/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

65
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,65 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "StarCitizenToolBox",
"request": "launch",
"type": "dart",
},
{
"name": "StarCitizenToolBox (MSE mode)",
"request": "launch",
"type": "dart",
"args": [
"--dart-define=MSE=true"
]
},
{
"name": "StarCitizenToolBox (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "StarCitizenToolBox (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "rust_builder",
"cwd": "rust_builder",
"request": "launch",
"type": "dart"
},
{
"name": "rust_builder (profile mode)",
"cwd": "rust_builder",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "rust_builder (release mode)",
"cwd": "rust_builder",
"request": "launch",
"type": "dart",
"flutterMode": "release"
},
{
"name": "sct_dev_tools",
"cwd": "packages\\sct_dev_tools",
"request": "launch",
"type": "dart"
},
{
"name": "build_tool",
"cwd": "rust_builder\\cargokit\\build_tool",
"request": "launch",
"type": "dart"
}
]
}

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"dart.flutterSdkPath": ".fvm/versions/stable",
"cmake.ignoreCMakeListsMissing": true
}

View File

@ -1,8 +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)
该工具为 星际公民玩家 提供 一键诊断,官网及工具网站汉化,游戏汉化,游戏性能优化 等功能,致力于带来更愉快的游戏体验。
[![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) [![Linux Nightly Build](https://github.com/StarCitizenToolBox/app/actions/workflows/linux_nightly.yml/badge.svg)](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml) [![Translate](http://translate.42kit.com/widget/sctoolbox/CoreApp/svg-badge.svg)](http://translate.42kit.com/engage/sctoolbox/)
[![](https://get.microsoft.com/images/zh-cn%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
@ -15,14 +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)
特别感谢 [JetBrains](https://www.jetbrains.com/?from=SCToolbox) 为开源项目提供免费的 IDE 授权
特别感谢 [Visual Studio Code](https://code.visualstudio.com/) 提供免费的开发工具

34
README_en.md Normal file
View File

@ -0,0 +1,34 @@
# 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
- Advanced localization: You can choose to translate only parts of the game content, or display it in both languages.
- Vehicle sorting: Utilizing game mechanics, vehicles are assigned numerical prefixes to help you quickly find your favorite spaceship.
- One-click diagnosis: log files from hundreds of guinea pig users, which can handle common problems of Star Citizen
- Website Localization: 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.
- unp4k_rs: Uses our own powerful engine to quickly unpack games and perform data mining.
### 📸 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
Special thanks to [Visual Studio Code](https://code.visualstudio.com/) for providing free development tools.

View File

@ -1,26 +1,31 @@
# 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) [![Translate](http://translate.42kit.com/widget/sctoolbox/CoreApp/svg-badge.svg)](http://translate.42kit.com/engage/sctoolbox/)
[![](https://get.microsoft.com/images/zh-tw%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
[![](https://get.microsoft.com/images/zh-cn%20dark.svg)](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
### ✨ 功能
- 本地化管理:一鍵安裝社群翻譯,切換語言
- 疑難排解:來自上百名小白鼠使用者的日誌文件,可處理星際公民常見問題
- 網站中文化:為星際公民官網,星際公民工具網站提供人工精翻 (感謝星際公民中文百科計畫),亦提供[瀏覽器擴充套件 (Github)](https://github.com/xkeyC/StarCitizenBoxBrowserEx )。
- 效能最佳化:為星際公民遊戲增加更細緻的效能參數控制,可用於最佳化效能,也可用於獲得更好的畫質。
- 伺服器狀態指示器:比官啟動器早了幾個小時增加了伺服器狀態指示功能,且指示的更為細緻。
- 其他常用工具:包括 p4k分流下載清除著色器快取重新安裝EAC等多種功能在內的工具箱。
- 社群在地化翻譯管理:一鍵即可快速完成社群翻譯安裝與切換遊戲語言
- 疑難排解:來自上百名小白鼠使用者的日誌文件,可處理常見的星際公民遊戲問題
- 網站中文翻譯:為星際公民官方網站及工具網站提供人工精翻 (感謝星際公民中文百科計畫),亦提供[瀏覽器擴充套件 (Github)](https://github.com/xkeyC/StarCitizenBoxBrowserEx )。
- 效能最佳化/畫面改善:為星際公民遊戲增加更細緻的效能參數調整,能夠用於改善遊戲效能,也可以用於獲得更好的畫質。
- 伺服器狀態指示器:比官啟動器早了幾個小時增加了伺服器狀態指示功能,且指示的更為細緻。
- 其他常用工具:包括 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/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 授權
特別感謝 [Visual Studio Code](https://code.visualstudio.com/) 提供的免費開發工具

View File

@ -29,6 +29,12 @@ linter:
analyzer:
plugins:
- custom_lint
exclude:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "**/generated/*.dart"
- "**/generated/**/*.dart"
errors:
invalid_annotation_target: ignore
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
assets/ic_hk_fps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 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

@ -0,0 +1,53 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no"/>
<meta name="renderer" content="webkit"/>
<link rel="stylesheet" href="style/mdui2.css">
<link href="style/google_icons.css" rel="stylesheet">
<script src="js/mdui2.global.js"></script>
<script src="js/main.js"></script>
<title>SCToolBox Community Input Method Web</title>
<style>
</style>
</head>
<body>
<div class="mdui-theme-light" style="position: relative;overflow: hidden">
<mdui-top-app-bar
scroll-behavior="shrink"
scroll-threshold="30"
scroll-target=".scroll-behavior-shrink">
<mdui-top-app-bar-title>SC汉化盒子社区输入法</mdui-top-app-bar-title>
<div style="flex-grow: 1"></div>
<mdui-button-icon icon="help" onclick="onShowHelp()"></mdui-button-icon>
</mdui-top-app-bar>
<div class="scroll-behavior-shrink" style="overflow: auto;">
<mdui-text-field id="input_message" style="padding-top: 6pt;padding-bottom: 6pt" rows="6" variant="outlined"
label="输入消息..."></mdui-text-field>
<div style="text-align: end">
<mdui-checkbox id="auto_copy" checked>自动复制</mdui-checkbox>
</div>
<mdui-button id="send_button" icon="send" onclick="onSendMessage()" full-width>发送</mdui-button>
</div>
<mdui-snackbar id="snackbar_message" auto-close-delay="1000">Text</mdui-snackbar>
</div>
<script>
init();
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
async function init() {
try {
let response = await fetch("/api");
let responseJson = await response.json();
if (responseJson.status === "ok") {
showMessage("服务连接成功!");
} else {
showMessage("服务连接失败!" + responseJson);
}
} catch (e) {
showMessage("服务连接失败!" + e);
}
}
async function onSendMessage() {
let send_button = document.getElementById("send_button");
let input = document.getElementById("input_message");
let isAutoCopy = document.getElementById("auto_copy").checked;
let messageJson = {
"text": input.value,
"autoCopy": isAutoCopy,
"autoInput": false
};
send_button.loading = true;
try {
let response = await fetch("/api/send", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(messageJson)
});
let responseJson = await response.json();
console.log(responseJson);
showMessage(responseJson.message);
if (response.ok) {
input.value = "";
}
} catch (e) {
showMessage("发送失败!" + e);
}
send_button.loading = false;
}
function showMessage(message) {
let snack = document.getElementById("snackbar_message");
snack.open = false;
snack.innerText = message;
snack.open = true;
}
function onShowHelp() {
alert("在浏览器中输入文本,将发送给汉化盒子转码。" +
"\n\n自动复制勾选后自动复制转码结果到剪贴板。");
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
/* fallback */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 1.5rem; /* 24px */
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}

File diff suppressed because one or more lines are too long

View File

@ -197,8 +197,6 @@ function GetSCLocalizationTranslateString(txtSrc) {
return txtSrc
}
InitWebLocalization();
function ReportUnTranslate(k, v) {
if (enable_webview_localization_capture) {
@ -209,7 +207,7 @@ function ReportUnTranslate(k, v) {
const jsRegex = /(?:^|[^<])<script[^>]*>[\s\S]*?<\/script>(?:[^>]|$)/i;
if (k.trim() !== "" && !cnPattern.test(k) && !htmlPattern.test(k) && !cssRegex.test(k) && !jsRegex.test(k)
&& enPattern.test(k) && !k.startsWith("http://") && !k.startsWith("https://")) {
window.chrome.webview.postMessage({action: 'webview_localization_capture', key: k, value: v});
window.ipc.postMessage(JSON.stringify({ action: 'webview_localization_capture', key: k, value: v }));
}
}
}
@ -219,57 +217,90 @@ InitWebLocalization();
/// ----- Login Script ----
async function getRSILauncherToken(channelId) {
if (!window.location.href.includes("robertsspaceindustries.com")) return;
console.log('[SCToolbox] getRSILauncherToken called with channel:', channelId);
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);
});
});
try {
if (!window.location.href.includes("robertsspaceindustries.com")) {
console.log('[SCToolbox] Not on RSI site, skipping');
return;
}
// check login
let r = await fetch("api/launcher/v3/account/check", {
// check if logged in and fix redirect
if (window.location.href.endsWith('/connect?jumpto=/account/dashboard')) {
if (document.body.textContent.trim() === "/account/dashboard") {
window.location.href = "https://robertsspaceindustries.com/account/dashboard";
return;
}
}
// Wait for jQuery to be ready
let waitCount = 0;
while (typeof $ === 'undefined' && waitCount < 50) {
console.log('[SCToolbox] Waiting for jQuery... attempt', waitCount);
await new Promise(r => setTimeout(r, 100));
waitCount++;
}
if (typeof $ === 'undefined') {
console.error('[SCToolbox] jQuery not available after waiting');
return;
}
// Get RSI token from cookie (don't rely on $.cookie plugin)
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
return null;
}
const rsiToken = getCookie('Rsi-Token');
console.log('[SCToolbox] RSI Token available:', !!rsiToken);
if (!rsiToken) {
console.log('[SCToolbox] No RSI token, showing login window');
let loginBodyElement = $(".c-form authenticationForm sign_in");
loginBodyElement.show();
window.ipc.postMessage(JSON.stringify({ action: 'webview_rsi_login_show_window' }));
return;
}
// get claims
console.log('[SCToolbox] Fetching claims...');
let claimsR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/claims", {
method: 'POST', headers: {
'x-rsi-token': $.cookie('Rsi-Token'),
'x-rsi-token': rsiToken,
},
});
if (r.status !== 200) {
// wait login
window.chrome.webview.postMessage({action: 'webview_rsi_login_show_window'});
console.log('[SCToolbox] Claims response status:', claimsR.status);
if (claimsR.status !== 200) {
console.error('[SCToolbox] Claims request failed');
return;
}
SCTShowToast("登录游戏中...");
// get claims
let claimsR = await fetch("api/launcher/v3/games/claims", {
method: 'POST', headers: {
'x-rsi-token': $.cookie('Rsi-Token'),
},
});
if (claimsR.status !== 200) return;
let claimsData = (await claimsR.json())["data"];
console.log('[SCToolbox] Claims data received');
let tokenFormData = new FormData();
tokenFormData.append('claims', claimsData);
tokenFormData.append('gameId', 'SC');
let tokenR = await fetch("api/launcher/v3/games/token", {
let tokenR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/token", {
method: 'POST', headers: {
'x-rsi-token': $.cookie('Rsi-Token'),
'x-rsi-token': rsiToken,
},
body: tokenFormData
});
if (tokenR.status !== 200) return;
console.log('[SCToolbox] Token response status:', tokenR.status);
if (tokenR.status !== 200) {
console.error('[SCToolbox] Token request failed');
return;
}
let TokenData = (await tokenR.json())["data"]["token"];
console.log(TokenData);
console.log('[SCToolbox] Token received');
// get release Data
let releaseFormData = new FormData();
@ -277,54 +308,58 @@ async function getRSILauncherToken(channelId) {
releaseFormData.append("claims", claimsData);
releaseFormData.append("gameId", "SC");
releaseFormData.append("platformId", "prod");
let releaseR = await fetch("api/launcher/v3/games/release", {
let releaseR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/release", {
method: 'POST', headers: {
'x-rsi-token': $.cookie('Rsi-Token'),
'x-rsi-token': rsiToken,
},
body: releaseFormData
});
if (releaseR.status !== 200) return;
console.log('[SCToolbox] Release response status:', releaseR.status);
if (releaseR.status !== 200) {
console.error('[SCToolbox] Release request failed');
return;
}
let releaseDataJson = (await releaseR.json())['data'];
console.log(releaseDataJson);
console.log('[SCToolbox] Release data received');
// get game library
let libraryR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/library", {
method: 'POST', headers: {
'x-rsi-token': rsiToken,
},
body: releaseFormData
});
let libraryData = (await libraryR.json())["data"];
console.log('[SCToolbox] Library data received');
// get user avatar
let $avatarElement = $(".c-account-sidebar__profile-metas-avatar");
let avatarUrl = $avatarElement.css("background-image");
let avatarUrl = $(".orion-c-avatar__image").attr("src") || '';
console.log('[SCToolbox] Avatar URL:', avatarUrl);
//post message
window.chrome.webview.postMessage({
console.log('[SCToolbox] Sending login success message...');
window.ipc.postMessage(JSON.stringify({
action: 'webview_rsi_login_success', data: {
'webToken': $.cookie('Rsi-Token'),
'webToken': rsiToken,
'claims': claimsData,
'authToken': TokenData,
'releaseInfo': releaseDataJson,
"avatar": avatarUrl,
"inputEmail": sessionStorage.getItem("inputEmail"),
"inputPassword": sessionStorage.getItem("inputPassword")
'libraryData': libraryData,
}
});
}));
console.log('[SCToolbox] Login success message sent');
} catch (error) {
console.error('[SCToolbox] Error in getRSILauncherToken:', error);
}
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();
}
});
}
function SCTShowToast(message) {
let m = document.createElement('div');
m.innerHTML = message;
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 9.375rem;padding:0 0.875rem;height: 2.5rem;color: rgb(255, 255, 255);line-height: 2.5rem;text-align: center;border-radius: 0.25rem;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 1rem;";
document.body.appendChild(m);
setTimeout(function () {
let d = 0.5;
@ -334,5 +369,4 @@ function SCTShowToast(message) {
document.body.removeChild(m)
}, d * 1000);
}, 3500);
}

3
devtools_options.yaml Normal file
View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

123
docs/AUTH_QUICK_START.md Normal file
View File

@ -0,0 +1,123 @@
# SCToolBox OAuth 认证系统
## 快速开始
### 授权流程
```
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌──────────┐
│ Web App │──1──▶│ Browser │──2──▶│ SCToolBox │──3──▶│ Server │
└─────────┘ └──────────┘ └────────────┘ └──────────┘
▲ │ │
│ ├──4──▶ 验证域名 │
│ │ 安全性 │
│ │ │
│ ├──5──▶ 生成 JWT │
│ │ 令牌 │
│ │ │
└─────────────────6─────────────────┘ │
返回令牌 │
```
### URL Scheme 格式
```
sctoolbox://auth/{domain}?callbackUrl={回调地址}
```
### 示例
```
sctoolbox://auth/example.com?callbackUrl=https%3A%2F%2Fexample.com%2Fauth%2Fcallback
```
### 回调格式
```
{callbackUrl}#access_token={jwt_token}&token_type=Bearer
```
## 功能特性
- ✅ 基于 JWT 的安全认证
- ✅ 域名白名单验证
- ✅ 跨平台支持Windows、macOS、Linux
- ✅ 两种授权方式(直接跳转 / 复制链接)
- ✅ 符合 OAuth 2.0 Implicit Flow 标准
## 实现文件
### 核心文件
- `lib/ui/auth/auth_page.dart` - 授权页面 UI
- `lib/ui/auth/auth_ui_model.dart` - 授权页面状态管理
- `lib/common/utils/url_scheme_handler.dart` - URL Scheme 处理器
### 平台配置
- `macos/Runner/Info.plist` - macOS URL Scheme 配置
- `windows/runner/main.cpp` - Windows Deep Link 处理
- `linux/my_application.cc` - Linux Deep Link 处理
- `linux/sctoolbox.desktop` - Linux MIME 类型注册
- `pubspec.yaml` - MSIX 协议激活配置
## 使用方法
### 初始化
URL Scheme handler 在 `IndexUI` 中自动初始化:
```dart
useEffect(() {
UrlSchemeHandler().initialize(context);
return () => UrlSchemeHandler().dispose();
}, const []);
```
### Web 应用集成
```javascript
// 发起授权
const authUrl = `sctoolbox://auth/example.com?callbackUrl=${encodeURIComponent(callbackUrl)}`;
window.location.href = authUrl;
// 处理回调
const params = new URLSearchParams(window.location.hash.substring(1));
const token = params.get('access_token');
```
## 平台要求
- **Windows**: 需要使用 MSIX 打包版本
- **macOS**: 需要配置 Info.plist
- **Linux**: 需要注册 .desktop 文件
## 安全性
- ✅ JWT 签名验证
- ✅ 域名白名单检查
- ✅ 令牌过期时间控制
- ✅ 使用 Fragment (#) 传递令牌(更安全)
## 详细文档
查看 [完整文档](./AUTH_SYSTEM.md) 了解更多信息,包括:
- 详细的授权流程
- API 接口说明
- Web 应用集成示例
- 安全最佳实践
- 常见问题解答
## API 端点
认证服务提供以下 gRPC 接口:
- `GenerateToken` - 生成 JWT 令牌
- `ValidateToken` - 验证令牌有效性
- `GetPublicKey` - 获取公钥用于验证
- `GetJWTDomainList` - 获取可信域名列表
## 测试
```bash
# macOS/Linux
open "sctoolbox://auth/test.example.com?callbackUrl=https%3A%2F%2Ftest.example.com%2Fcallback"
# Windows
start "sctoolbox://auth/test.example.com?callbackUrl=https%3A%2F%2Ftest.example.com%2Fcallback"
```

View File

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

View File

@ -6,8 +6,11 @@ import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class AnalyticsApi {
static touch(String key) async {
if (kDebugMode || kProfileMode) return;
static Future<void> touch(String key) async {
if (kDebugMode || kProfileMode) {
dPrint("AnalyticsApi.touch === $key skip");
return;
}
dPrint("AnalyticsApi.touch === $key start");
try {
final r = await RSHttp.postData(

View File

@ -1,26 +1,25 @@
import 'dart:convert';
import 'package:hive_ce/hive.dart';
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/input_method_api_data.dart';
import 'package:starcitizen_doctor/data/sc_localization_data.dart';
class Api {
static Future<AppVersionData> getAppVersion() async {
return AppVersionData.fromJson(
await getRepoJson("sc_doctor", "version.json"));
return AppVersionData.fromJson(await getRepoJson("sc_doctor", "version.json"));
}
static Future<AppPlacardData> getAppPlacard() async {
return AppPlacardData.fromJson(
await getRepoJson("sc_doctor", "placard.json"));
return AppPlacardData.fromJson(await getRepoJson("sc_doctor", "placard.json"));
}
static Future<List<CountdownFestivalItemData>>
getFestivalCountdownList() async {
static Future<List<CountdownFestivalItemData>> getFestivalCountdownList() async {
List<CountdownFestivalItemData> l = [];
final r = json.decode(await getRepoData("sc_doctor", "countdown.json"));
if (r is List) {
@ -28,19 +27,15 @@ class Api {
l.add(CountdownFestivalItemData.fromJson(element));
}
}
l.sort((a, b) => (a.time ?? 0) - (b.time ?? 0));
return l;
}
static Future<Map<String, dynamic>> getAppReleaseDataByVersionName(
String version) async {
final r = await RSHttp.getText(
"${URLConf.gitlabApiPath}repos/SCToolBox/Release/releases/tags/$version");
static Future<Map<String, dynamic>> getAppReleaseDataByVersionName(String version) async {
final r = await RSHttp.getText("${URLConf.gitlabApiPath}repos/SCToolBox/Release/releases/tags/$version");
return json.decode(r);
}
static Future<List<ScLocalizationData>> getScLocalizationData(
String lang) async {
static Future<List<ScLocalizationData>> getScLocalizationData(String lang) async {
final data = json.decode(await getRepoData("localizations", "$lang.json"));
List<ScLocalizationData> l = [];
if (data is List) {
@ -51,6 +46,15 @@ class Api {
return l;
}
static Future<InputMethodApiData> getCommunityInputMethodIndexData() async {
final data = await getCommunityInputMethodData("index.json");
return InputMethodApiData.fromJson(json.decode(data));
}
static Future<String> getCommunityInputMethodData(String file) async {
return getRepoData("input_method", file);
}
static Future<List<AppTorrentData>> getAppTorrentDataList() async {
final data = await getRepoData("sc_doctor", "torrent.json");
final dataJson = json.decode(data);
@ -69,20 +73,24 @@ class Api {
}
static Future<List> getScServerStatus() async {
final r = await RSHttp.getText(
"https://status.robertsspaceindustries.com/index.json");
final r = await RSHttp.getText("https://status.robertsspaceindustries.com/index.json");
final map = json.decode(r);
return map["systems"];
}
static Future<Map<String, dynamic>> getRepoJson(
String dir, String name) async {
static Future<Map<String, dynamic>> getRepoJson(String dir, String name) async {
final data = await getRepoData(dir, name);
return json.decode(data);
}
static Future<String> getRepoData(String dir, String name) async {
final r = await RSHttp.getText("${URLConf.apiRepoPath}/$dir/$name");
final r = await RSHttp.getText("${URLConf.apiRepoPath}/$dir/$name", withCustomDns: await isUseInternalDNS());
return r;
}
static Future<bool> isUseInternalDNS() async {
final userBox = await Hive.openBox("app_conf");
final isUseInternalDNS = userBox.get("isUseInternalDNS", defaultValue: false);
return isUseInternalDNS;
}
}

23
lib/api/news_api.dart Normal file
View File

@ -0,0 +1,23 @@
import 'dart:convert';
import '../common/conf/url_conf.dart';
import '../common/io/rs_http.dart';
import '../common/utils/log.dart';
import '../data/citizen_news_data.dart';
import 'api.dart';
class NewsApi {
static Future<CitizenNewsData?> getLatest() async {
try {
final data = await RSHttp.getText(
"${URLConf.newsApiHome}/api/latest",
withCustomDns: await Api.isUseInternalDNS(),
);
final map = json.decode(data);
return CitizenNewsData.fromJson(map);
} catch (e) {
dPrint("getLatestNews error: $e");
}
return null;
}
}

View File

@ -1,27 +0,0 @@
import 'dart:io';
import 'package:dart_rss/dart_rss.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
class RSSApi {
static Future<List<RssItem>> getRssVideo() async {
final r = await RSHttp.getText(URLConf.rssVideoUrl);
final f = RssFeed.parse(r);
return f.items.sublist(0, 8);
}
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);
items.sort((a, b) {
final aDate = HttpDate.parse(a.pubDate ?? "").millisecondsSinceEpoch;
final bDate = HttpDate.parse(b.pubDate ?? "").millisecondsSinceEpoch;
return bDate - aDate;
});
return items;
}
}

14
lib/api/udb.dart Normal file
View File

@ -0,0 +1,14 @@
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/nav_api_data.dart';
class UDBNavApi {
static Future<NavApiData> getNavItems({int pageNo = 1}) async {
final r = await RSHttp.getText(URLConf.nav42KitUrl);
if (r.isEmpty) throw "Network Error";
final result = NavApiData.fromJson(jsonDecode(r));
return result;
}
}

View File

@ -2,15 +2,17 @@ import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.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:hive_ce/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/conf/conf.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/ui/guide/guide_ui.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';
@ -20,22 +22,27 @@ import 'package:window_manager/window_manager.dart';
import 'api/analytics.dart';
import 'api/api.dart';
import 'common/helper/system_helper.dart';
import 'common/conf/url_conf.dart';
import 'common/io/rs_http.dart';
import 'common/rust/frb_generated.dart';
import 'common/rust/api/applinks_api.dart' as applinks;
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/dcb_viewer_ui.dart';
import 'ui/tools/unp4kc/unp4kc_ui.dart';
part 'app.g.dart';
part 'app.freezed.dart';
@freezed
class AppGlobalState with _$AppGlobalState {
abstract class AppGlobalState with _$AppGlobalState {
const factory AppGlobalState({
String? deviceUUID,
String? applicationSupportDir,
@ -43,39 +50,51 @@ class AppGlobalState with _$AppGlobalState {
AppVersionData? networkVersionData,
@Default(ThemeConf()) ThemeConf themeConf,
Locale? appLocale,
Box? appConfBox,
@Default(10) windowsVersion,
}) = _AppGlobalState;
}
@riverpod
GoRouter router(RouterRef ref) {
GoRouter router(Ref ref) {
return GoRouter(
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const SplashUI()),
),
GoRoute(path: '/', pageBuilder: (context, state) => myPageBuilder(context, state, const SplashUI())),
GoRoute(
path: '/index',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const IndexUI()),
pageBuilder: (context, state) => myPageBuilder(context, state, const IndexUI()),
routes: [
GoRoute(
path: "downloader",
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeDownloaderUI())),
pageBuilder: (context, state) => myPageBuilder(context, state, const HomeDownloaderUI()),
),
GoRoute(
path: 'game_doctor',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeGameDoctorUI()),
pageBuilder: (context, state) => myPageBuilder(context, state, const HomeGameDoctorUI()),
),
GoRoute(
path: 'performance',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomePerformanceUI()),
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())),
GoRoute(
path: 'dcb_viewer',
pageBuilder: (context, state) =>
myPageBuilder(context, state, DcbViewerUI(initialFilePath: (state.extra as Map?)?['path'])),
),
],
),
GoRoute(path: '/guide', pageBuilder: (context, state) => myPageBuilder(context, state, const GuideUI())),
],
);
}
@ -87,6 +106,8 @@ class AppGlobalModel extends _$AppGlobalModel {
const Locale("zh", "CN"): NoL10n.langZHS,
const Locale("zh", "TW"): NoL10n.langZHT,
const Locale("en"): NoL10n.langEn,
const Locale("ja"): NoL10n.langJa,
const Locale("ru"): NoL10n.langRU,
};
@override
@ -99,36 +120,24 @@ class AppGlobalModel extends _$AppGlobalModel {
Future<void> initApp() async {
if (_initialized) return;
// init Data
final userProfileDir = Platform.environment["USERPROFILE"];
final applicationSupportDir =
(await getApplicationSupportDirectory()).absolute.path;
String? applicationBinaryModuleDir;
final logFile = File(
"$applicationSupportDir\\logs\\${DateTime.now().millisecondsSinceEpoch}.log");
await logFile.create(recursive: true);
setDPrintFile(logFile);
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,
);
final applicationSupportDir = await _initAppDir();
// init Rust bridge
await RustLib.init();
await RSHttp.init();
dPrint("---- rust bridge init -----");
// Register URL scheme
if ((!ConstConf.isMSE || kDebugMode) && Platform.isWindows) {
await _registerUrlScheme();
}
// init Hive
try {
Hive.init("$applicationSupportDir/db");
await Future.delayed(const Duration(milliseconds: 100));
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");
@ -146,15 +155,9 @@ class AppGlobalModel extends _$AppGlobalModel {
}
state = state.copyWith(deviceUUID: deviceUUID, appLocale: locale);
} catch (e) {
exit(1);
}
// init powershell
try {
await SystemHelper.initPowershellPath();
dPrint("---- Powershell init -----");
}catch (e){
dPrint("powershell init failed : $e");
await win32.setForegroundWindow(windowName: "SCToolBox");
dPrint("exit: db is locking ...");
exit(0);
}
// get windows info
@ -167,19 +170,25 @@ class AppGlobalModel extends _$AppGlobalModel {
}
// init windows
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setSize(const Size(1280, 810));
await windowManager.setMinimumSize(const Size(1280, 810));
await windowManager.setTitle("SCToolBox");
await windowManager.setSkipTaskbar(false);
await windowManager.show();
await Window.initialize();
await Window.hideWindowControls();
if (Platform.isWindows) {
if (windowsDeviceInfo?.productName.contains("Windows 11") ?? false) {
await Window.setEffect(
effect: WindowEffect.acrylic,
);
// Apply acrylic effect before showing window
await Window.setEffect(effect: WindowEffect.acrylic, color: Colors.transparent, dark: true);
state = state.copyWith(windowsVersion: 11);
dPrint("---- Windows 11 Acrylic Effect applied -----");
} else {
state = state.copyWith(windowsVersion: 10);
await Window.setEffect(effect: WindowEffect.disabled);
}
} else {
state = state.copyWith(windowsVersion: 9);
await Window.setEffect(effect: WindowEffect.disabled);
}
// Show window after acrylic effect is applied
await windowManager.show();
});
dPrint("---- Window init -----");
@ -191,6 +200,8 @@ class AppGlobalModel extends _$AppGlobalModel {
return "${state.applicationSupportDir}/._upgrade";
}
bool isInOnlineMode() => state.networkVersionData != null;
// ignore: avoid_build_context_in_providers
Future<bool> checkUpdate(BuildContext context) async {
if (!ConstConf.isMSE) {
@ -204,15 +215,18 @@ class AppGlobalModel extends _$AppGlobalModel {
try {
final networkVersionData = await Api.getAppVersion();
dPrint("networkVersionData == ${networkVersionData.toJson()}");
AppConf.setNetworkChannels(networkVersionData.gameChannels);
checkActivityThemeColor(networkVersionData);
if (ConstConf.isMSE) {
dPrint(
"lastVersion=${networkVersionData.mSELastVersion} ${networkVersionData.mSELastVersionCode}");
dPrint("lastVersion=${networkVersionData.mSELastVersion} ${networkVersionData.mSELastVersionCode}");
} else {
dPrint(
"lastVersion=${networkVersionData.lastVersion} ${networkVersionData.lastVersionCode}");
dPrint("lastVersion=${networkVersionData.lastVersion} ${networkVersionData.lastVersionCode}");
}
state = state.copyWith(networkVersionData: networkVersionData);
if (networkVersionData.nav42KitUrl != null) {
URLConf.nav42KitUrl = networkVersionData.nav42KitUrl!;
}
} catch (e) {
checkUpdateError = e;
dPrint("_checkUpdate Error:$e");
@ -223,10 +237,11 @@ class AppGlobalModel extends _$AppGlobalModel {
if (!context.mounted) return false;
await showToast(
context,
S.current.app_common_network_error(
ConstConf.appVersionDate, checkUpdateError.toString()));
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;
@ -237,7 +252,8 @@ class AppGlobalModel extends _$AppGlobalModel {
final r = await showDialog(
dismissWithEsc: false,
context: context,
builder: (context) => const UpgradeDialogUI());
builder: (context) => const UpgradeDialogUI(),
);
if (r != true) {
if (!context.mounted) return false;
@ -251,7 +267,9 @@ class AppGlobalModel extends _$AppGlobalModel {
Timer? _activityThemeColorTimer;
checkActivityThemeColor(AppVersionData networkVersionData) {
void checkActivityThemeColor(AppVersionData networkVersionData) {
final isDisableAcrylic = state.windowsVersion <= 11;
if (_activityThemeColorTimer != null) {
_activityThemeColorTimer?.cancel();
_activityThemeColorTimer = null;
@ -264,8 +282,10 @@ class AppGlobalModel extends _$AppGlobalModel {
dPrint("now == $now start == $startTime end == $endTime");
if (now < startTime) {
_activityThemeColorTimer = Timer(Duration(milliseconds: startTime - now),
() => checkActivityThemeColor(networkVersionData));
_activityThemeColorTimer = Timer(
Duration(milliseconds: startTime - now),
() => checkActivityThemeColor(networkVersionData),
);
dPrint("start Timer ....");
} else if (now >= startTime && now <= endTime) {
dPrint("update Color ....");
@ -273,29 +293,30 @@ class AppGlobalModel extends _$AppGlobalModel {
final colorCfg = networkVersionData.activityColors;
state = state.copyWith(
themeConf: ThemeConf(
backgroundColor:
HexColor(colorCfg?.background ?? "#132431").withOpacity(.75),
menuColor: HexColor(colorCfg?.menu ?? "#132431").withOpacity(.95),
backgroundColor: HexColor(colorCfg?.background ?? "#132431").withValues(alpha: isDisableAcrylic ? 1 : .75),
menuColor: HexColor(colorCfg?.menu ?? "#132431").withValues(alpha: isDisableAcrylic ? 1 : .95),
micaColor: HexColor(colorCfg?.mica ?? "#0A3142"),
),
);
// wait for end
_activityThemeColorTimer = Timer(Duration(milliseconds: endTime - now),
() => checkActivityThemeColor(networkVersionData));
_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),
backgroundColor: HexColor("#132431").withValues(alpha: isDisableAcrylic ? 1 : .75),
menuColor: HexColor("#132431").withValues(alpha: isDisableAcrylic ? 1 : .95),
micaColor: HexColor("#0A3142"),
),
);
}
}
void changeLocale(value) async {
void changeLocale(dynamic value) async {
final appConfBox = await Hive.openBox("app_conf");
if (value is Locale) {
if (value.languageCode == "auto") {
@ -306,14 +327,71 @@ class AppGlobalModel extends _$AppGlobalModel {
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);
}
}
/// Register sctoolbox:// URL scheme for non-MSE builds
Future<void> _registerUrlScheme() async {
try {
const scheme = "sctoolbox";
const appName = "SCToolBox";
final result = await applinks.registerApplinks(scheme: scheme, appName: appName);
if (result.success) {
if (result.wasModified) {
dPrint("URL scheme '$scheme' registered successfully: ${result.message}");
} else {
dPrint("URL scheme '$scheme' already registered: ${result.message}");
}
} else {
dPrint("URL scheme '$scheme' registration check: ${result.message}");
// Even if check fails, the registration might have succeeded
}
} catch (e) {
dPrint("Failed to register URL scheme: $e");
}
}
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 {
abstract class ThemeConf with _$ThemeConf {
const factory ThemeConf({
@Default(Color(0xbf132431)) Color backgroundColor,
@Default(Color(0xf2132431)) Color menuColor,

View File

@ -1,5 +1,5 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// 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
@ -9,419 +9,565 @@ part of 'app.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
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;
@JsonKey(ignore: true)
$AppGlobalStateCopyWith<AppGlobalState> get copyWith =>
throw _privateConstructorUsedError;
String? get deviceUUID; String? get applicationSupportDir; String? get applicationBinaryModuleDir; AppVersionData? get networkVersionData; ThemeConf get themeConf; Locale? get appLocale; Box? get appConfBox; dynamic get windowsVersion;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppGlobalStateCopyWith<AppGlobalState> get copyWith => _$AppGlobalStateCopyWithImpl<AppGlobalState>(this as AppGlobalState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppGlobalState&&(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)&&const DeepCollectionEquality().equals(other.windowsVersion, windowsVersion));
}
@override
int get hashCode => Object.hash(runtimeType,deviceUUID,applicationSupportDir,applicationBinaryModuleDir,networkVersionData,themeConf,appLocale,appConfBox,const DeepCollectionEquality().hash(windowsVersion));
@override
String toString() {
return 'AppGlobalState(deviceUUID: $deviceUUID, applicationSupportDir: $applicationSupportDir, applicationBinaryModuleDir: $applicationBinaryModuleDir, networkVersionData: $networkVersionData, themeConf: $themeConf, appLocale: $appLocale, appConfBox: $appConfBox, windowsVersion: $windowsVersion)';
}
}
/// @nodoc
abstract class $AppGlobalStateCopyWith<$Res> {
factory $AppGlobalStateCopyWith(
AppGlobalState value, $Res Function(AppGlobalState) then) =
_$AppGlobalStateCopyWithImpl<$Res, AppGlobalState>;
abstract mixin class $AppGlobalStateCopyWith<$Res> {
factory $AppGlobalStateCopyWith(AppGlobalState value, $Res Function(AppGlobalState) _then) = _$AppGlobalStateCopyWithImpl;
@useResult
$Res call(
{String? deviceUUID,
String? applicationSupportDir,
String? applicationBinaryModuleDir,
AppVersionData? networkVersionData,
ThemeConf themeConf,
Locale? appLocale});
$Res call({
String? deviceUUID, String? applicationSupportDir, String? applicationBinaryModuleDir, AppVersionData? networkVersionData, ThemeConf themeConf, Locale? appLocale, Box? appConfBox, dynamic windowsVersion
});
$ThemeConfCopyWith<$Res> get themeConf;
}
}
/// @nodoc
class _$AppGlobalStateCopyWithImpl<$Res, $Val extends AppGlobalState>
class _$AppGlobalStateCopyWithImpl<$Res>
implements $AppGlobalStateCopyWith<$Res> {
_$AppGlobalStateCopyWithImpl(this._value, this._then);
_$AppGlobalStateCopyWithImpl(this._self, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
final AppGlobalState _self;
final $Res Function(AppGlobalState) _then;
@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,
}) {
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?,
) as $Val);
/// 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,Object? windowsVersion = freezed,}) {
return _then(_self.copyWith(
deviceUUID: freezed == deviceUUID ? _self.deviceUUID : deviceUUID // ignore: cast_nullable_to_non_nullable
as String?,applicationSupportDir: freezed == applicationSupportDir ? _self.applicationSupportDir : applicationSupportDir // ignore: cast_nullable_to_non_nullable
as String?,applicationBinaryModuleDir: freezed == applicationBinaryModuleDir ? _self.applicationBinaryModuleDir : applicationBinaryModuleDir // ignore: cast_nullable_to_non_nullable
as String?,networkVersionData: freezed == networkVersionData ? _self.networkVersionData : networkVersionData // ignore: cast_nullable_to_non_nullable
as AppVersionData?,themeConf: null == themeConf ? _self.themeConf : themeConf // ignore: cast_nullable_to_non_nullable
as ThemeConf,appLocale: freezed == appLocale ? _self.appLocale : appLocale // ignore: cast_nullable_to_non_nullable
as Locale?,appConfBox: freezed == appConfBox ? _self.appConfBox : appConfBox // ignore: cast_nullable_to_non_nullable
as Box?,windowsVersion: freezed == windowsVersion ? _self.windowsVersion : windowsVersion // ignore: cast_nullable_to_non_nullable
as dynamic,
));
}
/// 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);
return $ThemeConfCopyWith<$Res>(_self.themeConf, (value) {
return _then(_self.copyWith(themeConf: value));
});
}
}
/// Adds pattern-matching-related methods to [AppGlobalState].
extension AppGlobalStatePatterns on AppGlobalState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _AppGlobalState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _AppGlobalState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _AppGlobalState value) $default,){
final _that = this;
switch (_that) {
case _AppGlobalState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _AppGlobalState value)? $default,){
final _that = this;
switch (_that) {
case _AppGlobalState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? deviceUUID, String? applicationSupportDir, String? applicationBinaryModuleDir, AppVersionData? networkVersionData, ThemeConf themeConf, Locale? appLocale, Box? appConfBox, dynamic windowsVersion)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _AppGlobalState() when $default != null:
return $default(_that.deviceUUID,_that.applicationSupportDir,_that.applicationBinaryModuleDir,_that.networkVersionData,_that.themeConf,_that.appLocale,_that.appConfBox,_that.windowsVersion);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? deviceUUID, String? applicationSupportDir, String? applicationBinaryModuleDir, AppVersionData? networkVersionData, ThemeConf themeConf, Locale? appLocale, Box? appConfBox, dynamic windowsVersion) $default,) {final _that = this;
switch (_that) {
case _AppGlobalState():
return $default(_that.deviceUUID,_that.applicationSupportDir,_that.applicationBinaryModuleDir,_that.networkVersionData,_that.themeConf,_that.appLocale,_that.appConfBox,_that.windowsVersion);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? deviceUUID, String? applicationSupportDir, String? applicationBinaryModuleDir, AppVersionData? networkVersionData, ThemeConf themeConf, Locale? appLocale, Box? appConfBox, dynamic windowsVersion)? $default,) {final _that = this;
switch (_that) {
case _AppGlobalState() when $default != null:
return $default(_that.deviceUUID,_that.applicationSupportDir,_that.applicationBinaryModuleDir,_that.networkVersionData,_that.themeConf,_that.appLocale,_that.appConfBox,_that.windowsVersion);case _:
return null;
}
}
}
/// @nodoc
class _AppGlobalState implements AppGlobalState {
const _AppGlobalState({this.deviceUUID, this.applicationSupportDir, this.applicationBinaryModuleDir, this.networkVersionData, this.themeConf = const ThemeConf(), this.appLocale, this.appConfBox, this.windowsVersion = 10});
@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? appConfBox;
@override@JsonKey() final dynamic windowsVersion;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$AppGlobalStateCopyWith<_AppGlobalState> get copyWith => __$AppGlobalStateCopyWithImpl<_AppGlobalState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppGlobalState&&(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)&&const DeepCollectionEquality().equals(other.windowsVersion, windowsVersion));
}
@override
int get hashCode => Object.hash(runtimeType,deviceUUID,applicationSupportDir,applicationBinaryModuleDir,networkVersionData,themeConf,appLocale,appConfBox,const DeepCollectionEquality().hash(windowsVersion));
@override
String toString() {
return 'AppGlobalState(deviceUUID: $deviceUUID, applicationSupportDir: $applicationSupportDir, applicationBinaryModuleDir: $applicationBinaryModuleDir, networkVersionData: $networkVersionData, themeConf: $themeConf, appLocale: $appLocale, appConfBox: $appConfBox, windowsVersion: $windowsVersion)';
}
}
/// @nodoc
abstract mixin class _$AppGlobalStateCopyWith<$Res> implements $AppGlobalStateCopyWith<$Res> {
factory _$AppGlobalStateCopyWith(_AppGlobalState value, $Res Function(_AppGlobalState) _then) = __$AppGlobalStateCopyWithImpl;
@override @useResult
$Res call({
String? deviceUUID, String? applicationSupportDir, String? applicationBinaryModuleDir, AppVersionData? networkVersionData, ThemeConf themeConf, Locale? appLocale, Box? appConfBox, dynamic windowsVersion
});
@override $ThemeConfCopyWith<$Res> get themeConf;
}
/// @nodoc
class __$AppGlobalStateCopyWithImpl<$Res>
implements _$AppGlobalStateCopyWith<$Res> {
__$AppGlobalStateCopyWithImpl(this._self, this._then);
final _AppGlobalState _self;
final $Res Function(_AppGlobalState) _then;
/// Create a copy of AppGlobalState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? deviceUUID = freezed,Object? applicationSupportDir = freezed,Object? applicationBinaryModuleDir = freezed,Object? networkVersionData = freezed,Object? themeConf = null,Object? appLocale = freezed,Object? appConfBox = freezed,Object? windowsVersion = freezed,}) {
return _then(_AppGlobalState(
deviceUUID: freezed == deviceUUID ? _self.deviceUUID : deviceUUID // ignore: cast_nullable_to_non_nullable
as String?,applicationSupportDir: freezed == applicationSupportDir ? _self.applicationSupportDir : applicationSupportDir // ignore: cast_nullable_to_non_nullable
as String?,applicationBinaryModuleDir: freezed == applicationBinaryModuleDir ? _self.applicationBinaryModuleDir : applicationBinaryModuleDir // ignore: cast_nullable_to_non_nullable
as String?,networkVersionData: freezed == networkVersionData ? _self.networkVersionData : networkVersionData // ignore: cast_nullable_to_non_nullable
as AppVersionData?,themeConf: null == themeConf ? _self.themeConf : themeConf // ignore: cast_nullable_to_non_nullable
as ThemeConf,appLocale: freezed == appLocale ? _self.appLocale : appLocale // ignore: cast_nullable_to_non_nullable
as Locale?,appConfBox: freezed == appConfBox ? _self.appConfBox : appConfBox // ignore: cast_nullable_to_non_nullable
as Box?,windowsVersion: freezed == windowsVersion ? _self.windowsVersion : windowsVersion // ignore: cast_nullable_to_non_nullable
as dynamic,
));
}
/// 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>(_self.themeConf, (value) {
return _then(_self.copyWith(themeConf: value));
});
}
}
/// @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});
@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);
mixin _$ThemeConf {
Color get backgroundColor; Color get menuColor; Color get micaColor;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@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,
}) {
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?,
));
}
}
$ThemeConfCopyWith<ThemeConf> get copyWith => _$ThemeConfCopyWithImpl<ThemeConf>(this as ThemeConf, _$identity);
/// @nodoc
class _$AppGlobalStateImpl implements _AppGlobalState {
const _$AppGlobalStateImpl(
{this.deviceUUID,
this.applicationSupportDir,
this.applicationBinaryModuleDir,
this.networkVersionData,
this.themeConf = const ThemeConf(),
this.appLocale});
@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
String toString() {
return 'AppGlobalState(deviceUUID: $deviceUUID, applicationSupportDir: $applicationSupportDir, applicationBinaryModuleDir: $applicationBinaryModuleDir, networkVersionData: $networkVersionData, themeConf: $themeConf, appLocale: $appLocale)';
}
@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));
return identical(this, other) || (other.runtimeType == runtimeType&&other is ThemeConf&&(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,
deviceUUID,
applicationSupportDir,
applicationBinaryModuleDir,
networkVersionData,
themeConf,
appLocale);
@JsonKey(ignore: true)
@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}) = _$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
@JsonKey(ignore: true)
_$$AppGlobalStateImplCopyWith<_$AppGlobalStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ThemeConf {
Color get backgroundColor => throw _privateConstructorUsedError;
Color get menuColor => throw _privateConstructorUsedError;
Color get micaColor => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$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;
@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);
@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;
int get hashCode => Object.hash(runtimeType,backgroundColor,menuColor,micaColor);
@override
String toString() {
return 'ThemeConf(backgroundColor: $backgroundColor, menuColor: $menuColor, micaColor: $micaColor)';
}
}
/// @nodoc
abstract mixin class $ThemeConfCopyWith<$Res> {
factory $ThemeConfCopyWith(ThemeConf value, $Res Function(ThemeConf) _then) = _$ThemeConfCopyWithImpl;
@useResult
$Res call({
Color backgroundColor, Color menuColor, Color micaColor
});
}
/// @nodoc
class _$ThemeConfCopyWithImpl<$Res>
implements $ThemeConfCopyWith<$Res> {
_$ThemeConfCopyWithImpl(this._self, this._then);
final ThemeConf _self;
final $Res Function(ThemeConf) _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(_self.copyWith(
backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable
as Color,menuColor: null == menuColor ? _self.menuColor : menuColor // ignore: cast_nullable_to_non_nullable
as Color,micaColor: null == micaColor ? _self.micaColor : micaColor // ignore: cast_nullable_to_non_nullable
as Color,
));
}
}
/// Adds pattern-matching-related methods to [ThemeConf].
extension ThemeConfPatterns on ThemeConf {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ThemeConf value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ThemeConf() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ThemeConf value) $default,){
final _that = this;
switch (_that) {
case _ThemeConf():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ThemeConf value)? $default,){
final _that = this;
switch (_that) {
case _ThemeConf() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Color backgroundColor, Color menuColor, Color micaColor)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ThemeConf() when $default != null:
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Color backgroundColor, Color menuColor, Color micaColor) $default,) {final _that = this;
switch (_that) {
case _ThemeConf():
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Color backgroundColor, Color menuColor, Color micaColor)? $default,) {final _that = this;
switch (_that) {
case _ThemeConf() when $default != null:
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor);case _:
return null;
}
}
}
/// @nodoc
class _ThemeConf implements ThemeConf {
const _ThemeConf({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;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ThemeConfCopyWith<_ThemeConf> get copyWith => __$ThemeConfCopyWithImpl<_ThemeConf>(this, _$identity);
@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));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ThemeConf&&(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);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ThemeConfImplCopyWith<_$ThemeConfImpl> get copyWith =>
__$$ThemeConfImplCopyWithImpl<_$ThemeConfImpl>(this, _$identity);
int get hashCode => Object.hash(runtimeType,backgroundColor,menuColor,micaColor);
@override
String toString() {
return 'ThemeConf(backgroundColor: $backgroundColor, menuColor: $menuColor, micaColor: $micaColor)';
}
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;
@override
@JsonKey(ignore: true)
_$$ThemeConfImplCopyWith<_$ThemeConfImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class _$ThemeConfCopyWith<$Res> implements $ThemeConfCopyWith<$Res> {
factory _$ThemeConfCopyWith(_ThemeConf value, $Res Function(_ThemeConf) _then) = __$ThemeConfCopyWithImpl;
@override @useResult
$Res call({
Color backgroundColor, Color menuColor, Color micaColor
});
}
/// @nodoc
class __$ThemeConfCopyWithImpl<$Res>
implements _$ThemeConfCopyWith<$Res> {
__$ThemeConfCopyWithImpl(this._self, this._then);
final _ThemeConf _self;
final $Res Function(_ThemeConf) _then;
/// Create a copy of ThemeConf
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? backgroundColor = null,Object? menuColor = null,Object? micaColor = null,}) {
return _then(_ThemeConf(
backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable
as Color,menuColor: null == menuColor ? _self.menuColor : menuColor // ignore: cast_nullable_to_non_nullable
as Color,micaColor: null == micaColor ? _self.micaColor : micaColor // ignore: cast_nullable_to_non_nullable
as Color,
));
}
}
// dart format on

View File

@ -6,35 +6,98 @@ part of 'app.dart';
// RiverpodGenerator
// **************************************************************************
String _$routerHash() => r'e7b1e3a9fd74b4f00e3d71017615d7fb82bd649d';
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// See also [router].
@ProviderFor(router)
final routerProvider = AutoDisposeProvider<GoRouter>.internal(
router,
final routerProvider = RouterProvider._();
final class RouterProvider
extends $FunctionalProvider<GoRouter, GoRouter, GoRouter>
with $Provider<GoRouter> {
RouterProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'routerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$routerHash,
isAutoDispose: true,
dependencies: null,
allTransitiveDependencies: null,
$allTransitiveDependencies: null,
);
typedef RouterRef = AutoDisposeProviderRef<GoRouter>;
String _$appGlobalModelHash() => r'9c114910aed546bfd469c8bbfa50cdd4a5be5028';
@override
String debugGetCreateSourceHash() => _$routerHash();
@$internal
@override
$ProviderElement<GoRouter> $createElement($ProviderPointer pointer) =>
$ProviderElement(pointer);
@override
GoRouter create(Ref ref) {
return router(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(GoRouter value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<GoRouter>(value),
);
}
}
String _$routerHash() => r'e89f3f0277879147cdce5373cbe2554821e9cd31';
/// See also [AppGlobalModel].
@ProviderFor(AppGlobalModel)
final appGlobalModelProvider =
AutoDisposeNotifierProvider<AppGlobalModel, AppGlobalState>.internal(
AppGlobalModel.new,
final appGlobalModelProvider = AppGlobalModelProvider._();
final class AppGlobalModelProvider
extends $NotifierProvider<AppGlobalModel, AppGlobalState> {
AppGlobalModelProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'appGlobalModelProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$appGlobalModelHash,
isAutoDispose: true,
dependencies: null,
allTransitiveDependencies: 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
@override
String debugGetCreateSourceHash() => _$appGlobalModelHash();
@$internal
@override
AppGlobalModel create() => AppGlobalModel();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(AppGlobalState value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<AppGlobalState>(value),
);
}
}
String _$appGlobalModelHash() => r'74128d2194d00a0e3dbb000dcaf6452e0b966d9c';
abstract class _$AppGlobalModel extends $Notifier<AppGlobalState> {
AppGlobalState build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<AppGlobalState, AppGlobalState>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AppGlobalState, AppGlobalState>,
AppGlobalState,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View File

@ -1,13 +1,13 @@
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",
};
// aria2c has been replaced by rqbit (Rust-based torrent library)
static const _modules = <String, String>{};
static Future extractModule(List<String> modules, String workingDir) async {
for (var m in _modules.entries) {
@ -16,10 +16,8 @@ class BinaryModuleConf {
final version = m.value;
final dir = "$workingDir\\$name";
final versionFile = File("$dir\\version");
if (await versionFile.exists() &&
(await versionFile.readAsString()).trim() == version) {
dPrint(
"BinaryModuleConf.extractModule skip $name version == $version");
if (kReleaseMode && await versionFile.exists() && (await versionFile.readAsString()).trim() == version) {
dPrint("BinaryModuleConf.extractModule skip $name version == $version");
continue;
}
// write model file

31
lib/common/conf/conf.dart Normal file
View File

@ -0,0 +1,31 @@
import 'dart:io';
class ConstConf {
static const String appVersion = "3.0.0 Beta10";
static const int appVersionCode = 79;
static const String appVersionDate = "2025-12-27";
static const _gameChannels = ["LIVE", "4.0_PREVIEW", "PTU", "EPTU", "TECH-PREVIEW", "HOTFIX"];
static const isMSE = String.fromEnvironment("MSE", defaultValue: "false") == "true";
static const win32AppId = isMSE
? "56575xkeyC.MSE_bsn1nexg8e4qe!starcitizendoctor"
: "{6D809377-6AF0-444B-8957-A3773F02200E}\\Starcitizen_Doctor\\starcitizen_doctor.exe";
static const dohAddress = "https://223.6.6.6/resolve";
static const inputMethodServerPort = 59399;
}
class AppConf {
static List<String>? _networkGameChannels;
static void setNetworkChannels(List<String>? channels) {
_networkGameChannels = channels;
}
static List<String> get gameChannels {
final baseChannels = _networkGameChannels ?? ConstConf._gameChannels;
// On Linux, add lowercase variants for case-sensitive filesystem
if (Platform.isLinux) {
return [...baseChannels, ...baseChannels.map((c) => c.toLowerCase())];
}
return baseChannels;
}
}

View File

@ -1,8 +0,0 @@
class ConstConf {
static const String appVersion = "2.10.9 Beta";
static const int appVersionCode = 44;
static const String appVersionDate = "2024-03-26";
static const gameChannels = ["LIVE", "PTU", "EPTU"];
static const isMSE =
String.fromEnvironment("MSE", defaultValue: "false") == "true";
}

View File

@ -1,89 +1,75 @@
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/rust/http_package.dart';
import 'package:starcitizen_doctor/api/api.dart';
import 'package:starcitizen_doctor/common/io/doh_client.dart';
import 'package:starcitizen_doctor/common/rust/api/http_api.dart' as rust_http;
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 newsApiHome = "https://scbox.citizenwiki.cn";
static const String analyticsApiHome = "https://scbox.org";
/// PartyRoom Server
// static const String partyRoomServerAddress = "localhost";
// static const int partyRoomServerPort = 50051;
static const String partyRoomServerAddress = "ecdn.partyroom.grpc.scbox.xkeyc.cn";
static const int partyRoomServerPort = 443;
static bool isUrlCheckPass = false;
/// URLS
static String get giteaAttachmentsUrl => "$gitApiHome/SCToolBox/Release";
static String get gitlabLocalizationUrl =>
"$gitApiHome/SCToolBox/LocalizationData";
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/";
static String get webTranslateHomeUrl =>
"$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
static String get webTranslateHomeUrl => "$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
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&";
static const feedbackUrl = "https://txc.qq.com/products/614843";
static const feedbackUrl = "https://support.citizenwiki.cn/all";
static const feedbackFAQUrl = "https://support.citizenwiki.cn/t/sc-toolbox";
static String nav42KitUrl =
"https://payload.citizenwiki.cn/api/community-navs?sort=is_sponsored&depth=2&page=1&limit=1000";
static String get devReleaseUrl => "$gitApiHome/SCToolBox/Release/releases";
/// RSI Avatar Base URL
static const String rsiAvatarBaseUrl = "https://robertsspaceindustries.com";
static Future<bool> checkHost() async {
// 使 DNS
final gitApiList =
_genFinalList(await RSHttp.dnsLookupTxt("git.dns.scbox.org"));
final gitApiList = _genFinalList(await dnsLookupTxt("git.dns.scbox.org"));
dPrint("DNS gitApiList ==== $gitApiList");
final fasterGit = await getFasterUrl(gitApiList);
final fasterGit = await rust_http.getFasterUrl(
urls: gitApiList,
pathSuffix: "/SCToolBox/Api/raw/branch/main/sc_doctor/version.json",
);
dPrint("gitApiList.Faster ==== $fasterGit");
if (fasterGit != null) {
gitApiHome = fasterGit;
}
final rssApiList =
_genFinalList(await RSHttp.dnsLookupTxt("rss.dns.scbox.org"));
final fasterRss = await getFasterUrl(rssApiList);
dPrint("DNS rssApiList ==== $rssApiList");
dPrint("rssApiList.Faster ==== $fasterRss");
if (fasterRss != null) {
rssApiHome = fasterRss;
final newsApiList = _genFinalList(await dnsLookupTxt("news.dns.scbox.org"));
final fasterNews = await rust_http.getFasterUrl(urls: newsApiList, pathSuffix: "/api/latest");
dPrint("DNS newsApiList ==== $newsApiList");
dPrint("newsApiList.Faster ==== $fasterNews");
if (fasterNews != null) {
newsApiHome = fasterNews;
}
isUrlCheckPass = fasterGit != null && fasterRss != null;
isUrlCheckPass = fasterGit != null && fasterNews != null;
return isUrlCheckPass;
}
static Future<String?> getFasterUrl(List<String> urls) async {
String firstUrl = "";
int callLen = 0;
void onCall(RustHttpResponse? response, String url) {
callLen++;
if (response != null && response.statusCode == 200 && firstUrl.isEmpty) {
firstUrl = url;
}
}
for (var value in urls) {
RSHttp.head(value).then((resp) => onCall(resp, value), onError: (err) {
callLen++;
dPrint("RSHttp.head error $err");
});
}
while (true) {
await Future.delayed(const Duration(milliseconds: 16));
if (firstUrl.isNotEmpty) {
return firstUrl;
}
if (callLen == urls.length && firstUrl.isEmpty) {
return null;
}
static Future<List<String>> dnsLookupTxt(String host) async {
if (await Api.isUseInternalDNS()) {
dPrint("[URLConf] use internal DNS LookupTxt $host");
return rust_http.dnsLookupTxt(host: host);
}
dPrint("[URLConf] use DOH LookupTxt $host");
return (await DohClient.resolveTXT(host)) ?? [];
}
static List<String> _genFinalList(List<String> sList) {

View File

@ -0,0 +1,508 @@
import 'dart:convert';
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
import 'package:starcitizen_doctor/generated/l10n.dart';
///
class LogAnalyzeLineData {
final String type;
final String title;
final String? data;
final String? dateTime;
final String? tag; // "game_start"
//
final String? victimId; // ID (actor_death)
final String? location; // (request_location_inventory)
final String? area; //
final String? playerName; // (player_login)
const LogAnalyzeLineData({
required this.type,
required this.title,
this.data,
this.dateTime,
this.tag,
this.victimId,
this.location,
this.area,
this.playerName,
});
@override
String toString() {
return 'LogAnalyzeLineData(type: $type, title: $title, data: $data, dateTime: $dateTime)';
}
}
///
class LogAnalyzeStatistics {
final String playerName;
final int killCount;
final int deathCount;
final int selfKillCount;
final int vehicleDestructionCount;
final int vehicleDestructionCountHard;
final DateTime? gameStartTime;
final int gameCrashLineNumber;
final String? latestLocation; //
const LogAnalyzeStatistics({
required this.playerName,
required this.killCount,
required this.deathCount,
required this.selfKillCount,
required this.vehicleDestructionCount,
required this.vehicleDestructionCountHard,
this.gameStartTime,
required this.gameCrashLineNumber,
this.latestLocation,
});
}
///
class GameLogAnalyzer {
static const String unknownValue = "<Unknown>";
//
static final _baseRegExp = RegExp(r'\[Notice\]\s+<([^>]+)>');
static final _gameLoadingRegExp = RegExp(
r'<[^>]+>\s+Loading screen for\s+(\w+)\s+:\s+SC_Frontend closed after\s+(\d+\.\d+)\s+seconds',
);
static final _logDateTimeRegExp = RegExp(r'<(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)>');
static final DateFormat _dateTimeFormatter = DateFormat('yyyy-MM-dd HH:mm:ss:SSS');
//
static final _fatalCollisionPatterns = {
'vehicle': RegExp(r'Fatal Collision occured for vehicle\s+(\S+)'),
'zone': RegExp(r'Zone:\s*([^,\]]+)'),
'player_pilot': RegExp(r'PlayerPilot:\s*(\d)'),
'hit_entity': RegExp(r'hitting entity:\s*(\w+)'),
'distance': RegExp(r'Distance:\s*([\d.]+)'),
};
//
static final _vehicleDestructionPattern = RegExp(
r"Vehicle\s+'([^']+)'.*?" //
r"in zone\s+'([^']+)'.*?" // Zone
r"destroy level \d+ to (\d+).*?" //
r"caused by\s+'([^']+)'", //
);
//
static final _actorDeathPattern = RegExp(
r"Actor '([^']+)'.*?" // ID
r"ejected from zone '([^']+)'.*?" // /
r"to zone '([^']+)'", //
);
//
static final _characterNamePattern = RegExp(r"name\s+([^-]+)");
//
static final _requestLocationInventoryPattern = RegExp(r"Player\[([^\]]+)\].*?Location\[([^\]]+)\]");
//
static final vehicleControlPattern = RegExp(r"granted control token for '([^']+)'\s+\[(\d+)\]");
/// 使
static DateTime? getLogLineDateTime(String line) => _getLogLineDateTime(line);
///
static String? getLogLineDateTimeString(String line) => _getLogLineDateTimeString(line);
/// ID
/// : ANVL_Hornet_F7A_Mk2_3467069517923 -> ANVL_Hornet_F7A_Mk2
static String removeVehicleId(String vehicleName) {
final regex = RegExp(r'_\d+$');
return vehicleName.replaceAll(regex, '');
}
///
///
/// [logFile]
/// [startTime]
///
static Future<(List<LogAnalyzeLineData>, LogAnalyzeStatistics)> analyzeLogFile(
File logFile, {
DateTime? startTime,
}) async {
if (!(await logFile.exists())) {
return (
[LogAnalyzeLineData(type: "error", title: S.current.log_analyzer_no_log_file)],
LogAnalyzeStatistics(
playerName: "",
killCount: 0,
deathCount: 0,
selfKillCount: 0,
vehicleDestructionCount: 0,
vehicleDestructionCountHard: 0,
gameCrashLineNumber: -1,
),
);
}
final logLines = utf8.decode((await logFile.readAsBytes()), allowMalformed: true).split("\n");
return _analyzeLogLines(logLines, startTime: startTime);
}
///
///
/// [logLines]
/// [startTime] gameStartTime
///
static (List<LogAnalyzeLineData>, LogAnalyzeStatistics) _analyzeLogLines(
List<String> logLines, {
DateTime? startTime,
}) {
final results = <LogAnalyzeLineData>[];
String playerName = "";
int killCount = 0;
int deathCount = 0;
int selfKillCount = 0;
int vehicleDestructionCount = 0;
int vehicleDestructionCountHard = 0;
DateTime? gameStartTime; // startTime
String? latestLocation; //
int gameCrashLineNumber = -1;
bool shouldCount = startTime == null; //
for (var i = 0; i < logLines.length; i++) {
final line = logLines[i];
if (line.isEmpty) continue;
// startTime
if (startTime != null && !shouldCount) {
final lineTime = _getLogLineDateTime(line);
if (lineTime != null && lineTime.isAfter(startTime)) {
shouldCount = true;
}
}
//
if (gameStartTime == null) {
gameStartTime = _getLogLineDateTime(line);
if (gameStartTime != null) {
results.add(
LogAnalyzeLineData(
type: "info",
title: S.current.log_analyzer_game_start,
tag: "game_start", // 使 tag
),
);
}
}
//
final gameLoading = _parseGameLoading(line);
if (gameLoading != null) {
results.add(
LogAnalyzeLineData(
type: "info",
title: S.current.log_analyzer_game_loading,
data: S.current.log_analyzer_mode_loading_time(gameLoading.$1, gameLoading.$2),
dateTime: _getLogLineDateTimeString(line),
),
);
continue;
}
//
final baseEvent = _parseBaseEvent(line);
if (baseEvent != null) {
LogAnalyzeLineData? data;
switch (baseEvent) {
case "AccountLoginCharacterStatus_Character":
data = _parseCharacterName(line);
if (data != null && data.playerName != null) {
playerName = data.playerName!; //
}
break;
case "FatalCollision":
data = _parseFatalCollision(line);
break;
case "Vehicle Destruction":
data = _parseVehicleDestruction(line, playerName, shouldCount, (isHard) {
if (isHard) {
vehicleDestructionCountHard++;
} else {
vehicleDestructionCount++;
}
});
break;
case "[ActorState] Dead":
data = _parseActorDeath(line, playerName, shouldCount, (isKill, isDeath, isSelfKill) {
if (isSelfKill) {
selfKillCount++;
} else {
if (isKill) killCount++;
if (isDeath) deathCount++;
}
});
break;
case "RequestLocationInventory":
data = _parseRequestLocationInventory(line);
if (data != null && data.location != null) {
latestLocation = data.location; //
}
break;
}
if (data != null) {
results.add(data);
continue;
}
}
//
if (line.contains("[CIG] CCIGBroker::FastShutdown")) {
results.add(
LogAnalyzeLineData(
type: "info",
title: S.current.log_analyzer_game_close,
dateTime: _getLogLineDateTimeString(line),
),
);
continue;
}
//
if (line.contains("Cloud Imperium Games public crash handler")) {
gameCrashLineNumber = i;
}
}
//
if (gameCrashLineNumber > 0) {
final lastLineDateTime = gameStartTime != null
? _getLogLineDateTime(logLines.lastWhere((e) => e.startsWith("<20")))
: null;
final crashInfo = logLines.sublist(gameCrashLineNumber);
final info = SCLoggerHelper.getGameRunningLogInfo(crashInfo);
crashInfo.add(S.current.log_analyzer_one_click_diagnosis_header);
if (info != null) {
crashInfo.add(info.key);
if (info.value.isNotEmpty) {
crashInfo.add(S.current.log_analyzer_details_info(info.value));
}
} else {
crashInfo.add(S.current.log_analyzer_no_crash_detected);
}
results.add(
LogAnalyzeLineData(
type: "game_crash",
title: S.current.log_analyzer_game_crash,
data: crashInfo.join("\n"),
dateTime: lastLineDateTime != null ? _dateTimeFormatter.format(lastLineDateTime) : null,
),
);
}
//
if (killCount > 0 || deathCount > 0) {
results.add(
LogAnalyzeLineData(
type: "statistics",
title: S.current.log_analyzer_kill_summary,
data: S.current.log_analyzer_kill_death_suicide_count(
killCount,
deathCount,
selfKillCount,
vehicleDestructionCount,
vehicleDestructionCountHard,
),
),
);
}
//
if (gameStartTime != null) {
final lastLineDateTime = _getLogLineDateTime(logLines.lastWhere((e) => e.startsWith("<20"), orElse: () => ""));
if (lastLineDateTime != null) {
final duration = lastLineDateTime.difference(gameStartTime);
results.add(
LogAnalyzeLineData(
type: "statistics",
title: S.current.log_analyzer_play_time,
data: S.current.log_analyzer_play_time_format(
duration.inHours,
duration.inMinutes.remainder(60),
duration.inSeconds.remainder(60),
),
),
);
}
}
final statistics = LogAnalyzeStatistics(
playerName: playerName,
killCount: killCount,
deathCount: deathCount,
selfKillCount: selfKillCount,
vehicleDestructionCount: vehicleDestructionCount,
vehicleDestructionCountHard: vehicleDestructionCountHard,
gameStartTime: gameStartTime,
gameCrashLineNumber: gameCrashLineNumber,
latestLocation: latestLocation,
);
return (results, statistics);
}
// ==================== ====================
static String? _parseBaseEvent(String line) {
final match = _baseRegExp.firstMatch(line);
return match?.group(1);
}
static (String, String)? _parseGameLoading(String line) {
final match = _gameLoadingRegExp.firstMatch(line);
if (match != null) {
return (match.group(1) ?? "-", match.group(2) ?? "-");
}
return null;
}
static DateTime? _getLogLineDateTime(String line) {
final match = _logDateTimeRegExp.firstMatch(line);
if (match != null) {
final dateTimeString = match.group(1);
if (dateTimeString != null) {
return DateTime.parse(dateTimeString).toLocal();
}
}
return null;
}
static String? _getLogLineDateTimeString(String line) {
final dateTime = _getLogLineDateTime(line);
if (dateTime != null) {
return _dateTimeFormatter.format(dateTime);
}
return null;
}
static String? _safeExtract(RegExp pattern, String line) => pattern.firstMatch(line)?.group(1)?.trim();
static LogAnalyzeLineData? _parseFatalCollision(String line) {
final vehicle = _safeExtract(_fatalCollisionPatterns['vehicle']!, line) ?? unknownValue;
final zone = _safeExtract(_fatalCollisionPatterns['zone']!, line) ?? unknownValue;
final playerPilot = (_safeExtract(_fatalCollisionPatterns['player_pilot']!, line) ?? '0') == '1';
final hitEntity = _safeExtract(_fatalCollisionPatterns['hit_entity']!, line) ?? unknownValue;
final distance = double.tryParse(_safeExtract(_fatalCollisionPatterns['distance']!, line) ?? '') ?? 0.0;
return LogAnalyzeLineData(
type: "fatal_collision",
title: S.current.log_analyzer_filter_fatal_collision,
data: S.current.log_analyzer_collision_details(
zone,
playerPilot ? '' : '',
hitEntity,
vehicle,
distance.toStringAsFixed(2),
),
dateTime: _getLogLineDateTimeString(line),
);
}
static LogAnalyzeLineData? _parseVehicleDestruction(
String line,
String playerName,
bool shouldCount,
void Function(bool isHard) onDestruction,
) {
final match = _vehicleDestructionPattern.firstMatch(line);
if (match != null) {
final vehicleModel = match.group(1) ?? unknownValue;
final zone = match.group(2) ?? unknownValue;
final destructionLevel = int.tryParse(match.group(3) ?? '') ?? 0;
final causedBy = match.group(4) ?? unknownValue;
final destructionLevelMap = {1: S.current.log_analyzer_soft_death, 2: S.current.log_analyzer_disintegration};
if (shouldCount && causedBy.trim() == playerName) {
onDestruction(destructionLevel == 2);
}
return LogAnalyzeLineData(
type: "vehicle_destruction",
title: S.current.log_analyzer_filter_vehicle_damaged,
data: S.current.log_analyzer_vehicle_damage_details(
vehicleModel,
zone,
destructionLevel.toString(),
destructionLevelMap[destructionLevel] ?? unknownValue,
causedBy,
),
dateTime: _getLogLineDateTimeString(line),
);
}
return null;
}
static LogAnalyzeLineData? _parseActorDeath(
String line,
String playerName,
bool shouldCount,
void Function(bool isKill, bool isDeath, bool isSelfKill) onDeath,
) {
final match = _actorDeathPattern.firstMatch(line);
if (match != null) {
final victimId = match.group(1) ?? unknownValue;
final fromZone = match.group(2) ?? unknownValue;
final toZone = match.group(3) ?? unknownValue;
if (shouldCount) {
final isDeath = victimId.trim() == playerName;
if (isDeath) {
onDeath(false, true, false);
}
}
return LogAnalyzeLineData(
type: "actor_death",
title: S.current.log_analyzer_filter_character_death,
data: S.current.log_analyzer_death_details(victimId, fromZone, toZone),
dateTime: _getLogLineDateTimeString(line),
location: fromZone,
area: toZone,
victimId: victimId,
playerName: playerName,
);
}
return null;
}
static LogAnalyzeLineData? _parseCharacterName(String line) {
final match = _characterNamePattern.firstMatch(line);
if (match != null) {
final characterName = match.group(1)?.trim() ?? unknownValue;
return LogAnalyzeLineData(
type: "player_login",
title: S.current.log_analyzer_player_login(characterName),
dateTime: _getLogLineDateTimeString(line),
playerName: characterName, //
);
}
return null;
}
static LogAnalyzeLineData? _parseRequestLocationInventory(String line) {
final match = _requestLocationInventoryPattern.firstMatch(line);
if (match != null) {
final playerId = match.group(1) ?? unknownValue;
final location = match.group(2) ?? unknownValue;
return LogAnalyzeLineData(
type: "request_location_inventory",
title: S.current.log_analyzer_view_local_inventory,
data: S.current.log_analyzer_player_location(playerId, location),
dateTime: _getLogLineDateTimeString(line),
location: location, //
);
}
return null;
}
}

View File

@ -1,11 +1,22 @@
import 'dart:convert';
import 'dart:io';
import 'package:hive/hive.dart';
import 'package:hive_ce/hive.dart';
import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
class SCLoggerHelper {
static Future<String?> getLogFilePath() async {
if (!Platform.isWindows) {
final wineUserPath = await getWineUserPath();
if (wineUserPath == null) return null;
// /home/xkeyc/Games/star-citizen/drive_c/users/xkeyc/AppData/Roaming/rsilauncher/
final rsiLauncherPath = "$wineUserPath/AppData/Roaming/rsilauncher";
dPrint("rsiLauncherPath Wine:$rsiLauncherPath");
final jsonLogPath = "$rsiLauncherPath/logs/log.log";
return jsonLogPath;
}
Map<String, String> envVars = Platform.environment;
final appDataPath = envVars["appdata"];
if (appDataPath == null) {
@ -18,6 +29,14 @@ class SCLoggerHelper {
}
static Future<String?> getShaderCachePath() async {
if (!Platform.isWindows) {
final wineUserPath = await getWineUserPath();
if (wineUserPath == null) return null;
// /home/xkeyc/Games/star-citizen/drive_c/users/xkeyc/AppData/Local/star citizen/
final scCachePath = "$wineUserPath/AppData/Local/star citizen";
dPrint("getShaderCachePath Wine === $scCachePath");
return scCachePath;
}
Map<String, String> envVars = Platform.environment;
final appDataPath = envVars["LOCALAPPDATA"];
if (appDataPath == null) {
@ -28,34 +47,55 @@ class SCLoggerHelper {
return scCachePath;
}
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 (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<String?> getWineUserPath() async {
// get game path in hiveBox
final confBox = await Hive.openBox("app_conf");
final path = confBox.get("custom_game_path");
if (path?.isEmpty ?? true) return null;
// path eg: /home/xkeyc/Games/star-citizen/drive_c/Program Files/Roberts Space Industries/StarCitizen/LIVE/
// resolve wine c_drive path
final wineCDrivePath = path.toString().split('/drive_c/').first;
// scan wine user path == current_unix_user
final wineUserPath = "$wineCDrivePath/drive_c/users/${Platform.environment['USER']}";
// check exists
final wineUserDir = Directory(wineUserPath);
if (!await wineUserDir.exists()) return null;
dPrint("getWineUserPath === $wineUserPath");
return wineUserPath;
}
static Future<List<String>> getGameInstallPath(List listData,
{bool checkExists = true,
List<String> withVersion = const ["LIVE"]}) async {
static Future<List?> getLauncherLogList() async {
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 [];
}
}
static Future<List<String>> getGameInstallPath(
List listData, {
bool checkExists = true,
List<String> withVersion = const ["LIVE"],
}) async {
List<String> scInstallPaths = [];
checkAndAddPath(String path, bool checkExists) async {
if (path.isNotEmpty && !scInstallPaths.contains(path)) {
// Handle JSON-escaped backslashes (\\\\) -> single backslash (\\)
path = path.replaceAll(r'\\', r'\');
// Normalize path separators to current platform format
path = path.platformPath;
// Case-insensitive check for existing paths
if (path.isNotEmpty && !scInstallPaths.any((p) => p.toLowerCase() == path.toLowerCase())) {
if (!checkExists) {
dPrint("find installPath == $path");
scInstallPaths.add(path);
} else if (await File("$path/Bin64/StarCitizen.exe").exists() &&
await File("$path/Data.p4k").exists()) {
} else if (await File("$path/Bin64/StarCitizen.exe").exists() && await File("$path/Data.p4k").exists()) {
dPrint("find installPath == $path");
scInstallPaths.add(path);
}
@ -66,26 +106,50 @@ class SCLoggerHelper {
final path = confBox.get("custom_game_path");
if (path != null && path != "") {
for (var v in withVersion) {
await checkAndAddPath("$path\\$v", checkExists);
await checkAndAddPath("$path\\$v".platformPath, checkExists);
}
}
try {
for (var v in withVersion) {
// Platform-specific regex patterns for game install path detection
// Uses restrictive character class to avoid matching across JSON delimiters
String pattern;
if (Platform.isWindows) {
// Windows: Match paths like C:\...\StarCitizen\LIVE
// Path segments can only contain: letters, numbers, space, dot, underscore, hyphen, parentheses
// Handles both single backslash, forward slash, and JSON-escaped double backslash
pattern =
r'([a-zA-Z]:(?:[/\\]|\\\\)(?:[a-zA-Z0-9 ._()-]+(?:[/\\]|\\\\))*StarCitizen(?:[/\\]|\\\\)' + v + r')';
} else {
// Unix (Wine): Match paths like /home/user/.../StarCitizen/LIVE
pattern = r'(/(?:[a-zA-Z0-9 ._()-]+/)*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) {
final suffix = '\\$v'.platformPath.toLowerCase();
if (fileName.toString().toLowerCase().endsWith(suffix)) {
for (var nv in withVersion) {
final basePath = fileName.toString().replaceAll(
RegExp('${RegExp.escape(suffix)}\$', caseSensitive: false),
'',
);
final nextName = "$basePath\\$nv".platformPath;
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);
}
}
}
@ -94,22 +158,17 @@ 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;
}
return scInstallPaths;
static String getGameChannelID(String installPath) {
final pathLower = installPath.platformPath.toLowerCase();
for (var value in AppConf.gameChannels) {
if (pathLower.endsWith('\\${value.toLowerCase()}'.platformPath)) {
return value.toUpperCase();
}
}
return "UNKNOWN";
}
static Future<List<String>?> getGameRunningLogs(String gameDir) async {
@ -117,8 +176,7 @@ class SCLoggerHelper {
if (!await logFile.exists()) {
return null;
}
return await logFile.readAsLines(
encoding: const Utf8Codec(allowMalformed: true));
return await logFile.readAsLines(encoding: const Utf8Codec(allowMalformed: true));
}
static MapEntry<String, String>? getGameRunningLogInfo(List<String> logs) {
@ -134,42 +192,47 @@ class SCLoggerHelper {
static MapEntry<String, String>? _checkRunningLine(String line) {
if (line.contains("STATUS_CRYENGINE_OUT_OF_SYSMEM")) {
return MapEntry(S.current.doctor_game_error_low_memory,
S.current.doctor_game_error_low_memory_info);
return MapEntry(S.current.doctor_game_error_low_memory, S.current.doctor_game_error_low_memory_info);
}
if (line.contains("EXCEPTION_ACCESS_VIOLATION")) {
return MapEntry(S.current.doctor_game_error_generic_info,
"https://docs.qq.com/doc/DUURxUVhzTmZoY09Z");
return MapEntry(S.current.doctor_game_error_generic_info, "https://docs.qq.com/doc/DUURxUVhzTmZoY09Z");
}
if (line.contains("DXGI_ERROR_DEVICE_REMOVED")) {
return MapEntry(S.current.doctor_game_error_gpu_crash,
"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 MapEntry(S.current.doctor_game_error_socket_error,
S.current.doctor_game_error_socket_error_info);
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 MapEntry(S.current.doctor_game_error_permissions_error,
S.current.doctor_game_error_permissions_error_info);
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 MapEntry(S.current.doctor_game_error_game_process_error,
S.current.doctor_game_error_game_process_error_info);
if (line.contains("The process cannot access the file because is is being used by another process")) {
return MapEntry(
S.current.doctor_game_error_game_process_error,
S.current.doctor_game_error_game_process_error_info,
);
}
if (line.contains("0xc0000043")) {
return MapEntry(S.current.doctor_game_error_game_damaged_file,
S.current.doctor_game_error_game_damaged_file_info);
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 MapEntry(S.current.doctor_game_error_game_damaged_p4k_file,
S.current.doctor_game_error_game_damaged_p4k_file_info);
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 MapEntry(S.current.doctor_game_error_low_gpu_memory,
S.current.doctor_game_error_low_gpu_memory_info);
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,92 +1,49 @@
import 'dart:io';
import 'package:hive/hive.dart';
import 'package:hive_ce/hive.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/rust/api/win32_api.dart' as win32;
class SystemHelper {
static String powershellPath = "powershell.exe";
static initPowershellPath() async {
try {
var result = await Process.run(powershellPath, ["echo", "ping"]);
if (!result.stdout.toString().startsWith("ping") &&
powershellPath == "powershell.exe") {
throw "powershell check failed";
}
} catch (e) {
Map<String, String> envVars = Platform.environment;
final systemRoot = envVars["SYSTEMROOT"];
if (systemRoot != null) {
final autoSearchPath =
"$systemRoot\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
dPrint("auto search powershell path === $autoSearchPath");
powershellPath = autoSearchPath;
}
}
}
static Future<bool> checkNvmePatchStatus() async {
try {
var result = await Process.run(SystemHelper.powershellPath, [
"Get-ItemProperty",
"-Path",
"\"HKLM:\\SYSTEM\\CurrentControlSet\\Services\\stornvme\\Parameters\\Device\"",
"-Name",
"\"ForcedPhysicalSectorSizeInBytes\""
]);
dPrint("checkNvmePatchStatus result ==== ${result.stdout}");
if (result.stderr == "" &&
result.stdout.toString().contains("{* 4095}")) {
return true;
} else {
return false;
}
return await win32.checkNvmePatchStatus();
} catch (e) {
dPrint("checkNvmePatchStatus error: $e");
return false;
}
}
static Future<String> addNvmePatch() async {
var result = await Process.run(powershellPath, [
'New-ItemProperty',
"-Path",
"\"HKLM:\\SYSTEM\\CurrentControlSet\\Services\\stornvme\\Parameters\\Device\"",
"-Name",
"ForcedPhysicalSectorSizeInBytes",
"-PropertyType MultiString",
"-Force -Value",
"\"* 4095\""
]);
dPrint("nvme_PhysicalBytes result == ${result.stdout}");
return result.stderr;
try {
await win32.addNvmePatch();
return "";
} catch (e) {
dPrint("addNvmePatch error: $e");
return e.toString();
}
}
static doRemoveNvmePath() async {
static Future<bool> doRemoveNvmePath() async {
try {
var result = await Process.run(powershellPath, [
"Clear-ItemProperty",
"-Path",
"\"HKLM:\\SYSTEM\\CurrentControlSet\\Services\\stornvme\\Parameters\\Device\"",
"-Name",
"\"ForcedPhysicalSectorSizeInBytes\""
]);
dPrint("doRemoveNvmePath result ==== ${result.stdout}");
if (result.stderr == "") {
await win32.removeNvmePatch();
return true;
} else {
return false;
}
} catch (e) {
dPrint("doRemoveNvmePath error: $e");
return false;
}
}
/// 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".platformPath, "")}\\".platformPath;
}
return path;
}
}
@ -97,39 +54,44 @@ class SystemHelper {
"$programDataPath\\Microsoft\\Windows\\Start Menu\\Programs\\Roberts Space Industries\\RSI Launcher.lnk";
final rsiLinkFile = File(rsiFilePath);
if (await rsiLinkFile.exists()) {
final r = await Process.run(SystemHelper.powershellPath, [
"(New-Object -ComObject WScript.Shell).CreateShortcut(\"$rsiFilePath\").targetpath"
]);
if (r.stdout.toString().contains("RSI Launcher.exe")) {
final start = r.stdout.toString().split("RSI Launcher.exe");
try {
final targetPath = await win32.resolveShortcut(lnkPath: rsiFilePath);
if (targetPath.contains("RSI Launcher.exe")) {
final start = targetPath.split("RSI Launcher.exe");
if (skipEXE) {
return start[0];
}
return "${start[0]}RSI Launcher.exe";
}
} catch (e) {
dPrint("resolveShortcut error: $e");
}
}
return "";
}
static killRSILauncher() async {
var psr = await Process.run(
powershellPath, ["ps", "\"RSI Launcher\"", "|select -expand id"]);
if (psr.stderr == "") {
for (var value in (psr.stdout ?? "").toString().split("\n")) {
dPrint(value);
if (value != "") {
Process.killPid(int.parse(value));
}
static Future<void> killRSILauncher() async {
var pList = await getPID("RSI Launcher");
for (var pid in pList) {
try {
Process.killPid(pid);
} catch (e) {
dPrint("killRSILauncher Error: $e");
}
}
}
static Future<List<String>> getPID(String name) async {
final r = await Process.run(powershellPath, ["(ps $name).Id"]);
final str = r.stdout.toString().trim();
dPrint(str);
if (str.isEmpty) return [];
return str.split("\n");
static Future<List<int>> getPID(String name) async {
try {
final pList = await win32.getProcessListByName(processName: name);
return pList.map((e) => e.pid).toList();
} catch (e) {
dPrint("getPID Error: $e");
return [];
}
}
static checkAndLaunchRSILauncher(String path) async {
static Future<void> checkAndLaunchRSILauncher(String path) async {
// check running and kill
await killRSILauncher();
// launch
@ -137,65 +99,84 @@ class SystemHelper {
if (processorAffinity == null) {
Process.run(path, []);
} else {
Process.run("cmd.exe", [
'/C',
'Start',
'""',
'/High',
'/Affinity',
processorAffinity,
path,
]);
Process.run("cmd.exe", ['/C', 'Start', '""', '/High', '/Affinity', processorAffinity, path]);
}
dPrint(path);
}
static Future<int> getSystemMemorySizeGB() async {
final r = await Process.run(powershellPath, [
"(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb"
]);
return int.tryParse(r.stdout.toString().trim()) ?? 0;
try {
final memoryGb = await win32.getSystemMemorySizeGb();
return memoryGb.toInt();
} catch (e) {
dPrint("getSystemMemorySizeGB error: $e");
return 0;
}
}
static Future<String> getSystemCimInstance(String win32InstanceName,
{pathName = "Name"}) async {
final r = await Process.run(
powershellPath, ["(Get-CimInstance $win32InstanceName).$pathName"]);
return r.stdout.toString().trim();
static Future<String> getSystemCimInstance(String win32InstanceName, {pathName = "Name"}) async {
// This method is deprecated, use getSystemInfo() instead
try {
final sysInfo = await win32.getSystemInfo();
if (win32InstanceName.contains("OperatingSystem")) {
return sysInfo.osName;
} else if (win32InstanceName.contains("Processor")) {
return sysInfo.cpuName;
} else if (win32InstanceName.contains("VideoController")) {
return sysInfo.gpuInfo;
} else if (win32InstanceName.contains("DiskDrive")) {
return sysInfo.diskInfo;
}
} catch (e) {
dPrint("getSystemCimInstance error: $e");
}
return "";
}
static Future<String> getSystemName() async {
final r = await Process.run(
powershellPath, ["(Get-ComputerInfo | Select-Object -expand OsName)"]);
return r.stdout.toString().trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.osName;
} catch (e) {
dPrint("getSystemName error: $e");
return "";
}
}
static Future<String> getCpuName() async {
final r = await Process.run(
powershellPath, ["(Get-WmiObject -Class Win32_Processor).Name"]);
return r.stdout.toString().trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.cpuName;
} catch (e) {
dPrint("getCpuName error: $e");
return "";
}
}
static Future<String> getGpuInfo() async {
const cmd = r"""
$adapterMemory = (Get-ItemProperty -Path "HKLM:\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0*" -Name "HardwareInformation.AdapterString", "HardwareInformation.qwMemorySize" -Exclude PSPath -ErrorAction SilentlyContinue)
foreach ($adapter in $adapterMemory) {
[PSCustomObject] @{
Model=$adapter."HardwareInformation.AdapterString"
"VRAM (GB)"=[math]::round($adapter."HardwareInformation.qwMemorySize"/1GB)
try {
// Try registry first for more accurate VRAM info
final regInfo = await win32.getGpuInfoFromRegistry();
if (regInfo.isNotEmpty) {
return regInfo;
}
// Fallback to WMI
final sysInfo = await win32.getSystemInfo();
return sysInfo.gpuInfo;
} catch (e) {
dPrint("getGpuInfo error: $e");
return "";
}
""";
final r = await Process.run(powershellPath, [cmd]);
return r.stdout.toString().trim();
}
static Future<String> getDiskInfo() async {
return (await Process.run(powershellPath,
["Get-PhysicalDisk | format-table BusType,FriendlyName,Size"]))
.stdout
.toString()
.trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.diskInfo;
} catch (e) {
dPrint("getDiskInfo error: $e");
return "";
}
}
static Future<int> getDirLen(String path, {List<String>? skipPath}) async {
@ -222,17 +203,17 @@ foreach ($adapter in $adapterMemory) {
}
static Future<int> getNumberOfLogicalProcessors() async {
final cpuNumberResult = await Process.run(powershellPath,
["(Get-WmiObject -Class Win32_Processor).NumberOfLogicalProcessors"]);
if (cpuNumberResult.exitCode != 0) return 0;
return int.tryParse(cpuNumberResult.stdout.toString().trim()) ?? 0;
try {
return await win32.getNumberOfLogicalProcessors();
} catch (e) {
dPrint("getNumberOfLogicalProcessors error: $e");
return 0;
}
}
static Future<String?> getCpuAffinity() async {
final confBox = await Hive.openBox("app_conf");
final eCoreCount = int.tryParse(
confBox.get("gameLaunch_eCore_count", defaultValue: "0")) ??
0;
final eCoreCount = int.tryParse(confBox.get("gameLaunch_eCore_count", defaultValue: "0")) ?? 0;
final cpuNumber = await getNumberOfLogicalProcessors();
if (cpuNumber == 0 || eCoreCount == 0 || eCoreCount > cpuNumber) {
return null;
@ -249,21 +230,26 @@ foreach ($adapter in $adapterMemory) {
final binaryString = sb.toString();
int hexDigits = (binaryString.length / 4).ceil();
dPrint("Affinity sb ==== $sb");
return int.parse(binaryString, radix: 2)
.toRadixString(16)
.padLeft(hexDigits, '0')
.toUpperCase();
return int.parse(binaryString, radix: 2).toRadixString(16).padLeft(hexDigits, '0').toUpperCase();
}
static Future openDir(path) async {
static Future openDir(dynamic path, {bool isFile = false}) async {
dPrint("SystemHelper.openDir path === $path");
await Process.run(
SystemHelper.powershellPath, ["explorer.exe", "/select,\"\"$path\"\""]);
if (Platform.isWindows) {
try {
await win32.openDirWithExplorer(path: path.toString(), isFile: isFile);
} catch (e) {
dPrint("openDir error: $e");
}
}
}
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

@ -0,0 +1,839 @@
import 'dart:io';
import 'dart:convert';
import 'dart:isolate';
import 'package:starcitizen_doctor/common/helper/game_log_analyzer.dart';
///
class YearlyReportData {
//
final int totalLaunchCount; //
final Duration totalPlayTime; //
final int yearlyLaunchCount; //
final Duration yearlyPlayTime; //
final int totalCrashCount; //
final int yearlyCrashCount; //
//
final DateTime? yearlyFirstLaunchTime; //
final DateTime? earliestPlayDate; // (05:00)
final DateTime? latestPlayDate; // (04:00)
//
final Duration? longestSession; //
final DateTime? longestSessionDate; //
final Duration? shortestSession; // (5)
final DateTime? shortestSessionDate; //
final Duration? averageSessionTime; //
//
final int yearlyVehicleDestructionCount; //
final String? mostDestroyedVehicle; //
final int mostDestroyedVehicleCount; //
final String? mostPilotedVehicle; //
final int mostPilotedVehicleCount; //
//
final int accountCount; //
final String? mostPlayedAccount; //
final int mostPlayedAccountSessionCount; //
//
final List<MapEntry<String, int>> topLocations; // Top 访
// (K/D)
final int yearlyKillCount; //
final int yearlyDeathCount; //
final int yearlySelfKillCount; //
//
final int? mostPlayedMonth; // (1-12)
final int mostPlayedMonthCount; //
final int? leastPlayedMonth; // (1-12, )
final int leastPlayedMonthCount; //
// /线
final int longestPlayStreak; //
final DateTime? playStreakStartDate; //
final DateTime? playStreakEndDate; //
final int longestOfflineStreak; // 线
final DateTime? offlineStreakStartDate; // 线
final DateTime? offlineStreakEndDate; // 线
// ()
final Map<String, int> vehiclePilotedDetails; //
final Map<String, int> accountSessionDetails; //
final Map<String, int> locationDetails; // 访
const YearlyReportData({
required this.totalLaunchCount,
required this.totalPlayTime,
required this.yearlyLaunchCount,
required this.yearlyPlayTime,
required this.totalCrashCount,
required this.yearlyCrashCount,
this.yearlyFirstLaunchTime,
this.earliestPlayDate,
this.latestPlayDate,
this.longestSession,
this.longestSessionDate,
this.shortestSession,
this.shortestSessionDate,
this.averageSessionTime,
required this.yearlyVehicleDestructionCount,
this.mostDestroyedVehicle,
required this.mostDestroyedVehicleCount,
this.mostPilotedVehicle,
required this.mostPilotedVehicleCount,
required this.accountCount,
this.mostPlayedAccount,
required this.mostPlayedAccountSessionCount,
required this.topLocations,
required this.yearlyKillCount,
required this.yearlyDeathCount,
required this.yearlySelfKillCount,
this.mostPlayedMonth,
required this.mostPlayedMonthCount,
this.leastPlayedMonth,
required this.leastPlayedMonthCount,
required this.longestPlayStreak,
this.playStreakStartDate,
this.playStreakEndDate,
required this.longestOfflineStreak,
this.offlineStreakStartDate,
this.offlineStreakEndDate,
required this.vehiclePilotedDetails,
required this.accountSessionDetails,
required this.locationDetails,
});
/// DateTime UTC
static int? _toUtcTimestamp(DateTime? dateTime) {
if (dateTime == null) return null;
return dateTime.toUtc().millisecondsSinceEpoch;
}
/// JSON Map
///
/// 使 UTC (int) timezoneOffsetMinutes
Map<String, dynamic> toJson() {
final now = DateTime.now();
final offset = now.timeZoneOffset;
return {
//
'generatedAtUtc': _toUtcTimestamp(now),
'timezoneOffsetMinutes': offset.inMinutes,
//
'totalLaunchCount': totalLaunchCount,
'totalPlayTimeMs': totalPlayTime.inMilliseconds,
'yearlyLaunchCount': yearlyLaunchCount,
'yearlyPlayTimeMs': yearlyPlayTime.inMilliseconds,
'totalCrashCount': totalCrashCount,
'yearlyCrashCount': yearlyCrashCount,
// (UTC )
'yearlyFirstLaunchTimeUtc': _toUtcTimestamp(yearlyFirstLaunchTime),
'earliestPlayDateUtc': _toUtcTimestamp(earliestPlayDate),
'latestPlayDateUtc': _toUtcTimestamp(latestPlayDate),
//
'longestSessionMs': longestSession?.inMilliseconds,
'longestSessionDateUtc': _toUtcTimestamp(longestSessionDate),
'shortestSessionMs': shortestSession?.inMilliseconds,
'shortestSessionDateUtc': _toUtcTimestamp(shortestSessionDate),
'averageSessionTimeMs': averageSessionTime?.inMilliseconds,
//
'yearlyVehicleDestructionCount': yearlyVehicleDestructionCount,
'mostDestroyedVehicle': mostDestroyedVehicle,
'mostDestroyedVehicleCount': mostDestroyedVehicleCount,
'mostPilotedVehicle': mostPilotedVehicle,
'mostPilotedVehicleCount': mostPilotedVehicleCount,
//
'accountCount': accountCount,
'mostPlayedAccount': mostPlayedAccount,
'mostPlayedAccountSessionCount': mostPlayedAccountSessionCount,
//
'topLocations': topLocations.map((e) => {'location': e.key, 'count': e.value}).toList(),
//
'yearlyKillCount': yearlyKillCount,
'yearlyDeathCount': yearlyDeathCount,
'yearlySelfKillCount': yearlySelfKillCount,
//
'mostPlayedMonth': mostPlayedMonth,
'mostPlayedMonthCount': mostPlayedMonthCount,
'leastPlayedMonth': leastPlayedMonth,
'leastPlayedMonthCount': leastPlayedMonthCount,
// /线
'longestPlayStreak': longestPlayStreak,
'playStreakStartDateUtc': _toUtcTimestamp(playStreakStartDate),
'playStreakEndDateUtc': _toUtcTimestamp(playStreakEndDate),
'longestOfflineStreak': longestOfflineStreak,
'offlineStreakStartDateUtc': _toUtcTimestamp(offlineStreakStartDate),
'offlineStreakEndDateUtc': _toUtcTimestamp(offlineStreakEndDate),
//
'vehiclePilotedDetails': vehiclePilotedDetails,
'accountSessionDetails': accountSessionDetails,
'locationDetails': locationDetails,
};
}
@override
String toString() {
return '''YearlyReportData(
totalLaunchCount: $totalLaunchCount,
totalPlayTime: $totalPlayTime,
yearlyLaunchCount: $yearlyLaunchCount,
yearlyPlayTime: $yearlyPlayTime,
totalCrashCount: $totalCrashCount,
yearlyCrashCount: $yearlyCrashCount,
yearlyFirstLaunchTime: $yearlyFirstLaunchTime,
earliestPlayDate: $earliestPlayDate,
latestPlayDate: $latestPlayDate,
longestSession: $longestSession (on $longestSessionDate),
shortestSession: $shortestSession (on $shortestSessionDate),
averageSessionTime: $averageSessionTime,
yearlyVehicleDestructionCount: $yearlyVehicleDestructionCount,
mostDestroyedVehicle: $mostDestroyedVehicle ($mostDestroyedVehicleCount),
mostPilotedVehicle: $mostPilotedVehicle ($mostPilotedVehicleCount),
accountCount: $accountCount,
mostPlayedAccount: $mostPlayedAccount ($mostPlayedAccountSessionCount),
topLocations: ${topLocations.take(5).map((e) => '${e.key}: ${e.value}').join(', ')},
)''';
}
}
/// (使)
class _LogFileStats {
DateTime? startTime;
DateTime? endTime;
bool hasCrash = false;
int killCount = 0;
int deathCount = 0;
int selfKillCount = 0;
Set<String> playerNames = {};
String? currentPlayerName;
String? firstPlayerName; //
// : (ID后) ->
Map<String, int> vehicleDestruction = {};
// : (ID后) ->
Map<String, int> vehiclePiloted = {};
// 访: ->
Map<String, int> locationVisits = {};
// ( 2s )
DateTime? _lastDeathTime;
//
List<_SessionInfo> yearlySessions = [];
///
///
String? get uniqueKey {
if (startTime == null) return null;
final timeKey = startTime!.toUtc().toIso8601String();
final playerKey = firstPlayerName ?? 'unknown';
return '$timeKey|$playerKey';
}
}
///
class _SessionInfo {
final DateTime startTime;
final DateTime endTime;
_SessionInfo({required this.startTime, required this.endTime});
Duration get duration => endTime.difference(startTime);
}
///
class YearlyReportAnalyzer {
static final _characterNamePattern = RegExp(r'name\s+([^-]+)');
static final _vehicleDestructionPattern = RegExp(
r"Vehicle\s+'([^']+)'.*?" //
r"in zone\s+'([^']+)'.*?" // Zone
r"destroy level \d+ to (\d+).*?" //
r"caused by\s+'([^']+)'", //
);
static final _actorDeathPattern = RegExp(
r"Actor '([^']+)'.*?" // ID
r"ejected from zone '([^']+)'.*?" // /
r"to zone '([^']+)'", //
);
// Legacy ()
static final _legacyActorDeathPattern = RegExp(
r"CActor::Kill: '([^']+)'.*?" // ID
r"in zone '([^']+)'.*?" //
r"killed by '([^']+)'.*?" // ID
r"with damage type '([^']+)'", //
);
static final _requestLocationInventoryPattern = RegExp(r"Player\[([^\]]+)\].*?Location\[([^\]]+)\]");
///
static Future<_LogFileStats> _analyzeLogFile(File logFile, int targetYear) async {
final stats = _LogFileStats();
try {
if (!(await logFile.exists())) {
return stats;
}
final content = utf8.decode(await logFile.readAsBytes(), allowMalformed: true);
final lines = content.split('\n');
for (final line in lines) {
if (line.isEmpty) continue;
final lineTime = GameLogAnalyzer.getLogLineDateTime(line);
// ()
if (stats.startTime == null && lineTime != null) {
stats.startTime = lineTime;
}
// ()
if (lineTime != null) {
stats.endTime = lineTime;
}
//
if (line.contains("Cloud Imperium Games public crash handler")) {
stats.hasCrash = true;
}
//
if (line.contains('AccountLoginCharacterStatus_Character')) {
final nameMatch = _characterNamePattern.firstMatch(line);
if (nameMatch != null) {
final playerName = nameMatch.group(1)?.trim();
if (playerName != null &&
playerName.isNotEmpty &&
!playerName.contains(' ') &&
!playerName.contains('/') &&
!playerName.contains(r'\\') &&
!playerName.contains('.')) {
stats.currentPlayerName = playerName;
// ()
if (!stats.playerNames.any((n) => n.toLowerCase() == playerName.toLowerCase())) {
stats.playerNames.add(playerName);
}
stats.firstPlayerName ??= playerName;
}
}
}
//
if (lineTime != null && lineTime.year == targetYear) {
//
final destructionMatch = _vehicleDestructionPattern.firstMatch(line);
if (destructionMatch != null) {
final vehicleModel = destructionMatch.group(1);
final causedBy = destructionMatch.group(4)?.trim();
if (vehicleModel != null &&
causedBy != null &&
stats.currentPlayerName != null &&
causedBy == stats.currentPlayerName) {
final cleanVehicleName = GameLogAnalyzer.removeVehicleId(vehicleModel);
stats.vehicleDestruction[cleanVehicleName] = (stats.vehicleDestruction[cleanVehicleName] ?? 0) + 1;
}
}
//
final controlMatch = GameLogAnalyzer.vehicleControlPattern.firstMatch(line);
if (controlMatch != null) {
final vehicleName = controlMatch.group(1);
if (vehicleName != null) {
final cleanVehicleName = GameLogAnalyzer.removeVehicleId(vehicleName);
// "Default"
if (cleanVehicleName != 'Default') {
stats.vehiclePiloted[cleanVehicleName] = (stats.vehiclePiloted[cleanVehicleName] ?? 0) + 1;
}
}
}
// ()
var deathMatch = _actorDeathPattern.firstMatch(line);
if (deathMatch != null) {
final victimId = deathMatch.group(1)?.trim();
if (victimId != null && stats.currentPlayerName != null && victimId == stats.currentPlayerName) {
// (2)
if (stats._lastDeathTime == null || lineTime.difference(stats._lastDeathTime!).abs().inSeconds > 2) {
stats.deathCount++;
stats._lastDeathTime = lineTime;
}
}
}
// ( - Legacy)
final legacyDeathMatch = _legacyActorDeathPattern.firstMatch(line);
if (legacyDeathMatch != null) {
final victimId = legacyDeathMatch.group(1)?.trim();
final killerId = legacyDeathMatch.group(3)?.trim();
if (victimId != null && stats.currentPlayerName != null) {
bool isRecent =
stats._lastDeathTime != null && lineTime.difference(stats._lastDeathTime!).abs().inSeconds <= 2;
//
// selfKillCount
// deathCount + deathCount 退
if (victimId == killerId) {
if (victimId == stats.currentPlayerName) {
if (isRecent) {
// () deathCount
//
stats.selfKillCount++;
//
stats._lastDeathTime = lineTime;
} else {
// deathCount selfKillCount
stats.deathCount++;
stats.selfKillCount++;
stats._lastDeathTime = lineTime;
}
}
} else {
// ()
if (victimId == stats.currentPlayerName) {
// ()
if (!isRecent) {
stats.deathCount++;
stats._lastDeathTime = lineTime;
}
}
// ()
if (killerId == stats.currentPlayerName) {
stats.killCount++;
}
}
}
}
// 访 (RequestLocationInventory)
final locationMatch = _requestLocationInventoryPattern.firstMatch(line);
if (locationMatch != null) {
final location = locationMatch.group(2)?.trim();
if (location != null && location.isNotEmpty) {
// ID后缀
final cleanLocation = _cleanLocationName(location);
stats.locationVisits[cleanLocation] = (stats.locationVisits[cleanLocation] ?? 0) + 1;
}
}
}
}
//
if (stats.startTime != null && stats.endTime != null && stats.startTime!.year == targetYear) {
stats.yearlySessions.add(_SessionInfo(startTime: stats.startTime!, endTime: stats.endTime!));
}
} catch (e) {
// Error handled silently in isolate
}
return stats;
}
/// ID后缀
static String _cleanLocationName(String location) {
// ID ( "_12345678")
final cleanPattern = RegExp(r'_\d{6,}$');
return location.replaceAll(cleanPattern, '');
}
///
///
/// [gameInstallPaths] ( ["D:/Games/StarCitizen/LIVE", "D:/Games/StarCitizen/PTU"])
/// [targetYear]
///
/// Isolate UI
static Future<YearlyReportData> generateReport(List<String> gameInstallPaths, int targetYear) async {
// Isolate UI
return await Isolate.run(() async {
return await _generateReportInIsolate(gameInstallPaths, targetYear);
});
}
/// Isolate
static Future<YearlyReportData> _generateReportInIsolate(List<String> gameInstallPaths, int targetYear) async {
final List<File> allLogFiles = [];
//
for (final installPath in gameInstallPaths) {
try {
final installDir = Directory(installPath);
//
if (!await installDir.exists()) {
continue;
}
final gameLogFile = File('$installPath/Game.log');
final logBackupsDir = Directory('$installPath/logbackups');
// Game.log
try {
if (await gameLogFile.exists()) {
allLogFiles.add(gameLogFile);
}
} catch (_) {
//
}
//
try {
if (await logBackupsDir.exists()) {
await for (final entity in logBackupsDir.list()) {
if (entity is File && entity.path.endsWith('.log')) {
allLogFiles.add(entity);
}
}
}
} catch (_) {
//
}
} catch (_) {
//
continue;
}
}
// 使
final futures = allLogFiles.map((file) async {
try {
return await _analyzeLogFile(file, targetYear);
} catch (_) {
//
return _LogFileStats();
}
});
final allStatsRaw = await Future.wait(futures);
// : 使 uniqueKey ( + )
final seenKeys = <String>{};
final allStats = <_LogFileStats>[];
for (final stats in allStatsRaw) {
final key = stats.uniqueKey;
if (key == null) {
allStats.add(stats);
} else if (!seenKeys.contains(key)) {
seenKeys.add(key);
allStats.add(stats);
}
}
//
int totalLaunchCount = allStats.length;
Duration totalPlayTime = Duration.zero;
int yearlyLaunchCount = 0;
Duration yearlyPlayTime = Duration.zero;
int totalCrashCount = 0;
int yearlyCrashCount = 0;
DateTime? yearlyFirstLaunchTime;
DateTime? earliestPlayDate;
DateTime? latestPlayDate;
//
Duration? longestSession;
DateTime? longestSessionDate;
Duration? shortestSession;
DateTime? shortestSessionDate;
List<Duration> allSessionDurations = [];
// K/D
int yearlyKillCount = 0;
int yearlyDeathCount = 0;
int yearlySelfKillCount = 0;
final Map<String, int> vehicleDestructionDetails = {};
final Map<String, int> vehiclePilotedDetails = {};
final Map<String, int> accountSessionDetails = {};
final Map<String, int> locationDetails = {};
for (final stats in allStats) {
//
if (stats.startTime != null && stats.endTime != null) {
totalPlayTime += stats.endTime!.difference(stats.startTime!);
}
//
if (stats.hasCrash) {
totalCrashCount++;
if (stats.endTime != null && stats.endTime!.year == targetYear) {
yearlyCrashCount++;
}
}
//
for (final session in stats.yearlySessions) {
yearlyLaunchCount++;
final sessionDuration = session.duration;
yearlyPlayTime += sessionDuration;
allSessionDurations.add(sessionDuration);
//
if (yearlyFirstLaunchTime == null || session.startTime.isBefore(yearlyFirstLaunchTime)) {
yearlyFirstLaunchTime = session.startTime;
}
// (05:00)
if (session.startTime.hour >= 5) {
if (earliestPlayDate == null || _timeOfDayIsEarlier(session.startTime, earliestPlayDate)) {
earliestPlayDate = session.startTime;
}
}
// (04:00)
if (session.endTime.hour <= 4) {
if (latestPlayDate == null || _timeOfDayIsLater(session.endTime, latestPlayDate)) {
latestPlayDate = session.endTime;
}
}
//
if (longestSession == null || sessionDuration > longestSession) {
longestSession = sessionDuration;
longestSessionDate = session.startTime;
}
// (5)
if (sessionDuration.inMinutes >= 5) {
if (shortestSession == null || sessionDuration < shortestSession) {
shortestSession = sessionDuration;
shortestSessionDate = session.startTime;
}
}
}
// ( PU )
for (final entry in stats.vehicleDestruction.entries) {
if (!entry.key.contains('PU_')) {
vehicleDestructionDetails[entry.key] = (vehicleDestructionDetails[entry.key] ?? 0) + entry.value;
}
}
//
for (final entry in stats.vehiclePiloted.entries) {
vehiclePilotedDetails[entry.key] = (vehiclePilotedDetails[entry.key] ?? 0) + entry.value;
}
// K/D
yearlyKillCount += stats.killCount;
yearlyDeathCount += stats.deathCount;
yearlySelfKillCount += stats.selfKillCount;
//
for (final playerName in stats.playerNames) {
if (playerName.length > 16) continue;
String targetKey = playerName;
// key
for (final key in accountSessionDetails.keys) {
if (key.toLowerCase() == playerName.toLowerCase()) {
targetKey = key;
break;
}
}
accountSessionDetails[targetKey] = (accountSessionDetails[targetKey] ?? 0) + 1;
}
// 访
for (final entry in stats.locationVisits.entries) {
locationDetails[entry.key] = (locationDetails[entry.key] ?? 0) + entry.value;
}
}
//
Duration? averageSessionTime;
if (allSessionDurations.isNotEmpty) {
final totalMs = allSessionDurations.fold<int>(0, (sum, d) => sum + d.inMilliseconds);
averageSessionTime = Duration(milliseconds: totalMs ~/ allSessionDurations.length);
}
//
final yearlyVehicleDestructionCount = vehicleDestructionDetails.values.fold(0, (a, b) => a + b);
String? mostDestroyedVehicle;
int mostDestroyedVehicleCount = 0;
for (final entry in vehicleDestructionDetails.entries) {
if (entry.value > mostDestroyedVehicleCount) {
mostDestroyedVehicle = entry.key;
mostDestroyedVehicleCount = entry.value;
}
}
String? mostPilotedVehicle;
int mostPilotedVehicleCount = 0;
for (final entry in vehiclePilotedDetails.entries) {
if (entry.value > mostPilotedVehicleCount) {
mostPilotedVehicle = entry.key;
mostPilotedVehicleCount = entry.value;
}
}
String? mostPlayedAccount;
int mostPlayedAccountSessionCount = 0;
for (final entry in accountSessionDetails.entries) {
if (entry.value > mostPlayedAccountSessionCount) {
mostPlayedAccount = entry.key;
mostPlayedAccountSessionCount = entry.value;
}
}
// Top 10
final sortedLocations = locationDetails.entries.toList()..sort((a, b) => b.value.compareTo(a.value));
final topLocations = sortedLocations.take(10).toList();
//
final Map<int, int> monthlyPlayCount = {};
final Set<DateTime> playDates = {}; // ()
for (final stats in allStats) {
for (final session in stats.yearlySessions) {
final month = session.startTime.month;
monthlyPlayCount[month] = (monthlyPlayCount[month] ?? 0) + 1;
// ()
playDates.add(DateTime(session.startTime.year, session.startTime.month, session.startTime.day));
}
}
int? mostPlayedMonth;
int mostPlayedMonthCount = 0;
int? leastPlayedMonth;
int leastPlayedMonthCount = 0;
if (monthlyPlayCount.isNotEmpty) {
//
for (final entry in monthlyPlayCount.entries) {
if (entry.value > mostPlayedMonthCount) {
mostPlayedMonth = entry.key;
mostPlayedMonthCount = entry.value;
}
}
// ()
leastPlayedMonthCount = monthlyPlayCount.values.first;
for (final entry in monthlyPlayCount.entries) {
if (entry.value <= leastPlayedMonthCount) {
leastPlayedMonth = entry.key;
leastPlayedMonthCount = entry.value;
}
}
}
// 线
int longestPlayStreak = 0;
DateTime? playStreakStartDate;
DateTime? playStreakEndDate;
int longestOfflineStreak = 0;
DateTime? offlineStreakStartDate;
DateTime? offlineStreakEndDate;
if (playDates.isNotEmpty) {
//
final sortedDates = playDates.toList()..sort();
//
int currentStreak = 1;
DateTime streakStart = sortedDates.first;
for (int i = 1; i < sortedDates.length; i++) {
final diff = sortedDates[i].difference(sortedDates[i - 1]).inDays;
if (diff == 1) {
currentStreak++;
} else {
if (currentStreak > longestPlayStreak) {
longestPlayStreak = currentStreak;
playStreakStartDate = streakStart;
playStreakEndDate = sortedDates[i - 1];
}
currentStreak = 1;
streakStart = sortedDates[i];
}
}
//
if (currentStreak > longestPlayStreak) {
longestPlayStreak = currentStreak;
playStreakStartDate = streakStart;
playStreakEndDate = sortedDates.last;
}
// 线 ()
for (int i = 1; i < sortedDates.length; i++) {
final gapDays = sortedDates[i].difference(sortedDates[i - 1]).inDays - 1;
if (gapDays > longestOfflineStreak) {
longestOfflineStreak = gapDays;
offlineStreakStartDate = sortedDates[i - 1].add(const Duration(days: 1));
offlineStreakEndDate = sortedDates[i].subtract(const Duration(days: 1));
}
}
}
return YearlyReportData(
totalLaunchCount: totalLaunchCount,
totalPlayTime: totalPlayTime,
yearlyLaunchCount: yearlyLaunchCount,
yearlyPlayTime: yearlyPlayTime,
totalCrashCount: totalCrashCount,
yearlyCrashCount: yearlyCrashCount,
yearlyFirstLaunchTime: yearlyFirstLaunchTime,
earliestPlayDate: earliestPlayDate,
latestPlayDate: latestPlayDate,
longestSession: longestSession,
longestSessionDate: longestSessionDate,
shortestSession: shortestSession,
shortestSessionDate: shortestSessionDate,
averageSessionTime: averageSessionTime,
yearlyVehicleDestructionCount: yearlyVehicleDestructionCount,
mostDestroyedVehicle: mostDestroyedVehicle,
mostDestroyedVehicleCount: mostDestroyedVehicleCount,
mostPilotedVehicle: mostPilotedVehicle,
mostPilotedVehicleCount: mostPilotedVehicleCount,
accountCount: accountSessionDetails.length,
mostPlayedAccount: mostPlayedAccount,
mostPlayedAccountSessionCount: mostPlayedAccountSessionCount,
topLocations: topLocations,
yearlyKillCount: yearlyKillCount,
yearlyDeathCount: yearlyDeathCount,
yearlySelfKillCount: yearlySelfKillCount,
mostPlayedMonth: mostPlayedMonth,
mostPlayedMonthCount: mostPlayedMonthCount,
leastPlayedMonth: leastPlayedMonth,
leastPlayedMonthCount: leastPlayedMonthCount,
longestPlayStreak: longestPlayStreak,
playStreakStartDate: playStreakStartDate,
playStreakEndDate: playStreakEndDate,
longestOfflineStreak: longestOfflineStreak,
offlineStreakStartDate: offlineStreakStartDate,
offlineStreakEndDate: offlineStreakEndDate,
vehiclePilotedDetails: vehiclePilotedDetails,
accountSessionDetails: accountSessionDetails,
locationDetails: locationDetails,
);
}
/// :
static bool _timeOfDayIsEarlier(DateTime a, DateTime b) {
if (a.hour < b.hour) return true;
if (a.hour > b.hour) return false;
return a.minute < b.minute;
}
/// :
static bool _timeOfDayIsLater(DateTime a, DateTime b) {
if (a.hour > b.hour) return true;
if (a.hour < b.hour) return false;
return a.minute > b.minute;
}
}

View File

@ -0,0 +1,46 @@
import 'dart:convert';
import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/data/doh_client_response_data.dart';
class DohClient {
static Future<DohClientResponseData?> resolve(
String domain, String type) async {
try {
final r = await RSHttp.getText(
"${ConstConf.dohAddress}?name=$domain&type=$type");
final data = DohClientResponseData.fromJson(json.decode(r));
return data;
} catch (e) {
dPrint("DohClient.resolve error: $e");
return null;
}
}
static Future<List<String>?> resolveIP(String domain, String type) async {
final data = await resolve(domain, type);
if (data == null) return [];
return data.answer?.map((e) => _removeDataPadding(e.data)).toList();
}
static Future<List<String>?> resolveTXT(String domain) async {
final data = await resolve(domain, "TXT");
if (data == null) return [];
return data.answer?.map((e) => _removeDataPadding(e.data)).toList();
}
static String _removeDataPadding(String? data) {
// data demo: {"data":"\"https://git.scbox.xkeyc.cn,https://gitapi.scbox.org\""}
if (data == null) return "";
data = data.trim();
if (data.startsWith("\"")) {
data = data.substring(1);
}
if (data.endsWith("\"")) {
data = data.substring(0, data.length - 1);
}
return data;
}
}

View File

@ -1,42 +1,58 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/conf/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';
class RSHttp {
static init() async {
static Future<void> init() async {
await rust_http.setDefaultHeader(headers: {
"User-Agent":
"SCToolBox/${ConstConf.appVersion} (${ConstConf.appVersionCode})${ConstConf.isMSE ? "" : " DEV"} RSHttp"
});
}
static Future<RustHttpResponse> get(String url,
{Map<String, String>? headers, String? withIpAddress}) async {
static Future<RustHttpResponse> get(
String url, {
Map<String, String>? headers,
String? withIpAddress,
bool? withCustomDns,
}) async {
final r = await rust_http.fetch(
method: MyMethod.gets,
url: url,
headers: headers,
withIpAddress: withIpAddress);
withIpAddress: withIpAddress,
withCustomDns: withCustomDns,
);
return r;
}
static Future<String> getText(String url,
{Map<String, String>? headers, String? withIpAddress}) async {
final r = await get(url, headers: headers, withIpAddress: withIpAddress);
static Future<String> getText(
String url, {
Map<String, String>? headers,
String? withIpAddress,
bool? withCustomDns,
}) async {
final r = await get(url,
headers: headers,
withIpAddress: withIpAddress,
withCustomDns: withCustomDns);
if (r.data == null) return "";
final str = utf8.decode(r.data!);
return str;
}
static Future<RustHttpResponse> postData(String url,
{Map<String, String>? headers,
static Future<RustHttpResponse> postData(
String url, {
Map<String, String>? headers,
String? contentType,
Uint8List? data,
String? withIpAddress}) async {
String? withIpAddress,
bool? withCustomDns,
}) async {
if (contentType != null) {
headers ??= {};
headers["Content-Type"] = contentType;
@ -46,17 +62,25 @@ class RSHttp {
url: url,
headers: headers,
inputData: data,
withIpAddress: withIpAddress);
withIpAddress: withIpAddress,
withCustomDns: withCustomDns,
);
return r;
}
static Future<RustHttpResponse> head(String url,
{Map<String, String>? headers, String? withIpAddress}) async {
static Future<RustHttpResponse> head(
String url, {
Map<String, String>? headers,
String? withIpAddress,
bool? withCustomDns,
}) async {
final r = await rust_http.fetch(
method: MyMethod.head,
url: url,
headers: headers,
withIpAddress: withIpAddress);
withIpAddress: withIpAddress,
withCustomDns: withCustomDns,
);
return r;
}

View File

@ -0,0 +1,68 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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 function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt`
/// Check if the URL scheme is already registered with the correct executable path
Future<ApplinksRegistrationResult> checkApplinksRegistration({
required String scheme,
}) => RustLib.instance.api.crateApiApplinksApiCheckApplinksRegistration(
scheme: scheme,
);
/// Register URL scheme in Windows registry
/// This will create or update the registry keys for the custom URL scheme
///
/// # Arguments
/// * `scheme` - The URL scheme to register (e.g., "sctoolbox")
/// * `app_name` - Optional application display name (e.g., "SCToolBox"). If provided,
/// the registry will show "URL:{app_name} Protocol" as the scheme description.
Future<ApplinksRegistrationResult> registerApplinks({
required String scheme,
String? appName,
}) => RustLib.instance.api.crateApiApplinksApiRegisterApplinks(
scheme: scheme,
appName: appName,
);
/// Unregister URL scheme from Windows registry
Future<ApplinksRegistrationResult> unregisterApplinks({
required String scheme,
}) =>
RustLib.instance.api.crateApiApplinksApiUnregisterApplinks(scheme: scheme);
/// Applinks URL scheme registration result
class ApplinksRegistrationResult {
/// Whether registration was successful
final bool success;
/// Detailed message about the operation
final String message;
/// Whether the registry was modified (false if already configured correctly)
final bool wasModified;
const ApplinksRegistrationResult({
required this.success,
required this.message,
required this.wasModified,
});
@override
int get hashCode =>
success.hashCode ^ message.hashCode ^ wasModified.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ApplinksRegistrationResult &&
runtimeType == other.runtimeType &&
success == other.success &&
message == other.message &&
wasModified == other.wasModified;
}

View File

@ -0,0 +1,44 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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

@ -0,0 +1,284 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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`: `get_session`, `get_task_status`
// 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`, `clone`, `clone`, `eq`, `fmt`, `fmt`, `fmt`
/// Initialize the download manager session with persistence enabled
///
/// Parameters:
/// - working_dir: The directory to store session data (persistence, DHT, etc.)
/// - default_download_dir: The default directory to store downloads
/// - upload_limit_bps: Upload speed limit in bytes per second (0 = unlimited)
/// - download_limit_bps: Download speed limit in bytes per second (0 = unlimited)
Future<void> downloaderInit({
required String workingDir,
required String defaultDownloadDir,
int? uploadLimitBps,
int? downloadLimitBps,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderInit(
workingDir: workingDir,
defaultDownloadDir: defaultDownloadDir,
uploadLimitBps: uploadLimitBps,
downloadLimitBps: downloadLimitBps,
);
/// Check if the downloader is initialized
bool downloaderIsInitialized() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderIsInitialized();
/// Check if there are pending tasks to restore from session file (without starting the downloader)
/// This reads the session.json file directly to check if there are any torrents saved.
///
/// Parameters:
/// - working_dir: The directory where session data is stored (same as passed to downloader_init)
///
/// Returns: true if there are tasks to restore, false otherwise
bool downloaderHasPendingSessionTasks({required String workingDir}) =>
RustLib.instance.api.crateApiDownloaderApiDownloaderHasPendingSessionTasks(
workingDir: workingDir,
);
/// Add a torrent from bytes (e.g., .torrent file content)
Future<BigInt> downloaderAddTorrent({
required List<int> torrentBytes,
String? outputFolder,
List<String>? trackers,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddTorrent(
torrentBytes: torrentBytes,
outputFolder: outputFolder,
trackers: trackers,
);
/// Add a torrent from a magnet link
Future<BigInt> downloaderAddMagnet({
required String magnetLink,
String? outputFolder,
List<String>? trackers,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddMagnet(
magnetLink: magnetLink,
outputFolder: outputFolder,
trackers: trackers,
);
/// Add a torrent from URL (HTTP download not supported, only torrent file URLs)
Future<BigInt> downloaderAddUrl({
required String url,
String? outputFolder,
List<String>? trackers,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddUrl(
url: url,
outputFolder: outputFolder,
trackers: trackers,
);
/// Pause a download task
Future<void> downloaderPause({required BigInt taskId}) =>
RustLib.instance.api.crateApiDownloaderApiDownloaderPause(taskId: taskId);
/// Resume a download task
Future<void> downloaderResume({required BigInt taskId}) =>
RustLib.instance.api.crateApiDownloaderApiDownloaderResume(taskId: taskId);
/// Remove a download task
/// Handles both active tasks (task_id < 10000) and cached completed tasks (task_id >= 10000)
Future<void> downloaderRemove({
required BigInt taskId,
required bool deleteFiles,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderRemove(
taskId: taskId,
deleteFiles: deleteFiles,
);
/// Get information about a specific task
Future<DownloadTaskInfo> downloaderGetTaskInfo({required BigInt taskId}) =>
RustLib.instance.api.crateApiDownloaderApiDownloaderGetTaskInfo(
taskId: taskId,
);
/// Get all tasks (includes both active and completed tasks from cache)
Future<List<DownloadTaskInfo>> downloaderGetAllTasks() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderGetAllTasks();
/// Get global statistics
Future<DownloadGlobalStat> downloaderGetGlobalStats() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderGetGlobalStats();
/// Check if a task with given name exists
///
/// Parameters:
/// - name: Task name to search for
/// - downloading_only: If true, only search in active/waiting tasks. If false, include completed tasks (default: true)
Future<bool> downloaderIsNameInTask({
required String name,
bool? downloadingOnly,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderIsNameInTask(
name: name,
downloadingOnly: downloadingOnly,
);
/// Pause all tasks
Future<void> downloaderPauseAll() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderPauseAll();
/// Resume all tasks
Future<void> downloaderResumeAll() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderResumeAll();
/// Stop the downloader session (pauses all tasks but keeps session)
Future<void> downloaderStop() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderStop();
/// Shutdown the downloader session completely (allows restart with new settings)
Future<void> downloaderShutdown() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderShutdown();
/// Get all completed tasks from cache (tasks removed by downloader_remove_completed_tasks)
/// This cache is cleared when the downloader is shutdown/restarted
List<DownloadTaskInfo> downloaderGetCompletedTasksCache() => RustLib
.instance
.api
.crateApiDownloaderApiDownloaderGetCompletedTasksCache();
/// Clear the completed tasks cache manually
void downloaderClearCompletedTasksCache() => RustLib.instance.api
.crateApiDownloaderApiDownloaderClearCompletedTasksCache();
/// Update global speed limits
/// Note: rqbit Session doesn't support runtime limit changes,
/// this function is a placeholder that returns an error.
/// Speed limits should be set during downloader_init.
Future<void> downloaderUpdateSpeedLimits({
int? uploadLimitBps,
int? downloadLimitBps,
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderUpdateSpeedLimits(
uploadLimitBps: uploadLimitBps,
downloadLimitBps: downloadLimitBps,
);
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
/// Removed tasks are cached in memory and can be queried via downloader_get_completed_tasks_cache
Future<int> downloaderRemoveCompletedTasks() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderRemoveCompletedTasks();
/// Check if there are any active (non-completed) tasks
Future<bool> downloaderHasActiveTasks() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderHasActiveTasks();
/// Global statistics
class DownloadGlobalStat {
final BigInt downloadSpeed;
final BigInt uploadSpeed;
final BigInt numActive;
final BigInt numWaiting;
const DownloadGlobalStat({
required this.downloadSpeed,
required this.uploadSpeed,
required this.numActive,
required this.numWaiting,
});
static Future<DownloadGlobalStat> default_() =>
RustLib.instance.api.crateApiDownloaderApiDownloadGlobalStatDefault();
@override
int get hashCode =>
downloadSpeed.hashCode ^
uploadSpeed.hashCode ^
numActive.hashCode ^
numWaiting.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is DownloadGlobalStat &&
runtimeType == other.runtimeType &&
downloadSpeed == other.downloadSpeed &&
uploadSpeed == other.uploadSpeed &&
numActive == other.numActive &&
numWaiting == other.numWaiting;
}
/// Download task information
class DownloadTaskInfo {
final BigInt id;
final String name;
final DownloadTaskStatus status;
final BigInt totalBytes;
final BigInt downloadedBytes;
final BigInt uploadedBytes;
final BigInt downloadSpeed;
final BigInt uploadSpeed;
final double progress;
final BigInt numPeers;
final String outputFolder;
const DownloadTaskInfo({
required this.id,
required this.name,
required this.status,
required this.totalBytes,
required this.downloadedBytes,
required this.uploadedBytes,
required this.downloadSpeed,
required this.uploadSpeed,
required this.progress,
required this.numPeers,
required this.outputFolder,
});
@override
int get hashCode =>
id.hashCode ^
name.hashCode ^
status.hashCode ^
totalBytes.hashCode ^
downloadedBytes.hashCode ^
uploadedBytes.hashCode ^
downloadSpeed.hashCode ^
uploadSpeed.hashCode ^
progress.hashCode ^
numPeers.hashCode ^
outputFolder.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is DownloadTaskInfo &&
runtimeType == other.runtimeType &&
id == other.id &&
name == other.name &&
status == other.status &&
totalBytes == other.totalBytes &&
downloadedBytes == other.downloadedBytes &&
uploadedBytes == other.uploadedBytes &&
downloadSpeed == other.downloadSpeed &&
uploadSpeed == other.uploadSpeed &&
progress == other.progress &&
numPeers == other.numPeers &&
outputFolder == other.outputFolder;
}
/// Download task status
enum DownloadTaskStatus {
/// Checking/verifying existing files
checking,
/// Actively downloading
live,
/// Paused
paused,
/// Error occurred
error,
/// Download completed
finished,
}

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.28.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
@ -7,39 +7,46 @@ 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<RustHttpResponse> fetch(
{required MyMethod 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,
String? withIpAddress,
dynamic hint}) =>
RustLib.instance.api.fetch(
bool? withCustomDns,
}) => RustLib.instance.api.crateApiHttpApiFetch(
method: method,
url: url,
headers: headers,
inputData: inputData,
withIpAddress: withIpAddress,
hint: hint);
withCustomDns: withCustomDns,
);
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);
Future<List<String>> dnsLookupIps({required String host, dynamic hint}) =>
RustLib.instance.api.dnsLookupIps(host: host, hint: hint);
Future<List<String>> dnsLookupIps({required String host}) =>
RustLib.instance.api.crateApiHttpApiDnsLookupIps(host: host);
enum MyMethod {
options,
gets,
post,
put,
delete,
head,
trace,
connect,
patch,
}
/// Get the fastest URL from a list of URLs by testing them concurrently.
/// Returns the first URL that responds successfully, canceling other requests.
///
/// # Arguments
/// * `urls` - List of base URLs to test
/// * `path_suffix` - Optional path suffix to append to each URL (e.g., "/api/version")
/// If None, tests the base URL directly
Future<String?> getFasterUrl({
required List<String> urls,
String? pathSuffix,
}) => RustLib.instance.api.crateApiHttpApiGetFasterUrl(
urls: urls,
pathSuffix: pathSuffix,
);
enum MyMethod { options, gets, post, put, delete, head, trace, connect, patch }

View File

@ -0,0 +1,75 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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';
/// ONNX
///
/// # Arguments
/// * `model_path` -
/// * `model_key` - "zh-en"
/// * `quantization_suffix` - "_q4", "_q8"使
/// * `use_xnnpack` - 使 XNNPACK
///
Future<void> loadTranslationModel({
required String modelPath,
required String modelKey,
required String quantizationSuffix,
required bool useXnnpack,
}) => RustLib.instance.api.crateApiOrtApiLoadTranslationModel(
modelPath: modelPath,
modelKey: modelKey,
quantizationSuffix: quantizationSuffix,
useXnnpack: useXnnpack,
);
///
///
/// # Arguments
/// * `model_key` - "zh-en"
/// * `text` -
///
/// # Returns
/// * `Result<String>` -
Future<String> translateText({
required String modelKey,
required String text,
}) => RustLib.instance.api.crateApiOrtApiTranslateText(
modelKey: modelKey,
text: text,
);
///
///
/// # Arguments
/// * `model_key` - "zh-en"
/// * `texts` -
///
/// # Returns
/// * `Result<Vec<String>>` -
Future<List<String>> translateTextBatch({
required String modelKey,
required List<String> texts,
}) => RustLib.instance.api.crateApiOrtApiTranslateTextBatch(
modelKey: modelKey,
texts: texts,
);
///
///
/// # Arguments
/// * `model_key` - "zh-en"
///
Future<void> unloadTranslationModel({required String modelKey}) => RustLib
.instance
.api
.crateApiOrtApiUnloadTranslationModel(modelKey: modelKey);
///
///
/// # Returns
Future<void> clearAllModels() =>
RustLib.instance.api.crateApiOrtApiClearAllModels();

View File

@ -1,18 +0,0 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.28.
// 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';
Stream<String> startProcess(
{required String executable,
required List<String> arguments,
required String workingDirectory,
dynamic hint}) =>
RustLib.instance.api.startProcess(
executable: executable,
arguments: arguments,
workingDirectory: workingDirectory,
hint: hint);

View File

@ -0,0 +1,50 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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 neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `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,120 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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 'unp4k_api.freezed.dart';
// These functions are ignored because they are not marked as `pub`: `dos_datetime_to_millis`, `ensure_files_loaded`, `p4k_get_entry`
/// P4K
Future<void> p4KOpen({required String p4KPath}) =>
RustLib.instance.api.crateApiUnp4KApiP4KOpen(p4KPath: p4KPath);
///
Future<BigInt> p4KGetFileCount() =>
RustLib.instance.api.crateApiUnp4KApiP4KGetFileCount();
///
Future<List<P4kFileItem>> p4KGetAllFiles() =>
RustLib.instance.api.crateApiUnp4KApiP4KGetAllFiles();
///
Future<Uint8List> p4KExtractToMemory({required String filePath}) =>
RustLib.instance.api.crateApiUnp4KApiP4KExtractToMemory(filePath: filePath);
///
Future<void> p4KExtractToDisk({
required String filePath,
required String outputPath,
}) => RustLib.instance.api.crateApiUnp4KApiP4KExtractToDisk(
filePath: filePath,
outputPath: outputPath,
);
/// P4K
Future<void> p4KClose() => RustLib.instance.api.crateApiUnp4KApiP4KClose();
/// DataForge/DCB
Future<bool> dcbIsDataforge({required List<int> data}) =>
RustLib.instance.api.crateApiUnp4KApiDcbIsDataforge(data: data);
/// DCB
Future<void> dcbOpen({required List<int> data}) =>
RustLib.instance.api.crateApiUnp4KApiDcbOpen(data: data);
/// DCB
Future<BigInt> dcbGetRecordCount() =>
RustLib.instance.api.crateApiUnp4KApiDcbGetRecordCount();
/// DCB
Future<List<DcbRecordItem>> dcbGetRecordList() =>
RustLib.instance.api.crateApiUnp4KApiDcbGetRecordList();
/// XML
Future<String> dcbRecordToXml({required String path}) =>
RustLib.instance.api.crateApiUnp4KApiDcbRecordToXml(path: path);
/// XML
Future<String> dcbRecordToXmlByIndex({required BigInt index}) =>
RustLib.instance.api.crateApiUnp4KApiDcbRecordToXmlByIndex(index: index);
/// DCB
Future<List<DcbSearchResult>> dcbSearchAll({required String query}) =>
RustLib.instance.api.crateApiUnp4KApiDcbSearchAll(query: query);
/// DCB
/// merge: true = XMLfalse = XML
Future<void> dcbExportToDisk({
required String outputPath,
required String dcbPath,
required bool merge,
}) => RustLib.instance.api.crateApiUnp4KApiDcbExportToDisk(
outputPath: outputPath,
dcbPath: dcbPath,
merge: merge,
);
/// DCB
Future<void> dcbClose() => RustLib.instance.api.crateApiUnp4KApiDcbClose();
/// DCB
@freezed
sealed class DcbRecordItem with _$DcbRecordItem {
const factory DcbRecordItem({required String path, required BigInt index}) =
_DcbRecordItem;
}
@freezed
sealed class DcbSearchMatch with _$DcbSearchMatch {
const factory DcbSearchMatch({
required BigInt lineNumber,
required String lineContent,
}) = _DcbSearchMatch;
}
/// DCB
///
@freezed
sealed class DcbSearchResult with _$DcbSearchResult {
const factory DcbSearchResult({
required String path,
required BigInt index,
required List<DcbSearchMatch> matches,
}) = _DcbSearchResult;
}
/// P4K
@freezed
sealed class P4kFileItem with _$P4kFileItem {
const factory P4kFileItem({
required String name,
required bool isDirectory,
required BigInt size,
required BigInt compressedSize,
required PlatformInt64 dateModified,
}) = _P4kFileItem;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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 'webview_api.freezed.dart';
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `WebViewCommand`
// 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`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`
/// Create a new WebView window and return its ID
String webviewCreate({required WebViewConfiguration config}) =>
RustLib.instance.api.crateApiWebviewApiWebviewCreate(config: config);
/// Navigate to a URL
void webviewNavigate({required String id, required String url}) =>
RustLib.instance.api.crateApiWebviewApiWebviewNavigate(id: id, url: url);
/// Go back in history
void webviewGoBack({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewGoBack(id: id);
/// Go forward in history
void webviewGoForward({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewGoForward(id: id);
/// Reload the current page
void webviewReload({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewReload(id: id);
/// Stop loading
void webviewStop({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewStop(id: id);
/// Execute JavaScript in the WebView
void webviewExecuteScript({required String id, required String script}) =>
RustLib.instance.api.crateApiWebviewApiWebviewExecuteScript(
id: id,
script: script,
);
/// Set window visibility
void webviewSetVisibility({required String id, required bool visible}) =>
RustLib.instance.api.crateApiWebviewApiWebviewSetVisibility(
id: id,
visible: visible,
);
/// Close the WebView window
void webviewClose({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewClose(id: id);
/// Set window size
void webviewSetWindowSize({
required String id,
required int width,
required int height,
}) => RustLib.instance.api.crateApiWebviewApiWebviewSetWindowSize(
id: id,
width: width,
height: height,
);
/// Set window position
void webviewSetWindowPosition({
required String id,
required int x,
required int y,
}) => RustLib.instance.api.crateApiWebviewApiWebviewSetWindowPosition(
id: id,
x: x,
y: y,
);
/// Get the current navigation state
WebViewNavigationState webviewGetState({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewGetState(id: id);
/// Check if the WebView is closed
bool webviewIsClosed({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewIsClosed(id: id);
/// Poll for events from the WebView (non-blocking)
List<WebViewEvent> webviewPollEvents({required String id}) =>
RustLib.instance.api.crateApiWebviewApiWebviewPollEvents(id: id);
/// Get a list of all active WebView IDs
List<String> webviewListAll() =>
RustLib.instance.api.crateApiWebviewApiWebviewListAll();
/// WebView window configuration
@freezed
sealed class WebViewConfiguration with _$WebViewConfiguration {
const WebViewConfiguration._();
const factory WebViewConfiguration({
required String title,
required int width,
required int height,
String? userDataFolder,
required bool enableDevtools,
required bool transparent,
String? userAgent,
}) = _WebViewConfiguration;
static Future<WebViewConfiguration> default_() =>
RustLib.instance.api.crateApiWebviewApiWebViewConfigurationDefault();
}
@freezed
sealed class WebViewEvent with _$WebViewEvent {
const WebViewEvent._();
const factory WebViewEvent.navigationStarted({required String url}) =
WebViewEvent_NavigationStarted;
const factory WebViewEvent.navigationCompleted({required String url}) =
WebViewEvent_NavigationCompleted;
const factory WebViewEvent.titleChanged({required String title}) =
WebViewEvent_TitleChanged;
const factory WebViewEvent.webMessage({required String message}) =
WebViewEvent_WebMessage;
const factory WebViewEvent.windowClosed() = WebViewEvent_WindowClosed;
const factory WebViewEvent.error({required String message}) =
WebViewEvent_Error;
}
/// Navigation state of the WebView
@freezed
sealed class WebViewNavigationState with _$WebViewNavigationState {
const WebViewNavigationState._();
const factory WebViewNavigationState({
required String url,
required String title,
required bool canGoBack,
required bool canGoForward,
required bool isLoading,
}) = _WebViewNavigationState;
static Future<WebViewNavigationState> default_() =>
RustLib.instance.api.crateApiWebviewApiWebViewNavigationStateDefault();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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`: `get_process_path`
// 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`, `clone`, `fmt`, `fmt`
Future<void> sendNotify({
String? summary,
String? body,
String? appName,
String? appId,
}) => RustLib.instance.api.crateApiWin32ApiSendNotify(
summary: summary,
body: body,
appName: appName,
appId: appId,
);
/// Get system memory size in GB
Future<BigInt> getSystemMemorySizeGb() =>
RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb();
/// Get number of logical processors
Future<int> getNumberOfLogicalProcessors() =>
RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors();
/// Get all system information at once
Future<SystemInfo> getSystemInfo() =>
RustLib.instance.api.crateApiWin32ApiGetSystemInfo();
/// Get GPU info from registry (more accurate VRAM)
Future<String> getGpuInfoFromRegistry() =>
RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry();
/// Resolve shortcut (.lnk) file to get target path
Future<String> resolveShortcut({required String lnkPath}) =>
RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath);
/// Open file explorer and select file/folder
Future<void> openDirWithExplorer({
required String path,
required bool isFile,
}) => RustLib.instance.api.crateApiWin32ApiOpenDirWithExplorer(
path: path,
isFile: isFile,
);
Future<bool> setForegroundWindow({required String windowName}) => RustLib
.instance
.api
.crateApiWin32ApiSetForegroundWindow(windowName: windowName);
Future<int> getProcessPidByName({required String processName}) => RustLib
.instance
.api
.crateApiWin32ApiGetProcessPidByName(processName: processName);
Future<List<ProcessInfo>> getProcessListByName({required String processName}) =>
RustLib.instance.api.crateApiWin32ApiGetProcessListByName(
processName: processName,
);
/// Kill processes by name
Future<int> killProcessByName({required String processName}) => RustLib
.instance
.api
.crateApiWin32ApiKillProcessByName(processName: processName);
/// Get disk physical sector size for performance
Future<int> getDiskPhysicalSectorSize({required String driveLetter}) => RustLib
.instance
.api
.crateApiWin32ApiGetDiskPhysicalSectorSize(driveLetter: driveLetter);
/// Create a desktop shortcut
Future<void> createDesktopShortcut({
required String targetPath,
required String shortcutName,
}) => RustLib.instance.api.crateApiWin32ApiCreateDesktopShortcut(
targetPath: targetPath,
shortcutName: shortcutName,
);
/// Run a program with admin privileges (UAC)
Future<void> runAsAdmin({required String program, required String args}) =>
RustLib.instance.api.crateApiWin32ApiRunAsAdmin(
program: program,
args: args,
);
/// Start a program (without waiting)
Future<void> startProcess({
required String program,
required List<String> args,
}) => RustLib.instance.api.crateApiWin32ApiStartProcess(
program: program,
args: args,
);
/// Check if NVME patch is applied
Future<bool> checkNvmePatchStatus() =>
RustLib.instance.api.crateApiWin32ApiCheckNvmePatchStatus();
/// Add NVME patch to registry
Future<void> addNvmePatch() =>
RustLib.instance.api.crateApiWin32ApiAddNvmePatch();
/// Remove NVME patch from registry
Future<void> removeNvmePatch() =>
RustLib.instance.api.crateApiWin32ApiRemoveNvmePatch();
class ProcessInfo {
final int pid;
final String name;
final String path;
const ProcessInfo({
required this.pid,
required this.name,
required this.path,
});
@override
int get hashCode => pid.hashCode ^ name.hashCode ^ path.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ProcessInfo &&
runtimeType == other.runtimeType &&
pid == other.pid &&
name == other.name &&
path == other.path;
}
/// System information struct
class SystemInfo {
final String osName;
final String cpuName;
final String gpuInfo;
final String diskInfo;
const SystemInfo({
required this.osName,
required this.cpuName,
required this.gpuInfo,
required this.diskInfo,
});
@override
int get hashCode =>
osName.hashCode ^ cpuName.hashCode ^ gpuInfo.hashCode ^ diskInfo.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SystemInfo &&
runtimeType == other.runtimeType &&
osName == other.osName &&
cpuName == other.cpuName &&
gpuInfo == other.gpuInfo &&
diskInfo == other.diskInfo;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,18 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.28.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// 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';
enum MyHttpVersion {
http09,
http10,
http11,
http2,
http3,
httpUnknown,
}
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 BigInt? contentLength;
final MyHttpVersion version;
final String remoteAddr;
final Uint8List? data;

View File

@ -0,0 +1,340 @@
// Rust WebView
// 使 wry + tao WebView
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:starcitizen_doctor/common/rust/api/webview_api.dart'
as rust_webview;
import 'package:starcitizen_doctor/common/utils/log.dart';
typedef OnWebMessageCallback = void Function(String message);
typedef OnNavigationCallback = void Function(String url);
typedef OnNavigationCompletedCallback = void Function(String url);
typedef OnWindowClosedCallback = void Function();
/// Rust WebView
/// Rust wry + tao WebView
class RustWebViewController {
final String id;
final List<OnWebMessageCallback> _messageCallbacks = [];
final List<OnNavigationCallback> _navigationCallbacks = [];
final List<OnNavigationCompletedCallback> _navigationCompletedCallbacks = [];
final List<OnWindowClosedCallback> _closeCallbacks = [];
Timer? _pollTimer;
bool _isDisposed = false;
/// assets
String _localizationScript = "";
/// URL
String _currentUrl = "";
String get currentUrl => _currentUrl;
RustWebViewController._(this.id);
/// WebView
static Future<RustWebViewController> create({
String title = "WebView",
int width = 1280,
int height = 720,
String? userDataFolder,
bool enableDevtools = false,
bool transparent = false,
String? userAgent,
}) async {
try {
final config = rust_webview.WebViewConfiguration(
title: title,
width: width,
height: height,
userDataFolder: userDataFolder,
enableDevtools: enableDevtools,
transparent: transparent,
userAgent: userAgent,
);
final id = rust_webview.webviewCreate(config: config);
final controller = RustWebViewController._(id);
//
await controller._loadScripts();
//
controller._startEventPolling();
return controller;
} catch (e) {
throw Exception("Failed to create WebView: $e");
}
}
///
Future<void> _loadScripts() async {
try {
_localizationScript = await rootBundle.loadString('assets/web_script.js');
} catch (e) {
dPrint("Failed to load scripts: $e");
}
}
///
void _startEventPolling() {
_pollTimer = Timer.periodic(const Duration(milliseconds: 50), (_) {
if (_isDisposed) return;
_pollEvents();
});
}
///
void _pollEvents() {
try {
final events = rust_webview.webviewPollEvents(id: id);
for (final event in events) {
_handleEvent(event);
}
} catch (e) {
// WebView
if (!_isDisposed) {
dPrint("Error polling events: $e");
}
}
}
///
void _handleEvent(rust_webview.WebViewEvent event) {
switch (event) {
case rust_webview.WebViewEvent_NavigationStarted(:final url):
dPrint("Navigation started: $url");
_currentUrl = url;
//
for (final callback in _navigationCallbacks) {
callback(url);
}
break;
case rust_webview.WebViewEvent_NavigationCompleted(:final url):
dPrint("Navigation completed: $url");
_currentUrl = url;
//
for (final callback in _navigationCompletedCallbacks) {
callback(url);
}
for (final callback in _navigationCallbacks) {
callback(url);
}
break;
case rust_webview.WebViewEvent_TitleChanged(:final title):
dPrint("Title changed: $title");
break;
case rust_webview.WebViewEvent_WebMessage(:final message):
_handleWebMessage(message);
break;
case rust_webview.WebViewEvent_WindowClosed():
dPrint("Window closed");
for (final callback in _closeCallbacks) {
callback();
}
dispose();
break;
case rust_webview.WebViewEvent_Error(:final message):
dPrint("WebView error: $message");
break;
}
}
/// WebView
void _handleWebMessage(String message) {
dPrint("Web message: $message");
try {
final data = json.decode(message);
final action = data["action"];
switch (action) {
case "navigation_state":
// JS
final url = data["url"] ?? "";
final isLoading = data["isLoading"] ?? false;
_currentUrl = url;
if (!isLoading) {
for (final callback in _navigationCallbacks) {
callback(url);
}
}
break;
case "close_window":
//
close();
break;
default:
//
for (final callback in _messageCallbacks) {
callback(message);
}
}
} catch (e) {
// JSON
for (final callback in _messageCallbacks) {
callback(message);
}
}
}
/// URL
void navigate(String url) {
if (_isDisposed) return;
_currentUrl = url;
rust_webview.webviewNavigate(id: id, url: url);
}
/// 退
void goBack() {
if (_isDisposed) return;
rust_webview.webviewGoBack(id: id);
}
///
void goForward() {
if (_isDisposed) return;
rust_webview.webviewGoForward(id: id);
}
///
void reload() {
if (_isDisposed) return;
rust_webview.webviewReload(id: id);
}
///
void stop() {
if (_isDisposed) return;
rust_webview.webviewStop(id: id);
}
/// JavaScript
void executeScript(String script) {
if (_isDisposed) return;
rust_webview.webviewExecuteScript(id: id, script: script);
}
///
void setVisible(bool visible) {
if (_isDisposed) return;
rust_webview.webviewSetVisibility(id: id, visible: visible);
}
///
void close() {
if (_isDisposed) return;
rust_webview.webviewClose(id: id);
dispose();
}
///
void setWindowSize(int width, int height) {
if (_isDisposed) return;
rust_webview.webviewSetWindowSize(id: id, width: width, height: height);
}
///
void setWindowPosition(int x, int y) {
if (_isDisposed) return;
rust_webview.webviewSetWindowPosition(id: id, x: x, y: y);
}
///
rust_webview.WebViewNavigationState getState() {
return rust_webview.webviewGetState(id: id);
}
///
bool get isClosed {
if (_isDisposed) return true;
return rust_webview.webviewIsClosed(id: id);
}
///
void addOnWebMessageCallback(OnWebMessageCallback callback) {
_messageCallbacks.add(callback);
}
///
void removeOnWebMessageCallback(OnWebMessageCallback callback) {
_messageCallbacks.remove(callback);
}
///
void addOnNavigationCallback(OnNavigationCallback callback) {
_navigationCallbacks.add(callback);
}
///
void removeOnNavigationCallback(OnNavigationCallback callback) {
_navigationCallbacks.remove(callback);
}
///
void addOnNavigationCompletedCallback(
OnNavigationCompletedCallback callback,
) {
_navigationCompletedCallbacks.add(callback);
}
///
void removeOnNavigationCompletedCallback(
OnNavigationCompletedCallback callback,
) {
_navigationCompletedCallbacks.remove(callback);
}
///
void addOnCloseCallback(OnWindowClosedCallback callback) {
_closeCallbacks.add(callback);
}
///
void removeOnCloseCallback(OnWindowClosedCallback callback) {
_closeCallbacks.remove(callback);
}
///
void injectLocalizationScript() {
if (_localizationScript.isNotEmpty) {
executeScript(_localizationScript);
}
}
///
void initWebLocalization() {
executeScript("InitWebLocalization()");
}
///
void updateReplaceWords(List<Map<String, String>> words, bool enableCapture) {
final jsonWords = json.encode(words);
executeScript(
"WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)",
);
}
/// RSI
void executeRsiLogin(String channel) {
executeScript('getRSILauncherToken("$channel");');
}
///
void dispose() {
if (_isDisposed) return;
_isDisposed = true;
_pollTimer?.cancel();
_messageCallbacks.clear();
_navigationCallbacks.clear();
_navigationCompletedCallbacks.clear();
_closeCallbacks.clear();
}
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/rendering.dart';
@ -7,68 +8,79 @@ import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:starcitizen_doctor/generated/l10n.dart';
Future showToast(BuildContext context, String msg,
{BoxConstraints? constraints, String? title}) async {
return showBaseDialog(context,
/// String extension for cross-platform path compatibility
extension PathStringExtension on String {
/// Converts path separators to the current platform's format.
/// On Windows: / -> \
/// On Linux/macOS: \ -> /
String get platformPath {
if (Platform.isWindows) {
return replaceAll('/', '\\');
}
return replaceAll('\\', '/');
}
}
Future showToast(BuildContext context, String msg, {BoxConstraints? constraints, String? title}) async {
return showBaseDialog(
context,
title: title ?? S.current.app_common_tip,
content: Text(msg),
actions: [
FilledButton(
child: Padding(
padding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
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),
),
],
constraints: constraints);
constraints: constraints,
);
}
Future<bool> showConfirmDialogs(
BuildContext context, String title, Widget content,
{String confirm = "",
BuildContext context,
String title,
Widget content, {
String confirm = "",
String cancel = "",
BoxConstraints? constraints}) async {
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,
final r = await showBaseDialog(
context,
title: title,
content: content,
actions: [
if (confirm.isNotEmpty)
FilledButton(
child: Padding(
padding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
child: Text(confirm),
),
child: Padding(padding: const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text(confirm)),
onPressed: () => Navigator.pop(context, true),
),
if (cancel.isNotEmpty)
Button(
child: Padding(
padding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
child: Text(cancel),
),
child: Padding(padding: const EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8), child: Text(cancel)),
onPressed: () => Navigator.pop(context, false),
),
],
constraints: constraints);
constraints: constraints,
);
return r == true;
}
Future<String?> showInputDialogs(BuildContext context,
{required String title,
Future<String?> showInputDialogs(
BuildContext context, {
required String title,
required String content,
BoxConstraints? constraints,
String? initialValue,
List<TextInputFormatter>? inputFormatters}) async {
List<TextInputFormatter>? inputFormatters,
}) async {
String? userInput;
constraints ??=
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .38);
constraints ??= BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .38);
final ok = await showConfirmDialogs(
context,
title,
@ -76,11 +88,7 @@ Future<String?> showInputDialogs(BuildContext context,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (content.isNotEmpty)
Text(
content,
style: TextStyle(color: Colors.white.withOpacity(.6)),
),
if (content.isNotEmpty) Text(content, style: TextStyle(color: Colors.white.withValues(alpha: .6))),
const SizedBox(height: 8),
TextFormBox(
initialValue: initialValue,
@ -91,26 +99,25 @@ Future<String?> showInputDialogs(BuildContext context,
),
],
),
constraints: constraints);
constraints: constraints,
);
if (ok == true) return userInput;
return null;
}
Future showBaseDialog(BuildContext context,
{required String title,
Future showBaseDialog(
BuildContext context, {
required String title,
required Widget content,
List<Widget>? actions,
BoxConstraints? constraints}) async {
BoxConstraints? constraints,
}) async {
return await showDialog(
context: context,
builder: (context) => ContentDialog(
title: Text(title),
content: content,
constraints: constraints ??
const BoxConstraints(
maxWidth: 512,
maxHeight: 756.0,
),
constraints: constraints ?? const BoxConstraints(maxWidth: 512, maxHeight: 756.0),
actions: actions,
),
);
@ -120,10 +127,8 @@ bool stringIsNotEmpty(String? s) {
return s != null && (s.isNotEmpty);
}
Future<Uint8List?> widgetToPngImage(GlobalKey repaintBoundaryKey,
{double pixelRatio = 3.0}) async {
RenderRepaintBoundary? boundary = repaintBoundaryKey.currentContext
?.findRenderObject() as RenderRepaintBoundary?;
Future<Uint8List?> widgetToPngImage(GlobalKey repaintBoundaryKey, {double pixelRatio = 3.0}) async {
RenderRepaintBoundary? boundary = repaintBoundaryKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null;
ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);
@ -133,5 +138,25 @@ Future<Uint8List?> widgetToPngImage(GlobalKey repaintBoundaryKey,
return pngBytes;
}
double roundDoubleTo(double value, double precision) =>
(value * precision).round() / precision;
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;
}
String colorToHexCode(Color color, {ignoreTransparency = false}) {
final colorValue = color.toARGB32();
final colorAlpha = ((0xff000000 & colorValue) >> 24);
final r = ((0x00ff0000 & colorValue) >> 16).toRadixString(16).padLeft(2, '0');
final g = ((0x0000ff00 & colorValue) >> 8).toRadixString(16).padLeft(2, '0');
final b = ((0x000000ff & colorValue) >> 0).toRadixString(16).padLeft(2, '0');
final a = colorAlpha.toRadixString(16).padLeft(2, '0');
if (ignoreTransparency || colorAlpha == 255) {
return '#$r$g$b';
} else {
return '#$a$r$g$b';
}
}

View File

@ -0,0 +1,101 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
class FileCacheUtils {
//
static final Map<String, Future<File>> _downloadingTasks = {};
//
static Directory? _cacheDir;
///
static Future<Directory> _getCacheDirectory() async {
if (_cacheDir != null) return _cacheDir!;
final tempDir = await getTemporaryDirectory();
_cacheDir = Directory(path.join(tempDir.path, 'ScToolbox_File_Cache'));
if (!await _cacheDir!.exists()) {
await _cacheDir!.create(recursive: true);
}
return _cacheDir!;
}
/// URL获取文件
static Future<File> getFile(String url) async {
//
if (_downloadingTasks.containsKey(url)) {
return _downloadingTasks[url]!;
}
final fileTask = _downloadFile(url);
_downloadingTasks[url] = fileTask;
try {
final file = await fileTask;
return file;
} finally {
//
_downloadingTasks.remove(url);
}
}
///
static Future<File> _downloadFile(String url) async {
// (使URL的MD5哈希作为文件名)
final filename = md5.convert(utf8.encode(url)).toString();
final cacheDir = await _getCacheDirectory();
final file = File(path.join(cacheDir.path, filename));
//
if (await file.exists()) {
return file;
}
//
final response = await RSHttp.get(url);
if (response.statusCode == 200) {
await file.writeAsBytes(response.data ?? []);
return file;
} else {
throw Exception('Failed to download file: ${response.statusCode}');
}
}
/// URL的缓存
static Future<bool> clearCache(String url) async {
try {
final filename = md5.convert(utf8.encode(url)).toString();
final cacheDir = await _getCacheDirectory();
final file = File(path.join(cacheDir.path, filename));
if (await file.exists()) {
await file.delete();
return true;
}
return false;
} catch (e) {
return false;
}
}
///
static Future<void> clearAllCache() async {
try {
final cacheDir = await _getCacheDirectory();
if (await cacheDir.exists()) {
await cacheDir.delete(recursive: true);
await cacheDir.create();
}
} catch (e) {
debugPrint('clear All Cache Error: $e');
}
}
}

View File

@ -8,9 +8,10 @@ export 'package:starcitizen_doctor/generated/l10n.dart';
var _logLock = Lock();
File? _logFile;
void dPrint(src) async {
void dPrint(dynamic src) async {
if (kDebugMode) {
print(src);
return;
}
await _logLock.synchronized(() async {
try {
@ -19,8 +20,22 @@ void dPrint(src) async {
});
}
void setDPrintFile(File file) {
_logFile = file;
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() {

View File

@ -0,0 +1,239 @@
import 'dart:convert';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/services.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:starcitizen_doctor/app.dart';
import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
import 'package:starcitizen_doctor/generated/l10n.dart';
import 'package:starcitizen_doctor/ui/tools/log_analyze_ui/log_analyze_ui.dart';
import 'package:window_manager/window_manager.dart';
import 'base_utils.dart';
part 'multi_window_manager.freezed.dart';
part 'multi_window_manager.g.dart';
/// Window type definitions for multi-window support
class WindowTypes {
/// Main application window
static const String main = 'main';
/// Log analyzer window
static const String logAnalyze = 'log_analyze';
}
@freezed
abstract class MultiWindowAppState with _$MultiWindowAppState {
const factory MultiWindowAppState({
required String backgroundColor,
required String menuColor,
required String micaColor,
required List<String> gameInstallPaths,
String? languageCode,
String? countryCode,
@Default(10) windowsVersion,
}) = _MultiWindowAppState;
factory MultiWindowAppState.fromJson(Map<String, dynamic> json) => _$MultiWindowAppStateFromJson(json);
}
class MultiWindowManager {
/// Parse window type from arguments string
static String parseWindowType(String arguments) {
if (arguments.isEmpty) {
return WindowTypes.main;
}
try {
final Map<String, dynamic> argument = jsonDecode(arguments);
return argument['window_type'] ?? WindowTypes.main;
} catch (e) {
return WindowTypes.main;
}
}
/// Launch a sub-window with specified type and title
static Future<void> launchSubWindow(String type, String title, AppGlobalState appGlobalState) async {
final gameInstallPaths = await SCLoggerHelper.getGameInstallPath(
await SCLoggerHelper.getLauncherLogList() ?? [],
checkExists: true,
withVersion: AppConf.gameChannels,
);
final controller = await WindowController.create(
WindowConfiguration(
hiddenAtLaunch: true,
arguments: jsonEncode({
'window_type': type,
'app_state': _appStateToWindowState(appGlobalState, gameInstallPaths: gameInstallPaths).toJson(),
}),
),
);
await Future.delayed(Duration(milliseconds: 500)).then((_) async {
await controller.setFrame(const Rect.fromLTWH(0, 0, 720, 800));
await controller.setTitle(title);
await controller.center();
await controller.show();
});
}
static MultiWindowAppState _appStateToWindowState(AppGlobalState appGlobalState, {List<String>? gameInstallPaths}) {
return MultiWindowAppState(
backgroundColor: colorToHexCode(appGlobalState.themeConf.backgroundColor),
menuColor: colorToHexCode(appGlobalState.themeConf.menuColor),
micaColor: colorToHexCode(appGlobalState.themeConf.micaColor),
languageCode: appGlobalState.appLocale?.languageCode,
countryCode: appGlobalState.appLocale?.countryCode,
gameInstallPaths: gameInstallPaths ?? [],
windowsVersion: appGlobalState.windowsVersion,
);
}
/// Run sub-window app with parsed arguments
static Future<void> runSubWindowApp(String arguments, String windowType) async {
final Map<String, dynamic> argument = arguments.isEmpty ? const {} : jsonDecode(arguments);
final windowAppState = MultiWindowAppState.fromJson(argument['app_state'] ?? {});
Widget? windowWidget;
switch (windowType) {
case WindowTypes.logAnalyze:
windowWidget = ToolsLogAnalyzeDialogUI(appState: windowAppState);
break;
default:
throw Exception('Unknown window type: $windowType');
}
await Window.initialize();
if (Platform.isWindows && windowAppState.windowsVersion >= 10) {
await Window.setEffect(effect: WindowEffect.acrylic);
}
final backgroundColor = HexColor(windowAppState.backgroundColor).withValues(alpha: .1);
return runApp(
ProviderScope(
child: FluentApp(
title: "StarCitizenToolBox",
restorationScopeId: "StarCitizenToolBox",
themeMode: ThemeMode.dark,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
FluentLocalizations.delegate,
S.delegate,
],
supportedLocales: S.delegate.supportedLocales,
home: windowWidget,
theme: FluentThemeData(
brightness: Brightness.dark,
fontFamily: "SourceHanSansCN-Regular",
navigationPaneTheme: NavigationPaneThemeData(backgroundColor: backgroundColor),
menuColor: HexColor(windowAppState.menuColor),
micaBackgroundColor: HexColor(windowAppState.micaColor),
scaffoldBackgroundColor: backgroundColor,
buttonTheme: ButtonThemeData(
defaultButtonStyle: ButtonStyle(
shape: WidgetStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
side: BorderSide(color: Colors.white.withValues(alpha: .01)),
),
),
),
),
),
locale: windowAppState.languageCode != null
? Locale(windowAppState.languageCode!, windowAppState.countryCode)
: null,
debugShowCheckedModeBanner: false,
),
),
);
}
}
/// Extension methods for WindowController to add custom functionality
extension WindowControllerExtension on WindowController {
/// Initialize custom window method handlers
Future<void> doCustomInitialize() async {
windowManager.ensureInitialized();
return await setWindowMethodHandler((call) async {
switch (call.method) {
case 'window_center':
return await windowManager.center();
case 'window_close':
return await windowManager.close();
case 'window_show':
return await windowManager.show();
case 'window_hide':
return await windowManager.hide();
case 'window_focus':
return await windowManager.focus();
case 'window_set_frame':
final args = call.arguments as Map;
return await windowManager.setBounds(
Rect.fromLTWH(
args['left'] as double,
args['top'] as double,
args['width'] as double,
args['height'] as double,
),
);
case 'window_set_title':
return await windowManager.setTitle(call.arguments as String);
default:
throw MissingPluginException('Not implemented: ${call.method}');
}
});
}
/// Center the window
Future<void> center() {
return invokeMethod('window_center');
}
/// Close the window
void close() async {
await invokeMethod('window_close');
}
/// Show the window
Future<void> show() {
return invokeMethod('window_show');
}
/// Hide the window
Future<void> hide() {
return invokeMethod('window_hide');
}
/// Focus the window
Future<void> focus() {
return invokeMethod('window_focus');
}
/// Set window frame (position and size)
Future<void> setFrame(Rect frame) {
return invokeMethod('window_set_frame', {
'left': frame.left,
'top': frame.top,
'width': frame.width,
'height': frame.height,
});
}
/// Set window title
Future<void> setTitle(String title) {
return invokeMethod('window_set_title', title);
}
}

View File

@ -0,0 +1,301 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// 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 'multi_window_manager.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$MultiWindowAppState {
String get backgroundColor; String get menuColor; String get micaColor; List<String> get gameInstallPaths; String? get languageCode; String? get countryCode; dynamic get windowsVersion;
/// Create a copy of MultiWindowAppState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$MultiWindowAppStateCopyWith<MultiWindowAppState> get copyWith => _$MultiWindowAppStateCopyWithImpl<MultiWindowAppState>(this as MultiWindowAppState, _$identity);
/// Serializes this MultiWindowAppState to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is MultiWindowAppState&&(identical(other.backgroundColor, backgroundColor) || other.backgroundColor == backgroundColor)&&(identical(other.menuColor, menuColor) || other.menuColor == menuColor)&&(identical(other.micaColor, micaColor) || other.micaColor == micaColor)&&const DeepCollectionEquality().equals(other.gameInstallPaths, gameInstallPaths)&&(identical(other.languageCode, languageCode) || other.languageCode == languageCode)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other.windowsVersion, windowsVersion));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,backgroundColor,menuColor,micaColor,const DeepCollectionEquality().hash(gameInstallPaths),languageCode,countryCode,const DeepCollectionEquality().hash(windowsVersion));
@override
String toString() {
return 'MultiWindowAppState(backgroundColor: $backgroundColor, menuColor: $menuColor, micaColor: $micaColor, gameInstallPaths: $gameInstallPaths, languageCode: $languageCode, countryCode: $countryCode, windowsVersion: $windowsVersion)';
}
}
/// @nodoc
abstract mixin class $MultiWindowAppStateCopyWith<$Res> {
factory $MultiWindowAppStateCopyWith(MultiWindowAppState value, $Res Function(MultiWindowAppState) _then) = _$MultiWindowAppStateCopyWithImpl;
@useResult
$Res call({
String backgroundColor, String menuColor, String micaColor, List<String> gameInstallPaths, String? languageCode, String? countryCode, dynamic windowsVersion
});
}
/// @nodoc
class _$MultiWindowAppStateCopyWithImpl<$Res>
implements $MultiWindowAppStateCopyWith<$Res> {
_$MultiWindowAppStateCopyWithImpl(this._self, this._then);
final MultiWindowAppState _self;
final $Res Function(MultiWindowAppState) _then;
/// Create a copy of MultiWindowAppState
/// 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,Object? gameInstallPaths = null,Object? languageCode = freezed,Object? countryCode = freezed,Object? windowsVersion = freezed,}) {
return _then(_self.copyWith(
backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable
as String,menuColor: null == menuColor ? _self.menuColor : menuColor // ignore: cast_nullable_to_non_nullable
as String,micaColor: null == micaColor ? _self.micaColor : micaColor // ignore: cast_nullable_to_non_nullable
as String,gameInstallPaths: null == gameInstallPaths ? _self.gameInstallPaths : gameInstallPaths // ignore: cast_nullable_to_non_nullable
as List<String>,languageCode: freezed == languageCode ? _self.languageCode : languageCode // ignore: cast_nullable_to_non_nullable
as String?,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
as String?,windowsVersion: freezed == windowsVersion ? _self.windowsVersion : windowsVersion // ignore: cast_nullable_to_non_nullable
as dynamic,
));
}
}
/// Adds pattern-matching-related methods to [MultiWindowAppState].
extension MultiWindowAppStatePatterns on MultiWindowAppState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _MultiWindowAppState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _MultiWindowAppState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _MultiWindowAppState value) $default,){
final _that = this;
switch (_that) {
case _MultiWindowAppState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _MultiWindowAppState value)? $default,){
final _that = this;
switch (_that) {
case _MultiWindowAppState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String backgroundColor, String menuColor, String micaColor, List<String> gameInstallPaths, String? languageCode, String? countryCode, dynamic windowsVersion)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _MultiWindowAppState() when $default != null:
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor,_that.gameInstallPaths,_that.languageCode,_that.countryCode,_that.windowsVersion);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String backgroundColor, String menuColor, String micaColor, List<String> gameInstallPaths, String? languageCode, String? countryCode, dynamic windowsVersion) $default,) {final _that = this;
switch (_that) {
case _MultiWindowAppState():
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor,_that.gameInstallPaths,_that.languageCode,_that.countryCode,_that.windowsVersion);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String backgroundColor, String menuColor, String micaColor, List<String> gameInstallPaths, String? languageCode, String? countryCode, dynamic windowsVersion)? $default,) {final _that = this;
switch (_that) {
case _MultiWindowAppState() when $default != null:
return $default(_that.backgroundColor,_that.menuColor,_that.micaColor,_that.gameInstallPaths,_that.languageCode,_that.countryCode,_that.windowsVersion);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _MultiWindowAppState implements MultiWindowAppState {
const _MultiWindowAppState({required this.backgroundColor, required this.menuColor, required this.micaColor, required final List<String> gameInstallPaths, this.languageCode, this.countryCode, this.windowsVersion = 10}): _gameInstallPaths = gameInstallPaths;
factory _MultiWindowAppState.fromJson(Map<String, dynamic> json) => _$MultiWindowAppStateFromJson(json);
@override final String backgroundColor;
@override final String menuColor;
@override final String micaColor;
final List<String> _gameInstallPaths;
@override List<String> get gameInstallPaths {
if (_gameInstallPaths is EqualUnmodifiableListView) return _gameInstallPaths;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_gameInstallPaths);
}
@override final String? languageCode;
@override final String? countryCode;
@override@JsonKey() final dynamic windowsVersion;
/// Create a copy of MultiWindowAppState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$MultiWindowAppStateCopyWith<_MultiWindowAppState> get copyWith => __$MultiWindowAppStateCopyWithImpl<_MultiWindowAppState>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$MultiWindowAppStateToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MultiWindowAppState&&(identical(other.backgroundColor, backgroundColor) || other.backgroundColor == backgroundColor)&&(identical(other.menuColor, menuColor) || other.menuColor == menuColor)&&(identical(other.micaColor, micaColor) || other.micaColor == micaColor)&&const DeepCollectionEquality().equals(other._gameInstallPaths, _gameInstallPaths)&&(identical(other.languageCode, languageCode) || other.languageCode == languageCode)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other.windowsVersion, windowsVersion));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,backgroundColor,menuColor,micaColor,const DeepCollectionEquality().hash(_gameInstallPaths),languageCode,countryCode,const DeepCollectionEquality().hash(windowsVersion));
@override
String toString() {
return 'MultiWindowAppState(backgroundColor: $backgroundColor, menuColor: $menuColor, micaColor: $micaColor, gameInstallPaths: $gameInstallPaths, languageCode: $languageCode, countryCode: $countryCode, windowsVersion: $windowsVersion)';
}
}
/// @nodoc
abstract mixin class _$MultiWindowAppStateCopyWith<$Res> implements $MultiWindowAppStateCopyWith<$Res> {
factory _$MultiWindowAppStateCopyWith(_MultiWindowAppState value, $Res Function(_MultiWindowAppState) _then) = __$MultiWindowAppStateCopyWithImpl;
@override @useResult
$Res call({
String backgroundColor, String menuColor, String micaColor, List<String> gameInstallPaths, String? languageCode, String? countryCode, dynamic windowsVersion
});
}
/// @nodoc
class __$MultiWindowAppStateCopyWithImpl<$Res>
implements _$MultiWindowAppStateCopyWith<$Res> {
__$MultiWindowAppStateCopyWithImpl(this._self, this._then);
final _MultiWindowAppState _self;
final $Res Function(_MultiWindowAppState) _then;
/// Create a copy of MultiWindowAppState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? backgroundColor = null,Object? menuColor = null,Object? micaColor = null,Object? gameInstallPaths = null,Object? languageCode = freezed,Object? countryCode = freezed,Object? windowsVersion = freezed,}) {
return _then(_MultiWindowAppState(
backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable
as String,menuColor: null == menuColor ? _self.menuColor : menuColor // ignore: cast_nullable_to_non_nullable
as String,micaColor: null == micaColor ? _self.micaColor : micaColor // ignore: cast_nullable_to_non_nullable
as String,gameInstallPaths: null == gameInstallPaths ? _self._gameInstallPaths : gameInstallPaths // ignore: cast_nullable_to_non_nullable
as List<String>,languageCode: freezed == languageCode ? _self.languageCode : languageCode // ignore: cast_nullable_to_non_nullable
as String?,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
as String?,windowsVersion: freezed == windowsVersion ? _self.windowsVersion : windowsVersion // ignore: cast_nullable_to_non_nullable
as dynamic,
));
}
}
// dart format on

View File

@ -0,0 +1,32 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'multi_window_manager.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_MultiWindowAppState _$MultiWindowAppStateFromJson(Map<String, dynamic> json) =>
_MultiWindowAppState(
backgroundColor: json['backgroundColor'] as String,
menuColor: json['menuColor'] as String,
micaColor: json['micaColor'] as String,
gameInstallPaths: (json['gameInstallPaths'] as List<dynamic>)
.map((e) => e as String)
.toList(),
languageCode: json['languageCode'] as String?,
countryCode: json['countryCode'] as String?,
windowsVersion: json['windowsVersion'] ?? 10,
);
Map<String, dynamic> _$MultiWindowAppStateToJson(
_MultiWindowAppState instance,
) => <String, dynamic>{
'backgroundColor': instance.backgroundColor,
'menuColor': instance.menuColor,
'micaColor': instance.micaColor,
'gameInstallPaths': instance.gameInstallPaths,
'languageCode': instance.languageCode,
'countryCode': instance.countryCode,
'windowsVersion': instance.windowsVersion,
};

View File

@ -1,9 +1,13 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
// ignore_for_file: invalid_use_of_protected_member
import 'package:hive_ce/hive.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/app.dart';
extension ProviderExtension on AutoDisposeNotifier {
AppGlobalModel get appGlobalModel =>
ref.read(appGlobalModelProvider.notifier);
extension ProviderExtension<T> on $Notifier<T> {
AppGlobalModel get appGlobalModel => ref.read(appGlobalModelProvider.notifier);
AppGlobalState get appGlobalState => ref.read(appGlobalModelProvider);
Box<dynamic>? get appConfBox => appGlobalState.appConfBox;
}

View File

@ -0,0 +1,121 @@
import 'dart:async';
import 'package:app_links/app_links.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/ui/auth/auth_page.dart';
/// URL Scheme handler for deep linking
/// Handles: sctoolbox://auth?callbackUrl=https://example.com
class UrlSchemeHandler {
static final UrlSchemeHandler _instance = UrlSchemeHandler._internal();
factory UrlSchemeHandler() => _instance;
UrlSchemeHandler._internal();
final _appLinks = AppLinks();
StreamSubscription<Uri>? _linkSubscription;
BuildContext? _context;
// Debouncing variables
String? _lastHandledUri;
DateTime? _lastHandledTime;
static const _debounceDuration = Duration(seconds: 2);
/// Initialize URL scheme handler
Future<void> initialize(BuildContext context) async {
_context = context;
// Handle initial link when app is launched via URL scheme
try {
final initialUri = await _appLinks.getInitialLink();
if (initialUri != null) {
dPrint('Initial URI: $initialUri');
_handleUri(initialUri);
}
} catch (e) {
dPrint('Failed to get initial URI: $e');
}
// Handle links while app is running
_linkSubscription = _appLinks.uriLinkStream.listen(
(uri) {
dPrint('Received URI: $uri');
_handleUri(uri);
},
onError: (err) {
dPrint('URI link stream error: $err');
},
);
}
/// Handle incoming URI with debouncing
void _handleUri(Uri uri) {
final uriString = uri.toString();
final now = DateTime.now();
// Check if this is a duplicate URI within debounce duration
if (_lastHandledUri == uriString && _lastHandledTime != null) {
final timeSinceLastHandle = now.difference(_lastHandledTime!);
if (timeSinceLastHandle < _debounceDuration) {
dPrint('Debounced duplicate URI: $uriString (${timeSinceLastHandle.inMilliseconds}ms since last)');
return;
}
}
// Update last handled URI and time
_lastHandledUri = uriString;
_lastHandledTime = now;
dPrint('Handling URI: $uri');
// Check if it's an auth request
// Check if it's an auth request
// Expected format: sctoolbox://auth?callbackUrl=https://example.com&state=...&nonce=...
// Note: old format with domain in path (sctoolbox://auth/domain?...) is also supported but domain is ignored
if (uri.scheme == 'sctoolbox' && uri.host == 'auth') {
final callbackUrl = uri.queryParameters['callbackUrl'];
final state = uri.queryParameters['state'];
final nonce = uri.queryParameters['nonce'];
if (callbackUrl == null || callbackUrl.isEmpty) {
dPrint('Invalid auth URI: missing callbackUrl parameter');
return;
}
if (state == null || state.isEmpty) {
dPrint('Invalid auth URI: missing state parameter');
return;
}
dPrint('Auth request - callbackUrl: $callbackUrl, state: $state');
_showAuthDialog(callbackUrl, state, nonce);
}
}
/// Show auth dialog
void _showAuthDialog(String callbackUrl, String state, String? nonce) {
if (_context == null || !_context!.mounted) {
dPrint('Cannot show auth dialog: context not available');
return;
}
showDialog(
context: _context!,
builder: (context) => AuthPage(callbackUrl: callbackUrl, stateParameter: state, nonce: nonce),
);
}
/// Dispose the handler
void dispose() {
_linkSubscription?.cancel();
_linkSubscription = null;
_context = null;
_lastHandledUri = null;
_lastHandledTime = null;
}
/// Update context (useful when switching screens)
void updateContext(BuildContext context) {
_context = context;
}
}

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:starcitizen_doctor/common/utils/log.dart';
import 'package:win32/win32.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

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

View File

@ -0,0 +1,35 @@
/// name : "Data\\Textures\\planets\\surface\\ground\\architecture\\city\\city_suburbs_02_displ.dds.6"
/// size : 524288
/// compressedSize : 169812
/// isDirectory : false
class AppUnp4kP4kItemData {
AppUnp4kP4kItemData({this.name, this.size, this.compressedSize, this.isDirectory, this.dateModified});
AppUnp4kP4kItemData.fromJson(dynamic json) {
name = json['name'];
size = json['size'];
compressedSize = json['compressedSize'];
isDirectory = json['isDirectory'];
dateModified = json['dateModified'];
}
String? name;
num? size;
num? compressedSize;
bool? isDirectory;
///
int? dateModified;
List<AppUnp4kP4kItemData> children = [];
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['name'] = name;
map['size'] = size;
map['compressedSize'] = compressedSize;
map['isDirectory'] = isDirectory;
map['dateModified'] = dateModified;
return map;
}
}

View File

@ -17,6 +17,9 @@ class AppVersionData {
this.mSEMinVersionCode,
this.p4kDownloadUrl,
this.activityColors,
this.nav42KitUrl,
this.gameChannels,
this.webMirrors,
});
AppVersionData.fromJson(dynamic json) {
@ -27,10 +30,10 @@ class AppVersionData {
mSELastVersionCode = json['MSE_lastVersionCode'];
mSEMinVersionCode = json['MSE_minVersionCode'];
p4kDownloadUrl = json['p4kDownloadUrl'];
activityColors = json['activityColors'] != null
? ActivityColors.fromJson(json['activityColors'])
: null;
activityColors = json['activityColors'] != null ? ActivityColors.fromJson(json['activityColors']) : null;
gameChannels = List.from(json["game_channels"]).cast<String>();
webMirrors = json["web_mirrors"];
nav42KitUrl = json['nav_42kit_url'];
}
String? lastVersion;
@ -41,7 +44,9 @@ class AppVersionData {
num? mSEMinVersionCode;
String? p4kDownloadUrl;
ActivityColors? activityColors;
List<String>? gameChannels;
Map? webMirrors;
String? nav42KitUrl;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
@ -56,6 +61,8 @@ class AppVersionData {
map['activityColors'] = activityColors?.toJson();
}
map["web_mirrors"] = webMirrors;
map["game_channels"] = gameChannels;
map["nav_42kit_url"] = nav42KitUrl;
return map;
}
}

View File

@ -0,0 +1,54 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'citizen_news_data.freezed.dart';
part 'citizen_news_data.g.dart';
@freezed
sealed class CitizenNewsData with _$CitizenNewsData {
const factory CitizenNewsData({
@Default(<CitizenNewsVideosItemData>[]) @JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,
@Default(<CitizenNewsArticlesItemData>[]) @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles,
}) = _CitizenNewsData;
const CitizenNewsData._();
factory CitizenNewsData.fromJson(Map<String, Object?> json) => _$CitizenNewsDataFromJson(json);
}
@freezed
sealed class CitizenNewsVideosItemData with _$CitizenNewsVideosItemData {
const factory CitizenNewsVideosItemData({
@Default('') @JsonKey(name: 'title') String title,
@Default('') @JsonKey(name: 'author') String author,
@Default('') @JsonKey(name: 'description') String description,
@Default('') @JsonKey(name: 'link') String link,
@Default('') @JsonKey(name: 'pubDate') String pubDate,
@Default('') @JsonKey(name: 'postId') String postId,
@Default(<String>[]) @JsonKey(name: 'detailedDescription') List<String> detailedDescription,
@Default('') @JsonKey(name: 'tag') String tag,
}) = _CitizenNewsVideosItemData;
const CitizenNewsVideosItemData._();
factory CitizenNewsVideosItemData.fromJson(Map<String, Object?> json) => _$CitizenNewsVideosItemDataFromJson(json);
}
@freezed
sealed class CitizenNewsArticlesItemData with _$CitizenNewsArticlesItemData {
const factory CitizenNewsArticlesItemData({
@Default('') @JsonKey(name: 'title') String title,
@Default('') @JsonKey(name: 'author') String author,
@Default('') @JsonKey(name: 'description') String description,
@Default('') @JsonKey(name: 'link') String link,
@Default('') @JsonKey(name: 'pubDate') String pubDate,
@Default('') @JsonKey(name: 'postId') String postId,
@Default(<String>[]) @JsonKey(name: 'detailedDescription') List<String> detailedDescription,
@Default('') @JsonKey(name: 'tag') String tag,
}) = _CitizenNewsArticlesItemData;
const CitizenNewsArticlesItemData._();
factory CitizenNewsArticlesItemData.fromJson(Map<String, Object?> json) =>
_$CitizenNewsArticlesItemDataFromJson(json);
}

View File

@ -0,0 +1,854 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// 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 'citizen_news_data.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$CitizenNewsData {
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> get videos;@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> get articles;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsDataCopyWith<CitizenNewsData> get copyWith => _$CitizenNewsDataCopyWithImpl<CitizenNewsData>(this as CitizenNewsData, _$identity);
/// Serializes this CitizenNewsData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsData&&const DeepCollectionEquality().equals(other.videos, videos)&&const DeepCollectionEquality().equals(other.articles, articles));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(videos),const DeepCollectionEquality().hash(articles));
@override
String toString() {
return 'CitizenNewsData(videos: $videos, articles: $articles)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsDataCopyWith<$Res> {
factory $CitizenNewsDataCopyWith(CitizenNewsData value, $Res Function(CitizenNewsData) _then) = _$CitizenNewsDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles
});
}
/// @nodoc
class _$CitizenNewsDataCopyWithImpl<$Res>
implements $CitizenNewsDataCopyWith<$Res> {
_$CitizenNewsDataCopyWithImpl(this._self, this._then);
final CitizenNewsData _self;
final $Res Function(CitizenNewsData) _then;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? videos = null,Object? articles = null,}) {
return _then(_self.copyWith(
videos: null == videos ? _self.videos : videos // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsVideosItemData>,articles: null == articles ? _self.articles : articles // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsArticlesItemData>,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsData].
extension CitizenNewsDataPatterns on CitizenNewsData {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CitizenNewsData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CitizenNewsData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsData():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CitizenNewsData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that.videos,_that.articles);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsData():
return $default(_that.videos,_that.articles);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that.videos,_that.articles);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsData extends CitizenNewsData {
const _CitizenNewsData({@JsonKey(name: 'videos') final List<CitizenNewsVideosItemData> videos = const <CitizenNewsVideosItemData>[], @JsonKey(name: 'articles') final List<CitizenNewsArticlesItemData> articles = const <CitizenNewsArticlesItemData>[]}): _videos = videos,_articles = articles,super._();
factory _CitizenNewsData.fromJson(Map<String, dynamic> json) => _$CitizenNewsDataFromJson(json);
final List<CitizenNewsVideosItemData> _videos;
@override@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> get videos {
if (_videos is EqualUnmodifiableListView) return _videos;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_videos);
}
final List<CitizenNewsArticlesItemData> _articles;
@override@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> get articles {
if (_articles is EqualUnmodifiableListView) return _articles;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_articles);
}
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsDataCopyWith<_CitizenNewsData> get copyWith => __$CitizenNewsDataCopyWithImpl<_CitizenNewsData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsData&&const DeepCollectionEquality().equals(other._videos, _videos)&&const DeepCollectionEquality().equals(other._articles, _articles));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_videos),const DeepCollectionEquality().hash(_articles));
@override
String toString() {
return 'CitizenNewsData(videos: $videos, articles: $articles)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsDataCopyWith<$Res> implements $CitizenNewsDataCopyWith<$Res> {
factory _$CitizenNewsDataCopyWith(_CitizenNewsData value, $Res Function(_CitizenNewsData) _then) = __$CitizenNewsDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles
});
}
/// @nodoc
class __$CitizenNewsDataCopyWithImpl<$Res>
implements _$CitizenNewsDataCopyWith<$Res> {
__$CitizenNewsDataCopyWithImpl(this._self, this._then);
final _CitizenNewsData _self;
final $Res Function(_CitizenNewsData) _then;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? videos = null,Object? articles = null,}) {
return _then(_CitizenNewsData(
videos: null == videos ? _self._videos : videos // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsVideosItemData>,articles: null == articles ? _self._articles : articles // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsArticlesItemData>,
));
}
}
/// @nodoc
mixin _$CitizenNewsVideosItemData {
@JsonKey(name: 'title') String get title;@JsonKey(name: 'author') String get author;@JsonKey(name: 'description') String get description;@JsonKey(name: 'link') String get link;@JsonKey(name: 'pubDate') String get pubDate;@JsonKey(name: 'postId') String get postId;@JsonKey(name: 'detailedDescription') List<String> get detailedDescription;@JsonKey(name: 'tag') String get tag;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsVideosItemDataCopyWith<CitizenNewsVideosItemData> get copyWith => _$CitizenNewsVideosItemDataCopyWithImpl<CitizenNewsVideosItemData>(this as CitizenNewsVideosItemData, _$identity);
/// Serializes this CitizenNewsVideosItemData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsVideosItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other.detailedDescription, detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsVideosItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsVideosItemDataCopyWith<$Res> {
factory $CitizenNewsVideosItemDataCopyWith(CitizenNewsVideosItemData value, $Res Function(CitizenNewsVideosItemData) _then) = _$CitizenNewsVideosItemDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class _$CitizenNewsVideosItemDataCopyWithImpl<$Res>
implements $CitizenNewsVideosItemDataCopyWith<$Res> {
_$CitizenNewsVideosItemDataCopyWithImpl(this._self, this._then);
final CitizenNewsVideosItemData _self;
final $Res Function(CitizenNewsVideosItemData) _then;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_self.copyWith(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self.detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsVideosItemData].
extension CitizenNewsVideosItemDataPatterns on CitizenNewsVideosItemData {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CitizenNewsVideosItemData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CitizenNewsVideosItemData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CitizenNewsVideosItemData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData():
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsVideosItemData extends CitizenNewsVideosItemData {
const _CitizenNewsVideosItemData({@JsonKey(name: 'title') this.title = '', @JsonKey(name: 'author') this.author = '', @JsonKey(name: 'description') this.description = '', @JsonKey(name: 'link') this.link = '', @JsonKey(name: 'pubDate') this.pubDate = '', @JsonKey(name: 'postId') this.postId = '', @JsonKey(name: 'detailedDescription') final List<String> detailedDescription = const <String>[], @JsonKey(name: 'tag') this.tag = ''}): _detailedDescription = detailedDescription,super._();
factory _CitizenNewsVideosItemData.fromJson(Map<String, dynamic> json) => _$CitizenNewsVideosItemDataFromJson(json);
@override@JsonKey(name: 'title') final String title;
@override@JsonKey(name: 'author') final String author;
@override@JsonKey(name: 'description') final String description;
@override@JsonKey(name: 'link') final String link;
@override@JsonKey(name: 'pubDate') final String pubDate;
@override@JsonKey(name: 'postId') final String postId;
final List<String> _detailedDescription;
@override@JsonKey(name: 'detailedDescription') List<String> get detailedDescription {
if (_detailedDescription is EqualUnmodifiableListView) return _detailedDescription;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_detailedDescription);
}
@override@JsonKey(name: 'tag') final String tag;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsVideosItemDataCopyWith<_CitizenNewsVideosItemData> get copyWith => __$CitizenNewsVideosItemDataCopyWithImpl<_CitizenNewsVideosItemData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsVideosItemDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsVideosItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other._detailedDescription, _detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(_detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsVideosItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsVideosItemDataCopyWith<$Res> implements $CitizenNewsVideosItemDataCopyWith<$Res> {
factory _$CitizenNewsVideosItemDataCopyWith(_CitizenNewsVideosItemData value, $Res Function(_CitizenNewsVideosItemData) _then) = __$CitizenNewsVideosItemDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class __$CitizenNewsVideosItemDataCopyWithImpl<$Res>
implements _$CitizenNewsVideosItemDataCopyWith<$Res> {
__$CitizenNewsVideosItemDataCopyWithImpl(this._self, this._then);
final _CitizenNewsVideosItemData _self;
final $Res Function(_CitizenNewsVideosItemData) _then;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_CitizenNewsVideosItemData(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self._detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
mixin _$CitizenNewsArticlesItemData {
@JsonKey(name: 'title') String get title;@JsonKey(name: 'author') String get author;@JsonKey(name: 'description') String get description;@JsonKey(name: 'link') String get link;@JsonKey(name: 'pubDate') String get pubDate;@JsonKey(name: 'postId') String get postId;@JsonKey(name: 'detailedDescription') List<String> get detailedDescription;@JsonKey(name: 'tag') String get tag;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsArticlesItemDataCopyWith<CitizenNewsArticlesItemData> get copyWith => _$CitizenNewsArticlesItemDataCopyWithImpl<CitizenNewsArticlesItemData>(this as CitizenNewsArticlesItemData, _$identity);
/// Serializes this CitizenNewsArticlesItemData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsArticlesItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other.detailedDescription, detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsArticlesItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsArticlesItemDataCopyWith<$Res> {
factory $CitizenNewsArticlesItemDataCopyWith(CitizenNewsArticlesItemData value, $Res Function(CitizenNewsArticlesItemData) _then) = _$CitizenNewsArticlesItemDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class _$CitizenNewsArticlesItemDataCopyWithImpl<$Res>
implements $CitizenNewsArticlesItemDataCopyWith<$Res> {
_$CitizenNewsArticlesItemDataCopyWithImpl(this._self, this._then);
final CitizenNewsArticlesItemData _self;
final $Res Function(CitizenNewsArticlesItemData) _then;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_self.copyWith(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self.detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsArticlesItemData].
extension CitizenNewsArticlesItemDataPatterns on CitizenNewsArticlesItemData {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CitizenNewsArticlesItemData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CitizenNewsArticlesItemData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CitizenNewsArticlesItemData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData():
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsArticlesItemData extends CitizenNewsArticlesItemData {
const _CitizenNewsArticlesItemData({@JsonKey(name: 'title') this.title = '', @JsonKey(name: 'author') this.author = '', @JsonKey(name: 'description') this.description = '', @JsonKey(name: 'link') this.link = '', @JsonKey(name: 'pubDate') this.pubDate = '', @JsonKey(name: 'postId') this.postId = '', @JsonKey(name: 'detailedDescription') final List<String> detailedDescription = const <String>[], @JsonKey(name: 'tag') this.tag = ''}): _detailedDescription = detailedDescription,super._();
factory _CitizenNewsArticlesItemData.fromJson(Map<String, dynamic> json) => _$CitizenNewsArticlesItemDataFromJson(json);
@override@JsonKey(name: 'title') final String title;
@override@JsonKey(name: 'author') final String author;
@override@JsonKey(name: 'description') final String description;
@override@JsonKey(name: 'link') final String link;
@override@JsonKey(name: 'pubDate') final String pubDate;
@override@JsonKey(name: 'postId') final String postId;
final List<String> _detailedDescription;
@override@JsonKey(name: 'detailedDescription') List<String> get detailedDescription {
if (_detailedDescription is EqualUnmodifiableListView) return _detailedDescription;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_detailedDescription);
}
@override@JsonKey(name: 'tag') final String tag;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsArticlesItemDataCopyWith<_CitizenNewsArticlesItemData> get copyWith => __$CitizenNewsArticlesItemDataCopyWithImpl<_CitizenNewsArticlesItemData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsArticlesItemDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsArticlesItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other._detailedDescription, _detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(_detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsArticlesItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsArticlesItemDataCopyWith<$Res> implements $CitizenNewsArticlesItemDataCopyWith<$Res> {
factory _$CitizenNewsArticlesItemDataCopyWith(_CitizenNewsArticlesItemData value, $Res Function(_CitizenNewsArticlesItemData) _then) = __$CitizenNewsArticlesItemDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class __$CitizenNewsArticlesItemDataCopyWithImpl<$Res>
implements _$CitizenNewsArticlesItemDataCopyWith<$Res> {
__$CitizenNewsArticlesItemDataCopyWithImpl(this._self, this._then);
final _CitizenNewsArticlesItemData _self;
final $Res Function(_CitizenNewsArticlesItemData) _then;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_CitizenNewsArticlesItemData(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self._detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
// dart format on

View File

@ -0,0 +1,91 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'citizen_news_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_CitizenNewsData _$CitizenNewsDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsData(
videos:
(json['videos'] as List<dynamic>?)
?.map(
(e) =>
CitizenNewsVideosItemData.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const <CitizenNewsVideosItemData>[],
articles:
(json['articles'] as List<dynamic>?)
?.map(
(e) =>
CitizenNewsArticlesItemData.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const <CitizenNewsArticlesItemData>[],
);
Map<String, dynamic> _$CitizenNewsDataToJson(_CitizenNewsData instance) =>
<String, dynamic>{'videos': instance.videos, 'articles': instance.articles};
_CitizenNewsVideosItemData _$CitizenNewsVideosItemDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsVideosItemData(
title: json['title'] as String? ?? '',
author: json['author'] as String? ?? '',
description: json['description'] as String? ?? '',
link: json['link'] as String? ?? '',
pubDate: json['pubDate'] as String? ?? '',
postId: json['postId'] as String? ?? '',
detailedDescription:
(json['detailedDescription'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const <String>[],
tag: json['tag'] as String? ?? '',
);
Map<String, dynamic> _$CitizenNewsVideosItemDataToJson(
_CitizenNewsVideosItemData instance,
) => <String, dynamic>{
'title': instance.title,
'author': instance.author,
'description': instance.description,
'link': instance.link,
'pubDate': instance.pubDate,
'postId': instance.postId,
'detailedDescription': instance.detailedDescription,
'tag': instance.tag,
};
_CitizenNewsArticlesItemData _$CitizenNewsArticlesItemDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsArticlesItemData(
title: json['title'] as String? ?? '',
author: json['author'] as String? ?? '',
description: json['description'] as String? ?? '',
link: json['link'] as String? ?? '',
pubDate: json['pubDate'] as String? ?? '',
postId: json['postId'] as String? ?? '',
detailedDescription:
(json['detailedDescription'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const <String>[],
tag: json['tag'] as String? ?? '',
);
Map<String, dynamic> _$CitizenNewsArticlesItemDataToJson(
_CitizenNewsArticlesItemData instance,
) => <String, dynamic>{
'title': instance.title,
'author': instance.author,
'description': instance.description,
'link': instance.link,
'pubDate': instance.pubDate,
'postId': instance.postId,
'detailedDescription': instance.detailedDescription,
'tag': instance.tag,
};

24
lib/data/dcb_data.dart Normal file
View File

@ -0,0 +1,24 @@
/// DCB
class DcbRecordData {
final String path;
final int index;
const DcbRecordData({required this.path, required this.index});
}
/// DCB
class DcbSearchMatchData {
final int lineNumber;
final String lineContent;
const DcbSearchMatchData({required this.lineNumber, required this.lineContent});
}
/// DCB
class DcbSearchResultData {
final String path;
final int index;
final List<DcbSearchMatchData> matches;
const DcbSearchResultData({required this.path, required this.index, required this.matches});
}

View File

@ -0,0 +1,108 @@
class DohClientResponseData {
DohClientResponseData({
this.status,
this.tc,
this.rd,
this.ra,
this.ad,
this.cd,
this.question,
this.answer,
});
DohClientResponseData.fromJson(dynamic json) {
status = json['Status'];
tc = json['TC'];
rd = json['RD'];
ra = json['RA'];
ad = json['AD'];
cd = json['CD'];
question = json['Question'] != null
? DohClientResponseQuestionData.fromJson(json['Question'])
: null;
if (json['Answer'] != null) {
answer = [];
json['Answer'].forEach((v) {
answer?.add(DohClientResponseAnswerData.fromJson(v));
});
}
}
num? status;
bool? tc;
bool? rd;
bool? ra;
bool? ad;
bool? cd;
DohClientResponseQuestionData? question;
List<DohClientResponseAnswerData>? answer;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['Status'] = status;
map['TC'] = tc;
map['RD'] = rd;
map['RA'] = ra;
map['AD'] = ad;
map['CD'] = cd;
if (question != null) {
map['Question'] = question?.toJson();
}
if (answer != null) {
map['Answer'] = answer?.map((v) => v.toJson()).toList();
}
return map;
}
}
class DohClientResponseAnswerData {
DohClientResponseAnswerData({
this.name,
this.ttl,
this.type,
this.data,
});
DohClientResponseAnswerData.fromJson(dynamic json) {
name = json['name'];
ttl = json['TTL'];
type = json['type'];
data = json['data'];
}
String? name;
num? ttl;
num? type;
String? data;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['name'] = name;
map['TTL'] = ttl;
map['type'] = type;
map['data'] = data;
return map;
}
}
class DohClientResponseQuestionData {
DohClientResponseQuestionData({
this.name,
this.type,
});
DohClientResponseQuestionData.fromJson(dynamic json) {
name = json['name'];
type = json['type'];
}
String? name;
num? type;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['name'] = name;
map['type'] = type;
return map;
}
}

View File

@ -17,6 +17,7 @@ class GamePerformanceData {
this.min,
this.value,
this.group,
this.defaultValue,
});
GamePerformanceData.fromJson(dynamic json) {
@ -28,6 +29,8 @@ class GamePerformanceData {
min = json['min'];
value = json['value'];
group = json['group'];
// Store the initial value as default value
defaultValue = json['value'];
}
String? key;
String? name;
@ -37,6 +40,7 @@ class GamePerformanceData {
num? min;
num? value;
String? group;
num? defaultValue;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};

View File

@ -0,0 +1,52 @@
class InputMethodApiData {
InputMethodApiData({
this.enable,
this.languages,
});
InputMethodApiData.fromJson(dynamic json) {
enable = json['enable'];
if (json['languages'] != null) {
languages = <String, InputMethodApiLanguageData>{};
json['languages'].forEach((String key, dynamic v) {
languages![key] = InputMethodApiLanguageData.fromJson(v);
});
}
}
bool? enable;
Map<String, InputMethodApiLanguageData>? languages;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['enable'] = enable;
if (languages != null) {
map['languages'] = languages!.map<String, dynamic>((key, value) {
return MapEntry(key, value.toJson());
});
}
return map;
}
}
class InputMethodApiLanguageData {
InputMethodApiLanguageData({
this.file,
this.version,
});
InputMethodApiLanguageData.fromJson(dynamic json) {
file = json['file'];
version = json['version'];
}
String? file;
String? version;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['file'] = file;
map['version'] = version;
return map;
}
}

246
lib/data/nav_api_data.dart Normal file
View File

@ -0,0 +1,246 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'nav_api_data.freezed.dart';
part 'nav_api_data.g.dart';
@freezed
abstract class NavApiDocsItemData with _$NavApiDocsItemData {
const factory NavApiDocsItemData({
@Default('') @JsonKey(name: 'id') String id,
@Default('') @JsonKey(name: 'name') String name,
@Default('') @JsonKey(name: 'slug') String slug,
@Default('') @JsonKey(name: 'abstract') String abstract_,
@Default('') @JsonKey(name: 'description') String description,
@Default(NavApiDocsItemImageData())
@JsonKey(name: 'image')
NavApiDocsItemImageData image,
@Default('') @JsonKey(name: 'link') String link,
@Default(false) @JsonKey(name: 'is_sponsored') bool isSponsored,
@Default(<NavApiDocsItemTagsItemData>[])
@JsonKey(name: 'tags')
List<NavApiDocsItemTagsItemData> tags,
@Default('') @JsonKey(name: 'updatedAt') String updatedAt,
@Default('') @JsonKey(name: 'createdAt') String createdAt,
}) = _NavApiDocsItemData;
const NavApiDocsItemData._();
factory NavApiDocsItemData.fromJson(Map<String, Object?> json) =>
_$NavApiDocsItemDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageData with _$NavApiDocsItemImageData {
const factory NavApiDocsItemImageData({
@Default('') @JsonKey(name: 'id') String id,
@Default(NavApiDocsItemImageCreatedByData())
@JsonKey(name: 'createdBy')
NavApiDocsItemImageCreatedByData createdBy,
@Default('') @JsonKey(name: 'title') String title,
@Default(false) @JsonKey(name: 'original') bool original,
@Default('') @JsonKey(name: 'credit') String credit,
@Default('') @JsonKey(name: 'source') String source,
@Default('') @JsonKey(name: 'license') String license,
@JsonKey(name: 'caption') dynamic caption,
@Default('') @JsonKey(name: 'updatedAt') String updatedAt,
@Default('') @JsonKey(name: 'createdAt') String createdAt,
@Default('') @JsonKey(name: 'url') String url,
@Default('') @JsonKey(name: 'filename') String filename,
@Default('') @JsonKey(name: 'mimeType') String mimeType,
@Default(0) @JsonKey(name: 'filesize') int filesize,
@Default(0) @JsonKey(name: 'width') int width,
@Default(0) @JsonKey(name: 'height') int height,
@Default(NavApiDocsItemImageSizesData())
@JsonKey(name: 'sizes')
NavApiDocsItemImageSizesData sizes,
}) = _NavApiDocsItemImageData;
const NavApiDocsItemImageData._();
factory NavApiDocsItemImageData.fromJson(Map<String, Object?> json) =>
_$NavApiDocsItemImageDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageCreatedByData with _$NavApiDocsItemImageCreatedByData {
const factory NavApiDocsItemImageCreatedByData({
@Default('') @JsonKey(name: 'id') String id,
@Default('') @JsonKey(name: 'sub') String sub,
@Default('') @JsonKey(name: 'external_provider') String externalProvider,
@Default('') @JsonKey(name: 'username') String username,
@Default('') @JsonKey(name: 'name') String name,
@Default(<String>[]) @JsonKey(name: 'roles') List<String> roles,
@Default('') @JsonKey(name: 'avatar_url') String avatarUrl,
@Default('') @JsonKey(name: 'updatedAt') String updatedAt,
@Default('') @JsonKey(name: 'createdAt') String createdAt,
@Default('') @JsonKey(name: 'email') String email,
@Default(0) @JsonKey(name: 'loginAttempts') int loginAttempts,
@Default('') @JsonKey(name: 'avatar') String avatar,
}) = _NavApiDocsItemImageCreatedByData;
const NavApiDocsItemImageCreatedByData._();
factory NavApiDocsItemImageCreatedByData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageCreatedByDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesThumbnailData
with _$NavApiDocsItemImageSizesThumbnailData {
const factory NavApiDocsItemImageSizesThumbnailData({
@Default('') @JsonKey(name: 'url') String url,
@Default(0) @JsonKey(name: 'width') int width,
@Default(0) @JsonKey(name: 'height') int height,
@Default('') @JsonKey(name: 'mimeType') String mimeType,
@Default(0) @JsonKey(name: 'filesize') int filesize,
@Default('') @JsonKey(name: 'filename') String filename,
}) = _NavApiDocsItemImageSizesThumbnailData;
const NavApiDocsItemImageSizesThumbnailData._();
factory NavApiDocsItemImageSizesThumbnailData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesThumbnailDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesData with _$NavApiDocsItemImageSizesData {
const factory NavApiDocsItemImageSizesData({
@Default(NavApiDocsItemImageSizesThumbnailData())
@JsonKey(name: 'thumbnail')
NavApiDocsItemImageSizesThumbnailData thumbnail,
@Default(NavApiDocsItemImageSizesPreloadData())
@JsonKey(name: 'preload')
NavApiDocsItemImageSizesPreloadData preload,
@Default(NavApiDocsItemImageSizesCardData())
@JsonKey(name: 'card')
NavApiDocsItemImageSizesCardData card,
@Default(NavApiDocsItemImageSizesTabletData())
@JsonKey(name: 'tablet')
NavApiDocsItemImageSizesTabletData tablet,
@Default(NavApiDocsItemImageSizesAvatarData())
@JsonKey(name: 'avatar')
NavApiDocsItemImageSizesAvatarData avatar,
}) = _NavApiDocsItemImageSizesData;
const NavApiDocsItemImageSizesData._();
factory NavApiDocsItemImageSizesData.fromJson(Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesPreloadData
with _$NavApiDocsItemImageSizesPreloadData {
const factory NavApiDocsItemImageSizesPreloadData({
@JsonKey(name: 'url') dynamic url,
@JsonKey(name: 'width') dynamic width,
@JsonKey(name: 'height') dynamic height,
@JsonKey(name: 'mimeType') dynamic mimeType,
@JsonKey(name: 'filesize') dynamic filesize,
@JsonKey(name: 'filename') dynamic filename,
}) = _NavApiDocsItemImageSizesPreloadData;
const NavApiDocsItemImageSizesPreloadData._();
factory NavApiDocsItemImageSizesPreloadData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesPreloadDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesCardData with _$NavApiDocsItemImageSizesCardData {
const factory NavApiDocsItemImageSizesCardData({
@Default('') @JsonKey(name: 'url') String url,
@Default(0) @JsonKey(name: 'width') int width,
@Default(0) @JsonKey(name: 'height') int height,
@Default('') @JsonKey(name: 'mimeType') String mimeType,
@Default(0) @JsonKey(name: 'filesize') int filesize,
@Default('') @JsonKey(name: 'filename') String filename,
}) = _NavApiDocsItemImageSizesCardData;
const NavApiDocsItemImageSizesCardData._();
factory NavApiDocsItemImageSizesCardData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesCardDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesTabletData
with _$NavApiDocsItemImageSizesTabletData {
const factory NavApiDocsItemImageSizesTabletData({
@Default('') @JsonKey(name: 'url') String url,
@Default(0) @JsonKey(name: 'width') int width,
@Default(0) @JsonKey(name: 'height') int height,
@Default('') @JsonKey(name: 'mimeType') String mimeType,
@Default(0) @JsonKey(name: 'filesize') int filesize,
@Default('') @JsonKey(name: 'filename') String filename,
}) = _NavApiDocsItemImageSizesTabletData;
const NavApiDocsItemImageSizesTabletData._();
factory NavApiDocsItemImageSizesTabletData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesTabletDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemImageSizesAvatarData
with _$NavApiDocsItemImageSizesAvatarData {
const factory NavApiDocsItemImageSizesAvatarData({
@Default('') @JsonKey(name: 'url') String url,
@Default(0) @JsonKey(name: 'width') int width,
@Default(0) @JsonKey(name: 'height') int height,
@Default('') @JsonKey(name: 'mimeType') String mimeType,
@Default(0) @JsonKey(name: 'filesize') int filesize,
@Default('') @JsonKey(name: 'filename') String filename,
}) = _NavApiDocsItemImageSizesAvatarData;
const NavApiDocsItemImageSizesAvatarData._();
factory NavApiDocsItemImageSizesAvatarData.fromJson(
Map<String, Object?> json) =>
_$NavApiDocsItemImageSizesAvatarDataFromJson(json);
}
@freezed
abstract class NavApiDocsItemTagsItemData with _$NavApiDocsItemTagsItemData {
const factory NavApiDocsItemTagsItemData({
@Default('') @JsonKey(name: 'id') String id,
@Default('') @JsonKey(name: 'name') String name,
@Default('') @JsonKey(name: 'slug') String slug,
@Default('') @JsonKey(name: 'updatedAt') String updatedAt,
@Default('') @JsonKey(name: 'createdAt') String createdAt,
}) = _NavApiDocsItemTagsItemData;
const NavApiDocsItemTagsItemData._();
factory NavApiDocsItemTagsItemData.fromJson(Map<String, Object?> json) =>
_$NavApiDocsItemTagsItemDataFromJson(json);
}
@freezed
abstract class NavApiData with _$NavApiData {
const factory NavApiData({
@Default(<NavApiDocsItemData>[])
@JsonKey(name: 'docs')
List<NavApiDocsItemData> docs,
@Default(false) @JsonKey(name: 'hasNextPage') bool hasNextPage,
@Default(false) @JsonKey(name: 'hasPrevPage') bool hasPrevPage,
@Default(0) @JsonKey(name: 'limit') int limit,
@JsonKey(name: 'nextPage') dynamic nextPage,
@Default(0) @JsonKey(name: 'page') int page,
@Default(0) @JsonKey(name: 'pagingCounter') int pagingCounter,
@JsonKey(name: 'prevPage') dynamic prevPage,
@Default(0) @JsonKey(name: 'totalDocs') int totalDocs,
@Default(0) @JsonKey(name: 'totalPages') int totalPages,
}) = _NavApiData;
const NavApiData._();
factory NavApiData.fromJson(Map<String, Object?> json) =>
_$NavApiDataFromJson(json);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,336 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'nav_api_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_NavApiDocsItemData _$NavApiDocsItemDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemData(
id: json['id'] as String? ?? '',
name: json['name'] as String? ?? '',
slug: json['slug'] as String? ?? '',
abstract_: json['abstract'] as String? ?? '',
description: json['description'] as String? ?? '',
image: json['image'] == null
? const NavApiDocsItemImageData()
: NavApiDocsItemImageData.fromJson(json['image'] as Map<String, dynamic>),
link: json['link'] as String? ?? '',
isSponsored: json['is_sponsored'] as bool? ?? false,
tags:
(json['tags'] as List<dynamic>?)
?.map(
(e) =>
NavApiDocsItemTagsItemData.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const <NavApiDocsItemTagsItemData>[],
updatedAt: json['updatedAt'] as String? ?? '',
createdAt: json['createdAt'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemDataToJson(_NavApiDocsItemData instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'slug': instance.slug,
'abstract': instance.abstract_,
'description': instance.description,
'image': instance.image,
'link': instance.link,
'is_sponsored': instance.isSponsored,
'tags': instance.tags,
'updatedAt': instance.updatedAt,
'createdAt': instance.createdAt,
};
_NavApiDocsItemImageData _$NavApiDocsItemImageDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemImageData(
id: json['id'] as String? ?? '',
createdBy: json['createdBy'] == null
? const NavApiDocsItemImageCreatedByData()
: NavApiDocsItemImageCreatedByData.fromJson(
json['createdBy'] as Map<String, dynamic>,
),
title: json['title'] as String? ?? '',
original: json['original'] as bool? ?? false,
credit: json['credit'] as String? ?? '',
source: json['source'] as String? ?? '',
license: json['license'] as String? ?? '',
caption: json['caption'],
updatedAt: json['updatedAt'] as String? ?? '',
createdAt: json['createdAt'] as String? ?? '',
url: json['url'] as String? ?? '',
filename: json['filename'] as String? ?? '',
mimeType: json['mimeType'] as String? ?? '',
filesize: (json['filesize'] as num?)?.toInt() ?? 0,
width: (json['width'] as num?)?.toInt() ?? 0,
height: (json['height'] as num?)?.toInt() ?? 0,
sizes: json['sizes'] == null
? const NavApiDocsItemImageSizesData()
: NavApiDocsItemImageSizesData.fromJson(
json['sizes'] as Map<String, dynamic>,
),
);
Map<String, dynamic> _$NavApiDocsItemImageDataToJson(
_NavApiDocsItemImageData instance,
) => <String, dynamic>{
'id': instance.id,
'createdBy': instance.createdBy,
'title': instance.title,
'original': instance.original,
'credit': instance.credit,
'source': instance.source,
'license': instance.license,
'caption': instance.caption,
'updatedAt': instance.updatedAt,
'createdAt': instance.createdAt,
'url': instance.url,
'filename': instance.filename,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'width': instance.width,
'height': instance.height,
'sizes': instance.sizes,
};
_NavApiDocsItemImageCreatedByData _$NavApiDocsItemImageCreatedByDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemImageCreatedByData(
id: json['id'] as String? ?? '',
sub: json['sub'] as String? ?? '',
externalProvider: json['external_provider'] as String? ?? '',
username: json['username'] as String? ?? '',
name: json['name'] as String? ?? '',
roles:
(json['roles'] as List<dynamic>?)?.map((e) => e as String).toList() ??
const <String>[],
avatarUrl: json['avatar_url'] as String? ?? '',
updatedAt: json['updatedAt'] as String? ?? '',
createdAt: json['createdAt'] as String? ?? '',
email: json['email'] as String? ?? '',
loginAttempts: (json['loginAttempts'] as num?)?.toInt() ?? 0,
avatar: json['avatar'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemImageCreatedByDataToJson(
_NavApiDocsItemImageCreatedByData instance,
) => <String, dynamic>{
'id': instance.id,
'sub': instance.sub,
'external_provider': instance.externalProvider,
'username': instance.username,
'name': instance.name,
'roles': instance.roles,
'avatar_url': instance.avatarUrl,
'updatedAt': instance.updatedAt,
'createdAt': instance.createdAt,
'email': instance.email,
'loginAttempts': instance.loginAttempts,
'avatar': instance.avatar,
};
_NavApiDocsItemImageSizesThumbnailData
_$NavApiDocsItemImageSizesThumbnailDataFromJson(Map<String, dynamic> json) =>
_NavApiDocsItemImageSizesThumbnailData(
url: json['url'] as String? ?? '',
width: (json['width'] as num?)?.toInt() ?? 0,
height: (json['height'] as num?)?.toInt() ?? 0,
mimeType: json['mimeType'] as String? ?? '',
filesize: (json['filesize'] as num?)?.toInt() ?? 0,
filename: json['filename'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemImageSizesThumbnailDataToJson(
_NavApiDocsItemImageSizesThumbnailData instance,
) => <String, dynamic>{
'url': instance.url,
'width': instance.width,
'height': instance.height,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'filename': instance.filename,
};
_NavApiDocsItemImageSizesData _$NavApiDocsItemImageSizesDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemImageSizesData(
thumbnail: json['thumbnail'] == null
? const NavApiDocsItemImageSizesThumbnailData()
: NavApiDocsItemImageSizesThumbnailData.fromJson(
json['thumbnail'] as Map<String, dynamic>,
),
preload: json['preload'] == null
? const NavApiDocsItemImageSizesPreloadData()
: NavApiDocsItemImageSizesPreloadData.fromJson(
json['preload'] as Map<String, dynamic>,
),
card: json['card'] == null
? const NavApiDocsItemImageSizesCardData()
: NavApiDocsItemImageSizesCardData.fromJson(
json['card'] as Map<String, dynamic>,
),
tablet: json['tablet'] == null
? const NavApiDocsItemImageSizesTabletData()
: NavApiDocsItemImageSizesTabletData.fromJson(
json['tablet'] as Map<String, dynamic>,
),
avatar: json['avatar'] == null
? const NavApiDocsItemImageSizesAvatarData()
: NavApiDocsItemImageSizesAvatarData.fromJson(
json['avatar'] as Map<String, dynamic>,
),
);
Map<String, dynamic> _$NavApiDocsItemImageSizesDataToJson(
_NavApiDocsItemImageSizesData instance,
) => <String, dynamic>{
'thumbnail': instance.thumbnail,
'preload': instance.preload,
'card': instance.card,
'tablet': instance.tablet,
'avatar': instance.avatar,
};
_NavApiDocsItemImageSizesPreloadData
_$NavApiDocsItemImageSizesPreloadDataFromJson(Map<String, dynamic> json) =>
_NavApiDocsItemImageSizesPreloadData(
url: json['url'],
width: json['width'],
height: json['height'],
mimeType: json['mimeType'],
filesize: json['filesize'],
filename: json['filename'],
);
Map<String, dynamic> _$NavApiDocsItemImageSizesPreloadDataToJson(
_NavApiDocsItemImageSizesPreloadData instance,
) => <String, dynamic>{
'url': instance.url,
'width': instance.width,
'height': instance.height,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'filename': instance.filename,
};
_NavApiDocsItemImageSizesCardData _$NavApiDocsItemImageSizesCardDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemImageSizesCardData(
url: json['url'] as String? ?? '',
width: (json['width'] as num?)?.toInt() ?? 0,
height: (json['height'] as num?)?.toInt() ?? 0,
mimeType: json['mimeType'] as String? ?? '',
filesize: (json['filesize'] as num?)?.toInt() ?? 0,
filename: json['filename'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemImageSizesCardDataToJson(
_NavApiDocsItemImageSizesCardData instance,
) => <String, dynamic>{
'url': instance.url,
'width': instance.width,
'height': instance.height,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'filename': instance.filename,
};
_NavApiDocsItemImageSizesTabletData
_$NavApiDocsItemImageSizesTabletDataFromJson(Map<String, dynamic> json) =>
_NavApiDocsItemImageSizesTabletData(
url: json['url'] as String? ?? '',
width: (json['width'] as num?)?.toInt() ?? 0,
height: (json['height'] as num?)?.toInt() ?? 0,
mimeType: json['mimeType'] as String? ?? '',
filesize: (json['filesize'] as num?)?.toInt() ?? 0,
filename: json['filename'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemImageSizesTabletDataToJson(
_NavApiDocsItemImageSizesTabletData instance,
) => <String, dynamic>{
'url': instance.url,
'width': instance.width,
'height': instance.height,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'filename': instance.filename,
};
_NavApiDocsItemImageSizesAvatarData
_$NavApiDocsItemImageSizesAvatarDataFromJson(Map<String, dynamic> json) =>
_NavApiDocsItemImageSizesAvatarData(
url: json['url'] as String? ?? '',
width: (json['width'] as num?)?.toInt() ?? 0,
height: (json['height'] as num?)?.toInt() ?? 0,
mimeType: json['mimeType'] as String? ?? '',
filesize: (json['filesize'] as num?)?.toInt() ?? 0,
filename: json['filename'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemImageSizesAvatarDataToJson(
_NavApiDocsItemImageSizesAvatarData instance,
) => <String, dynamic>{
'url': instance.url,
'width': instance.width,
'height': instance.height,
'mimeType': instance.mimeType,
'filesize': instance.filesize,
'filename': instance.filename,
};
_NavApiDocsItemTagsItemData _$NavApiDocsItemTagsItemDataFromJson(
Map<String, dynamic> json,
) => _NavApiDocsItemTagsItemData(
id: json['id'] as String? ?? '',
name: json['name'] as String? ?? '',
slug: json['slug'] as String? ?? '',
updatedAt: json['updatedAt'] as String? ?? '',
createdAt: json['createdAt'] as String? ?? '',
);
Map<String, dynamic> _$NavApiDocsItemTagsItemDataToJson(
_NavApiDocsItemTagsItemData instance,
) => <String, dynamic>{
'id': instance.id,
'name': instance.name,
'slug': instance.slug,
'updatedAt': instance.updatedAt,
'createdAt': instance.createdAt,
};
_NavApiData _$NavApiDataFromJson(Map<String, dynamic> json) => _NavApiData(
docs:
(json['docs'] as List<dynamic>?)
?.map((e) => NavApiDocsItemData.fromJson(e as Map<String, dynamic>))
.toList() ??
const <NavApiDocsItemData>[],
hasNextPage: json['hasNextPage'] as bool? ?? false,
hasPrevPage: json['hasPrevPage'] as bool? ?? false,
limit: (json['limit'] as num?)?.toInt() ?? 0,
nextPage: json['nextPage'],
page: (json['page'] as num?)?.toInt() ?? 0,
pagingCounter: (json['pagingCounter'] as num?)?.toInt() ?? 0,
prevPage: json['prevPage'],
totalDocs: (json['totalDocs'] as num?)?.toInt() ?? 0,
totalPages: (json['totalPages'] as num?)?.toInt() ?? 0,
);
Map<String, dynamic> _$NavApiDataToJson(_NavApiData instance) =>
<String, dynamic>{
'docs': instance.docs,
'hasNextPage': instance.hasNextPage,
'hasPrevPage': instance.hasPrevPage,
'limit': instance.limit,
'nextPage': instance.nextPage,
'page': instance.page,
'pagingCounter': instance.pagingCounter,
'prevPage': instance.prevPage,
'totalDocs': instance.totalDocs,
'totalPages': instance.totalPages,
};

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

@ -18,6 +18,7 @@ import 'package:intl/src/intl_helpers.dart';
import 'messages_en.dart' as messages_en;
import 'messages_ja.dart' as messages_ja;
import 'messages_ru.dart' as messages_ru;
import 'messages_zh_CN.dart' as messages_zh_cn;
import 'messages_zh_TW.dart' as messages_zh_tw;
@ -25,6 +26,7 @@ typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en': () => new SynchronousFuture(null),
'ja': () => new SynchronousFuture(null),
'ru': () => new SynchronousFuture(null),
'zh_CN': () => new SynchronousFuture(null),
'zh_TW': () => new SynchronousFuture(null),
};
@ -35,6 +37,8 @@ MessageLookupByLibrary? _findExact(String localeName) {
return messages_en.messages;
case 'ja':
return messages_ja.messages;
case 'ru':
return messages_ru.messages;
case 'zh_CN':
return messages_zh_cn.messages;
case 'zh_TW':
@ -47,8 +51,10 @@ MessageLookupByLibrary? _findExact(String localeName) {
/// 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);
localeName,
(locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null,
);
if (availableLocale == null) {
return new SynchronousFuture(false);
}
@ -68,8 +74,11 @@ bool _messagesExistFor(String locale) {
}
MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
var actualLocale =
Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null);
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,4 +2,10 @@ 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';
static const String langRU = 'Русский';
static const String langCodeZhCn = 'zh_CN';
static const String aniCatTitle = '【寰宇周刊】';
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
// This is a generated file - do not edit.
//
// Generated from proto/auth/auth.proto.
// @dart = 3.3
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports

View File

@ -0,0 +1,341 @@
// This is a generated file - do not edit.
//
// Generated from proto/auth/auth.proto.
// @dart = 3.3
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
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 'auth.pb.dart' as $0;
export 'auth.pb.dart';
///
@$pb.GrpcServiceName('auth.AuthService')
class AuthServiceClient extends $grpc.Client {
/// The hostname for this service.
static const $core.String defaultHost = '';
/// OAuth scopes needed for the client.
static const $core.List<$core.String> oauthScopes = [
'',
];
AuthServiceClient(super.channel, {super.options, super.interceptors});
///
$grpc.ResponseFuture<$0.StatusResponse> status(
$0.StatusRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$status, request, options: options);
}
///
$grpc.ResponseFuture<$0.LoginResponse> login(
$0.LoginRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$login, request, options: options);
}
///
$grpc.ResponseFuture<$0.PreRegisterResponse> preRegister(
$0.PreRegisterRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$preRegister, request, options: options);
}
///
$grpc.ResponseFuture<$0.RegisterResponse> register(
$0.RegisterRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$register, request, options: options);
}
///
$grpc.ResponseFuture<$0.UnregisterResponse> unregister(
$0.UnregisterRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$unregister, request, options: options);
}
/// JWT token
$grpc.ResponseFuture<$0.ValidateTokenResponse> validateToken(
$0.ValidateTokenRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$validateToken, request, options: options);
}
///
$grpc.ResponseFuture<$0.GetPublicKeyResponse> getPublicKey(
$0.GetPublicKeyRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$getPublicKey, request, options: options);
}
$grpc.ResponseFuture<$0.GetJWTDomainListResponse> getJWTDomainList(
$0.GetJWTDomainListRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$getJWTDomainList, request, options: options);
}
///
$grpc.ResponseFuture<$0.RefreshUserProfileResponse> refreshUserProfile(
$0.RefreshUserProfileRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$refreshUserProfile, request, options: options);
}
/// OIDC App 使
$grpc.ResponseFuture<$0.GenerateOIDCAuthCodeResponse> generateOIDCAuthCode(
$0.GenerateOIDCAuthCodeRequest request, {
$grpc.CallOptions? options,
}) {
return $createUnaryCall(_$generateOIDCAuthCode, request, options: options);
}
// method descriptors
static final _$status =
$grpc.ClientMethod<$0.StatusRequest, $0.StatusResponse>(
'/auth.AuthService/Status',
($0.StatusRequest value) => value.writeToBuffer(),
$0.StatusResponse.fromBuffer);
static final _$login = $grpc.ClientMethod<$0.LoginRequest, $0.LoginResponse>(
'/auth.AuthService/Login',
($0.LoginRequest value) => value.writeToBuffer(),
$0.LoginResponse.fromBuffer);
static final _$preRegister =
$grpc.ClientMethod<$0.PreRegisterRequest, $0.PreRegisterResponse>(
'/auth.AuthService/PreRegister',
($0.PreRegisterRequest value) => value.writeToBuffer(),
$0.PreRegisterResponse.fromBuffer);
static final _$register =
$grpc.ClientMethod<$0.RegisterRequest, $0.RegisterResponse>(
'/auth.AuthService/Register',
($0.RegisterRequest value) => value.writeToBuffer(),
$0.RegisterResponse.fromBuffer);
static final _$unregister =
$grpc.ClientMethod<$0.UnregisterRequest, $0.UnregisterResponse>(
'/auth.AuthService/Unregister',
($0.UnregisterRequest value) => value.writeToBuffer(),
$0.UnregisterResponse.fromBuffer);
static final _$validateToken =
$grpc.ClientMethod<$0.ValidateTokenRequest, $0.ValidateTokenResponse>(
'/auth.AuthService/ValidateToken',
($0.ValidateTokenRequest value) => value.writeToBuffer(),
$0.ValidateTokenResponse.fromBuffer);
static final _$getPublicKey =
$grpc.ClientMethod<$0.GetPublicKeyRequest, $0.GetPublicKeyResponse>(
'/auth.AuthService/GetPublicKey',
($0.GetPublicKeyRequest value) => value.writeToBuffer(),
$0.GetPublicKeyResponse.fromBuffer);
static final _$getJWTDomainList = $grpc.ClientMethod<
$0.GetJWTDomainListRequest, $0.GetJWTDomainListResponse>(
'/auth.AuthService/GetJWTDomainList',
($0.GetJWTDomainListRequest value) => value.writeToBuffer(),
$0.GetJWTDomainListResponse.fromBuffer);
static final _$refreshUserProfile = $grpc.ClientMethod<
$0.RefreshUserProfileRequest, $0.RefreshUserProfileResponse>(
'/auth.AuthService/RefreshUserProfile',
($0.RefreshUserProfileRequest value) => value.writeToBuffer(),
$0.RefreshUserProfileResponse.fromBuffer);
static final _$generateOIDCAuthCode = $grpc.ClientMethod<
$0.GenerateOIDCAuthCodeRequest, $0.GenerateOIDCAuthCodeResponse>(
'/auth.AuthService/GenerateOIDCAuthCode',
($0.GenerateOIDCAuthCodeRequest value) => value.writeToBuffer(),
$0.GenerateOIDCAuthCodeResponse.fromBuffer);
}
@$pb.GrpcServiceName('auth.AuthService')
abstract class AuthServiceBase extends $grpc.Service {
$core.String get $name => 'auth.AuthService';
AuthServiceBase() {
$addMethod($grpc.ServiceMethod<$0.StatusRequest, $0.StatusResponse>(
'Status',
status_Pre,
false,
false,
($core.List<$core.int> value) => $0.StatusRequest.fromBuffer(value),
($0.StatusResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.LoginRequest, $0.LoginResponse>(
'Login',
login_Pre,
false,
false,
($core.List<$core.int> value) => $0.LoginRequest.fromBuffer(value),
($0.LoginResponse value) => value.writeToBuffer()));
$addMethod(
$grpc.ServiceMethod<$0.PreRegisterRequest, $0.PreRegisterResponse>(
'PreRegister',
preRegister_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.PreRegisterRequest.fromBuffer(value),
($0.PreRegisterResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.RegisterRequest, $0.RegisterResponse>(
'Register',
register_Pre,
false,
false,
($core.List<$core.int> value) => $0.RegisterRequest.fromBuffer(value),
($0.RegisterResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.UnregisterRequest, $0.UnregisterResponse>(
'Unregister',
unregister_Pre,
false,
false,
($core.List<$core.int> value) => $0.UnregisterRequest.fromBuffer(value),
($0.UnregisterResponse value) => value.writeToBuffer()));
$addMethod(
$grpc.ServiceMethod<$0.ValidateTokenRequest, $0.ValidateTokenResponse>(
'ValidateToken',
validateToken_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.ValidateTokenRequest.fromBuffer(value),
($0.ValidateTokenResponse value) => value.writeToBuffer()));
$addMethod(
$grpc.ServiceMethod<$0.GetPublicKeyRequest, $0.GetPublicKeyResponse>(
'GetPublicKey',
getPublicKey_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.GetPublicKeyRequest.fromBuffer(value),
($0.GetPublicKeyResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.GetJWTDomainListRequest,
$0.GetJWTDomainListResponse>(
'GetJWTDomainList',
getJWTDomainList_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.GetJWTDomainListRequest.fromBuffer(value),
($0.GetJWTDomainListResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.RefreshUserProfileRequest,
$0.RefreshUserProfileResponse>(
'RefreshUserProfile',
refreshUserProfile_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.RefreshUserProfileRequest.fromBuffer(value),
($0.RefreshUserProfileResponse value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.GenerateOIDCAuthCodeRequest,
$0.GenerateOIDCAuthCodeResponse>(
'GenerateOIDCAuthCode',
generateOIDCAuthCode_Pre,
false,
false,
($core.List<$core.int> value) =>
$0.GenerateOIDCAuthCodeRequest.fromBuffer(value),
($0.GenerateOIDCAuthCodeResponse value) => value.writeToBuffer()));
}
$async.Future<$0.StatusResponse> status_Pre(
$grpc.ServiceCall $call, $async.Future<$0.StatusRequest> $request) async {
return status($call, await $request);
}
$async.Future<$0.StatusResponse> status(
$grpc.ServiceCall call, $0.StatusRequest request);
$async.Future<$0.LoginResponse> login_Pre(
$grpc.ServiceCall $call, $async.Future<$0.LoginRequest> $request) async {
return login($call, await $request);
}
$async.Future<$0.LoginResponse> login(
$grpc.ServiceCall call, $0.LoginRequest request);
$async.Future<$0.PreRegisterResponse> preRegister_Pre($grpc.ServiceCall $call,
$async.Future<$0.PreRegisterRequest> $request) async {
return preRegister($call, await $request);
}
$async.Future<$0.PreRegisterResponse> preRegister(
$grpc.ServiceCall call, $0.PreRegisterRequest request);
$async.Future<$0.RegisterResponse> register_Pre($grpc.ServiceCall $call,
$async.Future<$0.RegisterRequest> $request) async {
return register($call, await $request);
}
$async.Future<$0.RegisterResponse> register(
$grpc.ServiceCall call, $0.RegisterRequest request);
$async.Future<$0.UnregisterResponse> unregister_Pre($grpc.ServiceCall $call,
$async.Future<$0.UnregisterRequest> $request) async {
return unregister($call, await $request);
}
$async.Future<$0.UnregisterResponse> unregister(
$grpc.ServiceCall call, $0.UnregisterRequest request);
$async.Future<$0.ValidateTokenResponse> validateToken_Pre(
$grpc.ServiceCall $call,
$async.Future<$0.ValidateTokenRequest> $request) async {
return validateToken($call, await $request);
}
$async.Future<$0.ValidateTokenResponse> validateToken(
$grpc.ServiceCall call, $0.ValidateTokenRequest request);
$async.Future<$0.GetPublicKeyResponse> getPublicKey_Pre(
$grpc.ServiceCall $call,
$async.Future<$0.GetPublicKeyRequest> $request) async {
return getPublicKey($call, await $request);
}
$async.Future<$0.GetPublicKeyResponse> getPublicKey(
$grpc.ServiceCall call, $0.GetPublicKeyRequest request);
$async.Future<$0.GetJWTDomainListResponse> getJWTDomainList_Pre(
$grpc.ServiceCall $call,
$async.Future<$0.GetJWTDomainListRequest> $request) async {
return getJWTDomainList($call, await $request);
}
$async.Future<$0.GetJWTDomainListResponse> getJWTDomainList(
$grpc.ServiceCall call, $0.GetJWTDomainListRequest request);
$async.Future<$0.RefreshUserProfileResponse> refreshUserProfile_Pre(
$grpc.ServiceCall $call,
$async.Future<$0.RefreshUserProfileRequest> $request) async {
return refreshUserProfile($call, await $request);
}
$async.Future<$0.RefreshUserProfileResponse> refreshUserProfile(
$grpc.ServiceCall call, $0.RefreshUserProfileRequest request);
$async.Future<$0.GenerateOIDCAuthCodeResponse> generateOIDCAuthCode_Pre(
$grpc.ServiceCall $call,
$async.Future<$0.GenerateOIDCAuthCodeRequest> $request) async {
return generateOIDCAuthCode($call, await $request);
}
$async.Future<$0.GenerateOIDCAuthCodeResponse> generateOIDCAuthCode(
$grpc.ServiceCall call, $0.GenerateOIDCAuthCodeRequest request);
}

View File

@ -0,0 +1,351 @@
// This is a generated file - do not edit.
//
// Generated from proto/auth/auth.proto.
// @dart = 3.3
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use generateOIDCAuthCodeRequestDescriptor instead')
const GenerateOIDCAuthCodeRequest$json = {
'1': 'GenerateOIDCAuthCodeRequest',
'2': [
{'1': 'nonce', '3': 1, '4': 1, '5': 9, '10': 'nonce'},
{'1': 'redirect_uri', '3': 2, '4': 1, '5': 9, '10': 'redirectUri'},
],
};
/// Descriptor for `GenerateOIDCAuthCodeRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List generateOIDCAuthCodeRequestDescriptor =
$convert.base64Decode(
'ChtHZW5lcmF0ZU9JRENBdXRoQ29kZVJlcXVlc3QSFAoFbm9uY2UYASABKAlSBW5vbmNlEiEKDH'
'JlZGlyZWN0X3VyaRgCIAEoCVILcmVkaXJlY3RVcmk=');
@$core.Deprecated('Use generateOIDCAuthCodeResponseDescriptor instead')
const GenerateOIDCAuthCodeResponse$json = {
'1': 'GenerateOIDCAuthCodeResponse',
'2': [
{'1': 'code', '3': 1, '4': 1, '5': 9, '10': 'code'},
{'1': 'expires_at', '3': 2, '4': 1, '5': 3, '10': 'expiresAt'},
],
};
/// Descriptor for `GenerateOIDCAuthCodeResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List generateOIDCAuthCodeResponseDescriptor =
$convert.base64Decode(
'ChxHZW5lcmF0ZU9JRENBdXRoQ29kZVJlc3BvbnNlEhIKBGNvZGUYASABKAlSBGNvZGUSHQoKZX'
'hwaXJlc19hdBgCIAEoA1IJZXhwaXJlc0F0');
@$core.Deprecated('Use refreshUserProfileRequestDescriptor instead')
const RefreshUserProfileRequest$json = {
'1': 'RefreshUserProfileRequest',
};
/// Descriptor for `RefreshUserProfileRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List refreshUserProfileRequestDescriptor =
$convert.base64Decode('ChlSZWZyZXNoVXNlclByb2ZpbGVSZXF1ZXN0');
@$core.Deprecated('Use refreshUserProfileResponseDescriptor instead')
const RefreshUserProfileResponse$json = {
'1': 'RefreshUserProfileResponse',
'2': [
{'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
{
'1': 'user_info',
'3': 2,
'4': 1,
'5': 11,
'6': '.auth.GameUserInfo',
'10': 'userInfo'
},
],
};
/// Descriptor for `RefreshUserProfileResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List refreshUserProfileResponseDescriptor =
$convert.base64Decode(
'ChpSZWZyZXNoVXNlclByb2ZpbGVSZXNwb25zZRIYCgdzdWNjZXNzGAEgASgIUgdzdWNjZXNzEi'
'8KCXVzZXJfaW5mbxgCIAEoCzISLmF1dGguR2FtZVVzZXJJbmZvUgh1c2VySW5mbw==');
@$core.Deprecated('Use statusRequestDescriptor instead')
const StatusRequest$json = {
'1': 'StatusRequest',
};
/// Descriptor for `StatusRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List statusRequestDescriptor =
$convert.base64Decode('Cg1TdGF0dXNSZXF1ZXN0');
@$core.Deprecated('Use statusResponseDescriptor instead')
const StatusResponse$json = {
'1': 'StatusResponse',
'2': [
{'1': 'online', '3': 1, '4': 1, '5': 8, '10': 'online'},
{'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'},
{'1': 'server_time', '3': 3, '4': 1, '5': 3, '10': 'serverTime'},
],
};
/// Descriptor for `StatusResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List statusResponseDescriptor = $convert.base64Decode(
'Cg5TdGF0dXNSZXNwb25zZRIWCgZvbmxpbmUYASABKAhSBm9ubGluZRIYCgdtZXNzYWdlGAIgAS'
'gJUgdtZXNzYWdlEh8KC3NlcnZlcl90aW1lGAMgASgDUgpzZXJ2ZXJUaW1l');
@$core.Deprecated('Use loginRequestDescriptor instead')
const LoginRequest$json = {
'1': 'LoginRequest',
};
/// Descriptor for `LoginRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List loginRequestDescriptor =
$convert.base64Decode('CgxMb2dpblJlcXVlc3Q=');
@$core.Deprecated('Use gameUserInfoDescriptor instead')
const GameUserInfo$json = {
'1': 'GameUserInfo',
'2': [
{'1': 'game_user_id', '3': 1, '4': 1, '5': 9, '10': 'gameUserId'},
{'1': 'handle_name', '3': 2, '4': 1, '5': 9, '10': 'handleName'},
{'1': 'avatar_url', '3': 3, '4': 1, '5': 9, '10': 'avatarUrl'},
{'1': 'citizen_record', '3': 4, '4': 1, '5': 9, '10': 'citizenRecord'},
{'1': 'enlisted_date', '3': 5, '4': 1, '5': 3, '10': 'enlistedDate'},
],
};
/// Descriptor for `GameUserInfo`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gameUserInfoDescriptor = $convert.base64Decode(
'CgxHYW1lVXNlckluZm8SIAoMZ2FtZV91c2VyX2lkGAEgASgJUgpnYW1lVXNlcklkEh8KC2hhbm'
'RsZV9uYW1lGAIgASgJUgpoYW5kbGVOYW1lEh0KCmF2YXRhcl91cmwYAyABKAlSCWF2YXRhclVy'
'bBIlCg5jaXRpemVuX3JlY29yZBgEIAEoCVINY2l0aXplblJlY29yZBIjCg1lbmxpc3RlZF9kYX'
'RlGAUgASgDUgxlbmxpc3RlZERhdGU=');
@$core.Deprecated('Use loginResponseDescriptor instead')
const LoginResponse$json = {
'1': 'LoginResponse',
'2': [
{'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
{
'1': 'user_info',
'3': 2,
'4': 1,
'5': 11,
'6': '.auth.GameUserInfo',
'10': 'userInfo'
},
{'1': 'last_login_time', '3': 3, '4': 1, '5': 3, '10': 'lastLoginTime'},
],
};
/// Descriptor for `LoginResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List loginResponseDescriptor = $convert.base64Decode(
'Cg1Mb2dpblJlc3BvbnNlEhIKBHV1aWQYASABKAlSBHV1aWQSLwoJdXNlcl9pbmZvGAIgASgLMh'
'IuYXV0aC5HYW1lVXNlckluZm9SCHVzZXJJbmZvEiYKD2xhc3RfbG9naW5fdGltZRgDIAEoA1IN'
'bGFzdExvZ2luVGltZQ==');
@$core.Deprecated('Use preRegisterRequestDescriptor instead')
const PreRegisterRequest$json = {
'1': 'PreRegisterRequest',
'2': [
{'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
{'1': 'game_user_id', '3': 2, '4': 1, '5': 9, '10': 'gameUserId'},
],
};
/// Descriptor for `PreRegisterRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List preRegisterRequestDescriptor = $convert.base64Decode(
'ChJQcmVSZWdpc3RlclJlcXVlc3QSEgoEdXVpZBgBIAEoCVIEdXVpZBIgCgxnYW1lX3VzZXJfaW'
'QYAiABKAlSCmdhbWVVc2VySWQ=');
@$core.Deprecated('Use preRegisterResponseDescriptor instead')
const PreRegisterResponse$json = {
'1': 'PreRegisterResponse',
'2': [
{
'1': 'verification_code',
'3': 1,
'4': 1,
'5': 9,
'10': 'verificationCode'
},
{'1': 'expire_time', '3': 2, '4': 1, '5': 3, '10': 'expireTime'},
],
};
/// Descriptor for `PreRegisterResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List preRegisterResponseDescriptor = $convert.base64Decode(
'ChNQcmVSZWdpc3RlclJlc3BvbnNlEisKEXZlcmlmaWNhdGlvbl9jb2RlGAEgASgJUhB2ZXJpZm'
'ljYXRpb25Db2RlEh8KC2V4cGlyZV90aW1lGAIgASgDUgpleHBpcmVUaW1l');
@$core.Deprecated('Use registerRequestDescriptor instead')
const RegisterRequest$json = {
'1': 'RegisterRequest',
'2': [
{'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
{'1': 'game_user_id', '3': 2, '4': 1, '5': 9, '10': 'gameUserId'},
],
};
/// Descriptor for `RegisterRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List registerRequestDescriptor = $convert.base64Decode(
'Cg9SZWdpc3RlclJlcXVlc3QSEgoEdXVpZBgBIAEoCVIEdXVpZBIgCgxnYW1lX3VzZXJfaWQYAi'
'ABKAlSCmdhbWVVc2VySWQ=');
@$core.Deprecated('Use registerResponseDescriptor instead')
const RegisterResponse$json = {
'1': 'RegisterResponse',
'2': [
{
'1': 'party_room_secret_key',
'3': 1,
'4': 1,
'5': 9,
'10': 'partyRoomSecretKey'
},
{
'1': 'user_info',
'3': 2,
'4': 1,
'5': 11,
'6': '.auth.GameUserInfo',
'10': 'userInfo'
},
],
};
/// Descriptor for `RegisterResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List registerResponseDescriptor = $convert.base64Decode(
'ChBSZWdpc3RlclJlc3BvbnNlEjEKFXBhcnR5X3Jvb21fc2VjcmV0X2tleRgBIAEoCVIScGFydH'
'lSb29tU2VjcmV0S2V5Ei8KCXVzZXJfaW5mbxgCIAEoCzISLmF1dGguR2FtZVVzZXJJbmZvUgh1'
'c2VySW5mbw==');
@$core.Deprecated('Use unregisterRequestDescriptor instead')
const UnregisterRequest$json = {
'1': 'UnregisterRequest',
};
/// Descriptor for `UnregisterRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List unregisterRequestDescriptor =
$convert.base64Decode('ChFVbnJlZ2lzdGVyUmVxdWVzdA==');
@$core.Deprecated('Use unregisterResponseDescriptor instead')
const UnregisterResponse$json = {
'1': 'UnregisterResponse',
'2': [
{'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
],
};
/// Descriptor for `UnregisterResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List unregisterResponseDescriptor =
$convert.base64Decode(
'ChJVbnJlZ2lzdGVyUmVzcG9uc2USGAoHc3VjY2VzcxgBIAEoCFIHc3VjY2Vzcw==');
@$core.Deprecated('Use validateTokenRequestDescriptor instead')
const ValidateTokenRequest$json = {
'1': 'ValidateTokenRequest',
'2': [
{'1': 'token', '3': 1, '4': 1, '5': 9, '10': 'token'},
],
};
/// Descriptor for `ValidateTokenRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List validateTokenRequestDescriptor =
$convert.base64Decode(
'ChRWYWxpZGF0ZVRva2VuUmVxdWVzdBIUCgV0b2tlbhgBIAEoCVIFdG9rZW4=');
@$core.Deprecated('Use validateTokenResponseDescriptor instead')
const ValidateTokenResponse$json = {
'1': 'ValidateTokenResponse',
'2': [
{'1': 'valid', '3': 1, '4': 1, '5': 8, '10': 'valid'},
{'1': 'domain', '3': 2, '4': 1, '5': 9, '10': 'domain'},
{'1': 'issued_at', '3': 3, '4': 1, '5': 3, '10': 'issuedAt'},
{'1': 'expires_at', '3': 4, '4': 1, '5': 3, '10': 'expiresAt'},
{'1': 'error_message', '3': 5, '4': 1, '5': 9, '10': 'errorMessage'},
],
};
/// Descriptor for `ValidateTokenResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List validateTokenResponseDescriptor = $convert.base64Decode(
'ChVWYWxpZGF0ZVRva2VuUmVzcG9uc2USFAoFdmFsaWQYASABKAhSBXZhbGlkEhYKBmRvbWFpbh'
'gCIAEoCVIGZG9tYWluEhsKCWlzc3VlZF9hdBgDIAEoA1IIaXNzdWVkQXQSHQoKZXhwaXJlc19h'
'dBgEIAEoA1IJZXhwaXJlc0F0EiMKDWVycm9yX21lc3NhZ2UYBSABKAlSDGVycm9yTWVzc2FnZQ'
'==');
@$core.Deprecated('Use getPublicKeyRequestDescriptor instead')
const GetPublicKeyRequest$json = {
'1': 'GetPublicKeyRequest',
};
/// Descriptor for `GetPublicKeyRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List getPublicKeyRequestDescriptor =
$convert.base64Decode('ChNHZXRQdWJsaWNLZXlSZXF1ZXN0');
@$core.Deprecated('Use getPublicKeyResponseDescriptor instead')
const GetPublicKeyResponse$json = {
'1': 'GetPublicKeyResponse',
'2': [
{'1': 'public_key_pem', '3': 1, '4': 1, '5': 9, '10': 'publicKeyPem'},
{'1': 'key_id', '3': 2, '4': 1, '5': 9, '10': 'keyId'},
{'1': 'algorithm', '3': 3, '4': 1, '5': 9, '10': 'algorithm'},
],
};
/// Descriptor for `GetPublicKeyResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List getPublicKeyResponseDescriptor = $convert.base64Decode(
'ChRHZXRQdWJsaWNLZXlSZXNwb25zZRIkCg5wdWJsaWNfa2V5X3BlbRgBIAEoCVIMcHVibGljS2'
'V5UGVtEhUKBmtleV9pZBgCIAEoCVIFa2V5SWQSHAoJYWxnb3JpdGhtGAMgASgJUglhbGdvcml0'
'aG0=');
@$core.Deprecated('Use jWTDomainInfoDescriptor instead')
const JWTDomainInfo$json = {
'1': 'JWTDomainInfo',
'2': [
{'1': 'domain', '3': 1, '4': 1, '5': 9, '10': 'domain'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `JWTDomainInfo`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List jWTDomainInfoDescriptor = $convert.base64Decode(
'Cg1KV1REb21haW5JbmZvEhYKBmRvbWFpbhgBIAEoCVIGZG9tYWluEhIKBG5hbWUYAiABKAlSBG'
'5hbWU=');
@$core.Deprecated('Use getJWTDomainListRequestDescriptor instead')
const GetJWTDomainListRequest$json = {
'1': 'GetJWTDomainListRequest',
};
/// Descriptor for `GetJWTDomainListRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List getJWTDomainListRequestDescriptor =
$convert.base64Decode('ChdHZXRKV1REb21haW5MaXN0UmVxdWVzdA==');
@$core.Deprecated('Use getJWTDomainListResponseDescriptor instead')
const GetJWTDomainListResponse$json = {
'1': 'GetJWTDomainListResponse',
'2': [
{
'1': 'domains',
'3': 1,
'4': 3,
'5': 11,
'6': '.auth.JWTDomainInfo',
'10': 'domains'
},
],
};
/// Descriptor for `GetJWTDomainListResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List getJWTDomainListResponseDescriptor =
$convert.base64Decode(
'ChhHZXRKV1REb21haW5MaXN0UmVzcG9uc2USLQoHZG9tYWlucxgBIAMoCzITLmF1dGguSldURG'
'9tYWluSW5mb1IHZG9tYWlucw==');

View File

@ -0,0 +1,601 @@
// This is a generated file - do not edit.
//
// Generated from proto/common/common.proto.
// @dart = 3.3
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
///
class GetServerTimeRequest extends $pb.GeneratedMessage {
factory GetServerTimeRequest() => create();
GetServerTimeRequest._();
factory GetServerTimeRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetServerTimeRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetServerTimeRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetServerTimeRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetServerTimeRequest copyWith(void Function(GetServerTimeRequest) updates) =>
super.copyWith((message) => updates(message as GetServerTimeRequest))
as GetServerTimeRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetServerTimeRequest create() => GetServerTimeRequest._();
@$core.override
GetServerTimeRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetServerTimeRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetServerTimeRequest>(create);
static GetServerTimeRequest? _defaultInstance;
}
///
class GetServerTimeResponse extends $pb.GeneratedMessage {
factory GetServerTimeResponse({
$fixnum.Int64? timestamp,
$core.String? timezone,
}) {
final result = create();
if (timestamp != null) result.timestamp = timestamp;
if (timezone != null) result.timezone = timezone;
return result;
}
GetServerTimeResponse._();
factory GetServerTimeResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetServerTimeResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetServerTimeResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..aInt64(1, _omitFieldNames ? '' : 'timestamp')
..aOS(2, _omitFieldNames ? '' : 'timezone')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetServerTimeResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetServerTimeResponse copyWith(
void Function(GetServerTimeResponse) updates) =>
super.copyWith((message) => updates(message as GetServerTimeResponse))
as GetServerTimeResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetServerTimeResponse create() => GetServerTimeResponse._();
@$core.override
GetServerTimeResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetServerTimeResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetServerTimeResponse>(create);
static GetServerTimeResponse? _defaultInstance;
@$pb.TagNumber(1)
$fixnum.Int64 get timestamp => $_getI64(0);
@$pb.TagNumber(1)
set timestamp($fixnum.Int64 value) => $_setInt64(0, value);
@$pb.TagNumber(1)
$core.bool hasTimestamp() => $_has(0);
@$pb.TagNumber(1)
void clearTimestamp() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get timezone => $_getSZ(1);
@$pb.TagNumber(2)
set timezone($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasTimezone() => $_has(1);
@$pb.TagNumber(2)
void clearTimezone() => $_clearField(2);
}
///
class GetVersionRequest extends $pb.GeneratedMessage {
factory GetVersionRequest() => create();
GetVersionRequest._();
factory GetVersionRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetVersionRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetVersionRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetVersionRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetVersionRequest copyWith(void Function(GetVersionRequest) updates) =>
super.copyWith((message) => updates(message as GetVersionRequest))
as GetVersionRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetVersionRequest create() => GetVersionRequest._();
@$core.override
GetVersionRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetVersionRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetVersionRequest>(create);
static GetVersionRequest? _defaultInstance;
}
///
class GetVersionResponse extends $pb.GeneratedMessage {
factory GetVersionResponse({
$core.int? version,
$core.int? latestVersion,
$core.int? minClientVersion,
}) {
final result = create();
if (version != null) result.version = version;
if (latestVersion != null) result.latestVersion = latestVersion;
if (minClientVersion != null) result.minClientVersion = minClientVersion;
return result;
}
GetVersionResponse._();
factory GetVersionResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetVersionResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetVersionResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..aI(1, _omitFieldNames ? '' : 'version')
..aI(2, _omitFieldNames ? '' : 'latestVersion')
..aI(3, _omitFieldNames ? '' : 'minClientVersion')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetVersionResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetVersionResponse copyWith(void Function(GetVersionResponse) updates) =>
super.copyWith((message) => updates(message as GetVersionResponse))
as GetVersionResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetVersionResponse create() => GetVersionResponse._();
@$core.override
GetVersionResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetVersionResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetVersionResponse>(create);
static GetVersionResponse? _defaultInstance;
@$pb.TagNumber(1)
$core.int get version => $_getIZ(0);
@$pb.TagNumber(1)
set version($core.int value) => $_setSignedInt32(0, value);
@$pb.TagNumber(1)
$core.bool hasVersion() => $_has(0);
@$pb.TagNumber(1)
void clearVersion() => $_clearField(1);
@$pb.TagNumber(2)
$core.int get latestVersion => $_getIZ(1);
@$pb.TagNumber(2)
set latestVersion($core.int value) => $_setSignedInt32(1, value);
@$pb.TagNumber(2)
$core.bool hasLatestVersion() => $_has(1);
@$pb.TagNumber(2)
void clearLatestVersion() => $_clearField(2);
@$pb.TagNumber(3)
$core.int get minClientVersion => $_getIZ(2);
@$pb.TagNumber(3)
set minClientVersion($core.int value) => $_setSignedInt32(2, value);
@$pb.TagNumber(3)
$core.bool hasMinClientVersion() => $_has(2);
@$pb.TagNumber(3)
void clearMinClientVersion() => $_clearField(3);
}
///
class SignalType extends $pb.GeneratedMessage {
factory SignalType({
$core.String? id,
$core.String? name,
$core.bool? isSpecial,
}) {
final result = create();
if (id != null) result.id = id;
if (name != null) result.name = name;
if (isSpecial != null) result.isSpecial = isSpecial;
return result;
}
SignalType._();
factory SignalType.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory SignalType.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'SignalType',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'id')
..aOS(2, _omitFieldNames ? '' : 'name')
..aOB(3, _omitFieldNames ? '' : 'isSpecial')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SignalType clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SignalType copyWith(void Function(SignalType) updates) =>
super.copyWith((message) => updates(message as SignalType)) as SignalType;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static SignalType create() => SignalType._();
@$core.override
SignalType createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static SignalType getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<SignalType>(create);
static SignalType? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => $_clearField(2);
@$pb.TagNumber(3)
$core.bool get isSpecial => $_getBF(2);
@$pb.TagNumber(3)
set isSpecial($core.bool value) => $_setBool(2, value);
@$pb.TagNumber(3)
$core.bool hasIsSpecial() => $_has(2);
@$pb.TagNumber(3)
void clearIsSpecial() => $_clearField(3);
}
///
class GetSignalTypesRequest extends $pb.GeneratedMessage {
factory GetSignalTypesRequest() => create();
GetSignalTypesRequest._();
factory GetSignalTypesRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetSignalTypesRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetSignalTypesRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetSignalTypesRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetSignalTypesRequest copyWith(
void Function(GetSignalTypesRequest) updates) =>
super.copyWith((message) => updates(message as GetSignalTypesRequest))
as GetSignalTypesRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetSignalTypesRequest create() => GetSignalTypesRequest._();
@$core.override
GetSignalTypesRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetSignalTypesRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetSignalTypesRequest>(create);
static GetSignalTypesRequest? _defaultInstance;
}
///
class GetSignalTypesResponse extends $pb.GeneratedMessage {
factory GetSignalTypesResponse({
$core.Iterable<SignalType>? signals,
}) {
final result = create();
if (signals != null) result.signals.addAll(signals);
return result;
}
GetSignalTypesResponse._();
factory GetSignalTypesResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetSignalTypesResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetSignalTypesResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..pPM<SignalType>(1, _omitFieldNames ? '' : 'signals',
subBuilder: SignalType.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetSignalTypesResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetSignalTypesResponse copyWith(
void Function(GetSignalTypesResponse) updates) =>
super.copyWith((message) => updates(message as GetSignalTypesResponse))
as GetSignalTypesResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetSignalTypesResponse create() => GetSignalTypesResponse._();
@$core.override
GetSignalTypesResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetSignalTypesResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetSignalTypesResponse>(create);
static GetSignalTypesResponse? _defaultInstance;
@$pb.TagNumber(1)
$pb.PbList<SignalType> get signals => $_getList(0);
}
///
class Tag extends $pb.GeneratedMessage {
factory Tag({
$core.String? id,
$core.String? name,
$core.String? info,
$core.String? color,
$core.Iterable<Tag>? subTags,
}) {
final result = create();
if (id != null) result.id = id;
if (name != null) result.name = name;
if (info != null) result.info = info;
if (color != null) result.color = color;
if (subTags != null) result.subTags.addAll(subTags);
return result;
}
Tag._();
factory Tag.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory Tag.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'Tag',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'id')
..aOS(2, _omitFieldNames ? '' : 'name')
..aOS(3, _omitFieldNames ? '' : 'info')
..aOS(4, _omitFieldNames ? '' : 'color')
..pPM<Tag>(5, _omitFieldNames ? '' : 'subTags', subBuilder: Tag.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
Tag clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
Tag copyWith(void Function(Tag) updates) =>
super.copyWith((message) => updates(message as Tag)) as Tag;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Tag create() => Tag._();
@$core.override
Tag createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static Tag getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Tag>(create);
static Tag? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => $_clearField(2);
@$pb.TagNumber(3)
$core.String get info => $_getSZ(2);
@$pb.TagNumber(3)
set info($core.String value) => $_setString(2, value);
@$pb.TagNumber(3)
$core.bool hasInfo() => $_has(2);
@$pb.TagNumber(3)
void clearInfo() => $_clearField(3);
@$pb.TagNumber(4)
$core.String get color => $_getSZ(3);
@$pb.TagNumber(4)
set color($core.String value) => $_setString(3, value);
@$pb.TagNumber(4)
$core.bool hasColor() => $_has(3);
@$pb.TagNumber(4)
void clearColor() => $_clearField(4);
@$pb.TagNumber(5)
$pb.PbList<Tag> get subTags => $_getList(4);
}
///
class GetTagsRequest extends $pb.GeneratedMessage {
factory GetTagsRequest() => create();
GetTagsRequest._();
factory GetTagsRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetTagsRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetTagsRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetTagsRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetTagsRequest copyWith(void Function(GetTagsRequest) updates) =>
super.copyWith((message) => updates(message as GetTagsRequest))
as GetTagsRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetTagsRequest create() => GetTagsRequest._();
@$core.override
GetTagsRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetTagsRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetTagsRequest>(create);
static GetTagsRequest? _defaultInstance;
}
///
class GetTagsResponse extends $pb.GeneratedMessage {
factory GetTagsResponse({
$core.Iterable<Tag>? tags,
}) {
final result = create();
if (tags != null) result.tags.addAll(tags);
return result;
}
GetTagsResponse._();
factory GetTagsResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory GetTagsResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'GetTagsResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'common'),
createEmptyInstance: create)
..pPM<Tag>(1, _omitFieldNames ? '' : 'tags', subBuilder: Tag.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetTagsResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
GetTagsResponse copyWith(void Function(GetTagsResponse) updates) =>
super.copyWith((message) => updates(message as GetTagsResponse))
as GetTagsResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetTagsResponse create() => GetTagsResponse._();
@$core.override
GetTagsResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static GetTagsResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<GetTagsResponse>(create);
static GetTagsResponse? _defaultInstance;
@$pb.TagNumber(1)
$pb.PbList<Tag> get tags => $_getList(0);
}
const $core.bool _omitFieldNames =
$core.bool.fromEnvironment('protobuf.omit_field_names');
const $core.bool _omitMessageNames =
$core.bool.fromEnvironment('protobuf.omit_message_names');

View File

@ -0,0 +1,11 @@
// This is a generated file - do not edit.
//
// Generated from proto/common/common.proto.
// @dart = 3.3
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports

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