mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-02-12 18:20:24 +00:00
Compare commits
32 Commits
copilot/ad
...
78aa644c68
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78aa644c68 | ||
|
|
9a0b97476e | ||
|
|
68f42060ff | ||
|
|
f812bf9890 | ||
|
|
2e8ec39752 | ||
|
|
a6c822ab85 | ||
|
|
f349b475e2 | ||
|
|
01438b22c1 | ||
|
|
5f21a61142 | ||
|
|
18df2d93cc | ||
|
|
70b6e29ad0 | ||
|
|
8f85d96488 | ||
|
|
c8a382c08f | ||
|
|
0f131203f2 | ||
|
|
bfbad50772 | ||
|
|
dc9816eb9e | ||
|
|
c6a0f5b8c0 | ||
|
|
91046e7f5e | ||
|
|
678f8d8cd7 | ||
|
|
6263a0a5e6 | ||
|
|
45c0476636 | ||
|
|
d86d454f52 | ||
|
|
2be5441cf4 | ||
|
|
a673f70862 | ||
|
|
1d59acff2d | ||
|
|
724f7d8242 | ||
|
|
3135edad8e | ||
|
|
bba2dbd360 | ||
|
|
66ead87d47 | ||
|
|
1a1f72a596 | ||
|
|
062014f24a | ||
|
|
3dab05fc0e |
@@ -4,7 +4,7 @@
|
||||
|
||||
该工具为 星际公民玩家 提供 一键诊断,官网及工具网站汉化,游戏汉化,游戏性能优化 等功能,致力于带来更愉快的游戏体验。
|
||||
|
||||
[](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml) [](http://translate.42kit.com/engage/sctoolbox/)
|
||||
[](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml) [](https://github.com/StarCitizenToolBox/app/actions/workflows/windows_nightly.yml) [](http://translate.42kit.com/engage/sctoolbox/)
|
||||
|
||||
[](https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true)
|
||||
|
||||
|
||||
123
docs/AUTH_QUICK_START.md
Normal file
123
docs/AUTH_QUICK_START.md
Normal 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"
|
||||
```
|
||||
54
lib/app.dart
54
lib/app.dart
@@ -2,6 +2,7 @@ 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';
|
||||
@@ -24,6 +25,7 @@ import 'api/api.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';
|
||||
@@ -125,6 +127,11 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
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");
|
||||
@@ -166,16 +173,22 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
windowManager.waitUntilReadyToShow().then((_) async {
|
||||
await windowManager.setTitle("SCToolBox");
|
||||
await windowManager.setSkipTaskbar(false);
|
||||
await windowManager.show();
|
||||
if (Platform.isWindows) {
|
||||
await Window.initialize();
|
||||
await Window.hideWindowControls();
|
||||
if (windowsDeviceInfo?.productName.contains("Windows 11") ?? false) {
|
||||
await Window.setEffect(effect: WindowEffect.acrylic);
|
||||
// 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 init -----");
|
||||
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 -----");
|
||||
@@ -255,6 +268,8 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
Timer? _activityThemeColorTimer;
|
||||
|
||||
void checkActivityThemeColor(AppVersionData networkVersionData) {
|
||||
final isDisableAcrylic = state.windowsVersion <= 11;
|
||||
|
||||
if (_activityThemeColorTimer != null) {
|
||||
_activityThemeColorTimer?.cancel();
|
||||
_activityThemeColorTimer = null;
|
||||
@@ -278,8 +293,8 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
final colorCfg = networkVersionData.activityColors;
|
||||
state = state.copyWith(
|
||||
themeConf: ThemeConf(
|
||||
backgroundColor: HexColor(colorCfg?.background ?? "#132431").withValues(alpha: .75),
|
||||
menuColor: HexColor(colorCfg?.menu ?? "#132431").withValues(alpha: .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"),
|
||||
),
|
||||
);
|
||||
@@ -293,8 +308,8 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
dPrint("reset Color ....");
|
||||
state = state.copyWith(
|
||||
themeConf: ThemeConf(
|
||||
backgroundColor: HexColor("#132431").withValues(alpha: .75),
|
||||
menuColor: HexColor("#132431").withValues(alpha: .95),
|
||||
backgroundColor: HexColor("#132431").withValues(alpha: isDisableAcrylic ? 1 : .75),
|
||||
menuColor: HexColor("#132431").withValues(alpha: isDisableAcrylic ? 1 : .95),
|
||||
micaColor: HexColor("#0A3142"),
|
||||
),
|
||||
);
|
||||
@@ -318,6 +333,27 @@ class AppGlobalModel extends _$AppGlobalModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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"];
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'app.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(router)
|
||||
const routerProvider = RouterProvider._();
|
||||
final routerProvider = RouterProvider._();
|
||||
|
||||
final class RouterProvider
|
||||
extends $FunctionalProvider<GoRouter, GoRouter, GoRouter>
|
||||
with $Provider<GoRouter> {
|
||||
const RouterProvider._()
|
||||
RouterProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -51,11 +51,11 @@ final class RouterProvider
|
||||
String _$routerHash() => r'e89f3f0277879147cdce5373cbe2554821e9cd31';
|
||||
|
||||
@ProviderFor(AppGlobalModel)
|
||||
const appGlobalModelProvider = AppGlobalModelProvider._();
|
||||
final appGlobalModelProvider = AppGlobalModelProvider._();
|
||||
|
||||
final class AppGlobalModelProvider
|
||||
extends $NotifierProvider<AppGlobalModel, AppGlobalState> {
|
||||
const AppGlobalModelProvider._()
|
||||
AppGlobalModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -82,14 +82,13 @@ final class AppGlobalModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$appGlobalModelHash() => r'0e46d72594d94e2beb4d2ccb8616eb37facba288';
|
||||
String _$appGlobalModelHash() => r'74128d2194d00a0e3dbb000dcaf6452e0b966d9c';
|
||||
|
||||
abstract class _$AppGlobalModel extends $Notifier<AppGlobalState> {
|
||||
AppGlobalState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AppGlobalState, AppGlobalState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -99,6 +98,6 @@ abstract class _$AppGlobalModel extends $Notifier<AppGlobalState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
class ConstConf {
|
||||
static const String appVersion = "3.0.0 Beta9";
|
||||
static const int appVersionCode = 79;
|
||||
static const String appVersionDate = "2025-12-22";
|
||||
static const String appVersion = "3.1.0";
|
||||
static const int appVersionCode = 80;
|
||||
static const String appVersionDate = "2026-01-19";
|
||||
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
|
||||
@@ -18,5 +20,12 @@ class AppConf {
|
||||
_networkGameChannels = channels;
|
||||
}
|
||||
|
||||
static List<String> get gameChannels => _networkGameChannels ?? ConstConf._gameChannels;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ class URLConf {
|
||||
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;
|
||||
|
||||
@@ -51,10 +53,7 @@ class URLConf {
|
||||
gitApiHome = fasterGit;
|
||||
}
|
||||
final newsApiList = _genFinalList(await dnsLookupTxt("news.dns.scbox.org"));
|
||||
final fasterNews = await rust_http.getFasterUrl(
|
||||
urls: newsApiList,
|
||||
pathSuffix: "/api/latest",
|
||||
);
|
||||
final fasterNews = await rust_http.getFasterUrl(urls: newsApiList, pathSuffix: "/api/latest");
|
||||
dPrint("DNS newsApiList ==== $newsApiList");
|
||||
dPrint("newsApiList.Faster ==== $fasterNews");
|
||||
if (fasterNews != null) {
|
||||
|
||||
@@ -3,11 +3,20 @@ import 'dart:io';
|
||||
|
||||
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) return null;
|
||||
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) {
|
||||
@@ -20,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) {
|
||||
@@ -30,6 +47,23 @@ class SCLoggerHelper {
|
||||
return scCachePath;
|
||||
}
|
||||
|
||||
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?> getLauncherLogList() async {
|
||||
if (!Platform.isWindows) return [];
|
||||
try {
|
||||
@@ -43,20 +77,25 @@ class SCLoggerHelper {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<String>> getGameInstallPath(List listData,
|
||||
{bool checkExists = true,
|
||||
List<String> withVersion = const ["LIVE"]}) async {
|
||||
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 {
|
||||
// 将所有连续的 \\ 替换为 \
|
||||
path = path.replaceAll(RegExp(r'\\+'), "\\");
|
||||
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);
|
||||
}
|
||||
@@ -67,14 +106,25 @@ 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) {
|
||||
String pattern =
|
||||
r'([a-zA-Z]:\\\\[^\\\\]*\\\\[^\\\\]*\\\\StarCitizen\\\\' + v + r')';
|
||||
// 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 line = listData[i];
|
||||
@@ -89,10 +139,14 @@ class SCLoggerHelper {
|
||||
// 动态检测更多位置
|
||||
for (var fileName in List.from(scInstallPaths)) {
|
||||
for (var v in withVersion) {
|
||||
if (fileName.toString().endsWith(v)) {
|
||||
final suffix = '\\$v'.platformPath.toLowerCase();
|
||||
if (fileName.toString().toLowerCase().endsWith(suffix)) {
|
||||
for (var nv in withVersion) {
|
||||
final nextName =
|
||||
"${fileName.toString().replaceAll("\\$v", "")}\\$nv";
|
||||
final basePath = fileName.toString().replaceAll(
|
||||
RegExp('${RegExp.escape(suffix)}\$', caseSensitive: false),
|
||||
'',
|
||||
);
|
||||
final nextName = "$basePath\\$nv".platformPath;
|
||||
await checkAndAddPath(nextName, true);
|
||||
}
|
||||
}
|
||||
@@ -108,9 +162,10 @@ class SCLoggerHelper {
|
||||
}
|
||||
|
||||
static String getGameChannelID(String installPath) {
|
||||
final pathLower = installPath.platformPath.toLowerCase();
|
||||
for (var value in AppConf.gameChannels) {
|
||||
if (installPath.endsWith("\\$value")) {
|
||||
return value;
|
||||
if (pathLower.endsWith('\\${value.toLowerCase()}'.platformPath)) {
|
||||
return value.toUpperCase();
|
||||
}
|
||||
}
|
||||
return "UNKNOWN";
|
||||
@@ -121,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) {
|
||||
@@ -138,47 +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);
|
||||
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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
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;
|
||||
|
||||
@@ -41,7 +42,7 @@ class SystemHelper {
|
||||
if (path != null && path != "") {
|
||||
if (await File(path).exists()) {
|
||||
if (skipEXE) {
|
||||
return "${path.toString().replaceAll("\\RSI Launcher.exe", "")}\\";
|
||||
return "${path.toString().replaceAll("\\RSI Launcher.exe".platformPath, "")}\\".platformPath;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
68
lib/common/rust/api/applinks_api.dart
Normal file
68
lib/common/rust/api/applinks_api.dart
Normal 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;
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
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({
|
||||
@@ -20,21 +21,27 @@ Future<void> sendNotify({
|
||||
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,
|
||||
@@ -58,16 +65,19 @@ Future<List<ProcessInfo>> getProcessListByName({required String processName}) =>
|
||||
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,
|
||||
@@ -76,12 +86,14 @@ Future<void> createDesktopShortcut({
|
||||
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,
|
||||
@@ -90,12 +102,15 @@ Future<void> startProcess({
|
||||
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();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||
|
||||
import 'api/applinks_api.dart';
|
||||
import 'api/asar_api.dart';
|
||||
import 'api/downloader_api.dart';
|
||||
import 'api/http_api.dart';
|
||||
@@ -72,7 +73,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||
String get codegenVersion => '2.11.1';
|
||||
|
||||
@override
|
||||
int get rustContentHash => -1903117367;
|
||||
int get rustContentHash => -351025706;
|
||||
|
||||
static const kDefaultExternalLibraryLoaderConfig =
|
||||
ExternalLibraryLoaderConfig(
|
||||
@@ -85,6 +86,9 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||
abstract class RustLibApi extends BaseApi {
|
||||
Future<void> crateApiWin32ApiAddNvmePatch();
|
||||
|
||||
Future<ApplinksRegistrationResult>
|
||||
crateApiApplinksApiCheckApplinksRegistration({required String scheme});
|
||||
|
||||
Future<bool> crateApiWin32ApiCheckNvmePatchStatus();
|
||||
|
||||
Future<void> crateApiOrtApiClearAllModels();
|
||||
@@ -268,6 +272,11 @@ abstract class RustLibApi extends BaseApi {
|
||||
|
||||
Future<void> crateApiUnp4KApiP4KOpen({required String p4KPath});
|
||||
|
||||
Future<ApplinksRegistrationResult> crateApiApplinksApiRegisterApplinks({
|
||||
required String scheme,
|
||||
String? appName,
|
||||
});
|
||||
|
||||
Future<void> crateApiWin32ApiRemoveNvmePatch();
|
||||
|
||||
Future<String> crateApiWin32ApiResolveShortcut({required String lnkPath});
|
||||
@@ -320,6 +329,10 @@ abstract class RustLibApi extends BaseApi {
|
||||
|
||||
Future<void> crateApiOrtApiUnloadTranslationModel({required String modelKey});
|
||||
|
||||
Future<ApplinksRegistrationResult> crateApiApplinksApiUnregisterApplinks({
|
||||
required String scheme,
|
||||
});
|
||||
|
||||
Future<WebViewConfiguration> crateApiWebviewApiWebViewConfigurationDefault();
|
||||
|
||||
Future<WebViewNavigationState>
|
||||
@@ -411,6 +424,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
TaskConstMeta get kCrateApiWin32ApiAddNvmePatchConstMeta =>
|
||||
const TaskConstMeta(debugName: "add_nvme_patch", argNames: []);
|
||||
|
||||
@override
|
||||
Future<ApplinksRegistrationResult>
|
||||
crateApiApplinksApiCheckApplinksRegistration({required String scheme}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
var arg0 = cst_encode_String(scheme);
|
||||
return wire
|
||||
.wire__crate__api__applinks_api__check_applinks_registration(
|
||||
port_,
|
||||
arg0,
|
||||
);
|
||||
},
|
||||
codec: DcoCodec(
|
||||
decodeSuccessData: dco_decode_applinks_registration_result,
|
||||
decodeErrorData: dco_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiApplinksApiCheckApplinksRegistrationConstMeta,
|
||||
argValues: [scheme],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiApplinksApiCheckApplinksRegistrationConstMeta =>
|
||||
const TaskConstMeta(
|
||||
debugName: "check_applinks_registration",
|
||||
argNames: ["scheme"],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<bool> crateApiWin32ApiCheckNvmePatchStatus() {
|
||||
return handler.executeNormal(
|
||||
@@ -1987,6 +2030,39 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
TaskConstMeta get kCrateApiUnp4KApiP4KOpenConstMeta =>
|
||||
const TaskConstMeta(debugName: "p4k_open", argNames: ["p4KPath"]);
|
||||
|
||||
@override
|
||||
Future<ApplinksRegistrationResult> crateApiApplinksApiRegisterApplinks({
|
||||
required String scheme,
|
||||
String? appName,
|
||||
}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
var arg0 = cst_encode_String(scheme);
|
||||
var arg1 = cst_encode_opt_String(appName);
|
||||
return wire.wire__crate__api__applinks_api__register_applinks(
|
||||
port_,
|
||||
arg0,
|
||||
arg1,
|
||||
);
|
||||
},
|
||||
codec: DcoCodec(
|
||||
decodeSuccessData: dco_decode_applinks_registration_result,
|
||||
decodeErrorData: dco_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiApplinksApiRegisterApplinksConstMeta,
|
||||
argValues: [scheme, appName],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiApplinksApiRegisterApplinksConstMeta =>
|
||||
const TaskConstMeta(
|
||||
debugName: "register_applinks",
|
||||
argNames: ["scheme", "appName"],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiWin32ApiRemoveNvmePatch() {
|
||||
return handler.executeNormal(
|
||||
@@ -2369,6 +2445,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
argNames: ["modelKey"],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<ApplinksRegistrationResult> crateApiApplinksApiUnregisterApplinks({
|
||||
required String scheme,
|
||||
}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
var arg0 = cst_encode_String(scheme);
|
||||
return wire.wire__crate__api__applinks_api__unregister_applinks(
|
||||
port_,
|
||||
arg0,
|
||||
);
|
||||
},
|
||||
codec: DcoCodec(
|
||||
decodeSuccessData: dco_decode_applinks_registration_result,
|
||||
decodeErrorData: dco_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiApplinksApiUnregisterApplinksConstMeta,
|
||||
argValues: [scheme],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiApplinksApiUnregisterApplinksConstMeta =>
|
||||
const TaskConstMeta(
|
||||
debugName: "unregister_applinks",
|
||||
argNames: ["scheme"],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<WebViewConfiguration> crateApiWebviewApiWebViewConfigurationDefault() {
|
||||
return handler.executeNormal(
|
||||
@@ -2869,6 +2975,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw as String;
|
||||
}
|
||||
|
||||
@protected
|
||||
ApplinksRegistrationResult dco_decode_applinks_registration_result(
|
||||
dynamic raw,
|
||||
) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
final arr = raw as List<dynamic>;
|
||||
if (arr.length != 3)
|
||||
throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
|
||||
return ApplinksRegistrationResult(
|
||||
success: dco_decode_bool(arr[0]),
|
||||
message: dco_decode_String(arr[1]),
|
||||
wasModified: dco_decode_bool(arr[2]),
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
bool dco_decode_bool(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -3347,6 +3468,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return utf8.decoder.convert(inner);
|
||||
}
|
||||
|
||||
@protected
|
||||
ApplinksRegistrationResult sse_decode_applinks_registration_result(
|
||||
SseDeserializer deserializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
var var_success = sse_decode_bool(deserializer);
|
||||
var var_message = sse_decode_String(deserializer);
|
||||
var var_wasModified = sse_decode_bool(deserializer);
|
||||
return ApplinksRegistrationResult(
|
||||
success: var_success,
|
||||
message: var_message,
|
||||
wasModified: var_wasModified,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
bool sse_decode_bool(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4047,6 +4183,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_applinks_registration_result(
|
||||
ApplinksRegistrationResult self,
|
||||
SseSerializer serializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_bool(self.success, serializer);
|
||||
sse_encode_String(self.message, serializer);
|
||||
sse_encode_bool(self.wasModified, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_bool(bool self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||
|
||||
import 'api/applinks_api.dart';
|
||||
import 'api/asar_api.dart';
|
||||
import 'api/downloader_api.dart';
|
||||
import 'api/http_api.dart';
|
||||
@@ -39,6 +40,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String dco_decode_String(dynamic raw);
|
||||
|
||||
@protected
|
||||
ApplinksRegistrationResult dco_decode_applinks_registration_result(
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
bool dco_decode_bool(dynamic raw);
|
||||
|
||||
@@ -216,6 +222,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String sse_decode_String(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
ApplinksRegistrationResult sse_decode_applinks_registration_result(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
bool sse_decode_bool(SseDeserializer deserializer);
|
||||
|
||||
@@ -672,6 +683,16 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
return raw.toSigned(64).toInt();
|
||||
}
|
||||
|
||||
@protected
|
||||
void cst_api_fill_to_wire_applinks_registration_result(
|
||||
ApplinksRegistrationResult apiObj,
|
||||
wire_cst_applinks_registration_result wireObj,
|
||||
) {
|
||||
wireObj.success = cst_encode_bool(apiObj.success);
|
||||
wireObj.message = cst_encode_String(apiObj.message);
|
||||
wireObj.was_modified = cst_encode_bool(apiObj.wasModified);
|
||||
}
|
||||
|
||||
@protected
|
||||
void cst_api_fill_to_wire_box_autoadd_rsi_launcher_asar_data(
|
||||
RsiLauncherAsarData apiObj,
|
||||
@@ -946,6 +967,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_String(String self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_applinks_registration_result(
|
||||
ApplinksRegistrationResult self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||
|
||||
@@ -1227,6 +1254,33 @@ class RustLibWire implements BaseWire {
|
||||
_wire__crate__api__win32_api__add_nvme_patchPtr
|
||||
.asFunction<void Function(int)>();
|
||||
|
||||
void wire__crate__api__applinks_api__check_applinks_registration(
|
||||
int port_,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> scheme,
|
||||
) {
|
||||
return _wire__crate__api__applinks_api__check_applinks_registration(
|
||||
port_,
|
||||
scheme,
|
||||
);
|
||||
}
|
||||
|
||||
late final _wire__crate__api__applinks_api__check_applinks_registrationPtr =
|
||||
_lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(
|
||||
ffi.Int64,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
)
|
||||
>
|
||||
>(
|
||||
'frbgen_starcitizen_doctor_wire__crate__api__applinks_api__check_applinks_registration',
|
||||
);
|
||||
late final _wire__crate__api__applinks_api__check_applinks_registration =
|
||||
_wire__crate__api__applinks_api__check_applinks_registrationPtr
|
||||
.asFunction<
|
||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||
>();
|
||||
|
||||
void wire__crate__api__win32_api__check_nvme_patch_status(int port_) {
|
||||
return _wire__crate__api__win32_api__check_nvme_patch_status(port_);
|
||||
}
|
||||
@@ -2453,6 +2507,40 @@ class RustLibWire implements BaseWire {
|
||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||
>();
|
||||
|
||||
void wire__crate__api__applinks_api__register_applinks(
|
||||
int port_,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> scheme,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> app_name,
|
||||
) {
|
||||
return _wire__crate__api__applinks_api__register_applinks(
|
||||
port_,
|
||||
scheme,
|
||||
app_name,
|
||||
);
|
||||
}
|
||||
|
||||
late final _wire__crate__api__applinks_api__register_applinksPtr =
|
||||
_lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(
|
||||
ffi.Int64,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
)
|
||||
>
|
||||
>(
|
||||
'frbgen_starcitizen_doctor_wire__crate__api__applinks_api__register_applinks',
|
||||
);
|
||||
late final _wire__crate__api__applinks_api__register_applinks =
|
||||
_wire__crate__api__applinks_api__register_applinksPtr
|
||||
.asFunction<
|
||||
void Function(
|
||||
int,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
)
|
||||
>();
|
||||
|
||||
void wire__crate__api__win32_api__remove_nvme_patch(int port_) {
|
||||
return _wire__crate__api__win32_api__remove_nvme_patch(port_);
|
||||
}
|
||||
@@ -2467,9 +2555,9 @@ class RustLibWire implements BaseWire {
|
||||
|
||||
void wire__crate__api__win32_api__resolve_shortcut(
|
||||
int port_,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> _lnk_path,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> lnk_path,
|
||||
) {
|
||||
return _wire__crate__api__win32_api__resolve_shortcut(port_, _lnk_path);
|
||||
return _wire__crate__api__win32_api__resolve_shortcut(port_, lnk_path);
|
||||
}
|
||||
|
||||
late final _wire__crate__api__win32_api__resolve_shortcutPtr =
|
||||
@@ -2799,6 +2887,30 @@ class RustLibWire implements BaseWire {
|
||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||
>();
|
||||
|
||||
void wire__crate__api__applinks_api__unregister_applinks(
|
||||
int port_,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> scheme,
|
||||
) {
|
||||
return _wire__crate__api__applinks_api__unregister_applinks(port_, scheme);
|
||||
}
|
||||
|
||||
late final _wire__crate__api__applinks_api__unregister_applinksPtr =
|
||||
_lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(
|
||||
ffi.Int64,
|
||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||
)
|
||||
>
|
||||
>(
|
||||
'frbgen_starcitizen_doctor_wire__crate__api__applinks_api__unregister_applinks',
|
||||
);
|
||||
late final _wire__crate__api__applinks_api__unregister_applinks =
|
||||
_wire__crate__api__applinks_api__unregister_applinksPtr
|
||||
.asFunction<
|
||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||
>();
|
||||
|
||||
void wire__crate__api__webview_api__web_view_configuration_default(
|
||||
int port_,
|
||||
) {
|
||||
@@ -3721,6 +3833,16 @@ final class wire_cst_list_web_view_event extends ffi.Struct {
|
||||
external int len;
|
||||
}
|
||||
|
||||
final class wire_cst_applinks_registration_result extends ffi.Struct {
|
||||
@ffi.Bool()
|
||||
external bool success;
|
||||
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> message;
|
||||
|
||||
@ffi.Bool()
|
||||
external bool was_modified;
|
||||
}
|
||||
|
||||
final class wire_cst_download_global_stat extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int download_speed;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@@ -7,105 +8,118 @@ 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,
|
||||
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),
|
||||
child: Text(S.current.app_common_tip_i_know),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
constraints: constraints);
|
||||
/// 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<bool> showConfirmDialogs(BuildContext context, String title, Widget content,
|
||||
{String confirm = "", String cancel = "", BoxConstraints? constraints}) async {
|
||||
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),
|
||||
child: Text(S.current.app_common_tip_i_know),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
constraints: constraints,
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> showConfirmDialogs(
|
||||
BuildContext context,
|
||||
String title,
|
||||
Widget content, {
|
||||
String confirm = "",
|
||||
String cancel = "",
|
||||
BoxConstraints? constraints,
|
||||
}) async {
|
||||
if (confirm.isEmpty) confirm = S.current.app_common_tip_confirm;
|
||||
if (cancel.isEmpty) cancel = S.current.app_common_tip_cancel;
|
||||
|
||||
final r = await showBaseDialog(context,
|
||||
title: title,
|
||||
content: content,
|
||||
actions: [
|
||||
if (confirm.isNotEmpty)
|
||||
FilledButton(
|
||||
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),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
),
|
||||
],
|
||||
constraints: constraints);
|
||||
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)),
|
||||
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)),
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
),
|
||||
],
|
||||
constraints: constraints,
|
||||
);
|
||||
return r == true;
|
||||
}
|
||||
|
||||
Future<String?> showInputDialogs(BuildContext context,
|
||||
{required String title,
|
||||
required String content,
|
||||
BoxConstraints? constraints,
|
||||
String? initialValue,
|
||||
List<TextInputFormatter>? inputFormatters}) async {
|
||||
Future<String?> showInputDialogs(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
required String content,
|
||||
BoxConstraints? constraints,
|
||||
String? initialValue,
|
||||
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,
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (content.isNotEmpty)
|
||||
Text(
|
||||
content,
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormBox(
|
||||
initialValue: initialValue,
|
||||
onChanged: (str) {
|
||||
userInput = str;
|
||||
},
|
||||
inputFormatters: inputFormatters,
|
||||
),
|
||||
],
|
||||
),
|
||||
constraints: constraints);
|
||||
context,
|
||||
title,
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (content.isNotEmpty) Text(content, style: TextStyle(color: Colors.white.withValues(alpha: .6))),
|
||||
const SizedBox(height: 8),
|
||||
TextFormBox(
|
||||
initialValue: initialValue,
|
||||
onChanged: (str) {
|
||||
userInput = str;
|
||||
},
|
||||
inputFormatters: inputFormatters,
|
||||
),
|
||||
],
|
||||
),
|
||||
constraints: constraints,
|
||||
);
|
||||
if (ok == true) return userInput;
|
||||
return null;
|
||||
}
|
||||
|
||||
Future showBaseDialog(BuildContext context,
|
||||
{required String title, required Widget content, List<Widget>? actions, BoxConstraints? constraints}) async {
|
||||
Future showBaseDialog(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
required Widget content,
|
||||
List<Widget>? actions,
|
||||
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,
|
||||
),
|
||||
actions: actions,
|
||||
),
|
||||
builder: (context) => ContentDialog(
|
||||
title: Text(title),
|
||||
content: content,
|
||||
constraints: constraints ?? const BoxConstraints(maxWidth: 512, maxHeight: 756.0),
|
||||
actions: actions,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
@@ -112,7 +113,7 @@ class MultiWindowManager {
|
||||
|
||||
await Window.initialize();
|
||||
|
||||
if (windowAppState.windowsVersion >= 10) {
|
||||
if (Platform.isWindows && windowAppState.windowsVersion >= 10) {
|
||||
await Window.setEffect(effect: WindowEffect.acrylic);
|
||||
}
|
||||
|
||||
|
||||
121
lib/common/utils/url_scheme_handler.dart
Normal file
121
lib/common/utils/url_scheme_handler.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -2406,6 +2406,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"tools_rsi_launcher_enhance_working_msg2": MessageLookupByLibrary.simpleMessage(
|
||||
"Installing patch, this will take some time depending on your computer\'s performance...",
|
||||
),
|
||||
"tools_shader_clean_all": MessageLookupByLibrary.simpleMessage("Clean All"),
|
||||
"tools_shader_clean_dialog_title": MessageLookupByLibrary.simpleMessage(
|
||||
"Clear Shader Cache",
|
||||
),
|
||||
"tools_shader_clean_keep_latest": MessageLookupByLibrary.simpleMessage(
|
||||
"Keep Latest",
|
||||
),
|
||||
"tools_unp4k_action_cancel_multi_select":
|
||||
MessageLookupByLibrary.simpleMessage("Cancel Multi-Select"),
|
||||
"tools_unp4k_action_deselect_all": MessageLookupByLibrary.simpleMessage(
|
||||
|
||||
@@ -2036,6 +2036,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"パッチをインストール中、これはコンピュータのパフォーマンスによって時間がかかります...",
|
||||
),
|
||||
"tools_shader_clean_all": MessageLookupByLibrary.simpleMessage("すべてクリア"),
|
||||
"tools_shader_clean_dialog_title": MessageLookupByLibrary.simpleMessage(
|
||||
"シェーダーキャッシュをクリア",
|
||||
),
|
||||
"tools_shader_clean_keep_latest": MessageLookupByLibrary.simpleMessage(
|
||||
"最新を保持",
|
||||
),
|
||||
"tools_unp4k_missing_runtime": MessageLookupByLibrary.simpleMessage(
|
||||
"ランタイムがありません",
|
||||
),
|
||||
|
||||
@@ -2293,6 +2293,15 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"tools_rsi_launcher_enhance_working_msg2": MessageLookupByLibrary.simpleMessage(
|
||||
"Установка патча, это займет некоторое время в зависимости от производительности вашего компьютера...",
|
||||
),
|
||||
"tools_shader_clean_all": MessageLookupByLibrary.simpleMessage(
|
||||
"Очистить всё",
|
||||
),
|
||||
"tools_shader_clean_dialog_title": MessageLookupByLibrary.simpleMessage(
|
||||
"Очистить кеш шейдеров",
|
||||
),
|
||||
"tools_shader_clean_keep_latest": MessageLookupByLibrary.simpleMessage(
|
||||
"Сохранить последнее",
|
||||
),
|
||||
"tools_unp4k_missing_runtime": MessageLookupByLibrary.simpleMessage(
|
||||
"Отсутствует среда выполнения",
|
||||
),
|
||||
|
||||
@@ -2044,6 +2044,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage("生成补丁 ..."),
|
||||
"tools_rsi_launcher_enhance_working_msg2":
|
||||
MessageLookupByLibrary.simpleMessage("安装补丁,这需要一点时间,取决于您的计算机性能 ..."),
|
||||
"tools_shader_clean_all": MessageLookupByLibrary.simpleMessage("全部清理"),
|
||||
"tools_shader_clean_dialog_title": MessageLookupByLibrary.simpleMessage(
|
||||
"清理着色器缓存",
|
||||
),
|
||||
"tools_shader_clean_keep_latest": MessageLookupByLibrary.simpleMessage(
|
||||
"保留最新",
|
||||
),
|
||||
"tools_unp4k_action_cancel_multi_select":
|
||||
MessageLookupByLibrary.simpleMessage("取消多选"),
|
||||
"tools_unp4k_action_deselect_all": MessageLookupByLibrary.simpleMessage(
|
||||
|
||||
@@ -1907,6 +1907,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage("生成補丁 ..."),
|
||||
"tools_rsi_launcher_enhance_working_msg2":
|
||||
MessageLookupByLibrary.simpleMessage("安裝補丁,這需要一點時間,取決於您的電腦性能 ..."),
|
||||
"tools_shader_clean_all": MessageLookupByLibrary.simpleMessage("全部清理"),
|
||||
"tools_shader_clean_dialog_title": MessageLookupByLibrary.simpleMessage(
|
||||
"清理著色器緩存",
|
||||
),
|
||||
"tools_shader_clean_keep_latest": MessageLookupByLibrary.simpleMessage(
|
||||
"保留最新",
|
||||
),
|
||||
"tools_unp4k_missing_runtime": MessageLookupByLibrary.simpleMessage(
|
||||
"缺少運行庫",
|
||||
),
|
||||
|
||||
@@ -9546,6 +9546,36 @@ class S {
|
||||
args: [year],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Clear Shader Cache`
|
||||
String get tools_shader_clean_dialog_title {
|
||||
return Intl.message(
|
||||
'Clear Shader Cache',
|
||||
name: 'tools_shader_clean_dialog_title',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Keep Latest`
|
||||
String get tools_shader_clean_keep_latest {
|
||||
return Intl.message(
|
||||
'Keep Latest',
|
||||
name: 'tools_shader_clean_keep_latest',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Clean All`
|
||||
String get tools_shader_clean_all {
|
||||
return Intl.message(
|
||||
'Clean All',
|
||||
name: 'tools_shader_clean_all',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
@@ -17,6 +17,258 @@ import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
|
||||
|
||||
/// 生成 OIDC 授权码请求
|
||||
class GenerateOIDCAuthCodeRequest extends $pb.GeneratedMessage {
|
||||
factory GenerateOIDCAuthCodeRequest({
|
||||
$core.String? nonce,
|
||||
$core.String? redirectUri,
|
||||
}) {
|
||||
final result = create();
|
||||
if (nonce != null) result.nonce = nonce;
|
||||
if (redirectUri != null) result.redirectUri = redirectUri;
|
||||
return result;
|
||||
}
|
||||
|
||||
GenerateOIDCAuthCodeRequest._();
|
||||
|
||||
factory GenerateOIDCAuthCodeRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GenerateOIDCAuthCodeRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GenerateOIDCAuthCodeRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'nonce')
|
||||
..aOS(2, _omitFieldNames ? '' : 'redirectUri')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GenerateOIDCAuthCodeRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GenerateOIDCAuthCodeRequest copyWith(
|
||||
void Function(GenerateOIDCAuthCodeRequest) updates) =>
|
||||
super.copyWith(
|
||||
(message) => updates(message as GenerateOIDCAuthCodeRequest))
|
||||
as GenerateOIDCAuthCodeRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GenerateOIDCAuthCodeRequest create() =>
|
||||
GenerateOIDCAuthCodeRequest._();
|
||||
@$core.override
|
||||
GenerateOIDCAuthCodeRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GenerateOIDCAuthCodeRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GenerateOIDCAuthCodeRequest>(create);
|
||||
static GenerateOIDCAuthCodeRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get nonce => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set nonce($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasNonce() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearNonce() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get redirectUri => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set redirectUri($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasRedirectUri() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearRedirectUri() => $_clearField(2);
|
||||
}
|
||||
|
||||
/// 生成 OIDC 授权码响应
|
||||
class GenerateOIDCAuthCodeResponse extends $pb.GeneratedMessage {
|
||||
factory GenerateOIDCAuthCodeResponse({
|
||||
$core.String? code,
|
||||
$fixnum.Int64? expiresAt,
|
||||
}) {
|
||||
final result = create();
|
||||
if (code != null) result.code = code;
|
||||
if (expiresAt != null) result.expiresAt = expiresAt;
|
||||
return result;
|
||||
}
|
||||
|
||||
GenerateOIDCAuthCodeResponse._();
|
||||
|
||||
factory GenerateOIDCAuthCodeResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GenerateOIDCAuthCodeResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GenerateOIDCAuthCodeResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'code')
|
||||
..aInt64(2, _omitFieldNames ? '' : 'expiresAt')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GenerateOIDCAuthCodeResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GenerateOIDCAuthCodeResponse copyWith(
|
||||
void Function(GenerateOIDCAuthCodeResponse) updates) =>
|
||||
super.copyWith(
|
||||
(message) => updates(message as GenerateOIDCAuthCodeResponse))
|
||||
as GenerateOIDCAuthCodeResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GenerateOIDCAuthCodeResponse create() =>
|
||||
GenerateOIDCAuthCodeResponse._();
|
||||
@$core.override
|
||||
GenerateOIDCAuthCodeResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GenerateOIDCAuthCodeResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GenerateOIDCAuthCodeResponse>(create);
|
||||
static GenerateOIDCAuthCodeResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get code => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set code($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasCode() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearCode() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$fixnum.Int64 get expiresAt => $_getI64(1);
|
||||
@$pb.TagNumber(2)
|
||||
set expiresAt($fixnum.Int64 value) => $_setInt64(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasExpiresAt() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearExpiresAt() => $_clearField(2);
|
||||
}
|
||||
|
||||
/// 刷新用户资料请求
|
||||
class RefreshUserProfileRequest extends $pb.GeneratedMessage {
|
||||
factory RefreshUserProfileRequest() => create();
|
||||
|
||||
RefreshUserProfileRequest._();
|
||||
|
||||
factory RefreshUserProfileRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory RefreshUserProfileRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'RefreshUserProfileRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
RefreshUserProfileRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
RefreshUserProfileRequest copyWith(
|
||||
void Function(RefreshUserProfileRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as RefreshUserProfileRequest))
|
||||
as RefreshUserProfileRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RefreshUserProfileRequest create() => RefreshUserProfileRequest._();
|
||||
@$core.override
|
||||
RefreshUserProfileRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RefreshUserProfileRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<RefreshUserProfileRequest>(create);
|
||||
static RefreshUserProfileRequest? _defaultInstance;
|
||||
}
|
||||
|
||||
/// 刷新用户资料响应
|
||||
class RefreshUserProfileResponse extends $pb.GeneratedMessage {
|
||||
factory RefreshUserProfileResponse({
|
||||
$core.bool? success,
|
||||
GameUserInfo? userInfo,
|
||||
}) {
|
||||
final result = create();
|
||||
if (success != null) result.success = success;
|
||||
if (userInfo != null) result.userInfo = userInfo;
|
||||
return result;
|
||||
}
|
||||
|
||||
RefreshUserProfileResponse._();
|
||||
|
||||
factory RefreshUserProfileResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory RefreshUserProfileResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'RefreshUserProfileResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'success')
|
||||
..aOM<GameUserInfo>(2, _omitFieldNames ? '' : 'userInfo',
|
||||
subBuilder: GameUserInfo.create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
RefreshUserProfileResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
RefreshUserProfileResponse copyWith(
|
||||
void Function(RefreshUserProfileResponse) updates) =>
|
||||
super.copyWith(
|
||||
(message) => updates(message as RefreshUserProfileResponse))
|
||||
as RefreshUserProfileResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RefreshUserProfileResponse create() => RefreshUserProfileResponse._();
|
||||
@$core.override
|
||||
RefreshUserProfileResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RefreshUserProfileResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<RefreshUserProfileResponse>(create);
|
||||
static RefreshUserProfileResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get success => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set success($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasSuccess() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearSuccess() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
GameUserInfo get userInfo => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set userInfo(GameUserInfo value) => $_setField(2, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasUserInfo() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearUserInfo() => $_clearField(2);
|
||||
@$pb.TagNumber(2)
|
||||
GameUserInfo ensureUserInfo() => $_ensure(1);
|
||||
}
|
||||
|
||||
/// 服务状态请求
|
||||
class StatusRequest extends $pb.GeneratedMessage {
|
||||
factory StatusRequest() => create();
|
||||
@@ -725,6 +977,441 @@ class UnregisterResponse extends $pb.GeneratedMessage {
|
||||
void clearSuccess() => $_clearField(1);
|
||||
}
|
||||
|
||||
/// 验证 token 请求
|
||||
class ValidateTokenRequest extends $pb.GeneratedMessage {
|
||||
factory ValidateTokenRequest({
|
||||
$core.String? token,
|
||||
}) {
|
||||
final result = create();
|
||||
if (token != null) result.token = token;
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidateTokenRequest._();
|
||||
|
||||
factory ValidateTokenRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ValidateTokenRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ValidateTokenRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'token')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ValidateTokenRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ValidateTokenRequest copyWith(void Function(ValidateTokenRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as ValidateTokenRequest))
|
||||
as ValidateTokenRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ValidateTokenRequest create() => ValidateTokenRequest._();
|
||||
@$core.override
|
||||
ValidateTokenRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ValidateTokenRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ValidateTokenRequest>(create);
|
||||
static ValidateTokenRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get token => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set token($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasToken() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearToken() => $_clearField(1);
|
||||
}
|
||||
|
||||
/// 验证 token 响应
|
||||
class ValidateTokenResponse extends $pb.GeneratedMessage {
|
||||
factory ValidateTokenResponse({
|
||||
$core.bool? valid,
|
||||
$core.String? domain,
|
||||
$fixnum.Int64? issuedAt,
|
||||
$fixnum.Int64? expiresAt,
|
||||
$core.String? errorMessage,
|
||||
}) {
|
||||
final result = create();
|
||||
if (valid != null) result.valid = valid;
|
||||
if (domain != null) result.domain = domain;
|
||||
if (issuedAt != null) result.issuedAt = issuedAt;
|
||||
if (expiresAt != null) result.expiresAt = expiresAt;
|
||||
if (errorMessage != null) result.errorMessage = errorMessage;
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidateTokenResponse._();
|
||||
|
||||
factory ValidateTokenResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ValidateTokenResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ValidateTokenResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'valid')
|
||||
..aOS(2, _omitFieldNames ? '' : 'domain')
|
||||
..aInt64(3, _omitFieldNames ? '' : 'issuedAt')
|
||||
..aInt64(4, _omitFieldNames ? '' : 'expiresAt')
|
||||
..aOS(5, _omitFieldNames ? '' : 'errorMessage')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ValidateTokenResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ValidateTokenResponse copyWith(
|
||||
void Function(ValidateTokenResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as ValidateTokenResponse))
|
||||
as ValidateTokenResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ValidateTokenResponse create() => ValidateTokenResponse._();
|
||||
@$core.override
|
||||
ValidateTokenResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ValidateTokenResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ValidateTokenResponse>(create);
|
||||
static ValidateTokenResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get valid => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set valid($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasValid() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearValid() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get domain => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set domain($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasDomain() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearDomain() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$fixnum.Int64 get issuedAt => $_getI64(2);
|
||||
@$pb.TagNumber(3)
|
||||
set issuedAt($fixnum.Int64 value) => $_setInt64(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasIssuedAt() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearIssuedAt() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$fixnum.Int64 get expiresAt => $_getI64(3);
|
||||
@$pb.TagNumber(4)
|
||||
set expiresAt($fixnum.Int64 value) => $_setInt64(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasExpiresAt() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearExpiresAt() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get errorMessage => $_getSZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set errorMessage($core.String value) => $_setString(4, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasErrorMessage() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearErrorMessage() => $_clearField(5);
|
||||
}
|
||||
|
||||
/// 获取公钥请求
|
||||
class GetPublicKeyRequest extends $pb.GeneratedMessage {
|
||||
factory GetPublicKeyRequest() => create();
|
||||
|
||||
GetPublicKeyRequest._();
|
||||
|
||||
factory GetPublicKeyRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GetPublicKeyRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GetPublicKeyRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetPublicKeyRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetPublicKeyRequest copyWith(void Function(GetPublicKeyRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as GetPublicKeyRequest))
|
||||
as GetPublicKeyRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetPublicKeyRequest create() => GetPublicKeyRequest._();
|
||||
@$core.override
|
||||
GetPublicKeyRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetPublicKeyRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GetPublicKeyRequest>(create);
|
||||
static GetPublicKeyRequest? _defaultInstance;
|
||||
}
|
||||
|
||||
/// 获取公钥响应
|
||||
class GetPublicKeyResponse extends $pb.GeneratedMessage {
|
||||
factory GetPublicKeyResponse({
|
||||
$core.String? publicKeyPem,
|
||||
$core.String? keyId,
|
||||
$core.String? algorithm,
|
||||
}) {
|
||||
final result = create();
|
||||
if (publicKeyPem != null) result.publicKeyPem = publicKeyPem;
|
||||
if (keyId != null) result.keyId = keyId;
|
||||
if (algorithm != null) result.algorithm = algorithm;
|
||||
return result;
|
||||
}
|
||||
|
||||
GetPublicKeyResponse._();
|
||||
|
||||
factory GetPublicKeyResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GetPublicKeyResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GetPublicKeyResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'publicKeyPem')
|
||||
..aOS(2, _omitFieldNames ? '' : 'keyId')
|
||||
..aOS(3, _omitFieldNames ? '' : 'algorithm')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetPublicKeyResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetPublicKeyResponse copyWith(void Function(GetPublicKeyResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as GetPublicKeyResponse))
|
||||
as GetPublicKeyResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetPublicKeyResponse create() => GetPublicKeyResponse._();
|
||||
@$core.override
|
||||
GetPublicKeyResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetPublicKeyResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GetPublicKeyResponse>(create);
|
||||
static GetPublicKeyResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get publicKeyPem => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set publicKeyPem($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasPublicKeyPem() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearPublicKeyPem() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get keyId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set keyId($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasKeyId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearKeyId() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get algorithm => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set algorithm($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasAlgorithm() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearAlgorithm() => $_clearField(3);
|
||||
}
|
||||
|
||||
/// JWT 域名信息
|
||||
class JWTDomainInfo extends $pb.GeneratedMessage {
|
||||
factory JWTDomainInfo({
|
||||
$core.String? domain,
|
||||
$core.String? name,
|
||||
}) {
|
||||
final result = create();
|
||||
if (domain != null) result.domain = domain;
|
||||
if (name != null) result.name = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
JWTDomainInfo._();
|
||||
|
||||
factory JWTDomainInfo.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory JWTDomainInfo.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'JWTDomainInfo',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'domain')
|
||||
..aOS(2, _omitFieldNames ? '' : 'name')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JWTDomainInfo clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JWTDomainInfo copyWith(void Function(JWTDomainInfo) updates) =>
|
||||
super.copyWith((message) => updates(message as JWTDomainInfo))
|
||||
as JWTDomainInfo;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JWTDomainInfo create() => JWTDomainInfo._();
|
||||
@$core.override
|
||||
JWTDomainInfo createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JWTDomainInfo getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<JWTDomainInfo>(create);
|
||||
static JWTDomainInfo? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get domain => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set domain($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasDomain() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearDomain() => $_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);
|
||||
}
|
||||
|
||||
/// 获取 JWT 域名列表请求
|
||||
class GetJWTDomainListRequest extends $pb.GeneratedMessage {
|
||||
factory GetJWTDomainListRequest() => create();
|
||||
|
||||
GetJWTDomainListRequest._();
|
||||
|
||||
factory GetJWTDomainListRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GetJWTDomainListRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GetJWTDomainListRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetJWTDomainListRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetJWTDomainListRequest copyWith(
|
||||
void Function(GetJWTDomainListRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as GetJWTDomainListRequest))
|
||||
as GetJWTDomainListRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetJWTDomainListRequest create() => GetJWTDomainListRequest._();
|
||||
@$core.override
|
||||
GetJWTDomainListRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetJWTDomainListRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GetJWTDomainListRequest>(create);
|
||||
static GetJWTDomainListRequest? _defaultInstance;
|
||||
}
|
||||
|
||||
/// 获取 JWT 域名列表响应
|
||||
class GetJWTDomainListResponse extends $pb.GeneratedMessage {
|
||||
factory GetJWTDomainListResponse({
|
||||
$core.Iterable<JWTDomainInfo>? domains,
|
||||
}) {
|
||||
final result = create();
|
||||
if (domains != null) result.domains.addAll(domains);
|
||||
return result;
|
||||
}
|
||||
|
||||
GetJWTDomainListResponse._();
|
||||
|
||||
factory GetJWTDomainListResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory GetJWTDomainListResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'GetJWTDomainListResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'auth'),
|
||||
createEmptyInstance: create)
|
||||
..pPM<JWTDomainInfo>(1, _omitFieldNames ? '' : 'domains',
|
||||
subBuilder: JWTDomainInfo.create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetJWTDomainListResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
GetJWTDomainListResponse copyWith(
|
||||
void Function(GetJWTDomainListResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as GetJWTDomainListResponse))
|
||||
as GetJWTDomainListResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetJWTDomainListResponse create() => GetJWTDomainListResponse._();
|
||||
@$core.override
|
||||
GetJWTDomainListResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static GetJWTDomainListResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<GetJWTDomainListResponse>(create);
|
||||
static GetJWTDomainListResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$pb.PbList<JWTDomainInfo> get domains => $_getList(0);
|
||||
}
|
||||
|
||||
const $core.bool _omitFieldNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const $core.bool _omitMessageNames =
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:async' as $async;
|
||||
import 'dart:core' as $core;
|
||||
@@ -73,6 +73,45 @@ class AuthServiceClient extends $grpc.Client {
|
||||
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 =
|
||||
@@ -99,6 +138,31 @@ class AuthServiceClient extends $grpc.Client {
|
||||
'/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')
|
||||
@@ -143,6 +207,51 @@ abstract class AuthServiceBase extends $grpc.Service {
|
||||
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(
|
||||
@@ -184,4 +293,49 @@ abstract class AuthServiceBase extends $grpc.Service {
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,74 @@
|
||||
// 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, unused_import
|
||||
// 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',
|
||||
@@ -186,3 +248,104 @@ const UnregisterResponse$json = {
|
||||
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==');
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:async' as $async;
|
||||
import 'dart:core' as $core;
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
// 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, unused_import
|
||||
// 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;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
|
||||
|
||||
import 'dart:async' as $async;
|
||||
import 'dart:core' as $core;
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
// 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, unused_import
|
||||
// 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;
|
||||
|
||||
@@ -1912,5 +1912,11 @@
|
||||
"yearly_report_card_title": "{year} Yearly Report (Limited Time)",
|
||||
"@yearly_report_card_title": {},
|
||||
"yearly_report_card_desc": "View your Star Citizen gameplay statistics for {year}. Data is from local logs, please check on your main computer.",
|
||||
"@yearly_report_card_desc": {}
|
||||
"@yearly_report_card_desc": {},
|
||||
"tools_shader_clean_dialog_title": "Clear Shader Cache",
|
||||
"@tools_shader_clean_dialog_title": {},
|
||||
"tools_shader_clean_keep_latest": "Keep Latest",
|
||||
"@tools_shader_clean_keep_latest": {},
|
||||
"tools_shader_clean_all": "Clean All",
|
||||
"@tools_shader_clean_all": {}
|
||||
}
|
||||
|
||||
@@ -1734,5 +1734,11 @@
|
||||
"yearly_report_card_title": "{year} 年間レポート(期間限定)",
|
||||
"@yearly_report_card_title": {},
|
||||
"yearly_report_card_desc": "{year}年のStar Citizenプレイ統計を表示します。データはローカルログからのものです。メインのコンピュータで確認してください。",
|
||||
"@yearly_report_card_desc": {}
|
||||
"@yearly_report_card_desc": {},
|
||||
"tools_shader_clean_dialog_title": "シェーダーキャッシュをクリア",
|
||||
"@tools_shader_clean_dialog_title": {},
|
||||
"tools_shader_clean_keep_latest": "最新を保持",
|
||||
"@tools_shader_clean_keep_latest": {},
|
||||
"tools_shader_clean_all": "すべてクリア",
|
||||
"@tools_shader_clean_all": {}
|
||||
}
|
||||
|
||||
@@ -1734,5 +1734,11 @@
|
||||
"yearly_report_card_title": "Ежегодный отчет {year} (Ограниченное время)",
|
||||
"@yearly_report_card_title": {},
|
||||
"yearly_report_card_desc": "Посмотрите статистику вашей игры в Star Citizen за {year} год. Данные из локальных логов, пожалуйста, проверяйте на основном компьютере.",
|
||||
"@yearly_report_card_desc": {}
|
||||
"@yearly_report_card_desc": {},
|
||||
"tools_shader_clean_dialog_title": "Очистить кеш шейдеров",
|
||||
"@tools_shader_clean_dialog_title": {},
|
||||
"tools_shader_clean_keep_latest": "Сохранить последнее",
|
||||
"@tools_shader_clean_keep_latest": {},
|
||||
"tools_shader_clean_all": "Очистить всё",
|
||||
"@tools_shader_clean_all": {}
|
||||
}
|
||||
|
||||
@@ -1328,5 +1328,8 @@
|
||||
"yearly_report_powered_by": "由 SC 汉化盒子为您呈现",
|
||||
"yearly_report_disclaimer": "数据使用您的本地日志生成,不会发送到任何第三方。因跨版本 Log 改动较大,数据可能不完整,仅供娱乐。",
|
||||
"yearly_report_card_title": "{year} 年度报告(限时)",
|
||||
"yearly_report_card_desc": "查看您在{year}年的星际公民游玩统计,数据来自本地 log ,请确保在常用电脑上查看。"
|
||||
"yearly_report_card_desc": "查看您在{year}年的星际公民游玩统计,数据来自本地 log ,请确保在常用电脑上查看。",
|
||||
"tools_shader_clean_dialog_title": "清理着色器缓存",
|
||||
"tools_shader_clean_keep_latest": "保留最新",
|
||||
"tools_shader_clean_all": "全部清理"
|
||||
}
|
||||
@@ -1670,5 +1670,8 @@
|
||||
"yearly_report_powered_by": "由 SC工具箱為您呈現",
|
||||
"yearly_report_disclaimer": "數據使用您的本地日誌生成,不會發送到任何第三方。因跨版本 Log 改動較大,數據可能不完整,僅供娛樂。",
|
||||
"yearly_report_card_title": "{year} 年度報告(限時)",
|
||||
"yearly_report_card_desc": "查看您在{year}年的星際公民遊玩統計,數據來自本地 log ,請確保在常用電腦上查看。"
|
||||
"yearly_report_card_desc": "查看您在{year}年的星際公民遊玩統計,數據來自本地 log ,請確保在常用電腦上查看。",
|
||||
"tools_shader_clean_dialog_title": "清理著色器緩存",
|
||||
"tools_shader_clean_keep_latest": "保留最新",
|
||||
"tools_shader_clean_all": "全部清理"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter_acrylic/flutter_acrylic.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/generated/l10n.dart';
|
||||
@@ -36,10 +37,16 @@ Future<void> main(List<String> args) async {
|
||||
}
|
||||
|
||||
Future<void> _initWindow() async {
|
||||
// Initialize flutter_acrylic before runApp (same as official example)
|
||||
await Window.initialize();
|
||||
await Window.hideWindowControls();
|
||||
await windowManager.setTitleBarStyle(TitleBarStyle.hidden, windowButtonVisibility: false);
|
||||
await windowManager.setSize(const Size(1280, 810));
|
||||
await windowManager.setMinimumSize(const Size(1280, 810));
|
||||
await windowManager.center(animate: true);
|
||||
if (Platform.isWindows) {
|
||||
await Window.setEffect(effect: WindowEffect.transparent, color: Colors.transparent, dark: true);
|
||||
}
|
||||
}
|
||||
|
||||
class App extends HookConsumerWidget with WindowListener {
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'dcb_viewer.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(DcbViewerModel)
|
||||
const dcbViewerModelProvider = DcbViewerModelProvider._();
|
||||
final dcbViewerModelProvider = DcbViewerModelProvider._();
|
||||
|
||||
final class DcbViewerModelProvider
|
||||
extends $NotifierProvider<DcbViewerModel, DcbViewerState> {
|
||||
const DcbViewerModelProvider._()
|
||||
DcbViewerModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -48,7 +48,6 @@ abstract class _$DcbViewerModel extends $Notifier<DcbViewerState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<DcbViewerState, DcbViewerState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$DcbViewerModel extends $Notifier<DcbViewerState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'download_manager.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(DownloadManager)
|
||||
const downloadManagerProvider = DownloadManagerProvider._();
|
||||
final downloadManagerProvider = DownloadManagerProvider._();
|
||||
|
||||
final class DownloadManagerProvider
|
||||
extends $NotifierProvider<DownloadManager, DownloadManagerState> {
|
||||
const DownloadManagerProvider._()
|
||||
DownloadManagerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -48,7 +48,6 @@ abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<DownloadManagerState, DownloadManagerState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,11 +127,17 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
final serverAddress = URLConf.partyRoomServerAddress;
|
||||
final serverPort = URLConf.partyRoomServerPort;
|
||||
var credentials = ChannelCredentials.secure();
|
||||
|
||||
if (serverAddress == '127.0.0.1' || serverAddress == 'localhost') {
|
||||
credentials = ChannelCredentials.insecure();
|
||||
}
|
||||
|
||||
final channel = ClientChannel(
|
||||
serverAddress,
|
||||
port: serverPort,
|
||||
options: ChannelOptions(
|
||||
credentials: credentials,
|
||||
keepAlive: ClientKeepAliveOptions(
|
||||
pingInterval: Duration(seconds: 30),
|
||||
timeout: Duration(seconds: 10),
|
||||
@@ -179,7 +185,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
}
|
||||
|
||||
/// 获取认证 CallOptions
|
||||
CallOptions _getAuthCallOptions() {
|
||||
CallOptions getAuthCallOptions() {
|
||||
return CallOptions(metadata: {'uuid': state.auth.uuid, 'secret-key': state.auth.secretKey});
|
||||
}
|
||||
|
||||
@@ -191,7 +197,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final client = state.client.authClient;
|
||||
if (client == null) throw Exception('Not connected to server');
|
||||
|
||||
final response = await client.login(auth.LoginRequest(), options: _getAuthCallOptions());
|
||||
final response = await client.login(auth.LoginRequest(), options: getAuthCallOptions());
|
||||
|
||||
state = state.copyWith(
|
||||
auth: state.auth.copyWith(
|
||||
@@ -255,7 +261,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final client = state.client.authClient;
|
||||
if (client == null) throw Exception('Not connected to server');
|
||||
|
||||
await client.unregister(auth.UnregisterRequest(), options: _getAuthCallOptions());
|
||||
await client.unregister(auth.UnregisterRequest(), options: getAuthCallOptions());
|
||||
|
||||
// 清除本地认证信息
|
||||
await _confBox?.delete(_secretKeyKey);
|
||||
@@ -271,6 +277,24 @@ class PartyRoom extends _$PartyRoom {
|
||||
}
|
||||
}
|
||||
|
||||
/// 刷新用户资料
|
||||
Future<void> refreshUserProfile() async {
|
||||
try {
|
||||
final client = state.client.authClient;
|
||||
if (client == null) throw Exception('Not connected to server');
|
||||
|
||||
final response = await client.refreshUserProfile(auth.RefreshUserProfileRequest(), options: getAuthCallOptions());
|
||||
|
||||
if (response.success && response.hasUserInfo()) {
|
||||
state = state.copyWith(auth: state.auth.copyWith(userInfo: response.userInfo));
|
||||
dPrint('[PartyRoom] User profile refreshed: ${response.userInfo.gameUserId}');
|
||||
}
|
||||
} catch (e) {
|
||||
dPrint('[PartyRoom] RefreshUserProfile error: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 房间相关方法 ==========
|
||||
|
||||
/// 加载标签和信号类型
|
||||
@@ -349,7 +373,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
password_5: password ?? '',
|
||||
socialLinks: socialLinks ?? [],
|
||||
),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
state = state.copyWith(room: state.room.copyWith(roomUuid: response.roomUuid, isInRoom: true, isOwner: true));
|
||||
@@ -376,7 +400,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
await client.joinRoom(
|
||||
partroom.JoinRoomRequest(roomUuid: roomUuid, password: password ?? ''),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
state = state.copyWith(room: state.room.copyWith(roomUuid: roomUuid, isInRoom: true, isOwner: false));
|
||||
@@ -404,7 +428,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final roomUuid = state.room.roomUuid;
|
||||
if (roomUuid == null) return;
|
||||
|
||||
await client.leaveRoom(partroom.LeaveRoomRequest(roomUuid: roomUuid), options: _getAuthCallOptions());
|
||||
await client.leaveRoom(partroom.LeaveRoomRequest(roomUuid: roomUuid), options: getAuthCallOptions());
|
||||
|
||||
await _stopHeartbeat();
|
||||
await _stopEventStream();
|
||||
@@ -427,7 +451,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final roomUuid = state.room.roomUuid;
|
||||
if (roomUuid == null) return;
|
||||
|
||||
await client.dismissRoom(partroom.DismissRoomRequest(roomUuid: roomUuid), options: _getAuthCallOptions());
|
||||
await client.dismissRoom(partroom.DismissRoomRequest(roomUuid: roomUuid), options: getAuthCallOptions());
|
||||
|
||||
await _stopHeartbeat();
|
||||
await _stopEventStream();
|
||||
@@ -449,7 +473,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
final response = await client.getRoomInfo(
|
||||
partroom.GetRoomInfoRequest(roomUuid: roomUuid),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
// 检查是否为房主
|
||||
@@ -477,7 +501,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
final response = await client.getRoomMembers(
|
||||
partroom.GetRoomMembersRequest(roomUuid: roomUuid, page: page, pageSize: pageSize),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
state = state.copyWith(room: state.room.copyWith(members: response.members));
|
||||
@@ -495,7 +519,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final client = state.client.roomClient;
|
||||
if (client == null) return;
|
||||
|
||||
final response = await client.getMyRoom(partroom.GetMyRoomRequest(), options: _getAuthCallOptions());
|
||||
final response = await client.getMyRoom(partroom.GetMyRoomRequest(), options: getAuthCallOptions());
|
||||
|
||||
if (response.hasRoom() && response.room.roomUuid.isNotEmpty) {
|
||||
final isOwner = response.room.ownerGameId == state.auth.userInfo?.gameUserId;
|
||||
@@ -553,7 +577,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
request.socialLinks.addAll(state.room.currentRoom!.socialLinks);
|
||||
}
|
||||
|
||||
await client.updateRoom(request, options: _getAuthCallOptions());
|
||||
await client.updateRoom(request, options: getAuthCallOptions());
|
||||
|
||||
// 刷新房间信息
|
||||
await getRoomInfo(roomUuid);
|
||||
@@ -576,7 +600,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
await client.kickMember(
|
||||
partroom.KickMemberRequest(roomUuid: roomUuid, targetGameUserId: targetGameUserId),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
dPrint('[PartyRoom] Member kicked: $targetGameUserId');
|
||||
@@ -608,7 +632,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
playTime: Int64(playTime ?? 0),
|
||||
),
|
||||
),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
dPrint('[PartyRoom] Status updated');
|
||||
@@ -638,7 +662,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
request.params.addAll(params);
|
||||
}
|
||||
|
||||
await client.sendSignal(request, options: _getAuthCallOptions());
|
||||
await client.sendSignal(request, options: getAuthCallOptions());
|
||||
|
||||
dPrint('[PartyRoom] Signal sent: $signalId');
|
||||
} catch (e) {
|
||||
@@ -658,7 +682,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
await client.transferOwnership(
|
||||
partroom.TransferOwnershipRequest(roomUuid: roomUuid, targetGameUserId: targetGameUserId),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
// 更新房主状态
|
||||
@@ -685,7 +709,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
final response = await client.getKickedMembers(
|
||||
partroom.GetKickedMembersRequest(roomUuid: roomUuid, page: page, pageSize: pageSize),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
return response;
|
||||
@@ -706,7 +730,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
await client.removeKickedMember(
|
||||
partroom.RemoveKickedMemberRequest(roomUuid: roomUuid, gameUserId: gameUserId),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
dPrint('[PartyRoom] Kicked member removed: $gameUserId');
|
||||
@@ -732,7 +756,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
final client = state.client.roomClient;
|
||||
if (client == null) return;
|
||||
|
||||
await client.heartbeat(partroom.HeartbeatRequest(roomUuid: roomUuid), options: _getAuthCallOptions());
|
||||
await client.heartbeat(partroom.HeartbeatRequest(roomUuid: roomUuid), options: getAuthCallOptions());
|
||||
|
||||
dPrint('[PartyRoom] Heartbeat sent');
|
||||
} catch (e) {
|
||||
@@ -760,7 +784,7 @@ class PartyRoom extends _$PartyRoom {
|
||||
|
||||
final stream = client.listenRoomEvents(
|
||||
partroom.ListenRoomEventsRequest(roomUuid: roomUuid),
|
||||
options: _getAuthCallOptions(),
|
||||
options: getAuthCallOptions(),
|
||||
);
|
||||
|
||||
_eventStreamSubscription = stream.listen(
|
||||
|
||||
@@ -11,13 +11,13 @@ part of 'party_room.dart';
|
||||
/// PartyRoom Provider
|
||||
|
||||
@ProviderFor(PartyRoom)
|
||||
const partyRoomProvider = PartyRoomProvider._();
|
||||
final partyRoomProvider = PartyRoomProvider._();
|
||||
|
||||
/// PartyRoom Provider
|
||||
final class PartyRoomProvider
|
||||
extends $NotifierProvider<PartyRoom, PartyRoomFullState> {
|
||||
/// PartyRoom Provider
|
||||
const PartyRoomProvider._()
|
||||
PartyRoomProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -44,7 +44,7 @@ final class PartyRoomProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$partyRoomHash() => r'2ce3ac365bec3af8f7e1d350b53262c8e4e2872d';
|
||||
String _$partyRoomHash() => r'446e4cc88be96c890f8e676c6faf0e4d3b33a529';
|
||||
|
||||
/// PartyRoom Provider
|
||||
|
||||
@@ -53,7 +53,6 @@ abstract class _$PartyRoom extends $Notifier<PartyRoomFullState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<PartyRoomFullState, PartyRoomFullState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -63,6 +62,6 @@ abstract class _$PartyRoom extends $Notifier<PartyRoomFullState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:path_provider/path_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:starcitizen_doctor/api/analytics.dart';
|
||||
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||
import 'package:starcitizen_doctor/data/app_unp4k_p4k_item_data.dart';
|
||||
import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart';
|
||||
@@ -80,7 +81,7 @@ class Unp4kCModel extends _$Unp4kCModel {
|
||||
|
||||
void _init() async {
|
||||
final gamePath = getGamePath();
|
||||
final gameP4kPath = "$gamePath\\Data.p4k";
|
||||
final gameP4kPath = "$gamePath\\Data.p4k".platformPath;
|
||||
|
||||
try {
|
||||
state = state.copyWith(endMessage: S.current.tools_unp4k_msg_reading);
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'unp4kc.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(Unp4kCModel)
|
||||
const unp4kCModelProvider = Unp4kCModelProvider._();
|
||||
final unp4kCModelProvider = Unp4kCModelProvider._();
|
||||
|
||||
final class Unp4kCModelProvider
|
||||
extends $NotifierProvider<Unp4kCModel, Unp4kcState> {
|
||||
const Unp4kCModelProvider._()
|
||||
Unp4kCModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -41,14 +41,13 @@ final class Unp4kCModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$unp4kCModelHash() => r'68c24d50113e9e734ae8d277f65999bbef05dc05';
|
||||
String _$unp4kCModelHash() => r'6713e8e95e2bec1adcb36b63f6c6f9240a5959be';
|
||||
|
||||
abstract class _$Unp4kCModel extends $Notifier<Unp4kcState> {
|
||||
Unp4kcState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<Unp4kcState, Unp4kcState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$Unp4kCModel extends $Notifier<Unp4kcState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
306
lib/ui/auth/auth_page.dart
Normal file
306
lib/ui/auth/auth_page.dart
Normal file
@@ -0,0 +1,306 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/ui/auth/auth_ui_model.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class AuthPage extends HookConsumerWidget {
|
||||
final String? callbackUrl;
|
||||
final String? stateParameter;
|
||||
final String? nonce;
|
||||
|
||||
const AuthPage({super.key, this.callbackUrl, this.stateParameter, this.nonce});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final provider = authUIModelProvider(callbackUrl: callbackUrl, stateParameter: stateParameter, nonce: nonce);
|
||||
final model = ref.watch(provider);
|
||||
final modelNotifier = ref.read(provider.notifier);
|
||||
|
||||
final partyRoomState = ref.watch(partyRoomProvider);
|
||||
final userName = partyRoomState.auth.userInfo?.handleName ?? '未知用户';
|
||||
final userEmail = partyRoomState.auth.userInfo?.gameUserId ?? ''; // Using gameUserId as email-like identifier
|
||||
final avatarUrl = partyRoomState.auth.userInfo?.avatarUrl;
|
||||
final fullAvatarUrl = PartyRoomUtils.getAvatarUrl(avatarUrl);
|
||||
|
||||
useEffect(() {
|
||||
Future.microtask(() => modelNotifier.initialize());
|
||||
return null;
|
||||
}, const []);
|
||||
|
||||
return ContentDialog(
|
||||
constraints: const BoxConstraints(maxWidth: 450, maxHeight: 600),
|
||||
// Remove standard title to customize layout
|
||||
title: const SizedBox.shrink(),
|
||||
content: _buildBody(context, model, modelNotifier, userName, userEmail, fullAvatarUrl),
|
||||
actions: [
|
||||
if (model.error == null && model.isLoggedIn) ...[
|
||||
// Cancel button
|
||||
Button(onPressed: () => Navigator.of(context).pop(), child: const Text('拒绝')),
|
||||
// Allow button (Primary)
|
||||
FilledButton(
|
||||
onPressed: model.isLoading ? null : () => _handleAuthorize(context, ref, false),
|
||||
child: const Text('允许'),
|
||||
),
|
||||
] else ...[
|
||||
Button(onPressed: () => Navigator.of(context).pop(), child: const Text('关闭')),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(
|
||||
BuildContext context,
|
||||
AuthUIState state,
|
||||
AuthUIModel model,
|
||||
String userName,
|
||||
String userEmail,
|
||||
String? avatarUrl,
|
||||
) {
|
||||
if (state.isLoading) {
|
||||
return const SizedBox(height: 300, child: Center(child: ProgressRing()));
|
||||
}
|
||||
|
||||
if (state.isWaitingForConnection) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Center(
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [const ProgressRing(), const SizedBox(height: 24)]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state.error != null) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(FluentIcons.error_badge, size: 48, color: Colors.red),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Text(
|
||||
state.error!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
FilledButton(onPressed: () => model.initialize(), child: const Text('重试')),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!state.isLoggedIn) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(FluentIcons.warning, size: 48, color: Colors.orange),
|
||||
const SizedBox(height: 16),
|
||||
const Text('您需要先登录才能授权', style: TextStyle(fontSize: 16)),
|
||||
const SizedBox(height: 24),
|
||||
FilledButton(onPressed: () => Navigator.of(context).pop(), child: const Text('前往登录')),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final name = state.domainName ?? state.domain ?? '未知应用';
|
||||
final domain = state.domain;
|
||||
final isTrusted = state.isDomainTrusted;
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
// Title
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: TextStyle(fontSize: 20, color: Colors.white.withValues(alpha: 0.95), fontFamily: 'Segoe UI'),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: name,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const TextSpan(text: ' 申请访问您的账户'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (domain != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (state.domainName != null)
|
||||
Text(domain, style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: 0.5))),
|
||||
if (state.domainName != null) const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: (isTrusted ? Colors.green : Colors.orange).withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(color: (isTrusted ? Colors.green : Colors.orange).withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
isTrusted ? FluentIcons.completed : FluentIcons.warning,
|
||||
size: 10,
|
||||
color: isTrusted ? Colors.green : Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
isTrusted ? '已认证' : '未验证',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: isTrusted ? Colors.green : Colors.orange,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 2. User Account Info
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white.withValues(alpha: 0.1)),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ClipOval(
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: avatarUrl != null
|
||||
? CacheNetImage(url: avatarUrl, fit: BoxFit.cover)
|
||||
: const Icon(FluentIcons.contact, size: 24),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
userEmail.isNotEmpty ? userEmail : userName,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.white.withValues(alpha: 0.8),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('此操作将允许 $domain:', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildPermissionItem(FluentIcons.contact_info, '访问您的公开资料', '包括用户名、头像'),
|
||||
|
||||
const SizedBox(height: 48),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPermissionItem(IconData icon, String title, String subtitle) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, size: 20, color: Colors.blue),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500)),
|
||||
const SizedBox(height: 2),
|
||||
Text(subtitle, style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.6))),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleAuthorize(BuildContext context, WidgetRef ref, bool copyOnly) async {
|
||||
final provider = authUIModelProvider(callbackUrl: callbackUrl, stateParameter: stateParameter, nonce: nonce);
|
||||
final modelNotifier = ref.read(provider.notifier);
|
||||
final model = ref.read(provider);
|
||||
|
||||
// First, generate the code if not already generated
|
||||
if (model.code == null) {
|
||||
final success = await modelNotifier.generateCodeOnConfirm();
|
||||
if (!success) {
|
||||
if (context.mounted) {
|
||||
final currentState = ref.read(provider);
|
||||
await showToast(context, currentState.error ?? '生成授权码失败');
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final authUrl = modelNotifier.getAuthorizationUrl();
|
||||
if (authUrl == null) {
|
||||
if (context.mounted) {
|
||||
await showToast(context, '生成授权链接失败');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (copyOnly) {
|
||||
await modelNotifier.copyAuthorizationUrl();
|
||||
if (context.mounted) {
|
||||
await showToast(context, '授权链接已复制到剪贴板');
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
final launched = await launchUrlString(authUrl);
|
||||
if (!launched) {
|
||||
if (context.mounted) {
|
||||
await showToast(context, '打开浏览器失败,请复制链接手动访问');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
await showToast(context, '打开浏览器失败: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
lib/ui/auth/auth_ui_model.dart
Normal file
237
lib/ui/auth/auth_ui_model.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||
import 'package:starcitizen_doctor/generated/proto/auth/auth.pb.dart';
|
||||
import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
||||
|
||||
part 'auth_ui_model.freezed.dart';
|
||||
part 'auth_ui_model.g.dart';
|
||||
|
||||
@freezed
|
||||
sealed class AuthUIState with _$AuthUIState {
|
||||
const factory AuthUIState({
|
||||
@Default(false) bool isLoading,
|
||||
@Default(false) bool isLoggedIn,
|
||||
@Default(false) bool isWaitingForConnection,
|
||||
String? domain,
|
||||
String? callbackUrl,
|
||||
String? stateParameter,
|
||||
String? nonce,
|
||||
String? code,
|
||||
String? error,
|
||||
@Default(false) bool isDomainTrusted,
|
||||
String? domainName,
|
||||
}) = _AuthUIState;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class AuthUIModel extends _$AuthUIModel {
|
||||
@override
|
||||
AuthUIState build({String? callbackUrl, String? stateParameter, String? nonce}) {
|
||||
// Listen to party room connection and auth state changes
|
||||
ref.listen(partyRoomProvider, (previous, next) {
|
||||
// If we're waiting for connection and now connected, re-initialize
|
||||
if (state.isWaitingForConnection && next.client.isConnected && next.client.authClient != null) {
|
||||
dPrint('[AuthUI] Connection established, re-initializing...');
|
||||
Future.microtask(() => initialize());
|
||||
}
|
||||
|
||||
// If not logged in before and now logged in, re-initialize
|
||||
if (!state.isLoggedIn && previous?.auth.isLoggedIn == false && next.auth.isLoggedIn) {
|
||||
dPrint('[AuthUI] User logged in, re-initializing...');
|
||||
Future.microtask(() => initialize());
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to party room UI model for login status changes
|
||||
ref.listen(partyRoomUIModelProvider, (previous, next) {
|
||||
// If was logging in and now finished (success or fail), re-check logic
|
||||
if (previous?.isLoggingIn == true && !next.isLoggingIn) {
|
||||
dPrint('[AuthUI] Login process finished, re-initializing...');
|
||||
Future.microtask(() => initialize());
|
||||
}
|
||||
});
|
||||
|
||||
return AuthUIState(callbackUrl: callbackUrl, stateParameter: stateParameter, nonce: nonce);
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
state = state.copyWith(isLoading: true, error: null, isWaitingForConnection: false);
|
||||
|
||||
try {
|
||||
// Check if domain and callbackUrl are provided
|
||||
|
||||
if (state.callbackUrl == null || state.callbackUrl!.isEmpty) {
|
||||
state = state.copyWith(isLoading: false, error: '缺少回调地址参数');
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.stateParameter == null || state.stateParameter!.isEmpty) {
|
||||
state = state.copyWith(isLoading: false, error: '缺少 state 参数');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract domain from callbackUrl
|
||||
String? domain;
|
||||
try {
|
||||
final uri = Uri.parse(state.callbackUrl!);
|
||||
if (uri.host.isNotEmpty) {
|
||||
domain = uri.host;
|
||||
}
|
||||
} catch (e) {
|
||||
dPrint('Failed to parse callbackUrl: $e');
|
||||
}
|
||||
|
||||
if (domain == null || domain.isEmpty) {
|
||||
state = state.copyWith(isLoading: false, error: '无法从回调地址解析域名');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state with extracted domain
|
||||
state = state.copyWith(domain: domain);
|
||||
|
||||
// Get party room providers
|
||||
final partyRoom = ref.read(partyRoomProvider);
|
||||
final partyRoomUI = ref.read(partyRoomUIModelProvider);
|
||||
|
||||
// Check if connected to server
|
||||
if (!partyRoom.client.isConnected || partyRoom.client.authClient == null) {
|
||||
dPrint('[AuthUI] Server not connected, waiting for connection...');
|
||||
state = state.copyWith(isLoading: false, isWaitingForConnection: true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user is logged in
|
||||
if (!partyRoom.auth.isLoggedIn) {
|
||||
// If still logging in process (auto-login after connect), keep waiting
|
||||
if (partyRoomUI.isLoggingIn) {
|
||||
dPrint('[AuthUI] Auto-login in progress, waiting...');
|
||||
state = state.copyWith(isLoading: false, isWaitingForConnection: true);
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: false, isLoggedIn: false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check domain trust status
|
||||
final domainListResponse = await _getDomainList();
|
||||
bool isDomainTrusted = false;
|
||||
String? domainName;
|
||||
|
||||
if (domainListResponse != null) {
|
||||
final domainInfo = domainListResponse.domains
|
||||
.cast<
|
||||
JWTDomainInfo?
|
||||
>() // Cast to nullable to use firstWhere with orElse returning null if needed, though JWTDomainInfo is not nullable in proto usually
|
||||
.firstWhere((d) => d?.domain.toLowerCase() == state.domain!.toLowerCase(), orElse: () => null);
|
||||
|
||||
if (domainInfo != null && domainInfo.domain.isNotEmpty) {
|
||||
isDomainTrusted = true;
|
||||
domainName = domainInfo.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't generate token yet - wait for user confirmation
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
isLoggedIn: true,
|
||||
isDomainTrusted: isDomainTrusted,
|
||||
domainName: domainName,
|
||||
);
|
||||
} catch (e) {
|
||||
dPrint('Auth initialization error: $e');
|
||||
state = state.copyWith(isLoading: false, error: '初始化失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> generateCodeOnConfirm() async {
|
||||
// Only generate code if user is logged in and no previous error
|
||||
if (!state.isLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: true);
|
||||
|
||||
try {
|
||||
// Generate OIDC Auth Code
|
||||
final code = await _generateOIDCAuthCode();
|
||||
|
||||
if (code == null) {
|
||||
state = state.copyWith(isLoading: false, error: '生成授权码失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: false, code: code);
|
||||
return true;
|
||||
} catch (e) {
|
||||
dPrint('Generate code on confirm error: $e');
|
||||
state = state.copyWith(isLoading: false, error: '生成授权码失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<GetJWTDomainListResponse?> _getDomainList() async {
|
||||
try {
|
||||
final partyRoom = ref.read(partyRoomProvider);
|
||||
final partyRoomNotifier = ref.read(partyRoomProvider.notifier);
|
||||
final client = partyRoom.client.authClient;
|
||||
if (client == null) return null;
|
||||
|
||||
final response = await client.getJWTDomainList(
|
||||
GetJWTDomainListRequest(),
|
||||
options: partyRoomNotifier.getAuthCallOptions(),
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
dPrint('Get domain list error: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> _generateOIDCAuthCode() async {
|
||||
try {
|
||||
final partyRoom = ref.read(partyRoomProvider);
|
||||
final partyRoomNotifier = ref.read(partyRoomProvider.notifier);
|
||||
final client = partyRoom.client.authClient;
|
||||
if (client == null || state.callbackUrl == null) return null;
|
||||
|
||||
final request = GenerateOIDCAuthCodeRequest(redirectUri: state.callbackUrl!, nonce: state.nonce ?? '');
|
||||
|
||||
final response = await client.generateOIDCAuthCode(request, options: partyRoomNotifier.getAuthCallOptions());
|
||||
return response.code;
|
||||
} catch (e) {
|
||||
dPrint('Generate OIDC Auth Code error: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? getAuthorizationUrl() {
|
||||
if (state.code == null || state.callbackUrl == null || state.stateParameter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build authorization URL
|
||||
// Using query parameters (?) to allow both server-side and client-side processing
|
||||
final uri = Uri.parse(state.callbackUrl!);
|
||||
|
||||
// Merge existing query parameters with new ones
|
||||
final newQueryParameters = Map<String, dynamic>.from(uri.queryParameters);
|
||||
newQueryParameters['code'] = state.code!;
|
||||
newQueryParameters['state'] = state.stateParameter!;
|
||||
|
||||
final authUri = uri.replace(queryParameters: newQueryParameters);
|
||||
return authUri.toString();
|
||||
}
|
||||
|
||||
Future<void> copyAuthorizationUrl() async {
|
||||
final url = getAuthorizationUrl();
|
||||
if (url != null) {
|
||||
await Clipboard.setData(ClipboardData(text: url));
|
||||
}
|
||||
}
|
||||
}
|
||||
295
lib/ui/auth/auth_ui_model.freezed.dart
Normal file
295
lib/ui/auth/auth_ui_model.freezed.dart
Normal file
@@ -0,0 +1,295 @@
|
||||
// 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 'auth_ui_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$AuthUIState {
|
||||
|
||||
bool get isLoading; bool get isLoggedIn; bool get isWaitingForConnection; String? get domain; String? get callbackUrl; String? get stateParameter; String? get nonce; String? get code; String? get error; bool get isDomainTrusted; String? get domainName;
|
||||
/// Create a copy of AuthUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$AuthUIStateCopyWith<AuthUIState> get copyWith => _$AuthUIStateCopyWithImpl<AuthUIState>(this as AuthUIState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AuthUIState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoggedIn, isLoggedIn) || other.isLoggedIn == isLoggedIn)&&(identical(other.isWaitingForConnection, isWaitingForConnection) || other.isWaitingForConnection == isWaitingForConnection)&&(identical(other.domain, domain) || other.domain == domain)&&(identical(other.callbackUrl, callbackUrl) || other.callbackUrl == callbackUrl)&&(identical(other.stateParameter, stateParameter) || other.stateParameter == stateParameter)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.code, code) || other.code == code)&&(identical(other.error, error) || other.error == error)&&(identical(other.isDomainTrusted, isDomainTrusted) || other.isDomainTrusted == isDomainTrusted)&&(identical(other.domainName, domainName) || other.domainName == domainName));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,isLoggedIn,isWaitingForConnection,domain,callbackUrl,stateParameter,nonce,code,error,isDomainTrusted,domainName);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthUIState(isLoading: $isLoading, isLoggedIn: $isLoggedIn, isWaitingForConnection: $isWaitingForConnection, domain: $domain, callbackUrl: $callbackUrl, stateParameter: $stateParameter, nonce: $nonce, code: $code, error: $error, isDomainTrusted: $isDomainTrusted, domainName: $domainName)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $AuthUIStateCopyWith<$Res> {
|
||||
factory $AuthUIStateCopyWith(AuthUIState value, $Res Function(AuthUIState) _then) = _$AuthUIStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isLoading, bool isLoggedIn, bool isWaitingForConnection, String? domain, String? callbackUrl, String? stateParameter, String? nonce, String? code, String? error, bool isDomainTrusted, String? domainName
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$AuthUIStateCopyWithImpl<$Res>
|
||||
implements $AuthUIStateCopyWith<$Res> {
|
||||
_$AuthUIStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final AuthUIState _self;
|
||||
final $Res Function(AuthUIState) _then;
|
||||
|
||||
/// Create a copy of AuthUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? isLoggedIn = null,Object? isWaitingForConnection = null,Object? domain = freezed,Object? callbackUrl = freezed,Object? stateParameter = freezed,Object? nonce = freezed,Object? code = freezed,Object? error = freezed,Object? isDomainTrusted = null,Object? domainName = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoggedIn: null == isLoggedIn ? _self.isLoggedIn : isLoggedIn // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isWaitingForConnection: null == isWaitingForConnection ? _self.isWaitingForConnection : isWaitingForConnection // ignore: cast_nullable_to_non_nullable
|
||||
as bool,domain: freezed == domain ? _self.domain : domain // ignore: cast_nullable_to_non_nullable
|
||||
as String?,callbackUrl: freezed == callbackUrl ? _self.callbackUrl : callbackUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,stateParameter: freezed == stateParameter ? _self.stateParameter : stateParameter // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||
as String?,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isDomainTrusted: null == isDomainTrusted ? _self.isDomainTrusted : isDomainTrusted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,domainName: freezed == domainName ? _self.domainName : domainName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [AuthUIState].
|
||||
extension AuthUIStatePatterns on AuthUIState {
|
||||
/// 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( _AuthUIState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState() 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( _AuthUIState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState():
|
||||
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( _AuthUIState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState() 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( bool isLoading, bool isLoggedIn, bool isWaitingForConnection, String? domain, String? callbackUrl, String? stateParameter, String? nonce, String? code, String? error, bool isDomainTrusted, String? domainName)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState() when $default != null:
|
||||
return $default(_that.isLoading,_that.isLoggedIn,_that.isWaitingForConnection,_that.domain,_that.callbackUrl,_that.stateParameter,_that.nonce,_that.code,_that.error,_that.isDomainTrusted,_that.domainName);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( bool isLoading, bool isLoggedIn, bool isWaitingForConnection, String? domain, String? callbackUrl, String? stateParameter, String? nonce, String? code, String? error, bool isDomainTrusted, String? domainName) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState():
|
||||
return $default(_that.isLoading,_that.isLoggedIn,_that.isWaitingForConnection,_that.domain,_that.callbackUrl,_that.stateParameter,_that.nonce,_that.code,_that.error,_that.isDomainTrusted,_that.domainName);}
|
||||
}
|
||||
/// 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( bool isLoading, bool isLoggedIn, bool isWaitingForConnection, String? domain, String? callbackUrl, String? stateParameter, String? nonce, String? code, String? error, bool isDomainTrusted, String? domainName)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AuthUIState() when $default != null:
|
||||
return $default(_that.isLoading,_that.isLoggedIn,_that.isWaitingForConnection,_that.domain,_that.callbackUrl,_that.stateParameter,_that.nonce,_that.code,_that.error,_that.isDomainTrusted,_that.domainName);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _AuthUIState implements AuthUIState {
|
||||
const _AuthUIState({this.isLoading = false, this.isLoggedIn = false, this.isWaitingForConnection = false, this.domain, this.callbackUrl, this.stateParameter, this.nonce, this.code, this.error, this.isDomainTrusted = false, this.domainName});
|
||||
|
||||
|
||||
@override@JsonKey() final bool isLoading;
|
||||
@override@JsonKey() final bool isLoggedIn;
|
||||
@override@JsonKey() final bool isWaitingForConnection;
|
||||
@override final String? domain;
|
||||
@override final String? callbackUrl;
|
||||
@override final String? stateParameter;
|
||||
@override final String? nonce;
|
||||
@override final String? code;
|
||||
@override final String? error;
|
||||
@override@JsonKey() final bool isDomainTrusted;
|
||||
@override final String? domainName;
|
||||
|
||||
/// Create a copy of AuthUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$AuthUIStateCopyWith<_AuthUIState> get copyWith => __$AuthUIStateCopyWithImpl<_AuthUIState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AuthUIState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoggedIn, isLoggedIn) || other.isLoggedIn == isLoggedIn)&&(identical(other.isWaitingForConnection, isWaitingForConnection) || other.isWaitingForConnection == isWaitingForConnection)&&(identical(other.domain, domain) || other.domain == domain)&&(identical(other.callbackUrl, callbackUrl) || other.callbackUrl == callbackUrl)&&(identical(other.stateParameter, stateParameter) || other.stateParameter == stateParameter)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.code, code) || other.code == code)&&(identical(other.error, error) || other.error == error)&&(identical(other.isDomainTrusted, isDomainTrusted) || other.isDomainTrusted == isDomainTrusted)&&(identical(other.domainName, domainName) || other.domainName == domainName));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,isLoggedIn,isWaitingForConnection,domain,callbackUrl,stateParameter,nonce,code,error,isDomainTrusted,domainName);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthUIState(isLoading: $isLoading, isLoggedIn: $isLoggedIn, isWaitingForConnection: $isWaitingForConnection, domain: $domain, callbackUrl: $callbackUrl, stateParameter: $stateParameter, nonce: $nonce, code: $code, error: $error, isDomainTrusted: $isDomainTrusted, domainName: $domainName)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$AuthUIStateCopyWith<$Res> implements $AuthUIStateCopyWith<$Res> {
|
||||
factory _$AuthUIStateCopyWith(_AuthUIState value, $Res Function(_AuthUIState) _then) = __$AuthUIStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isLoading, bool isLoggedIn, bool isWaitingForConnection, String? domain, String? callbackUrl, String? stateParameter, String? nonce, String? code, String? error, bool isDomainTrusted, String? domainName
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$AuthUIStateCopyWithImpl<$Res>
|
||||
implements _$AuthUIStateCopyWith<$Res> {
|
||||
__$AuthUIStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _AuthUIState _self;
|
||||
final $Res Function(_AuthUIState) _then;
|
||||
|
||||
/// Create a copy of AuthUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? isLoggedIn = null,Object? isWaitingForConnection = null,Object? domain = freezed,Object? callbackUrl = freezed,Object? stateParameter = freezed,Object? nonce = freezed,Object? code = freezed,Object? error = freezed,Object? isDomainTrusted = null,Object? domainName = freezed,}) {
|
||||
return _then(_AuthUIState(
|
||||
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoggedIn: null == isLoggedIn ? _self.isLoggedIn : isLoggedIn // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isWaitingForConnection: null == isWaitingForConnection ? _self.isWaitingForConnection : isWaitingForConnection // ignore: cast_nullable_to_non_nullable
|
||||
as bool,domain: freezed == domain ? _self.domain : domain // ignore: cast_nullable_to_non_nullable
|
||||
as String?,callbackUrl: freezed == callbackUrl ? _self.callbackUrl : callbackUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,stateParameter: freezed == stateParameter ? _self.stateParameter : stateParameter // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||
as String?,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable
|
||||
as String?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isDomainTrusted: null == isDomainTrusted ? _self.isDomainTrusted : isDomainTrusted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,domainName: freezed == domainName ? _self.domainName : domainName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
133
lib/ui/auth/auth_ui_model.g.dart
Normal file
133
lib/ui/auth/auth_ui_model.g.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_ui_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(AuthUIModel)
|
||||
final authUIModelProvider = AuthUIModelFamily._();
|
||||
|
||||
final class AuthUIModelProvider
|
||||
extends $NotifierProvider<AuthUIModel, AuthUIState> {
|
||||
AuthUIModelProvider._({
|
||||
required AuthUIModelFamily super.from,
|
||||
required ({String? callbackUrl, String? stateParameter, String? nonce})
|
||||
super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'authUIModelProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$authUIModelHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'authUIModelProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
AuthUIModel create() => AuthUIModel();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AuthUIState value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<AuthUIState>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AuthUIModelProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$authUIModelHash() => r'485bf56e488ba01cd1371131e6d92077c76176df';
|
||||
|
||||
final class AuthUIModelFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
AuthUIModel,
|
||||
AuthUIState,
|
||||
AuthUIState,
|
||||
AuthUIState,
|
||||
({String? callbackUrl, String? stateParameter, String? nonce})
|
||||
> {
|
||||
AuthUIModelFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'authUIModelProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
AuthUIModelProvider call({
|
||||
String? callbackUrl,
|
||||
String? stateParameter,
|
||||
String? nonce,
|
||||
}) => AuthUIModelProvider._(
|
||||
argument: (
|
||||
callbackUrl: callbackUrl,
|
||||
stateParameter: stateParameter,
|
||||
nonce: nonce,
|
||||
),
|
||||
from: this,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => r'authUIModelProvider';
|
||||
}
|
||||
|
||||
abstract class _$AuthUIModel extends $Notifier<AuthUIState> {
|
||||
late final _$args =
|
||||
ref.$arg
|
||||
as ({String? callbackUrl, String? stateParameter, String? nonce});
|
||||
String? get callbackUrl => _$args.callbackUrl;
|
||||
String? get stateParameter => _$args.stateParameter;
|
||||
String? get nonce => _$args.nonce;
|
||||
|
||||
AuthUIState build({
|
||||
String? callbackUrl,
|
||||
String? stateParameter,
|
||||
String? nonce,
|
||||
});
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AuthUIState, AuthUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AuthUIState, AuthUIState>,
|
||||
AuthUIState,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(
|
||||
ref,
|
||||
() => build(
|
||||
callbackUrl: _$args.callbackUrl,
|
||||
stateParameter: _$args.stateParameter,
|
||||
nonce: _$args.nonce,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -36,17 +36,9 @@ class GuideUI extends HookConsumerWidget {
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/app_logo_mini.png",
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
Image.asset("assets/app_logo_mini.png", width: 20, height: 20, fit: BoxFit.cover),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
S.current.app_index_version_info(
|
||||
ConstConf.appVersion, ConstConf.isMSE ? "" : " Dev"),
|
||||
)
|
||||
Text(S.current.app_index_version_info(ConstConf.appVersion, ConstConf.isMSE ? "" : " Dev")),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -56,42 +48,34 @@ class GuideUI extends HookConsumerWidget {
|
||||
children: [
|
||||
Image.asset("assets/app_logo.png", width: 192, height: 192),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
S.current.guide_title_welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 38,
|
||||
),
|
||||
),
|
||||
Text(S.current.guide_title_welcome, style: TextStyle(fontSize: 38)),
|
||||
SizedBox(height: 24),
|
||||
Text(S.current.guide_info_check_settings),
|
||||
SizedBox(height: 32),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
makeGameLauncherPathSelect(
|
||||
context, toolsModel, toolsState, settingModel),
|
||||
const SizedBox(height: 12),
|
||||
makeGamePathSelect(
|
||||
context, toolsModel, toolsState, settingModel),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
makeGameLauncherPathSelect(context, toolsModel, toolsState, settingModel),
|
||||
const SizedBox(height: 12),
|
||||
makeGamePathSelect(context, toolsModel, toolsState, settingModel),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Button(
|
||||
onPressed: () => toolsModel.reScanPath(context,
|
||||
checkActive: true, skipToast: true),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 30, bottom: 30, left: 12, right: 12),
|
||||
child: Icon(FluentIcons.refresh),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Button(
|
||||
onPressed: () => toolsModel.reScanPath(context, checkActive: true, skipToast: true),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(top: 30, bottom: 30, left: 12, right: 12),
|
||||
child: Icon(FluentIcons.refresh),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 32, left: 32),
|
||||
@@ -100,9 +84,7 @@ class GuideUI extends HookConsumerWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
S.current.guide_info_game_download_note,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white.withValues(alpha: .6)),
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
),
|
||||
@@ -115,8 +97,7 @@ class GuideUI extends HookConsumerWidget {
|
||||
Spacer(),
|
||||
Button(
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Text(S.current.guide_action_get_help),
|
||||
),
|
||||
onPressed: () {
|
||||
@@ -126,26 +107,25 @@ class GuideUI extends HookConsumerWidget {
|
||||
SizedBox(width: 24),
|
||||
FilledButton(
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Text(S.current.guide_action_complete_setup),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (toolsState.rsiLauncherInstallPaths.isEmpty) {
|
||||
final ok = await showConfirmDialogs(
|
||||
context,
|
||||
S.current.guide_dialog_confirm_complete_setup,
|
||||
Text(S.current
|
||||
.guide_action_info_no_launcher_path_warning));
|
||||
context,
|
||||
S.current.guide_dialog_confirm_complete_setup,
|
||||
Text(S.current.guide_action_info_no_launcher_path_warning),
|
||||
);
|
||||
if (!ok) return;
|
||||
}
|
||||
if (toolsState.scInstallPaths.isEmpty) {
|
||||
if (!context.mounted) return;
|
||||
final ok = await showConfirmDialogs(
|
||||
context,
|
||||
S.current.guide_dialog_confirm_complete_setup,
|
||||
Text(S
|
||||
.current.guide_action_info_no_game_path_warning));
|
||||
context,
|
||||
S.current.guide_dialog_confirm_complete_setup,
|
||||
Text(S.current.guide_action_info_no_game_path_warning),
|
||||
);
|
||||
if (!ok) return;
|
||||
}
|
||||
final appConf = await Hive.openBox("app_conf");
|
||||
@@ -164,8 +144,12 @@ class GuideUI extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeGameLauncherPathSelect(BuildContext context, ToolsUIModel model,
|
||||
ToolsUIState state, SettingsUIModel settingModel) {
|
||||
Widget makeGameLauncherPathSelect(
|
||||
BuildContext context,
|
||||
ToolsUIModel model,
|
||||
ToolsUIState state,
|
||||
SettingsUIModel settingModel,
|
||||
) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -177,13 +161,7 @@ class GuideUI extends HookConsumerWidget {
|
||||
child: ComboBox<String>(
|
||||
isExpanded: true,
|
||||
value: state.rsiLauncherInstalledPath,
|
||||
items: [
|
||||
for (final path in state.rsiLauncherInstallPaths)
|
||||
ComboBoxItem(
|
||||
value: path,
|
||||
child: Text(path),
|
||||
)
|
||||
],
|
||||
items: [for (final path in state.rsiLauncherInstallPaths) ComboBoxItem(value: path, child: Text(path))],
|
||||
onChanged: (v) {
|
||||
model.onChangeLauncherPath(v!);
|
||||
},
|
||||
@@ -192,10 +170,7 @@ class GuideUI extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Button(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(6),
|
||||
child: Icon(FluentIcons.folder_search),
|
||||
),
|
||||
child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.folder_search)),
|
||||
onPressed: () async {
|
||||
await settingModel.setLauncherPath(context);
|
||||
if (!context.mounted) return;
|
||||
@@ -206,8 +181,12 @@ class GuideUI extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeGamePathSelect(BuildContext context, ToolsUIModel model,
|
||||
ToolsUIState state, SettingsUIModel settingModel) {
|
||||
Widget makeGamePathSelect(
|
||||
BuildContext context,
|
||||
ToolsUIModel model,
|
||||
ToolsUIState state,
|
||||
SettingsUIModel settingModel,
|
||||
) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -219,13 +198,7 @@ class GuideUI extends HookConsumerWidget {
|
||||
child: ComboBox<String>(
|
||||
isExpanded: true,
|
||||
value: state.scInstalledPath,
|
||||
items: [
|
||||
for (final path in state.scInstallPaths)
|
||||
ComboBoxItem(
|
||||
value: path,
|
||||
child: Text(path),
|
||||
)
|
||||
],
|
||||
items: [for (final path in state.scInstallPaths) ComboBoxItem(value: path, child: Text(path))],
|
||||
onChanged: (v) {
|
||||
model.onChangeGamePath(v!);
|
||||
},
|
||||
@@ -234,15 +207,13 @@ class GuideUI extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Button(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(6),
|
||||
child: Icon(FluentIcons.folder_search),
|
||||
),
|
||||
onPressed: () async {
|
||||
await settingModel.setGamePath(context);
|
||||
if (!context.mounted) return;
|
||||
model.reScanPath(context, checkActive: true, skipToast: true);
|
||||
})
|
||||
child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.folder_search)),
|
||||
onPressed: () async {
|
||||
await settingModel.setGamePath(context);
|
||||
if (!context.mounted) return;
|
||||
model.reScanPath(context, checkActive: true, skipToast: true);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -216,7 +216,8 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
||||
}
|
||||
|
||||
String getChannelID(String installPath) {
|
||||
if (installPath.endsWith("\\LIVE")) {
|
||||
final pathLower = installPath.platformPath.toLowerCase();
|
||||
if (pathLower.endsWith('\\live'.platformPath)) {
|
||||
return "LIVE";
|
||||
}
|
||||
return "PTU";
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'home_game_login_dialog_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(HomeGameLoginUIModel)
|
||||
const homeGameLoginUIModelProvider = HomeGameLoginUIModelProvider._();
|
||||
final homeGameLoginUIModelProvider = HomeGameLoginUIModelProvider._();
|
||||
|
||||
final class HomeGameLoginUIModelProvider
|
||||
extends $NotifierProvider<HomeGameLoginUIModel, HomeGameLoginState> {
|
||||
const HomeGameLoginUIModelProvider._()
|
||||
HomeGameLoginUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -42,14 +42,13 @@ final class HomeGameLoginUIModelProvider
|
||||
}
|
||||
|
||||
String _$homeGameLoginUIModelHash() =>
|
||||
r'd81831f54c6b1e98ea8a1e94b5e6049fe552996f';
|
||||
r'ca905904d20a6b1956fee04dcb501f0d1c19f86b';
|
||||
|
||||
abstract class _$HomeGameLoginUIModel extends $Notifier<HomeGameLoginState> {
|
||||
HomeGameLoginState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<HomeGameLoginState, HomeGameLoginState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -59,6 +58,6 @@ abstract class _$HomeGameLoginUIModel extends $Notifier<HomeGameLoginState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'home_downloader_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(HomeDownloaderUIModel)
|
||||
const homeDownloaderUIModelProvider = HomeDownloaderUIModelProvider._();
|
||||
final homeDownloaderUIModelProvider = HomeDownloaderUIModelProvider._();
|
||||
|
||||
final class HomeDownloaderUIModelProvider
|
||||
extends $NotifierProvider<HomeDownloaderUIModel, HomeDownloaderUIState> {
|
||||
const HomeDownloaderUIModelProvider._()
|
||||
HomeDownloaderUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -50,7 +50,6 @@ abstract class _$HomeDownloaderUIModel
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<HomeDownloaderUIState, HomeDownloaderUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -60,6 +59,6 @@ abstract class _$HomeDownloaderUIModel
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'game_doctor_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(HomeGameDoctorUIModel)
|
||||
const homeGameDoctorUIModelProvider = HomeGameDoctorUIModelProvider._();
|
||||
final homeGameDoctorUIModelProvider = HomeGameDoctorUIModelProvider._();
|
||||
|
||||
final class HomeGameDoctorUIModelProvider
|
||||
extends $NotifierProvider<HomeGameDoctorUIModel, HomeGameDoctorState> {
|
||||
const HomeGameDoctorUIModelProvider._()
|
||||
HomeGameDoctorUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -49,7 +49,6 @@ abstract class _$HomeGameDoctorUIModel extends $Notifier<HomeGameDoctorState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<HomeGameDoctorState, HomeGameDoctorState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -59,6 +58,6 @@ abstract class _$HomeGameDoctorUIModel extends $Notifier<HomeGameDoctorState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,9 +247,21 @@ class HomeUIModel extends _$HomeUIModel {
|
||||
final fixedList = list.map((item) {
|
||||
if (item.time == null) return item;
|
||||
final itemDateTime = DateTime.fromMillisecondsSinceEpoch(item.time!);
|
||||
final itemDatePlusSeven = itemDateTime.add(const Duration(days: 7));
|
||||
if (itemDatePlusSeven.isBefore(now)) {
|
||||
final nextDate = DateTime(
|
||||
|
||||
// 计算今年的节日日期
|
||||
final thisYearDate = DateTime(
|
||||
now.year,
|
||||
itemDateTime.month,
|
||||
itemDateTime.day,
|
||||
itemDateTime.hour,
|
||||
itemDateTime.minute,
|
||||
itemDateTime.second,
|
||||
);
|
||||
|
||||
// 如果今年的节日日期 + 7天已经过了,使用明年的日期
|
||||
final thisYearDatePlusSeven = thisYearDate.add(const Duration(days: 7));
|
||||
if (thisYearDatePlusSeven.isBefore(now)) {
|
||||
final nextYearDate = DateTime(
|
||||
now.year + 1,
|
||||
itemDateTime.month,
|
||||
itemDateTime.day,
|
||||
@@ -257,11 +269,13 @@ class HomeUIModel extends _$HomeUIModel {
|
||||
itemDateTime.minute,
|
||||
itemDateTime.second,
|
||||
);
|
||||
final newTimestamp = (nextDate.millisecondsSinceEpoch).round();
|
||||
final newTimestamp = (nextYearDate.millisecondsSinceEpoch).round();
|
||||
return CountdownFestivalItemData(name: item.name, time: newTimestamp, icon: item.icon);
|
||||
}
|
||||
|
||||
return item;
|
||||
// 否则使用今年的日期
|
||||
final newTimestamp = (thisYearDate.millisecondsSinceEpoch).round();
|
||||
return CountdownFestivalItemData(name: item.name, time: newTimestamp, icon: item.icon);
|
||||
}).toList();
|
||||
|
||||
// Sort by time (ascending order - nearest festival first)
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'home_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(HomeUIModel)
|
||||
const homeUIModelProvider = HomeUIModelProvider._();
|
||||
final homeUIModelProvider = HomeUIModelProvider._();
|
||||
|
||||
final class HomeUIModelProvider
|
||||
extends $NotifierProvider<HomeUIModel, HomeUIModelState> {
|
||||
const HomeUIModelProvider._()
|
||||
HomeUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -48,7 +48,6 @@ abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<HomeUIModelState, HomeUIModelState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'input_method_dialog_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(InputMethodDialogUIModel)
|
||||
const inputMethodDialogUIModelProvider = InputMethodDialogUIModelProvider._();
|
||||
final inputMethodDialogUIModelProvider = InputMethodDialogUIModelProvider._();
|
||||
|
||||
final class InputMethodDialogUIModelProvider
|
||||
extends
|
||||
$NotifierProvider<InputMethodDialogUIModel, InputMethodDialogUIState> {
|
||||
const InputMethodDialogUIModelProvider._()
|
||||
InputMethodDialogUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -51,7 +51,6 @@ abstract class _$InputMethodDialogUIModel
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref as $Ref<InputMethodDialogUIState, InputMethodDialogUIState>;
|
||||
final element =
|
||||
@@ -62,16 +61,16 @@ abstract class _$InputMethodDialogUIModel
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(OnnxTranslation)
|
||||
const onnxTranslationProvider = OnnxTranslationFamily._();
|
||||
final onnxTranslationProvider = OnnxTranslationFamily._();
|
||||
|
||||
final class OnnxTranslationProvider
|
||||
extends $NotifierProvider<OnnxTranslation, bool> {
|
||||
const OnnxTranslationProvider._({
|
||||
OnnxTranslationProvider._({
|
||||
required OnnxTranslationFamily super.from,
|
||||
required (String, String, bool) super.argument,
|
||||
}) : super(
|
||||
@@ -126,7 +125,7 @@ final class OnnxTranslationFamily extends $Family
|
||||
bool,
|
||||
(String, String, bool)
|
||||
> {
|
||||
const OnnxTranslationFamily._()
|
||||
OnnxTranslationFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'onnxTranslationProvider',
|
||||
@@ -158,7 +157,6 @@ abstract class _$OnnxTranslation extends $Notifier<bool> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args.$1, _$args.$2, _$args.$3);
|
||||
final ref = this.ref as $Ref<bool, bool>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -168,6 +166,6 @@ abstract class _$OnnxTranslation extends $Notifier<bool> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args.$1, _$args.$2, _$args.$3));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'server.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(InputMethodServer)
|
||||
const inputMethodServerProvider = InputMethodServerProvider._();
|
||||
final inputMethodServerProvider = InputMethodServerProvider._();
|
||||
|
||||
final class InputMethodServerProvider
|
||||
extends $NotifierProvider<InputMethodServer, InputMethodServerState> {
|
||||
const InputMethodServerProvider._()
|
||||
InputMethodServerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -48,7 +48,6 @@ abstract class _$InputMethodServer extends $Notifier<InputMethodServerState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref as $Ref<InputMethodServerState, InputMethodServerState>;
|
||||
final element =
|
||||
@@ -59,6 +58,6 @@ abstract class _$InputMethodServer extends $Notifier<InputMethodServerState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'server_qr_dialog_ui.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ServerQrState)
|
||||
const serverQrStateProvider = ServerQrStateProvider._();
|
||||
final serverQrStateProvider = ServerQrStateProvider._();
|
||||
|
||||
final class ServerQrStateProvider
|
||||
extends $NotifierProvider<ServerQrState, bool> {
|
||||
const ServerQrStateProvider._()
|
||||
ServerQrStateProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -48,7 +48,6 @@ abstract class _$ServerQrState extends $Notifier<bool> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<bool, bool>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$ServerQrState extends $Notifier<bool> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'advanced_localization_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(AdvancedLocalizationUIModel)
|
||||
const advancedLocalizationUIModelProvider =
|
||||
final advancedLocalizationUIModelProvider =
|
||||
AdvancedLocalizationUIModelProvider._();
|
||||
|
||||
final class AdvancedLocalizationUIModelProvider
|
||||
@@ -19,7 +19,7 @@ final class AdvancedLocalizationUIModelProvider
|
||||
AdvancedLocalizationUIModel,
|
||||
AdvancedLocalizationUIState
|
||||
> {
|
||||
const AdvancedLocalizationUIModelProvider._()
|
||||
AdvancedLocalizationUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -55,7 +55,6 @@ abstract class _$AdvancedLocalizationUIModel
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AdvancedLocalizationUIState, AdvancedLocalizationUIState>;
|
||||
@@ -70,6 +69,6 @@ abstract class _$AdvancedLocalizationUIModel
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,9 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
return ContentDialog(
|
||||
title: makeTitle(context, model, state),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery
|
||||
.of(context)
|
||||
.size
|
||||
.width * .7, minHeight: MediaQuery
|
||||
.of(context)
|
||||
.size
|
||||
.height * .9),
|
||||
maxWidth: MediaQuery.of(context).size.width * .7,
|
||||
minHeight: MediaQuery.of(context).size.height * .9,
|
||||
),
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.only(left: 12, right: 12, top: 12),
|
||||
child: SingleChildScrollView(
|
||||
@@ -44,132 +40,128 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
children: [
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 130),
|
||||
child: state.patchStatus?.key == true &&
|
||||
state.patchStatus?.value == S.current.home_action_info_game_built_in
|
||||
child:
|
||||
state.patchStatus?.key == true &&
|
||||
state.patchStatus?.value == S.current.home_action_info_game_built_in
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: InfoBar(
|
||||
title: Text(S.current.home_action_info_warning),
|
||||
content: Text(S.current.localization_info_machine_translation_warning),
|
||||
severity: InfoBarSeverity.info,
|
||||
style: InfoBarThemeData(decoration: (severity) {
|
||||
return const BoxDecoration(color: Color.fromRGBO(155, 7, 7, 1.0));
|
||||
}, iconColor: (severity) {
|
||||
return Colors.white;
|
||||
}),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
width: MediaQuery
|
||||
.of(context)
|
||||
.size
|
||||
.width,
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: InfoBar(
|
||||
title: Text(S.current.home_action_info_warning),
|
||||
content: Text(S.current.localization_info_machine_translation_warning),
|
||||
severity: InfoBarSeverity.info,
|
||||
style: InfoBarThemeData(
|
||||
decoration: (severity) {
|
||||
return const BoxDecoration(color: Color.fromRGBO(155, 7, 7, 1.0));
|
||||
},
|
||||
iconColor: (severity) {
|
||||
return Colors.white;
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox(width: MediaQuery.of(context).size.width),
|
||||
),
|
||||
makeToolsListContainer(context, model, state),
|
||||
makeListContainer(
|
||||
S.current.localization_info_translation,
|
||||
[
|
||||
if (state.patchStatus == null)
|
||||
makeLoading(context)
|
||||
else
|
||||
...[
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(S.current.localization_info_enabled(
|
||||
LocalizationUIModel.languageSupport[state.selectedLanguage] ?? "")),
|
||||
),
|
||||
const Spacer(),
|
||||
ToggleSwitch(
|
||||
checked: state.patchStatus?.key == true,
|
||||
onChanged: model.updateLangCfg,
|
||||
)
|
||||
],
|
||||
makeListContainer(S.current.localization_info_translation, [
|
||||
if (state.patchStatus == null)
|
||||
makeLoading(context)
|
||||
else ...[
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
S.current.localization_info_enabled(
|
||||
LocalizationUIModel.languageSupport[state.selectedLanguage] ?? "",
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
),
|
||||
const Spacer(),
|
||||
ToggleSwitch(checked: state.patchStatus?.key == true, onChanged: model.updateLangCfg),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(S.current.localization_info_installed_version(
|
||||
"${state.patchStatus?.value ?? ""} ${(state.isInstalledAdvanced ?? false) ? S
|
||||
.current.home_localization_msg_version_advanced : ""}")),
|
||||
SizedBox(width: 24),
|
||||
if (state.installedCommunityInputMethodSupportVersion != null)
|
||||
Text(
|
||||
S.current.input_method_community_input_method_support_version(
|
||||
state.installedCommunityInputMethodSupportVersion ?? "?"),
|
||||
)
|
||||
],
|
||||
Text(
|
||||
S.current.localization_info_installed_version(
|
||||
"${state.patchStatus?.value ?? ""} ${(state.isInstalledAdvanced ?? false) ? S.current.home_localization_msg_version_advanced : ""}",
|
||||
),
|
||||
),
|
||||
if (state.patchStatus?.value != S.current.home_action_info_game_built_in)
|
||||
Row(
|
||||
children: [
|
||||
Button(
|
||||
onPressed: model.goFeedback,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(FluentIcons.feedback),
|
||||
const SizedBox(width: 6),
|
||||
Text(S.current.localization_action_translation_feedback),
|
||||
],
|
||||
),
|
||||
)),
|
||||
const SizedBox(width: 16),
|
||||
Button(
|
||||
onPressed: model.doDelIniFile(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(FluentIcons.delete),
|
||||
const SizedBox(width: 6),
|
||||
Text(S.current.localization_action_uninstall_translation),
|
||||
],
|
||||
),
|
||||
)),
|
||||
],
|
||||
SizedBox(width: 24),
|
||||
if (state.installedCommunityInputMethodSupportVersion != null)
|
||||
Text(
|
||||
S.current.input_method_community_input_method_support_version(
|
||||
state.installedCommunityInputMethodSupportVersion ?? "?",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
color: Colors.white.withValues(alpha: .1),
|
||||
height: 1,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (state.apiLocalizationData == null)
|
||||
makeLoading(context)
|
||||
else
|
||||
if (state.apiLocalizationData!.isEmpty)
|
||||
Center(
|
||||
child: Text(
|
||||
S.current.localization_info_no_translation_available,
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .8)),
|
||||
),
|
||||
if (state.patchStatus?.value != S.current.home_action_info_game_built_in)
|
||||
Row(
|
||||
children: [
|
||||
Button(
|
||||
onPressed: model.goFeedback,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(FluentIcons.feedback),
|
||||
const SizedBox(width: 6),
|
||||
Text(S.current.localization_action_translation_feedback),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
AlignedGridView.count(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final item = state.apiLocalizationData!.entries.elementAt(index);
|
||||
return makeRemoteList(context, model, item, state, index);
|
||||
},
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: state.apiLocalizationData?.length ?? 0,
|
||||
)
|
||||
],
|
||||
],
|
||||
context),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Button(
|
||||
onPressed: model.doDelIniFile(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(FluentIcons.delete),
|
||||
const SizedBox(width: 6),
|
||||
Text(S.current.localization_action_uninstall_translation),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Container(color: Colors.white.withValues(alpha: .1), height: 1),
|
||||
const SizedBox(height: 12),
|
||||
if (state.apiLocalizationData == null)
|
||||
makeLoading(context)
|
||||
else if (state.apiLocalizationData!.isEmpty)
|
||||
Center(
|
||||
child: Text(
|
||||
S.current.localization_info_no_translation_available,
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .8)),
|
||||
),
|
||||
)
|
||||
else
|
||||
AlignedGridView.count(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final item = state.apiLocalizationData!.entries.elementAt(index);
|
||||
return makeRemoteList(context, model, item, state, index);
|
||||
},
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: state.apiLocalizationData?.length ?? 0,
|
||||
),
|
||||
],
|
||||
], context),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -177,11 +169,16 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeRemoteList(BuildContext context, LocalizationUIModel model, MapEntry<String, ScLocalizationData> item,
|
||||
LocalizationUIState state, int index) {
|
||||
Widget makeRemoteList(
|
||||
BuildContext context,
|
||||
LocalizationUIModel model,
|
||||
MapEntry<String, ScLocalizationData> item,
|
||||
LocalizationUIState state,
|
||||
int index,
|
||||
) {
|
||||
final isWorking = state.workingVersion.isNotEmpty;
|
||||
final isMineWorking = state.workingVersion == item.key;
|
||||
final isInstalled = state.patchStatus?.value == item.key;
|
||||
final isInstalled = state.patchStatus?.value == item.key || state.patchStatus?.value == item.value.versionName;
|
||||
final isItemEnabled = ((item.value.enable ?? false));
|
||||
final tapDisabled = isInstalled || isWorking || !isItemEnabled || isMineWorking;
|
||||
return GridItemAnimator(
|
||||
@@ -207,10 +204,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${item.value.info}",
|
||||
style: const TextStyle(fontSize: 19),
|
||||
),
|
||||
Text("${item.value.info}", style: const TextStyle(fontSize: 19)),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
S.current.localization_info_version_number(item.value.versionName ?? ""),
|
||||
@@ -230,40 +224,30 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
if (isMineWorking)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 12),
|
||||
child: ProgressRing(),
|
||||
)
|
||||
else
|
||||
...[
|
||||
Icon(
|
||||
isInstalled
|
||||
? FluentIcons.check_mark
|
||||
: isItemEnabled
|
||||
? FluentIcons.download
|
||||
: FluentIcons.disable_updates,
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
isInstalled
|
||||
? S.current.localization_info_installed
|
||||
: (isItemEnabled
|
||||
? S.current.localization_action_install
|
||||
: S.current.localization_info_unavailable),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
if ((!isInstalled) && isItemEnabled)
|
||||
Icon(
|
||||
FluentIcons.chevron_right,
|
||||
size: 14,
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
)
|
||||
]
|
||||
const Padding(padding: EdgeInsets.only(right: 12), child: ProgressRing())
|
||||
else ...[
|
||||
Icon(
|
||||
isInstalled
|
||||
? FluentIcons.check_mark
|
||||
: isItemEnabled
|
||||
? FluentIcons.download
|
||||
: FluentIcons.disable_updates,
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
isInstalled
|
||||
? S.current.localization_info_installed
|
||||
: (isItemEnabled
|
||||
? S.current.localization_action_install
|
||||
: S.current.localization_info_unavailable),
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .8)),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
if ((!isInstalled) && isItemEnabled)
|
||||
Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (item.value.note != null) ...[
|
||||
@@ -272,10 +256,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
"${item.value.note}",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .4),
|
||||
fontSize: 13,
|
||||
),
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .4), fontSize: 13),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -286,16 +267,20 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeListContainer(String title, List<Widget> children, BuildContext context,
|
||||
{List<Widget> actions = const [], bool gridViewMode = false, int gridViewCrossAxisCount = 2}) {
|
||||
Widget makeListContainer(
|
||||
String title,
|
||||
List<Widget> children,
|
||||
BuildContext context, {
|
||||
List<Widget> actions = const [],
|
||||
bool gridViewMode = false,
|
||||
int gridViewCrossAxisCount = 2,
|
||||
}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: AnimatedSize(
|
||||
duration: const Duration(milliseconds: 130),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: FluentTheme
|
||||
.of(context)
|
||||
.cardColor, borderRadius: BorderRadius.circular(7)),
|
||||
decoration: BoxDecoration(color: FluentTheme.of(context).cardColor, borderRadius: BorderRadius.circular(7)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 12, bottom: 12, left: 24, right: 24),
|
||||
child: Column(
|
||||
@@ -303,21 +288,13 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(fontSize: 22),
|
||||
),
|
||||
Text(title, style: const TextStyle(fontSize: 22)),
|
||||
const Spacer(),
|
||||
if (actions.isNotEmpty) ...actions,
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Container(
|
||||
color: Colors.white.withValues(alpha: .1),
|
||||
height: 1,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Container(color: Colors.white.withValues(alpha: .1), height: 1),
|
||||
const SizedBox(height: 12),
|
||||
if (gridViewMode)
|
||||
AlignedGridView.count(
|
||||
@@ -332,7 +309,7 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
itemCount: children.length,
|
||||
)
|
||||
else
|
||||
...children
|
||||
...children,
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -344,55 +321,46 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
Widget makeTitle(BuildContext context, LocalizationUIModel model, LocalizationUIState state) {
|
||||
return Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
FluentIcons.back,
|
||||
size: 22,
|
||||
),
|
||||
onPressed: model.onBack(context)),
|
||||
IconButton(icon: const Icon(FluentIcons.back, size: 22), onPressed: model.onBack(context)),
|
||||
const SizedBox(width: 12),
|
||||
Text(S.current.home_action_localization_management),
|
||||
const SizedBox(width: 24),
|
||||
Text(
|
||||
"${model.getScInstallPath()}",
|
||||
style: const TextStyle(fontSize: 13),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"${model.getScInstallPath()}",
|
||||
style: const TextStyle(fontSize: 13),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
SizedBox(width: 24),
|
||||
SizedBox(
|
||||
height: 36,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
S.current.localization_info_language,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
Text(S.current.localization_info_language, style: const TextStyle(fontSize: 16)),
|
||||
const SizedBox(width: 12),
|
||||
ComboBox<String>(
|
||||
value: state.selectedLanguage,
|
||||
items: [
|
||||
for (final lang in LocalizationUIModel.languageSupport.entries)
|
||||
ComboBoxItem(
|
||||
value: lang.key,
|
||||
child: Text(lang.value),
|
||||
)
|
||||
ComboBoxItem(value: lang.key, child: Text(lang.value)),
|
||||
],
|
||||
onChanged: state.workingVersion.isNotEmpty
|
||||
? null
|
||||
: (v) {
|
||||
if (v == null) return;
|
||||
model.selectLang(v);
|
||||
},
|
||||
)
|
||||
if (v == null) return;
|
||||
model.selectLang(v);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Button(
|
||||
onPressed: model.doRefresh(),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(6),
|
||||
child: Icon(FluentIcons.refresh),
|
||||
)),
|
||||
onPressed: model.doRefresh(),
|
||||
child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.refresh)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -400,85 +368,77 @@ class LocalizationDialogUI extends HookConsumerWidget {
|
||||
Widget makeToolsListContainer(BuildContext context, LocalizationUIModel model, LocalizationUIState state) {
|
||||
final toolsMenu = {
|
||||
"launcher_mod": (
|
||||
const Icon(FluentIcons.c_plus_plus, size: 24),
|
||||
(S.current.home_localization_action_rsi_launcher_localization),
|
||||
),
|
||||
"advanced": (
|
||||
const Icon(FluentIcons.queue_advanced, size: 24),
|
||||
(S.current.home_localization_action_advanced),
|
||||
const Icon(FluentIcons.c_plus_plus, size: 24),
|
||||
(S.current.home_localization_action_rsi_launcher_localization),
|
||||
),
|
||||
"advanced": (const Icon(FluentIcons.queue_advanced, size: 24), (S.current.home_localization_action_advanced)),
|
||||
"custom_files": (
|
||||
const Icon(FluentIcons.custom_activity, size: 24),
|
||||
(S.current.home_localization_action_install_customize),
|
||||
const Icon(FluentIcons.custom_activity, size: 24),
|
||||
(S.current.home_localization_action_install_customize),
|
||||
),
|
||||
};
|
||||
|
||||
final enableTap = state.workingVersion.isEmpty;
|
||||
|
||||
return makeListContainer(
|
||||
S.current.home_localization_title_localization_tools,
|
||||
[
|
||||
for (final item in toolsMenu.entries)
|
||||
Tilt(
|
||||
disable: !enableTap,
|
||||
shadowConfig: const ShadowConfig(maxIntensity: .3),
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
child: GestureDetector(
|
||||
onTap: enableTap
|
||||
? () async {
|
||||
switch (item.key) {
|
||||
case "launcher_mod":
|
||||
ToolsUIModel.rsiEnhance(context);
|
||||
break;
|
||||
case "advanced":
|
||||
context.push("/index/advanced_localization");
|
||||
break;
|
||||
case "custom_files":
|
||||
final sb = await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => const LocalizationFromFileDialogUI(),
|
||||
);
|
||||
if (sb is (StringBuffer, bool)) {
|
||||
if (!context.mounted) return;
|
||||
await model.installFormString(
|
||||
sb.$1,
|
||||
S.current.localization_info_custom_files,
|
||||
isEnableCommunityInputMethod: sb.$2,
|
||||
context: context,
|
||||
);
|
||||
S.current.home_localization_title_localization_tools,
|
||||
[
|
||||
for (final item in toolsMenu.entries)
|
||||
Tilt(
|
||||
disable: !enableTap,
|
||||
shadowConfig: const ShadowConfig(maxIntensity: .3),
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
child: GestureDetector(
|
||||
onTap: enableTap
|
||||
? () async {
|
||||
switch (item.key) {
|
||||
case "launcher_mod":
|
||||
ToolsUIModel.rsiEnhance(context);
|
||||
break;
|
||||
case "advanced":
|
||||
context.push("/index/advanced_localization");
|
||||
break;
|
||||
case "custom_files":
|
||||
final sb = await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => const LocalizationFromFileDialogUI(),
|
||||
);
|
||||
if (sb is (StringBuffer, bool)) {
|
||||
if (!context.mounted) return;
|
||||
await model.installFormString(
|
||||
sb.$1,
|
||||
S.current.localization_info_custom_files,
|
||||
isEnableCommunityInputMethod: sb.$2,
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme
|
||||
.of(context)
|
||||
.cardColor,
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
item.value.$1,
|
||||
const SizedBox(width: 12),
|
||||
Text(item.value.$2),
|
||||
const SizedBox(width: 12),
|
||||
const Spacer(),
|
||||
Icon(
|
||||
FluentIcons.chevron_right,
|
||||
size: 14,
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
)
|
||||
],
|
||||
),
|
||||
}
|
||||
: null,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
item.value.$1,
|
||||
const SizedBox(width: 12),
|
||||
Text(item.value.$2),
|
||||
const SizedBox(width: 12),
|
||||
const Spacer(),
|
||||
Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
context,
|
||||
gridViewMode: true,
|
||||
gridViewCrossAxisCount: 3);
|
||||
),
|
||||
],
|
||||
context,
|
||||
gridViewMode: true,
|
||||
gridViewCrossAxisCount: 3,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +48,12 @@ abstract class LocalizationUIState with _$LocalizationUIState {
|
||||
class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
static const languageSupport = {"chinese_(simplified)": NoL10n.langZHS, "chinese_(traditional)": NoL10n.langZHT};
|
||||
|
||||
Directory get _downloadDir => Directory("${appGlobalState.applicationSupportDir}\\Localizations");
|
||||
Directory get _downloadDir => Directory("${appGlobalState.applicationSupportDir}\\Localizations".platformPath);
|
||||
|
||||
Directory getDownloadDir() => _downloadDir;
|
||||
|
||||
Directory get _scDataDir => Directory("${ref.read(homeUIModelProvider).scInstalledPath}\\data");
|
||||
|
||||
File get _cfgFile => File("${_scDataDir.absolute.path}\\system.cfg");
|
||||
Directory get _scDataDir => Directory("${ref.read(homeUIModelProvider).scInstalledPath}\\data".platformPath);
|
||||
File get _cfgFile => File("${_scDataDir.absolute.path}\\system.cfg".platformPath);
|
||||
|
||||
StreamSubscription? _customizeDirListenSub;
|
||||
|
||||
@@ -155,7 +154,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}
|
||||
|
||||
void checkUserCfg(BuildContext context) async {
|
||||
final userCfgFile = File("$_scInstallPath\\USER.cfg");
|
||||
final userCfgFile = File("$_scInstallPath\\USER.cfg".platformPath);
|
||||
if (await userCfgFile.exists()) {
|
||||
final cfgString = await userCfgFile.readAsString();
|
||||
if (cfgString.contains("g_language") && !cfgString.contains("g_language=${state.selectedLanguage}")) {
|
||||
@@ -241,7 +240,9 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
|
||||
VoidCallback? doDelIniFile() {
|
||||
return () async {
|
||||
final iniFile = File("${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini");
|
||||
final iniFile = File(
|
||||
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath,
|
||||
);
|
||||
if (await iniFile.exists()) await iniFile.delete();
|
||||
await updateLangCfg(false);
|
||||
await _updateStatus();
|
||||
@@ -249,7 +250,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}
|
||||
|
||||
String getCustomizeFileName(String path) {
|
||||
return path.split("\\").last;
|
||||
return path.split("\\".platformPath).last;
|
||||
}
|
||||
|
||||
Future<void> installFormString(
|
||||
@@ -261,7 +262,9 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
BuildContext? context,
|
||||
}) async {
|
||||
dPrint("LocalizationUIModel -> installFormString $versionName");
|
||||
final iniFile = File("${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini");
|
||||
final iniFile = File(
|
||||
"${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath,
|
||||
);
|
||||
if (versionName.isNotEmpty) {
|
||||
if (!globalIni.toString().endsWith("\n")) {
|
||||
globalIni.write("\n");
|
||||
@@ -323,7 +326,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}
|
||||
|
||||
Future<Map<String, String>?> getCommunityInputMethodSupportData() async {
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini";
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath;
|
||||
final iniFile = File(iniPath);
|
||||
if (!await iniFile.exists()) {
|
||||
return {};
|
||||
@@ -351,7 +354,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}
|
||||
|
||||
Future<(String, String)> getIniContentWithoutCommunityInputMethodSupportData() async {
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini";
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath;
|
||||
final iniFile = File(iniPath);
|
||||
if (!await iniFile.exists()) {
|
||||
return ("", "");
|
||||
@@ -383,7 +386,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}) async {
|
||||
AnalyticsApi.touch("install_localization");
|
||||
|
||||
final savePath = File("${_downloadDir.absolute.path}\\${value.versionName}.sclang");
|
||||
final savePath = File("${_downloadDir.absolute.path}\\${value.versionName}.sclang".platformPath);
|
||||
try {
|
||||
state = state.copyWith(workingVersion: value.versionName!);
|
||||
if (!await savePath.exists()) {
|
||||
@@ -488,7 +491,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
}
|
||||
|
||||
Future<void> _updateStatus() async {
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini";
|
||||
final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath;
|
||||
final patchStatus = MapEntry(
|
||||
await _getLangCfgEnableLang(lang: state.selectedLanguage!),
|
||||
await _getInstalledIniVersion(iniPath),
|
||||
@@ -535,7 +538,7 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
if (gamePath.isEmpty) {
|
||||
gamePath = _scInstallPath;
|
||||
}
|
||||
final cfgFile = File("${_scDataDir.absolute.path}\\system.cfg");
|
||||
final cfgFile = File("${_scDataDir.absolute.path}\\system.cfg".platformPath);
|
||||
if (!await cfgFile.exists()) return false;
|
||||
final str = (await cfgFile.readAsString()).replaceAll(" ", "");
|
||||
return str.contains("sys_languages=$lang") &&
|
||||
@@ -573,13 +576,13 @@ class LocalizationUIModel extends _$LocalizationUIModel {
|
||||
|
||||
for (var scInstallPath in homeState.scInstallPaths) {
|
||||
// 读取游戏安装文件夹
|
||||
final scDataDir = Directory("$scInstallPath\\data\\Localization");
|
||||
final scDataDir = Directory("$scInstallPath\\data\\Localization".platformPath);
|
||||
// 扫描目录确认已安装的语言
|
||||
final dirList = await scDataDir.list().toList();
|
||||
for (var element in dirList) {
|
||||
for (var lang in languageSupport.keys) {
|
||||
if (element.path.contains(lang) && await _getLangCfgEnableLang(lang: lang, gamePath: scInstallPath)) {
|
||||
final installedVersion = await _getInstalledIniVersion("${element.path}\\global.ini");
|
||||
final installedVersion = await _getInstalledIniVersion("${element.path}\\global.ini".platformPath);
|
||||
if (installedVersion == S.current.home_action_info_game_built_in ||
|
||||
installedVersion == S.current.localization_info_custom_files) {
|
||||
continue;
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'localization_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(LocalizationUIModel)
|
||||
const localizationUIModelProvider = LocalizationUIModelProvider._();
|
||||
final localizationUIModelProvider = LocalizationUIModelProvider._();
|
||||
|
||||
final class LocalizationUIModelProvider
|
||||
extends $NotifierProvider<LocalizationUIModel, LocalizationUIState> {
|
||||
const LocalizationUIModelProvider._()
|
||||
LocalizationUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -42,14 +42,13 @@ final class LocalizationUIModelProvider
|
||||
}
|
||||
|
||||
String _$localizationUIModelHash() =>
|
||||
r'7b398d3b2ddd306ff8f328be39f28200fe8bf49e';
|
||||
r'34bfb83eb271b16d24a10219bbf86fc4b873f9aa';
|
||||
|
||||
abstract class _$LocalizationUIModel extends $Notifier<LocalizationUIState> {
|
||||
LocalizationUIState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<LocalizationUIState, LocalizationUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -59,6 +58,6 @@ abstract class _$LocalizationUIModel extends $Notifier<LocalizationUIState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'performance_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(HomePerformanceUIModel)
|
||||
const homePerformanceUIModelProvider = HomePerformanceUIModelProvider._();
|
||||
final homePerformanceUIModelProvider = HomePerformanceUIModelProvider._();
|
||||
|
||||
final class HomePerformanceUIModelProvider
|
||||
extends $NotifierProvider<HomePerformanceUIModel, HomePerformanceUIState> {
|
||||
const HomePerformanceUIModelProvider._()
|
||||
HomePerformanceUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -50,7 +50,6 @@ abstract class _$HomePerformanceUIModel
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref as $Ref<HomePerformanceUIState, HomePerformanceUIState>;
|
||||
final element =
|
||||
@@ -61,6 +60,6 @@ abstract class _$HomePerformanceUIModel
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import 'party_room/party_room_ui_model.dart';
|
||||
import 'settings/settings_ui.dart';
|
||||
import 'tools/tools_ui.dart';
|
||||
import 'index_ui_widgets/user_avatar_widget.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/url_scheme_handler.dart';
|
||||
|
||||
class IndexUI extends HookConsumerWidget {
|
||||
const IndexUI({super.key});
|
||||
@@ -32,6 +33,13 @@ class IndexUI extends HookConsumerWidget {
|
||||
ref.watch(partyRoomUIModelProvider.select((value) => null));
|
||||
|
||||
final curIndex = useState(0);
|
||||
|
||||
// Initialize URL scheme handler
|
||||
useEffect(() {
|
||||
UrlSchemeHandler().initialize(context);
|
||||
return () => UrlSchemeHandler().dispose();
|
||||
}, const []);
|
||||
|
||||
return NavigationView(
|
||||
appBar: NavigationAppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:starcitizen_doctor/provider/party_room.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui_model.dart';
|
||||
import 'package:starcitizen_doctor/ui/party_room/utils/party_room_utils.dart';
|
||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
|
||||
class UserAvatarWidget extends HookConsumerWidget {
|
||||
final VoidCallback onTapNavigateToPartyRoom;
|
||||
@@ -52,14 +53,14 @@ class UserAvatarWidget extends HookConsumerWidget {
|
||||
child: uiState.isLoggingIn
|
||||
? const Padding(padding: EdgeInsets.all(4), child: ProgressRing(strokeWidth: 2))
|
||||
: (fullAvatarUrl != null
|
||||
? CacheNetImage(url: fullAvatarUrl, fit: BoxFit.cover)
|
||||
: Center(
|
||||
child: Icon(
|
||||
isLoggedIn ? FluentIcons.contact : FluentIcons.unknown,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
)),
|
||||
? CacheNetImage(url: fullAvatarUrl, fit: BoxFit.cover)
|
||||
: Center(
|
||||
child: Icon(
|
||||
isLoggedIn ? FluentIcons.contact : FluentIcons.unknown,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -85,91 +86,154 @@ class UserAvatarWidget extends HookConsumerWidget {
|
||||
barrierDismissible: true,
|
||||
barrierColor: Colors.transparent,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return Stack(
|
||||
children: [
|
||||
// 透明遮罩,点击关闭
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(dialogContext).pop(),
|
||||
child: Container(color: Colors.transparent),
|
||||
),
|
||||
// 账户卡片
|
||||
Positioned(
|
||||
left: offset.dx - 100,
|
||||
top: offset.dy + (box?.size.height ?? 0) + 8,
|
||||
child: Container(
|
||||
width: 360,
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme
|
||||
.of(context)
|
||||
.micaBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.white.withValues(alpha: .1), width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.black.withValues(alpha: .3), blurRadius: 20, offset: const Offset(0, 8)),
|
||||
],
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final partyRoomState = ref.watch(partyRoomProvider);
|
||||
final uiState = ref.watch(partyRoomUIModelProvider);
|
||||
final userInfo = partyRoomState.auth.userInfo;
|
||||
final displayUserName = userInfo?.gameUserId ?? userName;
|
||||
final displayAvatarUrl = PartyRoomUtils.getAvatarUrl(userInfo?.avatarUrl);
|
||||
final displayEnlistedDate = userInfo?.enlistedDate ?? enlistedDate;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
// 透明遮罩,点击关闭
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(dialogContext).pop(),
|
||||
child: Container(color: Colors.transparent),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 用户信息
|
||||
Row(
|
||||
// 账户卡片
|
||||
Positioned(
|
||||
left: offset.dx - 100,
|
||||
top: offset.dy + (box?.size.height ?? 0) + 8,
|
||||
child: Container(
|
||||
width: 360,
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme.of(context).micaBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.white.withValues(alpha: .1), width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: .3),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(24)),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: avatarUrl != null
|
||||
? CacheNetImage(url: avatarUrl, fit: BoxFit.cover)
|
||||
: const Center(child: Icon(FluentIcons.contact, size: 24, color: Colors.white)),
|
||||
),
|
||||
// 用户信息
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(24)),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: displayAvatarUrl != null
|
||||
? CacheNetImage(url: displayAvatarUrl, fit: BoxFit.cover)
|
||||
: const Center(child: Icon(FluentIcons.contact, size: 24, color: Colors.white)),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
displayUserName,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'注册时间:${PartyRoomUtils.formatDateTime(displayEnlistedDate)}',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
userName,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 8),
|
||||
// 按钮组
|
||||
Row(
|
||||
children: [
|
||||
// 刷新按钮
|
||||
Expanded(
|
||||
child: Tooltip(
|
||||
message: '每小时仅可刷新一次',
|
||||
child: FilledButton(
|
||||
onPressed: uiState.isRefreshingProfile
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
await ref.read(partyRoomUIModelProvider.notifier).refreshUserProfile();
|
||||
if (context.mounted) {
|
||||
showToast(context, '刷新成功');
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
if (e is GrpcError && e.code == StatusCode.resourceExhausted) {
|
||||
showToast(context, '资料刷新过于频繁,请一小时后再试');
|
||||
} else {
|
||||
showToast(context, '刷新失败: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (uiState.isRefreshingProfile)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: SizedBox(width: 12, height: 12, child: ProgressRing(strokeWidth: 2)),
|
||||
),
|
||||
const Text('刷新资料'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'注册时间:${PartyRoomUtils.formatDateTime(enlistedDate)}',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// 注销按钮
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(dialogContext).pop();
|
||||
await _handleUnregister(context, ref);
|
||||
},
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.isHovered) return Colors.red.withValues(alpha: 0.8);
|
||||
return Colors.red;
|
||||
}),
|
||||
),
|
||||
child: Text(
|
||||
S.current.user_action_unregister,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 8),
|
||||
// 注销按钮
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: FilledButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(dialogContext).pop();
|
||||
await _handleUnregister(context, ref);
|
||||
},
|
||||
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.red)),
|
||||
child: Text(S.current.user_action_unregister, style: const TextStyle(color: Colors.white)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -10,10 +10,10 @@ part of 'nav_state.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(Nav)
|
||||
const navProvider = NavProvider._();
|
||||
final navProvider = NavProvider._();
|
||||
|
||||
final class NavProvider extends $NotifierProvider<Nav, NavState> {
|
||||
const NavProvider._()
|
||||
NavProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -47,7 +47,6 @@ abstract class _$Nav extends $Notifier<NavState> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<NavState, NavState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -57,6 +56,6 @@ abstract class _$Nav extends $Notifier<NavState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,9 @@ sealed class PartyRoomUIState with _$PartyRoomUIState {
|
||||
@Default(false) bool isReconnecting,
|
||||
@Default(0) int reconnectAttempts,
|
||||
@Default(false) bool isMinimized,
|
||||
@Default(true) bool isLoggingIn,
|
||||
@Default(false) bool isLoggingIn,
|
||||
@Default(true) bool isGuestMode,
|
||||
@Default(false) bool isRefreshingProfile,
|
||||
}) = _PartyRoomUIState;
|
||||
}
|
||||
|
||||
@@ -108,7 +109,9 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
|
||||
if (next.deathEvents?.isNotEmpty ?? false) {
|
||||
for (final event in next.deathEvents!) {
|
||||
ref.read(partyRoomProvider.notifier).sendSignal("special_death", params: {"location": event.$1, "area": event.$2});
|
||||
ref
|
||||
.read(partyRoomProvider.notifier)
|
||||
.sendSignal("special_death", params: {"location": event.$1, "area": event.$2});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,6 +217,17 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// 刷新用户资料
|
||||
Future<void> refreshUserProfile() async {
|
||||
if (state.isRefreshingProfile) return;
|
||||
state = state.copyWith(isRefreshingProfile: true);
|
||||
try {
|
||||
await ref.read(partyRoomProvider.notifier).refreshUserProfile();
|
||||
} finally {
|
||||
state = state.copyWith(isRefreshingProfile: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// 请求注册验证码
|
||||
Future<void> requestPreRegister(String gameUserId) async {
|
||||
state = state.copyWith(isLoading: true, errorMessage: null, registerGameUserId: gameUserId);
|
||||
@@ -338,4 +352,4 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
void setMinimized(bool minimized) {
|
||||
state = state.copyWith(isMinimized: minimized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$PartyRoomUIState {
|
||||
|
||||
bool get isConnecting; bool get showRoomList; List<RoomListItem> get roomListItems; int get currentPage; int get pageSize; int get totalRooms; String? get selectedMainTagId; String? get selectedSubTagId; String get searchOwnerName; bool get isLoading; String? get errorMessage; String get preRegisterCode; String get registerGameUserId; bool get isReconnecting; int get reconnectAttempts; bool get isMinimized; bool get isLoggingIn; bool get isGuestMode;
|
||||
bool get isConnecting; bool get showRoomList; List<RoomListItem> get roomListItems; int get currentPage; int get pageSize; int get totalRooms; String? get selectedMainTagId; String? get selectedSubTagId; String get searchOwnerName; bool get isLoading; String? get errorMessage; String get preRegisterCode; String get registerGameUserId; bool get isReconnecting; int get reconnectAttempts; bool get isMinimized; bool get isLoggingIn; bool get isGuestMode; bool get isRefreshingProfile;
|
||||
/// Create a copy of PartyRoomUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $PartyRoomUIStateCopyWith<PartyRoomUIState> get copyWith => _$PartyRoomUIStateCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PartyRoomUIState&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.showRoomList, showRoomList) || other.showRoomList == showRoomList)&&const DeepCollectionEquality().equals(other.roomListItems, roomListItems)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.pageSize, pageSize) || other.pageSize == pageSize)&&(identical(other.totalRooms, totalRooms) || other.totalRooms == totalRooms)&&(identical(other.selectedMainTagId, selectedMainTagId) || other.selectedMainTagId == selectedMainTagId)&&(identical(other.selectedSubTagId, selectedSubTagId) || other.selectedSubTagId == selectedSubTagId)&&(identical(other.searchOwnerName, searchOwnerName) || other.searchOwnerName == searchOwnerName)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.preRegisterCode, preRegisterCode) || other.preRegisterCode == preRegisterCode)&&(identical(other.registerGameUserId, registerGameUserId) || other.registerGameUserId == registerGameUserId)&&(identical(other.isReconnecting, isReconnecting) || other.isReconnecting == isReconnecting)&&(identical(other.reconnectAttempts, reconnectAttempts) || other.reconnectAttempts == reconnectAttempts)&&(identical(other.isMinimized, isMinimized) || other.isMinimized == isMinimized)&&(identical(other.isLoggingIn, isLoggingIn) || other.isLoggingIn == isLoggingIn)&&(identical(other.isGuestMode, isGuestMode) || other.isGuestMode == isGuestMode));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PartyRoomUIState&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.showRoomList, showRoomList) || other.showRoomList == showRoomList)&&const DeepCollectionEquality().equals(other.roomListItems, roomListItems)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.pageSize, pageSize) || other.pageSize == pageSize)&&(identical(other.totalRooms, totalRooms) || other.totalRooms == totalRooms)&&(identical(other.selectedMainTagId, selectedMainTagId) || other.selectedMainTagId == selectedMainTagId)&&(identical(other.selectedSubTagId, selectedSubTagId) || other.selectedSubTagId == selectedSubTagId)&&(identical(other.searchOwnerName, searchOwnerName) || other.searchOwnerName == searchOwnerName)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.preRegisterCode, preRegisterCode) || other.preRegisterCode == preRegisterCode)&&(identical(other.registerGameUserId, registerGameUserId) || other.registerGameUserId == registerGameUserId)&&(identical(other.isReconnecting, isReconnecting) || other.isReconnecting == isReconnecting)&&(identical(other.reconnectAttempts, reconnectAttempts) || other.reconnectAttempts == reconnectAttempts)&&(identical(other.isMinimized, isMinimized) || other.isMinimized == isMinimized)&&(identical(other.isLoggingIn, isLoggingIn) || other.isLoggingIn == isLoggingIn)&&(identical(other.isGuestMode, isGuestMode) || other.isGuestMode == isGuestMode)&&(identical(other.isRefreshingProfile, isRefreshingProfile) || other.isRefreshingProfile == isRefreshingProfile));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnecting,showRoomList,const DeepCollectionEquality().hash(roomListItems),currentPage,pageSize,totalRooms,selectedMainTagId,selectedSubTagId,searchOwnerName,isLoading,errorMessage,preRegisterCode,registerGameUserId,isReconnecting,reconnectAttempts,isMinimized,isLoggingIn,isGuestMode);
|
||||
int get hashCode => Object.hashAll([runtimeType,isConnecting,showRoomList,const DeepCollectionEquality().hash(roomListItems),currentPage,pageSize,totalRooms,selectedMainTagId,selectedSubTagId,searchOwnerName,isLoading,errorMessage,preRegisterCode,registerGameUserId,isReconnecting,reconnectAttempts,isMinimized,isLoggingIn,isGuestMode,isRefreshingProfile]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PartyRoomUIState(isConnecting: $isConnecting, showRoomList: $showRoomList, roomListItems: $roomListItems, currentPage: $currentPage, pageSize: $pageSize, totalRooms: $totalRooms, selectedMainTagId: $selectedMainTagId, selectedSubTagId: $selectedSubTagId, searchOwnerName: $searchOwnerName, isLoading: $isLoading, errorMessage: $errorMessage, preRegisterCode: $preRegisterCode, registerGameUserId: $registerGameUserId, isReconnecting: $isReconnecting, reconnectAttempts: $reconnectAttempts, isMinimized: $isMinimized, isLoggingIn: $isLoggingIn, isGuestMode: $isGuestMode)';
|
||||
return 'PartyRoomUIState(isConnecting: $isConnecting, showRoomList: $showRoomList, roomListItems: $roomListItems, currentPage: $currentPage, pageSize: $pageSize, totalRooms: $totalRooms, selectedMainTagId: $selectedMainTagId, selectedSubTagId: $selectedSubTagId, searchOwnerName: $searchOwnerName, isLoading: $isLoading, errorMessage: $errorMessage, preRegisterCode: $preRegisterCode, registerGameUserId: $registerGameUserId, isReconnecting: $isReconnecting, reconnectAttempts: $reconnectAttempts, isMinimized: $isMinimized, isLoggingIn: $isLoggingIn, isGuestMode: $isGuestMode, isRefreshingProfile: $isRefreshingProfile)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $PartyRoomUIStateCopyWith<$Res> {
|
||||
factory $PartyRoomUIStateCopyWith(PartyRoomUIState value, $Res Function(PartyRoomUIState) _then) = _$PartyRoomUIStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode
|
||||
bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode, bool isRefreshingProfile
|
||||
});
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class _$PartyRoomUIStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PartyRoomUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnecting = null,Object? showRoomList = null,Object? roomListItems = null,Object? currentPage = null,Object? pageSize = null,Object? totalRooms = null,Object? selectedMainTagId = freezed,Object? selectedSubTagId = freezed,Object? searchOwnerName = null,Object? isLoading = null,Object? errorMessage = freezed,Object? preRegisterCode = null,Object? registerGameUserId = null,Object? isReconnecting = null,Object? reconnectAttempts = null,Object? isMinimized = null,Object? isLoggingIn = null,Object? isGuestMode = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnecting = null,Object? showRoomList = null,Object? roomListItems = null,Object? currentPage = null,Object? pageSize = null,Object? totalRooms = null,Object? selectedMainTagId = freezed,Object? selectedSubTagId = freezed,Object? searchOwnerName = null,Object? isLoading = null,Object? errorMessage = freezed,Object? preRegisterCode = null,Object? registerGameUserId = null,Object? isReconnecting = null,Object? reconnectAttempts = null,Object? isMinimized = null,Object? isLoggingIn = null,Object? isGuestMode = null,Object? isRefreshingProfile = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
isConnecting: null == isConnecting ? _self.isConnecting : isConnecting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,showRoomList: null == showRoomList ? _self.showRoomList : showRoomList // ignore: cast_nullable_to_non_nullable
|
||||
@@ -82,6 +82,7 @@ as bool,reconnectAttempts: null == reconnectAttempts ? _self.reconnectAttempts :
|
||||
as int,isMinimized: null == isMinimized ? _self.isMinimized : isMinimized // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoggingIn: null == isLoggingIn ? _self.isLoggingIn : isLoggingIn // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isGuestMode: null == isGuestMode ? _self.isGuestMode : isGuestMode // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isRefreshingProfile: null == isRefreshingProfile ? _self.isRefreshingProfile : isRefreshingProfile // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
@@ -164,10 +165,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode, bool isRefreshingProfile)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomUIState() when $default != null:
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode);case _:
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode,_that.isRefreshingProfile);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -185,10 +186,10 @@ return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode, bool isRefreshingProfile) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomUIState():
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode);}
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode,_that.isRefreshingProfile);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -202,10 +203,10 @@ return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode, bool isRefreshingProfile)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomUIState() when $default != null:
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode);case _:
|
||||
return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.currentPage,_that.pageSize,_that.totalRooms,_that.selectedMainTagId,_that.selectedSubTagId,_that.searchOwnerName,_that.isLoading,_that.errorMessage,_that.preRegisterCode,_that.registerGameUserId,_that.isReconnecting,_that.reconnectAttempts,_that.isMinimized,_that.isLoggingIn,_that.isGuestMode,_that.isRefreshingProfile);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -217,7 +218,7 @@ return $default(_that.isConnecting,_that.showRoomList,_that.roomListItems,_that.
|
||||
|
||||
|
||||
class _PartyRoomUIState implements PartyRoomUIState {
|
||||
const _PartyRoomUIState({this.isConnecting = false, this.showRoomList = false, final List<RoomListItem> roomListItems = const [], this.currentPage = 1, this.pageSize = 20, this.totalRooms = 0, this.selectedMainTagId, this.selectedSubTagId, this.searchOwnerName = '', this.isLoading = false, this.errorMessage, this.preRegisterCode = '', this.registerGameUserId = '', this.isReconnecting = false, this.reconnectAttempts = 0, this.isMinimized = false, this.isLoggingIn = true, this.isGuestMode = true}): _roomListItems = roomListItems;
|
||||
const _PartyRoomUIState({this.isConnecting = false, this.showRoomList = false, final List<RoomListItem> roomListItems = const [], this.currentPage = 1, this.pageSize = 20, this.totalRooms = 0, this.selectedMainTagId, this.selectedSubTagId, this.searchOwnerName = '', this.isLoading = false, this.errorMessage, this.preRegisterCode = '', this.registerGameUserId = '', this.isReconnecting = false, this.reconnectAttempts = 0, this.isMinimized = false, this.isLoggingIn = false, this.isGuestMode = true, this.isRefreshingProfile = false}): _roomListItems = roomListItems;
|
||||
|
||||
|
||||
@override@JsonKey() final bool isConnecting;
|
||||
@@ -244,6 +245,7 @@ class _PartyRoomUIState implements PartyRoomUIState {
|
||||
@override@JsonKey() final bool isMinimized;
|
||||
@override@JsonKey() final bool isLoggingIn;
|
||||
@override@JsonKey() final bool isGuestMode;
|
||||
@override@JsonKey() final bool isRefreshingProfile;
|
||||
|
||||
/// Create a copy of PartyRoomUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -255,16 +257,16 @@ _$PartyRoomUIStateCopyWith<_PartyRoomUIState> get copyWith => __$PartyRoomUIStat
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PartyRoomUIState&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.showRoomList, showRoomList) || other.showRoomList == showRoomList)&&const DeepCollectionEquality().equals(other._roomListItems, _roomListItems)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.pageSize, pageSize) || other.pageSize == pageSize)&&(identical(other.totalRooms, totalRooms) || other.totalRooms == totalRooms)&&(identical(other.selectedMainTagId, selectedMainTagId) || other.selectedMainTagId == selectedMainTagId)&&(identical(other.selectedSubTagId, selectedSubTagId) || other.selectedSubTagId == selectedSubTagId)&&(identical(other.searchOwnerName, searchOwnerName) || other.searchOwnerName == searchOwnerName)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.preRegisterCode, preRegisterCode) || other.preRegisterCode == preRegisterCode)&&(identical(other.registerGameUserId, registerGameUserId) || other.registerGameUserId == registerGameUserId)&&(identical(other.isReconnecting, isReconnecting) || other.isReconnecting == isReconnecting)&&(identical(other.reconnectAttempts, reconnectAttempts) || other.reconnectAttempts == reconnectAttempts)&&(identical(other.isMinimized, isMinimized) || other.isMinimized == isMinimized)&&(identical(other.isLoggingIn, isLoggingIn) || other.isLoggingIn == isLoggingIn)&&(identical(other.isGuestMode, isGuestMode) || other.isGuestMode == isGuestMode));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PartyRoomUIState&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.showRoomList, showRoomList) || other.showRoomList == showRoomList)&&const DeepCollectionEquality().equals(other._roomListItems, _roomListItems)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.pageSize, pageSize) || other.pageSize == pageSize)&&(identical(other.totalRooms, totalRooms) || other.totalRooms == totalRooms)&&(identical(other.selectedMainTagId, selectedMainTagId) || other.selectedMainTagId == selectedMainTagId)&&(identical(other.selectedSubTagId, selectedSubTagId) || other.selectedSubTagId == selectedSubTagId)&&(identical(other.searchOwnerName, searchOwnerName) || other.searchOwnerName == searchOwnerName)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.preRegisterCode, preRegisterCode) || other.preRegisterCode == preRegisterCode)&&(identical(other.registerGameUserId, registerGameUserId) || other.registerGameUserId == registerGameUserId)&&(identical(other.isReconnecting, isReconnecting) || other.isReconnecting == isReconnecting)&&(identical(other.reconnectAttempts, reconnectAttempts) || other.reconnectAttempts == reconnectAttempts)&&(identical(other.isMinimized, isMinimized) || other.isMinimized == isMinimized)&&(identical(other.isLoggingIn, isLoggingIn) || other.isLoggingIn == isLoggingIn)&&(identical(other.isGuestMode, isGuestMode) || other.isGuestMode == isGuestMode)&&(identical(other.isRefreshingProfile, isRefreshingProfile) || other.isRefreshingProfile == isRefreshingProfile));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnecting,showRoomList,const DeepCollectionEquality().hash(_roomListItems),currentPage,pageSize,totalRooms,selectedMainTagId,selectedSubTagId,searchOwnerName,isLoading,errorMessage,preRegisterCode,registerGameUserId,isReconnecting,reconnectAttempts,isMinimized,isLoggingIn,isGuestMode);
|
||||
int get hashCode => Object.hashAll([runtimeType,isConnecting,showRoomList,const DeepCollectionEquality().hash(_roomListItems),currentPage,pageSize,totalRooms,selectedMainTagId,selectedSubTagId,searchOwnerName,isLoading,errorMessage,preRegisterCode,registerGameUserId,isReconnecting,reconnectAttempts,isMinimized,isLoggingIn,isGuestMode,isRefreshingProfile]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PartyRoomUIState(isConnecting: $isConnecting, showRoomList: $showRoomList, roomListItems: $roomListItems, currentPage: $currentPage, pageSize: $pageSize, totalRooms: $totalRooms, selectedMainTagId: $selectedMainTagId, selectedSubTagId: $selectedSubTagId, searchOwnerName: $searchOwnerName, isLoading: $isLoading, errorMessage: $errorMessage, preRegisterCode: $preRegisterCode, registerGameUserId: $registerGameUserId, isReconnecting: $isReconnecting, reconnectAttempts: $reconnectAttempts, isMinimized: $isMinimized, isLoggingIn: $isLoggingIn, isGuestMode: $isGuestMode)';
|
||||
return 'PartyRoomUIState(isConnecting: $isConnecting, showRoomList: $showRoomList, roomListItems: $roomListItems, currentPage: $currentPage, pageSize: $pageSize, totalRooms: $totalRooms, selectedMainTagId: $selectedMainTagId, selectedSubTagId: $selectedSubTagId, searchOwnerName: $searchOwnerName, isLoading: $isLoading, errorMessage: $errorMessage, preRegisterCode: $preRegisterCode, registerGameUserId: $registerGameUserId, isReconnecting: $isReconnecting, reconnectAttempts: $reconnectAttempts, isMinimized: $isMinimized, isLoggingIn: $isLoggingIn, isGuestMode: $isGuestMode, isRefreshingProfile: $isRefreshingProfile)';
|
||||
}
|
||||
|
||||
|
||||
@@ -275,7 +277,7 @@ abstract mixin class _$PartyRoomUIStateCopyWith<$Res> implements $PartyRoomUISta
|
||||
factory _$PartyRoomUIStateCopyWith(_PartyRoomUIState value, $Res Function(_PartyRoomUIState) _then) = __$PartyRoomUIStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode
|
||||
bool isConnecting, bool showRoomList, List<RoomListItem> roomListItems, int currentPage, int pageSize, int totalRooms, String? selectedMainTagId, String? selectedSubTagId, String searchOwnerName, bool isLoading, String? errorMessage, String preRegisterCode, String registerGameUserId, bool isReconnecting, int reconnectAttempts, bool isMinimized, bool isLoggingIn, bool isGuestMode, bool isRefreshingProfile
|
||||
});
|
||||
|
||||
|
||||
@@ -292,7 +294,7 @@ class __$PartyRoomUIStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PartyRoomUIState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnecting = null,Object? showRoomList = null,Object? roomListItems = null,Object? currentPage = null,Object? pageSize = null,Object? totalRooms = null,Object? selectedMainTagId = freezed,Object? selectedSubTagId = freezed,Object? searchOwnerName = null,Object? isLoading = null,Object? errorMessage = freezed,Object? preRegisterCode = null,Object? registerGameUserId = null,Object? isReconnecting = null,Object? reconnectAttempts = null,Object? isMinimized = null,Object? isLoggingIn = null,Object? isGuestMode = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnecting = null,Object? showRoomList = null,Object? roomListItems = null,Object? currentPage = null,Object? pageSize = null,Object? totalRooms = null,Object? selectedMainTagId = freezed,Object? selectedSubTagId = freezed,Object? searchOwnerName = null,Object? isLoading = null,Object? errorMessage = freezed,Object? preRegisterCode = null,Object? registerGameUserId = null,Object? isReconnecting = null,Object? reconnectAttempts = null,Object? isMinimized = null,Object? isLoggingIn = null,Object? isGuestMode = null,Object? isRefreshingProfile = null,}) {
|
||||
return _then(_PartyRoomUIState(
|
||||
isConnecting: null == isConnecting ? _self.isConnecting : isConnecting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,showRoomList: null == showRoomList ? _self.showRoomList : showRoomList // ignore: cast_nullable_to_non_nullable
|
||||
@@ -312,6 +314,7 @@ as bool,reconnectAttempts: null == reconnectAttempts ? _self.reconnectAttempts :
|
||||
as int,isMinimized: null == isMinimized ? _self.isMinimized : isMinimized // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoggingIn: null == isLoggingIn ? _self.isLoggingIn : isLoggingIn // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isGuestMode: null == isGuestMode ? _self.isGuestMode : isGuestMode // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isRefreshingProfile: null == isRefreshingProfile ? _self.isRefreshingProfile : isRefreshingProfile // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'party_room_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(PartyRoomUIModel)
|
||||
const partyRoomUIModelProvider = PartyRoomUIModelProvider._();
|
||||
final partyRoomUIModelProvider = PartyRoomUIModelProvider._();
|
||||
|
||||
final class PartyRoomUIModelProvider
|
||||
extends $NotifierProvider<PartyRoomUIModel, PartyRoomUIState> {
|
||||
const PartyRoomUIModelProvider._()
|
||||
PartyRoomUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -41,14 +41,13 @@ final class PartyRoomUIModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$partyRoomUIModelHash() => r'b22ad79b6d4a877876b2534f35fb0448b34d4ad5';
|
||||
String _$partyRoomUIModelHash() => r'cb37e8a29d22b122a5e0e552cca1af537dddc703';
|
||||
|
||||
abstract class _$PartyRoomUIModel extends $Notifier<PartyRoomUIState> {
|
||||
PartyRoomUIState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<PartyRoomUIState, PartyRoomUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$PartyRoomUIModel extends $Notifier<PartyRoomUIState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'game_log_tracker_provider.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(PartyRoomGameLogTrackerProvider)
|
||||
const partyRoomGameLogTrackerProviderProvider =
|
||||
final partyRoomGameLogTrackerProviderProvider =
|
||||
PartyRoomGameLogTrackerProviderFamily._();
|
||||
|
||||
final class PartyRoomGameLogTrackerProviderProvider
|
||||
@@ -19,7 +19,7 @@ final class PartyRoomGameLogTrackerProviderProvider
|
||||
PartyRoomGameLogTrackerProvider,
|
||||
PartyRoomGameLogTrackerProviderState
|
||||
> {
|
||||
const PartyRoomGameLogTrackerProviderProvider._({
|
||||
PartyRoomGameLogTrackerProviderProvider._({
|
||||
required PartyRoomGameLogTrackerProviderFamily super.from,
|
||||
required DateTime super.argument,
|
||||
}) : super(
|
||||
@@ -77,7 +77,7 @@ final class PartyRoomGameLogTrackerProviderFamily extends $Family
|
||||
PartyRoomGameLogTrackerProviderState,
|
||||
DateTime
|
||||
> {
|
||||
const PartyRoomGameLogTrackerProviderFamily._()
|
||||
PartyRoomGameLogTrackerProviderFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'partyRoomGameLogTrackerProviderProvider',
|
||||
@@ -105,7 +105,6 @@ abstract class _$PartyRoomGameLogTrackerProvider
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(startTime: _$args);
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<
|
||||
@@ -123,6 +122,6 @@ abstract class _$PartyRoomGameLogTrackerProvider
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(startTime: _$args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ class SettingsUIModel extends _$SettingsUIModel {
|
||||
lockParentWindow: true,
|
||||
);
|
||||
if (r == null || r.files.firstOrNull?.path == null) return;
|
||||
final fileName = r.files.first.path!;
|
||||
if (fileName.endsWith("\\RSI Launcher.exe")) {
|
||||
final fileName = r.files.first.path!.platformPath;
|
||||
if (fileName.toLowerCase().endsWith('\\rsi launcher.exe'.platformPath)) {
|
||||
await _saveCustomPath("custom_launcher_path", fileName);
|
||||
if (!context.mounted) return;
|
||||
showToast(context, S.current.setting_action_info_setting_success);
|
||||
@@ -101,11 +101,14 @@ class SettingsUIModel extends _$SettingsUIModel {
|
||||
lockParentWindow: true,
|
||||
);
|
||||
if (r == null || r.files.firstOrNull?.path == null) return;
|
||||
final fileName = r.files.first.path!;
|
||||
final fileName = r.files.first.path!.platformPath;
|
||||
dPrint(fileName);
|
||||
final fileNameRegExp = RegExp(r"^(.*\\StarCitizen\\.*\\)Bin64\\StarCitizen\.exe$", caseSensitive: false);
|
||||
final fileNameRegExp = RegExp(
|
||||
r'^(.*[/\\]starcitizen[/\\].*[/\\])bin64[/\\]starcitizen\.exe$',
|
||||
caseSensitive: false,
|
||||
);
|
||||
if (fileNameRegExp.hasMatch(fileName)) {
|
||||
RegExp pathRegex = RegExp(r"\\[^\\]+\\Bin64\\StarCitizen\.exe$");
|
||||
RegExp pathRegex = RegExp(r'[/\\][^/\\]+[/\\]bin64[/\\]starcitizen\.exe$', caseSensitive: false);
|
||||
String extractedPath = fileName.replaceFirst(pathRegex, '');
|
||||
await _saveCustomPath("custom_game_path", extractedPath);
|
||||
if (!context.mounted) return;
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'settings_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(SettingsUIModel)
|
||||
const settingsUIModelProvider = SettingsUIModelProvider._();
|
||||
final settingsUIModelProvider = SettingsUIModelProvider._();
|
||||
|
||||
final class SettingsUIModelProvider
|
||||
extends $NotifierProvider<SettingsUIModel, SettingsUIState> {
|
||||
const SettingsUIModelProvider._()
|
||||
SettingsUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -41,14 +41,13 @@ final class SettingsUIModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$settingsUIModelHash() => r'd34b1a2fac69d10f560d9a2e1a7431dd5a7954ca';
|
||||
String _$settingsUIModelHash() => r'302b8ce09601218c28c0cf2bd133f1749ec471dc';
|
||||
|
||||
abstract class _$SettingsUIModel extends $Notifier<SettingsUIState> {
|
||||
SettingsUIState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<SettingsUIState, SettingsUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$SettingsUIModel extends $Notifier<SettingsUIState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,11 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
workingText.value = S.current.tools_rsi_launcher_enhance_working_msg1;
|
||||
if ((await SystemHelper.getPID("RSI Launcher")).isNotEmpty) {
|
||||
if (!context.mounted) return;
|
||||
showToast(context, S.current.tools_action_info_rsi_launcher_running_warning,
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .35));
|
||||
showToast(
|
||||
context,
|
||||
S.current.tools_action_info_rsi_launcher_running_warning,
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .35),
|
||||
);
|
||||
workingText.value = "";
|
||||
return;
|
||||
}
|
||||
@@ -92,16 +95,16 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
|
||||
return ContentDialog(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .48),
|
||||
title: Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
FluentIcons.back,
|
||||
size: 22,
|
||||
),
|
||||
onPressed: workingText.value.isEmpty ? Navigator.of(context).pop : null),
|
||||
const SizedBox(width: 12),
|
||||
Text(S.current.tools_rsi_launcher_enhance_title),
|
||||
]),
|
||||
title: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(FluentIcons.back, size: 22),
|
||||
onPressed: workingText.value.isEmpty ? Navigator.of(context).pop : null,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(S.current.tools_rsi_launcher_enhance_title),
|
||||
],
|
||||
),
|
||||
content: AnimatedSize(
|
||||
duration: const Duration(milliseconds: 130),
|
||||
child: Column(
|
||||
@@ -112,17 +115,16 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
InfoBar(
|
||||
title: const SizedBox(),
|
||||
content: Text(S.current.home_localization_action_rsi_launcher_no_game_path_msg),
|
||||
style: InfoBarThemeData(decoration: (severity) {
|
||||
return BoxDecoration(
|
||||
color: Colors.orange,
|
||||
);
|
||||
}, iconColor: (severity) {
|
||||
return Colors.white;
|
||||
}),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
style: InfoBarThemeData(
|
||||
decoration: (severity) {
|
||||
return BoxDecoration(color: Colors.orange);
|
||||
},
|
||||
iconColor: (severity) {
|
||||
return Colors.white;
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
if (workingText.value.isNotEmpty) ...[
|
||||
Center(
|
||||
@@ -144,19 +146,17 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
S.current.tools_rsi_launcher_enhance_msg_version(assarState.value?.version ?? ""),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
),
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
S.current.tools_rsi_launcher_enhance_msg_patch_status((assarState.value?.isPatchInstalled ?? false)
|
||||
? S.current.localization_info_installed
|
||||
: S.current.tools_action_info_not_installed),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
S.current.tools_rsi_launcher_enhance_msg_patch_status(
|
||||
(assarState.value?.isPatchInstalled ?? false)
|
||||
? S.current.localization_info_installed
|
||||
: S.current.tools_action_info_not_installed,
|
||||
),
|
||||
)
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (assarState.value?.serverData.isEmpty ?? true) ...[
|
||||
@@ -165,6 +165,84 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
const SizedBox(height: 24),
|
||||
if (assarState.value?.enabledLocalization != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(S.current.tools_rsi_launcher_enhance_title_localization),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
S.current.tools_rsi_launcher_enhance_subtitle_localization,
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ComboBox(
|
||||
items: [
|
||||
for (final key in supportLocalizationMap.keys)
|
||||
ComboBoxItem(value: key, child: Text(supportLocalizationMap[key]!)),
|
||||
],
|
||||
value: assarState.value?.enabledLocalization,
|
||||
onChanged: (v) {
|
||||
assarState.value = assarState.value!.copyWith(enabledLocalization: v);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
if (assarState.value?.enableDownloaderBoost != null) ...[
|
||||
IconButton(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.only(top: 3, bottom: 3),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(expandEnhance.value ? FluentIcons.chevron_up : FluentIcons.chevron_down),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
expandEnhance.value
|
||||
? S.current.tools_rsi_launcher_enhance_action_fold
|
||||
: S.current.tools_rsi_launcher_enhance_action_expand,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (!expandEnhance.value) {
|
||||
final userOK = await showConfirmDialogs(
|
||||
context,
|
||||
S.current.tools_rsi_launcher_enhance_note_title,
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [Text(S.current.tools_rsi_launcher_enhance_note_msg)],
|
||||
),
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55),
|
||||
);
|
||||
if (!userOK) return;
|
||||
}
|
||||
expandEnhance.value = !expandEnhance.value;
|
||||
},
|
||||
),
|
||||
if (expandEnhance.value)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
@@ -174,111 +252,38 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(S.current.tools_rsi_launcher_enhance_title_localization),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
S.current.tools_rsi_launcher_enhance_subtitle_localization,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
ComboBox(
|
||||
items: [
|
||||
for (final key in supportLocalizationMap.keys)
|
||||
ComboBoxItem(value: key, child: Text(supportLocalizationMap[key]!))
|
||||
],
|
||||
value: assarState.value?.enabledLocalization,
|
||||
onChanged: (v) {
|
||||
assarState.value = assarState.value!.copyWith(enabledLocalization: v);
|
||||
},
|
||||
),
|
||||
],
|
||||
)),
|
||||
const SizedBox(height: 3),
|
||||
if (assarState.value?.enableDownloaderBoost != null) ...[
|
||||
IconButton(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.only(top: 3, bottom: 3),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(expandEnhance.value ? FluentIcons.chevron_up : FluentIcons.chevron_down),
|
||||
const SizedBox(width: 12),
|
||||
Text(expandEnhance.value
|
||||
? S.current.tools_rsi_launcher_enhance_action_fold
|
||||
: S.current.tools_rsi_launcher_enhance_action_expand),
|
||||
],
|
||||
))),
|
||||
],
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (!expandEnhance.value) {
|
||||
final userOK = await showConfirmDialogs(
|
||||
context,
|
||||
S.current.tools_rsi_launcher_enhance_note_title,
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(S.current.tools_rsi_launcher_enhance_note_msg),
|
||||
Text(S.current.tools_rsi_launcher_enhance_title_download_booster),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
S.current.tools_rsi_launcher_enhance_subtitle_download_booster,
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .6)),
|
||||
),
|
||||
],
|
||||
),
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55));
|
||||
if (!userOK) return;
|
||||
}
|
||||
expandEnhance.value = !expandEnhance.value;
|
||||
},
|
||||
),
|
||||
if (expandEnhance.value)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: FluentTheme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(S.current.tools_rsi_launcher_enhance_title_download_booster),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
S.current.tools_rsi_launcher_enhance_subtitle_download_booster,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
ToggleSwitch(
|
||||
onChanged: (value) {
|
||||
assarState.value = assarState.value?.copyWith(enableDownloaderBoost: value);
|
||||
},
|
||||
checked: assarState.value?.enableDownloaderBoost ?? false,
|
||||
)
|
||||
])),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Center(
|
||||
child: FilledButton(
|
||||
onPressed: doInstall,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
child: Text(S.current.tools_rsi_launcher_enhance_action_install),
|
||||
))),
|
||||
child: FilledButton(
|
||||
onPressed: doInstall,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
child: Text(S.current.tools_rsi_launcher_enhance_action_install),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
@@ -300,7 +305,7 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
return null;
|
||||
}
|
||||
dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherPath ==== $lPath");
|
||||
final dataPath = "${lPath}resources\\app.asar";
|
||||
final dataPath = "${lPath}resources\\app.asar".platformPath;
|
||||
dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherDataPath ==== $dataPath");
|
||||
try {
|
||||
final data = await asar_api.getRsiLauncherAsarData(asarPath: dataPath);
|
||||
@@ -333,7 +338,10 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
Future<String> _loadEnhanceData(
|
||||
BuildContext context, WidgetRef ref, ValueNotifier<RSILauncherStateData?> assarState) async {
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
ValueNotifier<RSILauncherStateData?> assarState,
|
||||
) async {
|
||||
final globalModel = ref.read(appGlobalModelProvider);
|
||||
final enhancePath = "${globalModel.applicationSupportDir}/launcher_enhance_data";
|
||||
|
||||
@@ -418,11 +426,13 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
|
||||
for (final line in serverScriptLines) {
|
||||
final lineTrim = line.trim();
|
||||
if (lineTrim.startsWith(SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START)) {
|
||||
scriptBuffer
|
||||
.writeln("$SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START\"${assarState.value!.enabledLocalization}\";");
|
||||
scriptBuffer.writeln(
|
||||
"$SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START\"${assarState.value!.enabledLocalization}\";",
|
||||
);
|
||||
} else if (lineTrim.startsWith(SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START)) {
|
||||
scriptBuffer
|
||||
.writeln("$SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START${assarState.value!.enableDownloaderBoost};");
|
||||
scriptBuffer.writeln(
|
||||
"$SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START${assarState.value!.enableDownloaderBoost};",
|
||||
);
|
||||
} else {
|
||||
scriptBuffer.writeln(line);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'log_analyze_provider.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ToolsLogAnalyze)
|
||||
const toolsLogAnalyzeProvider = ToolsLogAnalyzeFamily._();
|
||||
final toolsLogAnalyzeProvider = ToolsLogAnalyzeFamily._();
|
||||
|
||||
final class ToolsLogAnalyzeProvider
|
||||
extends $AsyncNotifierProvider<ToolsLogAnalyze, List<LogAnalyzeLineData>> {
|
||||
const ToolsLogAnalyzeProvider._({
|
||||
ToolsLogAnalyzeProvider._({
|
||||
required ToolsLogAnalyzeFamily super.from,
|
||||
required (String, bool, {String? selectedLogFile}) super.argument,
|
||||
}) : super(
|
||||
@@ -61,7 +61,7 @@ final class ToolsLogAnalyzeFamily extends $Family
|
||||
FutureOr<List<LogAnalyzeLineData>>,
|
||||
(String, bool, {String? selectedLogFile})
|
||||
> {
|
||||
const ToolsLogAnalyzeFamily._()
|
||||
ToolsLogAnalyzeFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'toolsLogAnalyzeProvider',
|
||||
@@ -102,11 +102,6 @@ abstract class _$ToolsLogAnalyze
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(
|
||||
_$args.$1,
|
||||
_$args.$2,
|
||||
selectedLogFile: _$args.selectedLogFile,
|
||||
);
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<
|
||||
@@ -124,6 +119,10 @@ abstract class _$ToolsLogAnalyze
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(
|
||||
ref,
|
||||
() =>
|
||||
build(_$args.$1, _$args.$2, selectedLogFile: _$args.selectedLogFile),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +72,14 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
}
|
||||
try {
|
||||
items = [
|
||||
ToolsItemData(
|
||||
"systemnfo",
|
||||
S.current.tools_action_view_system_info,
|
||||
S.current.tools_action_info_view_critical_system_info,
|
||||
const Icon(FluentIcons.system, size: 24),
|
||||
onTap: () => _showSystemInfo(context),
|
||||
),
|
||||
if (Platform.isWindows)
|
||||
ToolsItemData(
|
||||
"systemnfo",
|
||||
S.current.tools_action_view_system_info,
|
||||
S.current.tools_action_info_view_critical_system_info,
|
||||
const Icon(FluentIcons.system, size: 24),
|
||||
onTap: () => _showSystemInfo(context),
|
||||
),
|
||||
];
|
||||
|
||||
// 年度报告入口 logic
|
||||
@@ -108,13 +109,14 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
if (!context.mounted) return;
|
||||
items.add(await _addP4kCard(context));
|
||||
items.addAll([
|
||||
ToolsItemData(
|
||||
"hosts_booster",
|
||||
S.current.tools_action_hosts_acceleration_experimental,
|
||||
S.current.tools_action_info_hosts_acceleration_experimental_tip,
|
||||
const Icon(FluentIcons.virtual_network, size: 24),
|
||||
onTap: () => _doHostsBooster(context),
|
||||
),
|
||||
if (Platform.isWindows)
|
||||
ToolsItemData(
|
||||
"hosts_booster",
|
||||
S.current.tools_action_hosts_acceleration_experimental,
|
||||
S.current.tools_action_info_hosts_acceleration_experimental_tip,
|
||||
const Icon(FluentIcons.virtual_network, size: 24),
|
||||
onTap: () => _doHostsBooster(context),
|
||||
),
|
||||
ToolsItemData(
|
||||
"log_analyze",
|
||||
S.current.log_analyzer_title,
|
||||
@@ -129,20 +131,22 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
const Icon(FluentIcons.c_plus_plus, size: 24),
|
||||
onTap: () => rsiEnhance(context),
|
||||
),
|
||||
ToolsItemData(
|
||||
"reinstall_eac",
|
||||
S.current.tools_action_reinstall_easyanticheat,
|
||||
S.current.tools_action_info_reinstall_eac,
|
||||
const Icon(FluentIcons.game, size: 24),
|
||||
onTap: () => _reinstallEAC(context),
|
||||
),
|
||||
ToolsItemData(
|
||||
"rsilauncher_admin_mode",
|
||||
S.current.tools_action_rsi_launcher_admin_mode,
|
||||
S.current.tools_action_info_run_rsi_as_admin,
|
||||
const Icon(FluentIcons.admin, size: 24),
|
||||
onTap: () => _adminRSILauncher(context),
|
||||
),
|
||||
if (Platform.isWindows)
|
||||
ToolsItemData(
|
||||
"reinstall_eac",
|
||||
S.current.tools_action_reinstall_easyanticheat,
|
||||
S.current.tools_action_info_reinstall_eac,
|
||||
const Icon(FluentIcons.game, size: 24),
|
||||
onTap: () => _reinstallEAC(context),
|
||||
),
|
||||
if (Platform.isWindows)
|
||||
ToolsItemData(
|
||||
"rsilauncher_admin_mode",
|
||||
S.current.tools_action_rsi_launcher_admin_mode,
|
||||
S.current.tools_action_info_run_rsi_as_admin,
|
||||
const Icon(FluentIcons.admin, size: 24),
|
||||
onTap: () => _adminRSILauncher(context),
|
||||
),
|
||||
ToolsItemData(
|
||||
"unp4kc",
|
||||
S.current.tools_action_unp4k,
|
||||
@@ -169,8 +173,10 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
if (!context.mounted) return;
|
||||
items.add(await _addPhotographyCard(context));
|
||||
state = state.copyWith(items: items);
|
||||
if (!context.mounted) return;
|
||||
items.addAll(await _addNvmePatchCard(context));
|
||||
if (Platform.isWindows) {
|
||||
if (!context.mounted) return;
|
||||
items.addAll(await _addNvmePatchCard(context));
|
||||
}
|
||||
state = state.copyWith(items: items, isItemLoading: false);
|
||||
} catch (e) {
|
||||
if (!context.mounted) return;
|
||||
@@ -250,7 +256,10 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
Future<ToolsItemData> _addShaderCard(BuildContext context) async {
|
||||
final gameShaderCachePath = await SCLoggerHelper.getShaderCachePath();
|
||||
final shaderSize =
|
||||
((await SystemHelper.getDirLen(gameShaderCachePath ?? "", skipPath: ["$gameShaderCachePath\\Crashes"])) /
|
||||
((await SystemHelper.getDirLen(
|
||||
gameShaderCachePath ?? "",
|
||||
skipPath: ["$gameShaderCachePath\\Crashes".platformPath],
|
||||
)) /
|
||||
1024 /
|
||||
1024)
|
||||
.toStringAsFixed(4);
|
||||
@@ -300,7 +309,8 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
|
||||
// 使用最新版本
|
||||
final latestVersion = versions.first;
|
||||
final settingsPath = "$gameShaderCachePath\\starcitizen_$latestVersion\\GraphicsSettings\\GraphicsSettings.json";
|
||||
final settingsPath =
|
||||
"$gameShaderCachePath\\starcitizen_$latestVersion\\GraphicsSettings\\GraphicsSettings.json".platformPath;
|
||||
|
||||
final file = File(settingsPath);
|
||||
if (!await file.exists()) return (-1, latestVersion);
|
||||
@@ -544,27 +554,132 @@ class ToolsUIModel extends _$ToolsUIModel {
|
||||
state = state.copyWith(working: false);
|
||||
}
|
||||
|
||||
/// 清理着色器缓存(全部清理模式),保留最新两个文件夹的 GraphicsSettings
|
||||
static Future<void> cleanShaderCache() async {
|
||||
await _cleanShaderCacheWithMode(keepLatest: false);
|
||||
}
|
||||
|
||||
/// 清理着色器缓存(保留最新模式)
|
||||
/// 保留最新文件夹的所有内容,保留第二新文件夹的 GraphicsSettings,清理其他
|
||||
static Future<void> cleanShaderCacheKeepLatest() async {
|
||||
await _cleanShaderCacheWithMode(keepLatest: true);
|
||||
}
|
||||
|
||||
/// 内部清理方法
|
||||
/// [keepLatest] true: 保留最新模式,false: 全部清理模式
|
||||
static Future<void> _cleanShaderCacheWithMode({required bool keepLatest}) async {
|
||||
final gameShaderCachePath = await SCLoggerHelper.getShaderCachePath();
|
||||
final l = await Directory(gameShaderCachePath!).list(recursive: false).toList();
|
||||
for (var value in l) {
|
||||
if (value is Directory) {
|
||||
final dirName = value.path.split(Platform.pathSeparator).last;
|
||||
if (gameShaderCachePath == null) return;
|
||||
|
||||
final dir = Directory(gameShaderCachePath);
|
||||
if (!await dir.exists()) return;
|
||||
|
||||
// 获取所有 starcitizen_* 目录并按创建时间排序
|
||||
final scDirs = <Directory>[];
|
||||
final otherDirs = <Directory>[];
|
||||
|
||||
await for (var entity in dir.list(recursive: false)) {
|
||||
if (entity is Directory) {
|
||||
final dirName = entity.path.split(Platform.pathSeparator).last;
|
||||
if (dirName == "Crashes") continue;
|
||||
|
||||
// 对于 starcitizen_* 目录,手动遍历删除,保留 GraphicsSettings 文件夹
|
||||
if (dirName.startsWith("starcitizen_")) {
|
||||
await _cleanShaderCacheDirectory(value);
|
||||
scDirs.add(entity);
|
||||
} else {
|
||||
await value.delete(recursive: true);
|
||||
otherDirs.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按目录名(版本号)降序排序,最新的在前面
|
||||
scDirs.sort((a, b) {
|
||||
final aName = a.path.split(Platform.pathSeparator).last;
|
||||
final bName = b.path.split(Platform.pathSeparator).last;
|
||||
return bName.compareTo(aName);
|
||||
});
|
||||
|
||||
// 清理非 starcitizen_* 目录
|
||||
for (var d in otherDirs) {
|
||||
try {
|
||||
await d.delete(recursive: true);
|
||||
} catch (e) {
|
||||
dPrint("_cleanShaderCacheWithMode delete other dir error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
// 根据模式清理 starcitizen_* 目录
|
||||
for (var i = 0; i < scDirs.length; i++) {
|
||||
final scDir = scDirs[i];
|
||||
|
||||
if (keepLatest) {
|
||||
// 保留最新模式:
|
||||
// 第一个(最新):完全保留
|
||||
// 第二个:仅保留 GraphicsSettings
|
||||
// 其他:仅保留 GraphicsSettings
|
||||
if (i == 0) {
|
||||
// 最新的文件夹完全保留,不做任何操作
|
||||
continue;
|
||||
} else {
|
||||
// 其他文件夹:清理内容,保留 GraphicsSettings
|
||||
await _cleanShaderCacheDirectory(scDir);
|
||||
}
|
||||
} else {
|
||||
// 全部清理模式:
|
||||
// 前两个:仅保留 GraphicsSettings
|
||||
// 其他:仅保留 GraphicsSettings
|
||||
await _cleanShaderCacheDirectory(scDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _cleanShaderCache(BuildContext context) async {
|
||||
// 显示对话框让用户选择清理模式
|
||||
final result = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (dialogContext) => ContentDialog(
|
||||
constraints: BoxConstraints(maxWidth: 380),
|
||||
title: Text(S.current.tools_shader_clean_dialog_title),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: FilledButton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Text(S.current.tools_shader_clean_keep_latest),
|
||||
),
|
||||
onPressed: () => Navigator.pop(dialogContext, "keep_latest"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Button(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Text(S.current.tools_shader_clean_all),
|
||||
),
|
||||
onPressed: () => Navigator.pop(dialogContext, "clean_all"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [Button(child: Text(S.current.app_common_tip_cancel), onPressed: () => Navigator.pop(dialogContext))],
|
||||
),
|
||||
);
|
||||
|
||||
if (result == null || !context.mounted) return;
|
||||
|
||||
state = state.copyWith(working: true);
|
||||
await cleanShaderCache();
|
||||
|
||||
if (result == "keep_latest") {
|
||||
await cleanShaderCacheKeepLatest();
|
||||
} else {
|
||||
await cleanShaderCache();
|
||||
}
|
||||
|
||||
if (!context.mounted) return;
|
||||
loadToolsCard(context, skipPathScan: true);
|
||||
state = state.copyWith(working: false);
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'tools_ui_model.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ToolsUIModel)
|
||||
const toolsUIModelProvider = ToolsUIModelProvider._();
|
||||
final toolsUIModelProvider = ToolsUIModelProvider._();
|
||||
|
||||
final class ToolsUIModelProvider
|
||||
extends $NotifierProvider<ToolsUIModel, ToolsUIState> {
|
||||
const ToolsUIModelProvider._()
|
||||
ToolsUIModelProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -41,14 +41,13 @@ final class ToolsUIModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$toolsUIModelHash() => r'd50710acb3cf2e858128541dbfe8389ea9db4452';
|
||||
String _$toolsUIModelHash() => r'85ccd6ff3fe9622f9d2bfbf3c8385fd8c9363e7e';
|
||||
|
||||
abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
||||
ToolsUIState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<ToolsUIState, ToolsUIState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ project(runner LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "app")
|
||||
set(BINARY_NAME "starcitizen_doctor")
|
||||
# The unique GTK application identifier for this application. See:
|
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||
set(APPLICATION_ID "com.example.app")
|
||||
set(APPLICATION_ID "com.starcitizen_doctor")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
@@ -53,6 +53,7 @@ add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
# System-level dependencies.
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||
pkg_check_modules(GDK_PIXBUF REQUIRED IMPORTED_TARGET gdk-pixbuf-2.0)
|
||||
|
||||
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||
|
||||
@@ -73,6 +74,7 @@ apply_standard_settings(${BINARY_NAME})
|
||||
# Add dependency libraries. Add any application-specific dependencies here.
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GDK_PIXBUF)
|
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed.
|
||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
@@ -143,3 +145,13 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
# Install application icons
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/icons/hicolor"
|
||||
DESTINATION "share/icons"
|
||||
COMPONENT Runtime)
|
||||
|
||||
# Install desktop file
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/com.starcitizen_doctor.desktop"
|
||||
DESTINATION "share/applications"
|
||||
COMPONENT Runtime)
|
||||
|
||||
9
linux/com.starcitizen_doctor.desktop
Normal file
9
linux/com.starcitizen_doctor.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=SC汉化盒子
|
||||
Comment=Star Citizen Tool Box for Chinese players
|
||||
Exec=starcitizen_doctor
|
||||
Icon=starcitizen_doctor
|
||||
Categories=Utility;Game;
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <desktop_multi_window/desktop_multi_window_plugin.h>
|
||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||
#include <gtk/gtk_plugin.h>
|
||||
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
@@ -19,6 +20,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin");
|
||||
flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar);
|
||||
g_autoptr(FlPluginRegistrar) gtk_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
|
||||
gtk_plugin_register_with_registrar(gtk_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
|
||||
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_multi_window
|
||||
flutter_acrylic
|
||||
gtk
|
||||
screen_retriever_linux
|
||||
url_launcher_linux
|
||||
window_manager
|
||||
|
||||
BIN
linux/icons/hicolor/128x128/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/128x128/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
BIN
linux/icons/hicolor/16x16/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/16x16/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 879 B |
BIN
linux/icons/hicolor/256x256/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/256x256/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
linux/icons/hicolor/32x32/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/32x32/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
linux/icons/hicolor/48x48/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/48x48/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
linux/icons/hicolor/64x64/apps/starcitizen_doctor.png
Normal file
BIN
linux/icons/hicolor/64x64/apps/starcitizen_doctor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
@@ -4,6 +4,7 @@
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
#include <glib.h>
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
|
||||
@@ -19,6 +20,13 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||
// Implements GApplication::activate.
|
||||
static void my_application_activate(GApplication* application) {
|
||||
MyApplication* self = MY_APPLICATION(application);
|
||||
|
||||
GList* windows = gtk_application_get_windows(GTK_APPLICATION(application));
|
||||
if (windows) {
|
||||
gtk_window_present(GTK_WINDOW(windows->data));
|
||||
return;
|
||||
}
|
||||
|
||||
GtkWindow* window =
|
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
|
||||
@@ -42,11 +50,11 @@ static void my_application_activate(GApplication* application) {
|
||||
if (use_header_bar) {
|
||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||
gtk_header_bar_set_title(header_bar, "app");
|
||||
gtk_header_bar_set_title(header_bar, "SC汉化盒子");
|
||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||
} else {
|
||||
gtk_window_set_title(window, "app");
|
||||
gtk_window_set_title(window, "SC汉化盒子");
|
||||
}
|
||||
|
||||
gtk_window_set_default_size(window, 1280, 720);
|
||||
@@ -84,7 +92,7 @@ static gboolean my_application_local_command_line(GApplication* application, gch
|
||||
g_application_activate(application);
|
||||
*exit_status = 0;
|
||||
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Implements GApplication::startup.
|
||||
@@ -125,6 +133,6 @@ static void my_application_init(MyApplication* self) {}
|
||||
MyApplication* my_application_new() {
|
||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||
"application-id", APPLICATION_ID,
|
||||
"flags", G_APPLICATION_NON_UNIQUE,
|
||||
"flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
10
linux/sctoolbox.desktop
Normal file
10
linux/sctoolbox.desktop
Normal file
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=StarCitizen ToolBox
|
||||
Comment=StarCitizen ToolBox Application
|
||||
Exec=app %u
|
||||
Icon=app
|
||||
Terminal=false
|
||||
Categories=Utility;
|
||||
MimeType=x-scheme-handler/sctoolbox;
|
||||
@@ -5,6 +5,7 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import app_links
|
||||
import desktop_multi_window
|
||||
import device_info_plus
|
||||
import file_picker
|
||||
@@ -15,6 +16,7 @@ import url_launcher_macos
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
|
||||
FlutterMultiWindowPlugin.register(with: registry.registrar(forPlugin: "FlutterMultiWindowPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
PODS:
|
||||
- app_links (6.4.1):
|
||||
- FlutterMacOS
|
||||
- desktop_multi_window (0.0.1):
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
@@ -21,6 +23,7 @@ PODS:
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
|
||||
- desktop_multi_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_multi_window/macos`)
|
||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
||||
@@ -33,6 +36,8 @@ DEPENDENCIES:
|
||||
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/app_links/macos
|
||||
desktop_multi_window:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_multi_window/macos
|
||||
device_info_plus:
|
||||
@@ -55,6 +60,7 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: 05a6ec2341985eb05e9f97dc63f5837c39895c3f
|
||||
desktop_multi_window: 93667594ccc4b88d91a97972fd3b1b89667fa80a
|
||||
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
|
||||
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
||||
|
||||
@@ -31,6 +31,17 @@
|
||||
<string>$(PRODUCT_COPYRIGHT)</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.xkeyc.sctoolbox</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>sctoolbox</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
|
||||
132
pubspec.lock
132
pubspec.lock
@@ -9,6 +9,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "91.0.0"
|
||||
analysis_server_plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analysis_server_plugin
|
||||
sha256: "26844e7f977087567135d62532b67d5639fe206c5194c3f410ba75e1a04a2747"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -41,6 +49,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
app_links:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: app_links
|
||||
sha256: "3462d9defc61565fde4944858b59bec5be2b9d5b05f20aed190adb3ad08a7abc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
app_links_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_linux
|
||||
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
app_links_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_platform_interface
|
||||
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
app_links_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_web
|
||||
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
archive:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -109,10 +149,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "110c56ef29b5eb367b4d17fc79375fa8c18a6cd7acd92c05bb3986c17a079057"
|
||||
sha256: b4d854962a32fd9f8efc0b76f98214790b833af8b2e9b2df6bfc927c0415a072
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.4"
|
||||
version: "2.10.5"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -265,14 +305,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.1"
|
||||
custom_lint_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_builder
|
||||
sha256: "1128db6f58e71d43842f3b9be7465c83f0c47f4dd8918f878dd6ad3b72a32072"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.1"
|
||||
custom_lint_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -333,10 +365,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9
|
||||
sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.9.0"
|
||||
version: "5.9.1"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -373,10 +405,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
|
||||
sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.5"
|
||||
ffigen:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -421,10 +453,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluent_ui
|
||||
sha256: "569f61002931665b9613ed12008a368d60ae66baab78b6270c4dc8b44f24d1df"
|
||||
sha256: "8645eabacb46bfc9632fadc6e106756cdc6f2a4efb5a4fed4410bd3131306fe8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.11.3"
|
||||
version: "4.12.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -479,10 +511,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: "9e2d6907f12cc7d23a846847615941bddee8709bf2bfd274acdf5e80bcf22fde"
|
||||
sha256: "38ec6c303e2c83ee84512f5fc2a82ae311531021938e63d7137eccc107bf3c02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.1.0"
|
||||
flutter_rust_bridge:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -561,10 +593,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: get_it
|
||||
sha256: ae78de7c3f2304b8d81f2bb6e320833e5e81de942188542328f074978cc0efa9
|
||||
sha256: "1d648d2dd2047d7f7450d5727ca24ee435f240385753d90b49650e3cdff32e56"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.3.0"
|
||||
version: "9.2.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -613,6 +645,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
gtk:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: gtk
|
||||
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
hexcolor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -633,26 +673,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hive_ce
|
||||
sha256: "412c638aeac0f003bba664884e3048b9547e541aaca13f10cc639da788184bed"
|
||||
sha256: b844955c89f61f479170632b971dcf6fbb8e7233d2a5c2e3c7b89e1b2986bdb5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.16.0"
|
||||
version: "2.19.1"
|
||||
hooks_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hooks_riverpod
|
||||
sha256: ae4a2f6d82dd895379f9b95457e090ac2d2fef9446f9325f8d31b9c86cadc131
|
||||
sha256: b880efcd17757af0aa242e5dceac2fb781a014c22a32435a5daa8f17e9d5d8a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
version: "3.1.0"
|
||||
html:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -729,10 +761,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: isolate_channel
|
||||
sha256: f3d36f783b301e6b312c3450eeb2656b0e7d1db81331af2a151d9083a3f6b18d
|
||||
sha256: "000d617d021a608186b468584bbc6df2509ecba048f08510f832fdb9cf7aafbe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2+1"
|
||||
version: "0.4.1"
|
||||
isolate_contactor:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -897,10 +929,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: msix
|
||||
sha256: f88033fcb9e0dd8de5b18897cbebbd28ea30596810f4a7c86b12b0c03ace87e5
|
||||
sha256: b6b08e7a7b5d1845f2b1d31216d5b1fb558e98251efefe54eb79ed00d27bc2ac
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.12"
|
||||
version: "3.16.13"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1097,42 +1129,42 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: c406de02bff19d920b832bddfb8283548bfa05ce41c59afba57ce643e116aa59
|
||||
sha256: "16ff608d21e8ea64364f2b7c049c94a02ab81668f78845862b6e88b71dd4935a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.1.0"
|
||||
riverpod_analyzer_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod_analyzer_utils
|
||||
sha256: a0f68adb078b790faa3c655110a017f9a7b7b079a57bbd40f540e80dce5fcd29
|
||||
sha256: "947b05d04c52a546a2ac6b19ef2a54b08520ff6bdf9f23d67957a4c8df1c3bc0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0-dev.7"
|
||||
version: "1.0.0-dev.8"
|
||||
riverpod_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: "7230014155777fc31ba3351bc2cb5a3b5717b11bfafe52b1553cb47d385f8897"
|
||||
sha256: cc1474bc2df55ec3c1da1989d139dcef22cd5e2bd78da382e867a69a8eca2e46
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "4.0.0"
|
||||
riverpod_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_generator
|
||||
sha256: "49894543a42cf7a9954fc4e7366b6d3cb2e6ec0fa07775f660afcdd92d097702"
|
||||
sha256: e43b1537229cc8f487f09b0c20d15dba840acbadcf5fc6dad7ad5e8ab75950dc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "4.0.0+1"
|
||||
riverpod_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_lint
|
||||
sha256: "7ef9c43469e9b5ac4e4c3b24d7c30642e47ce1b12cd7dcdd643534db0a72ed13"
|
||||
sha256: "4d2eb0d19bbe7e3323bd0ce4553b2e6170d161a13914bfdd85a3612329edcb43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.1.0"
|
||||
rust_builder:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1532,10 +1564,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: watcher
|
||||
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
|
||||
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1618,5 +1650,5 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
sdks:
|
||||
dart: ">=3.9.0 <4.0.0"
|
||||
flutter: ">=3.35.0"
|
||||
dart: ">=3.10.0 <4.0.0"
|
||||
flutter: ">=3.38.1"
|
||||
|
||||
32
pubspec.yaml
32
pubspec.yaml
@@ -2,7 +2,7 @@ name: starcitizen_doctor
|
||||
description: Designed for "StarCitizen" players, providing many convenient functions.
|
||||
publish_to: 'none'
|
||||
|
||||
version: 3.0.1+78
|
||||
version: 3.1.0+80
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.0
|
||||
@@ -13,10 +13,10 @@ dependencies:
|
||||
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
flutter_riverpod: ^3.0.3
|
||||
riverpod_annotation: ^3.0.3
|
||||
flutter_riverpod: ^3.1.0
|
||||
riverpod_annotation: ^4.0.0
|
||||
flutter_hooks: ^0.21.3+1
|
||||
hooks_riverpod: ^3.0.3
|
||||
hooks_riverpod: ^3.1.0
|
||||
json_annotation: ^4.9.0
|
||||
go_router: ^17.0.1
|
||||
window_manager:
|
||||
@@ -24,15 +24,15 @@ dependencies:
|
||||
url: https://github.com/boyan01/window_manager.git
|
||||
path: packages/window_manager
|
||||
ref: 6fae92d21b4c80ce1b8f71c1190d7970cf722bd4
|
||||
fluent_ui: 4.11.3
|
||||
fluent_ui: 4.12.0
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
flutter_acrylic: ^1.1.4
|
||||
url_launcher: ^6.3.2
|
||||
font_awesome_flutter: ^10.12.0
|
||||
cupertino_icons: ^1.0.8
|
||||
hive_ce: ^2.16.0
|
||||
hive_ce: ^2.19.1
|
||||
path_provider: ^2.1.5
|
||||
dio: ^5.9.0
|
||||
dio: ^5.9.1
|
||||
markdown: ^7.3.0
|
||||
markdown_widget: ^2.3.2+8
|
||||
extended_image: ^10.0.1
|
||||
@@ -46,7 +46,7 @@ dependencies:
|
||||
uuid: ^4.5.2
|
||||
flutter_tilt: ^3.3.2
|
||||
card_swiper: ^3.0.1
|
||||
ffi: ^2.1.4
|
||||
ffi: ^2.1.5
|
||||
flutter_rust_bridge: ^2.11.1
|
||||
freezed_annotation: ^3.1.0
|
||||
meta: ^1.17.0
|
||||
@@ -65,14 +65,15 @@ dependencies:
|
||||
shelf: ^1.4.2
|
||||
qr_flutter: ^4.1.0
|
||||
desktop_multi_window: ^0.3.0
|
||||
watcher: ^1.2.0
|
||||
watcher: ^1.2.1
|
||||
path: ^1.9.1
|
||||
crypto: ^3.0.7
|
||||
xml: ^6.6.1
|
||||
|
||||
# gRPC and protobuf
|
||||
grpc: ^5.0.0
|
||||
grpc: ^5.1.0
|
||||
protobuf: ^6.0.0
|
||||
app_links: ^7.0.0
|
||||
dependency_overrides:
|
||||
http: ^1.6.0
|
||||
intl: ^0.20.2
|
||||
@@ -81,13 +82,13 @@ dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
msix: ^3.16.12
|
||||
build_runner: ^2.10.4
|
||||
msix: ^3.16.13
|
||||
build_runner: ^2.10.5
|
||||
freezed: ^3.2.3
|
||||
json_serializable: ^6.11.2
|
||||
riverpod_generator: ^3.0.3
|
||||
riverpod_generator: ^4.0.0+1
|
||||
custom_lint: ^0.8.1
|
||||
riverpod_lint: ^3.0.3
|
||||
riverpod_lint: ^3.1.0
|
||||
ffigen: ^20.1.1
|
||||
sct_dev_tools:
|
||||
path: ./packages/sct_dev_tools
|
||||
@@ -112,11 +113,12 @@ msix_config:
|
||||
publisher_display_name: xkeyC Studio
|
||||
identity_name: 56575xkeyC.MSE
|
||||
publisher: CN=B54C897B-C263-4680-B6AB-4913C603DF87
|
||||
msix_version: 3.0.9.0
|
||||
msix_version: 3.1.0.0
|
||||
logo_path: ./assets/app_logo.png
|
||||
capabilities: internetClient,allowElevation
|
||||
languages: zh-cn
|
||||
windows_build_args: --dart-define="MSE=true"
|
||||
store: true
|
||||
protocol_activation: sctoolbox
|
||||
flutter_intl:
|
||||
enabled: true
|
||||
192
rust/Cargo.lock
generated
192
rust/Cargo.lock
generated
@@ -763,7 +763,7 @@ version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
|
||||
dependencies = [
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
@@ -1186,7 +1186,7 @@ dependencies = [
|
||||
"phf 0.10.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@@ -1710,18 +1710,6 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"libredox",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.5"
|
||||
@@ -2160,7 +2148,7 @@ dependencies = [
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
@@ -2196,7 +2184,7 @@ dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
@@ -2284,7 +2272,7 @@ dependencies = [
|
||||
"portable-atomic",
|
||||
"quanta",
|
||||
"rand 0.9.2",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"spinning_top",
|
||||
"web-time",
|
||||
]
|
||||
@@ -2447,7 +2435,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"rand 0.9.2",
|
||||
"resolv-conf",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -2462,6 +2450,12 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac-sha256"
|
||||
version = "1.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad6880c8d4a9ebf39c6e8b77007ce223f646a4d21ce29d99f70cb16420545425"
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.29.1"
|
||||
@@ -2537,7 +2531,7 @@ dependencies = [
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
]
|
||||
@@ -2661,7 +2655,7 @@ dependencies = [
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
@@ -2719,7 +2713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
@@ -2804,7 +2798,7 @@ version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "270bc34e57047cab801a8c871c124d9dc7132f6473c6401f645524f4e6edd111"
|
||||
dependencies = [
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2988,13 +2982,12 @@ checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
"redox_syscall 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librqbit"
|
||||
version = "9.0.0-beta.1"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3058,7 +3051,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-bencode"
|
||||
version = "3.1.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
@@ -3074,7 +3067,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-buffers"
|
||||
version = "4.2.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"librqbit-clone-to-owned",
|
||||
@@ -3085,7 +3078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-clone-to-owned"
|
||||
version = "3.0.1"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
]
|
||||
@@ -3093,7 +3086,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-core"
|
||||
version = "5.0.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -3122,7 +3115,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-dht"
|
||||
version = "5.3.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backon",
|
||||
@@ -3169,7 +3162,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-lsd"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atoi",
|
||||
@@ -3189,7 +3182,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-peer-protocol"
|
||||
version = "4.3.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitvec",
|
||||
@@ -3209,7 +3202,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-sha1-wrapper"
|
||||
version = "4.1.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"assert_cfg",
|
||||
"aws-lc-rs",
|
||||
@@ -3218,7 +3211,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-tracker-comms"
|
||||
version = "3.0.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -3246,7 +3239,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "librqbit-upnp"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=1e281d545c068a4f5ec98553539cd46a159cad14#1e281d545c068a4f5ec98553539cd46a159cad14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bstr",
|
||||
@@ -3345,6 +3338,12 @@ dependencies = [
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lzma-rust2"
|
||||
version = "0.15.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f7337d278fec032975dc884152491580dd23750ee957047856735fe0e61ede"
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@@ -3525,7 +3524,7 @@ dependencies = [
|
||||
"equivalent",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
"tagptr",
|
||||
"uuid",
|
||||
]
|
||||
@@ -3581,24 +3580,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ndarray"
|
||||
version = "0.16.1"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
||||
dependencies = [
|
||||
"matrixmultiply",
|
||||
"num-complex 0.4.6",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndarray"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7c9125e8f6f10c9da3aad044cc918cf8784fa34de857b1aa68038eb05a50a9"
|
||||
checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d"
|
||||
dependencies = [
|
||||
"matrixmultiply",
|
||||
"num-complex 0.4.6",
|
||||
@@ -4012,26 +3996,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ort"
|
||||
version = "2.0.0-rc.10"
|
||||
version = "2.0.0-rc.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa7e49bd669d32d7bc2a15ec540a527e7764aec722a45467814005725bcd721"
|
||||
checksum = "4a5df903c0d2c07b56950f1058104ab0c8557159f2741782223704de9be73c3c"
|
||||
dependencies = [
|
||||
"ndarray 0.16.1",
|
||||
"ndarray",
|
||||
"ort-sys",
|
||||
"smallvec 2.0.0-alpha.10",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ort-sys"
|
||||
version = "2.0.0-rc.10"
|
||||
version = "2.0.0-rc.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2aba9f5c7c479925205799216e7e5d07cc1d4fa76ea8058c60a9a30f6a4e890"
|
||||
checksum = "06503bb33f294c5f1ba484011e053bfa6ae227074bdb841e9863492dc5960d4b"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"pkg-config",
|
||||
"sha2",
|
||||
"tar",
|
||||
"hmac-sha256",
|
||||
"lzma-rust2 0.15.6",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
@@ -4101,8 +4084,8 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.18",
|
||||
"smallvec 1.15.1",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
@@ -4747,15 +4730,6 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
@@ -4918,7 +4892,7 @@ dependencies = [
|
||||
"hickory-resolver",
|
||||
"image",
|
||||
"librqbit",
|
||||
"ndarray 0.17.1",
|
||||
"ndarray",
|
||||
"notify-rust",
|
||||
"once_cell",
|
||||
"ort",
|
||||
@@ -5108,7 +5082,7 @@ dependencies = [
|
||||
"phf_codegen 0.8.0",
|
||||
"precomputed-hash",
|
||||
"servo_arc",
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5162,15 +5136,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.146"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "217ca874ae0207aac254aa02c957ded05585a90892cc8d87f9e5fa49669dadd8"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5343,12 +5317,6 @@ version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "2.0.0-alpha.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d44cfb396c3caf6fbfd0ab422af02631b69ddd96d2eff0b0f0724f9024051b"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
@@ -5616,17 +5584,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
@@ -5818,9 +5775,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.48.0"
|
||||
version = "1.49.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
|
||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
@@ -6125,7 +6082,7 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de"
|
||||
dependencies = [
|
||||
"smallvec 1.15.1",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6230,14 +6187,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.7"
|
||||
version = "2.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
|
||||
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6266,9 +6224,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
|
||||
checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"js-sys",
|
||||
@@ -6454,9 +6412,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a"
|
||||
checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cairo-rs",
|
||||
@@ -6478,9 +6436,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk-sys"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c"
|
||||
checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cairo-sys-rs",
|
||||
@@ -7161,9 +7119,9 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.53.5"
|
||||
version = "0.54.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2"
|
||||
checksum = "5ed1a195b0375491dd15a7066a10251be217ce743cf4bbbbdcf5391d6473bee0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2",
|
||||
@@ -7234,16 +7192,6 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.1"
|
||||
@@ -7438,7 +7386,7 @@ dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"hmac",
|
||||
"indexmap 2.12.1",
|
||||
"lzma-rust2",
|
||||
"lzma-rust2 0.13.0",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
"ppmd-rust",
|
||||
@@ -7455,6 +7403,12 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.3"
|
||||
|
||||
@@ -15,34 +15,54 @@ crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
flutter_rust_bridge = "=2.11.1"
|
||||
tokio = { version = "1.48.0", features = ["rt", "rt-multi-thread", "macros", "process", "sync"] }
|
||||
futures = { version = "0.3.31", default-features = false, features = ["executor"] }
|
||||
url = "2.5.7"
|
||||
tokio = { version = "1.49.0", features = [
|
||||
"rt",
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
"process",
|
||||
"sync",
|
||||
] }
|
||||
futures = { version = "0.3.31", default-features = false, features = [
|
||||
"executor",
|
||||
] }
|
||||
url = "2.5.8"
|
||||
once_cell = "1.21.3"
|
||||
reqwest = { version = "0.12.26", features = ["rustls-tls-webpki-roots", "cookies", "gzip", "json", "stream"] }
|
||||
reqwest = { version = "0.12.26", features = [
|
||||
"rustls-tls-webpki-roots",
|
||||
"cookies",
|
||||
"gzip",
|
||||
"json",
|
||||
"stream",
|
||||
] }
|
||||
hickory-resolver = { version = "0.25.2" }
|
||||
anyhow = "1.0.100"
|
||||
scopeguard = "1.0"
|
||||
notify-rust = "4.11.7"
|
||||
asar = "0.3.0"
|
||||
walkdir = "2.5.0"
|
||||
ort = { version = "2.0.0-rc.10", features = ["xnnpack", "download-binaries", "ndarray"] }
|
||||
tokenizers = { version = "0.22.2", default-features = false, features = ["onig"] }
|
||||
ndarray = "0.17.1"
|
||||
serde_json = "1.0.145"
|
||||
ort = { version = "2.0.0-rc.11", features = [
|
||||
"xnnpack",
|
||||
"download-binaries",
|
||||
"ndarray",
|
||||
] }
|
||||
tokenizers = { version = "0.22.2", default-features = false, features = [
|
||||
"onig",
|
||||
] }
|
||||
ndarray = "0.17.2"
|
||||
serde_json = "1.0.149"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
unp4k_rs = { git = "https://github.com/StarCitizenToolBox/unp4k_rs", rev = "29430002d6f3a8d87feabac26c03ae0311c81263" }
|
||||
#unp4k_rs = { path = "../../unp4k_rs" }
|
||||
uuid = { version = "1.19.0", features = ["v4"] }
|
||||
uuid = { version = "1.20.0", features = ["v4"] }
|
||||
rayon = "1.10"
|
||||
parking_lot = "0.12.5"
|
||||
crossbeam-channel = "0.5.15"
|
||||
librqbit = { git = "https://github.com/StarCitizenToolBox/rqbit", rev = "f8c0b0927904e1d8b0e28e708bd69fd8069d413a" }
|
||||
librqbit = { git = "https://github.com/StarCitizenToolBox/rqbit", rev = "1e281d545c068a4f5ec98553539cd46a159cad14" }
|
||||
bytes = "1.10"
|
||||
|
||||
# WebView
|
||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||
wry = "0.53.5"
|
||||
wry = "0.54.1"
|
||||
tao = { version = "0.34.5", features = ["serde"] }
|
||||
image = { version = "0.25.9", default-features = false, features = ["ico"] }
|
||||
|
||||
@@ -61,7 +81,7 @@ windows = { version = "0.62.2", features = [
|
||||
"Win32_System_Variant",
|
||||
"Win32_Security",
|
||||
"Win32_System_IO",
|
||||
"Win32_System_Ioctl"
|
||||
"Win32_System_Ioctl",
|
||||
] }
|
||||
win32job = "2.0.3"
|
||||
wmi = "0.18"
|
||||
|
||||
400
rust/src/api/applinks_api.rs
Normal file
400
rust/src/api/applinks_api.rs
Normal file
@@ -0,0 +1,400 @@
|
||||
use std::env;
|
||||
|
||||
/// Applinks URL scheme registration result
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ApplinksRegistrationResult {
|
||||
/// Whether registration was successful
|
||||
pub success: bool,
|
||||
/// Detailed message about the operation
|
||||
pub message: String,
|
||||
/// Whether the registry was modified (false if already configured correctly)
|
||||
pub was_modified: bool,
|
||||
}
|
||||
|
||||
/// Check if the URL scheme is already registered with the correct executable path
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn check_applinks_registration(scheme: String) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
use windows::core::{HSTRING, PCWSTR};
|
||||
use windows::Win32::System::Registry::{
|
||||
RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER, KEY_READ,
|
||||
REG_VALUE_TYPE,
|
||||
};
|
||||
|
||||
let app_path = env::current_exe()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to get current executable path: {}", e))?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
let expected_command = format!("\"{}\" \"%1\"", app_path);
|
||||
let protocol_key_path = format!("Software\\Classes\\{}", scheme);
|
||||
let command_key_path = format!("{}\\shell\\open\\command", protocol_key_path);
|
||||
|
||||
unsafe {
|
||||
// Check if URL Protocol value exists
|
||||
let mut protocol_key = std::mem::zeroed();
|
||||
let protocol_key_hstring = HSTRING::from(&protocol_key_path);
|
||||
|
||||
if RegOpenKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(protocol_key_hstring.as_ptr()),
|
||||
Some(0),
|
||||
KEY_READ,
|
||||
&mut protocol_key,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!("URL scheme '{}' is not registered", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Check URL Protocol value
|
||||
let url_protocol_name = HSTRING::from("URL Protocol");
|
||||
let mut data_type: REG_VALUE_TYPE = REG_VALUE_TYPE::default();
|
||||
let mut data_size: u32 = 0;
|
||||
|
||||
if RegQueryValueExW(
|
||||
protocol_key,
|
||||
PCWSTR(url_protocol_name.as_ptr()),
|
||||
None,
|
||||
Some(&mut data_type),
|
||||
None,
|
||||
Some(&mut data_size),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
let _ = RegCloseKey(protocol_key);
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!("URL Protocol value not found for scheme '{}'", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
|
||||
let _ = RegCloseKey(protocol_key);
|
||||
|
||||
// Check command key
|
||||
let mut command_key = std::mem::zeroed();
|
||||
let command_key_hstring = HSTRING::from(&command_key_path);
|
||||
|
||||
if RegOpenKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(command_key_hstring.as_ptr()),
|
||||
Some(0),
|
||||
KEY_READ,
|
||||
&mut command_key,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!("Command key not found for scheme '{}'", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Read command value (default value with empty name)
|
||||
let empty_name = HSTRING::from("");
|
||||
let mut data_size: u32 = 0;
|
||||
|
||||
if RegQueryValueExW(
|
||||
command_key,
|
||||
PCWSTR(empty_name.as_ptr()),
|
||||
None,
|
||||
Some(&mut data_type),
|
||||
None,
|
||||
Some(&mut data_size),
|
||||
)
|
||||
.is_err()
|
||||
|| data_size == 0
|
||||
{
|
||||
let _ = RegCloseKey(command_key);
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!("Command value not found for scheme '{}'", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Read the actual command value
|
||||
let mut buffer: Vec<u8> = vec![0; data_size as usize];
|
||||
if RegQueryValueExW(
|
||||
command_key,
|
||||
PCWSTR(empty_name.as_ptr()),
|
||||
None,
|
||||
Some(&mut data_type),
|
||||
Some(buffer.as_mut_ptr()),
|
||||
Some(&mut data_size),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
let _ = RegCloseKey(command_key);
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!("Failed to read command value for scheme '{}'", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
|
||||
let _ = RegCloseKey(command_key);
|
||||
|
||||
// Convert buffer to string (UTF-16 to UTF-8)
|
||||
let command_value = String::from_utf16_lossy(
|
||||
&buffer
|
||||
.chunks_exact(2)
|
||||
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
|
||||
.take_while(|&c| c != 0)
|
||||
.collect::<Vec<u16>>(),
|
||||
);
|
||||
|
||||
// Compare with expected command (case-insensitive for path)
|
||||
if command_value.to_lowercase() == expected_command.to_lowercase() {
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: true,
|
||||
message: format!("URL scheme '{}' is already registered correctly", scheme),
|
||||
was_modified: false,
|
||||
})
|
||||
} else {
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!(
|
||||
"URL scheme '{}' is registered but with different path. Current: '{}', Expected: '{}'",
|
||||
scheme, command_value, expected_command
|
||||
),
|
||||
was_modified: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn check_applinks_registration(scheme: String) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!(
|
||||
"URL scheme registration check is not supported on this platform for scheme '{}'",
|
||||
scheme
|
||||
),
|
||||
was_modified: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn register_applinks(scheme: String, app_name: Option<String>) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
use windows::core::{HSTRING, PCWSTR};
|
||||
use windows::Win32::System::Registry::{
|
||||
RegCloseKey, RegCreateKeyExW, RegSetValueExW, HKEY_CURRENT_USER, KEY_WRITE,
|
||||
REG_CREATE_KEY_DISPOSITION, REG_OPTION_NON_VOLATILE, REG_SZ,
|
||||
};
|
||||
|
||||
// First check if already registered correctly
|
||||
let check_result = check_applinks_registration(scheme.clone())?;
|
||||
if check_result.success {
|
||||
return Ok(check_result);
|
||||
}
|
||||
|
||||
let app_path = env::current_exe()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to get current executable path: {}", e))?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
let command_value = format!("\"{}\" \"%1\"", app_path);
|
||||
let protocol_key_path = format!("Software\\Classes\\{}", scheme);
|
||||
let command_key_path = format!("{}\\shell\\open\\command", protocol_key_path);
|
||||
|
||||
unsafe {
|
||||
// Create protocol key
|
||||
let mut protocol_key = std::mem::zeroed();
|
||||
let protocol_key_hstring = HSTRING::from(&protocol_key_path);
|
||||
let mut disposition: REG_CREATE_KEY_DISPOSITION = REG_CREATE_KEY_DISPOSITION::default();
|
||||
|
||||
if RegCreateKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(protocol_key_hstring.as_ptr()),
|
||||
Some(0),
|
||||
PCWSTR::null(),
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE,
|
||||
None,
|
||||
&mut protocol_key,
|
||||
Some(&mut disposition),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return Err(anyhow::anyhow!(
|
||||
"Failed to create registry key '{}'",
|
||||
protocol_key_path
|
||||
));
|
||||
}
|
||||
|
||||
// Set default value (display name) if app_name is provided
|
||||
if let Some(ref name) = app_name {
|
||||
let display_name = format!("URL:{} Protocol", name);
|
||||
let empty_name = HSTRING::from("");
|
||||
let display_name_bytes: Vec<u8> = display_name
|
||||
.encode_utf16()
|
||||
.chain(std::iter::once(0))
|
||||
.flat_map(|c| c.to_le_bytes())
|
||||
.collect();
|
||||
|
||||
if RegSetValueExW(
|
||||
protocol_key,
|
||||
PCWSTR(empty_name.as_ptr()),
|
||||
Some(0),
|
||||
REG_SZ,
|
||||
Some(&display_name_bytes),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
let _ = RegCloseKey(protocol_key);
|
||||
return Err(anyhow::anyhow!("Failed to set display name value"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set URL Protocol value (empty string)
|
||||
let url_protocol_name = HSTRING::from("URL Protocol");
|
||||
let empty_value: [u8; 2] = [0, 0]; // Empty UTF-16 string
|
||||
|
||||
if RegSetValueExW(
|
||||
protocol_key,
|
||||
PCWSTR(url_protocol_name.as_ptr()),
|
||||
Some(0),
|
||||
REG_SZ,
|
||||
Some(&empty_value),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
let _ = RegCloseKey(protocol_key);
|
||||
return Err(anyhow::anyhow!("Failed to set URL Protocol value"));
|
||||
}
|
||||
|
||||
let _ = RegCloseKey(protocol_key);
|
||||
|
||||
// Create command key
|
||||
let mut command_key = std::mem::zeroed();
|
||||
let command_key_hstring = HSTRING::from(&command_key_path);
|
||||
|
||||
if RegCreateKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(command_key_hstring.as_ptr()),
|
||||
Some(0),
|
||||
PCWSTR::null(),
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE,
|
||||
None,
|
||||
&mut command_key,
|
||||
Some(&mut disposition),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return Err(anyhow::anyhow!(
|
||||
"Failed to create command key '{}'",
|
||||
command_key_path
|
||||
));
|
||||
}
|
||||
|
||||
// Set command value
|
||||
let empty_name = HSTRING::from("");
|
||||
let command_bytes: Vec<u8> = command_value
|
||||
.encode_utf16()
|
||||
.chain(std::iter::once(0))
|
||||
.flat_map(|c| c.to_le_bytes())
|
||||
.collect();
|
||||
|
||||
if RegSetValueExW(
|
||||
command_key,
|
||||
PCWSTR(empty_name.as_ptr()),
|
||||
Some(0),
|
||||
REG_SZ,
|
||||
Some(&command_bytes),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
let _ = RegCloseKey(command_key);
|
||||
return Err(anyhow::anyhow!("Failed to set command value"));
|
||||
}
|
||||
|
||||
let _ = RegCloseKey(command_key);
|
||||
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: true,
|
||||
message: format!(
|
||||
"Successfully registered URL scheme '{}' with command '{}'",
|
||||
scheme, command_value
|
||||
),
|
||||
was_modified: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn register_applinks(scheme: String, _app_name: Option<String>) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!(
|
||||
"URL scheme registration is not supported on this platform for scheme '{}'",
|
||||
scheme
|
||||
),
|
||||
was_modified: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Unregister URL scheme from Windows registry
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn unregister_applinks(scheme: String) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
use windows::core::{HSTRING, PCWSTR};
|
||||
use windows::Win32::System::Registry::{RegDeleteTreeW, HKEY_CURRENT_USER};
|
||||
|
||||
let protocol_key_path = format!("Software\\Classes\\{}", scheme);
|
||||
|
||||
unsafe {
|
||||
let protocol_key_hstring = HSTRING::from(&protocol_key_path);
|
||||
|
||||
let result = RegDeleteTreeW(HKEY_CURRENT_USER, PCWSTR(protocol_key_hstring.as_ptr()));
|
||||
|
||||
if result.is_err() {
|
||||
// Check if the key doesn't exist (not an error in this case)
|
||||
let error_code = result.0 as u32;
|
||||
if error_code == 2 {
|
||||
// ERROR_FILE_NOT_FOUND
|
||||
return Ok(ApplinksRegistrationResult {
|
||||
success: true,
|
||||
message: format!("URL scheme '{}' was not registered", scheme),
|
||||
was_modified: false,
|
||||
});
|
||||
}
|
||||
return Err(anyhow::anyhow!(
|
||||
"Failed to delete registry key '{}': error code {}",
|
||||
protocol_key_path,
|
||||
error_code
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: true,
|
||||
message: format!("Successfully unregistered URL scheme '{}'", scheme),
|
||||
was_modified: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn unregister_applinks(scheme: String) -> anyhow::Result<ApplinksRegistrationResult> {
|
||||
Ok(ApplinksRegistrationResult {
|
||||
success: false,
|
||||
message: format!(
|
||||
"URL scheme unregistration is not supported on this platform for scheme '{}'",
|
||||
scheme
|
||||
),
|
||||
was_modified: false,
|
||||
})
|
||||
}
|
||||
@@ -71,8 +71,8 @@ pub async fn get_rsi_launcher_asar_data(asar_path: &str) -> anyhow::Result<RsiLa
|
||||
let mut main_js_content: Vec<u8> = Vec::new();
|
||||
asar.files().iter().for_each(|v| {
|
||||
let (path, file) = v;
|
||||
let path_string = path.clone().into_os_string().into_string().unwrap();
|
||||
if path_string.starts_with("app\\static\\js\\main.") && path_string.ends_with(".js") {
|
||||
let path_string = path.clone().into_os_string().into_string().unwrap().replace("\\", "/");
|
||||
if path_string.starts_with("app/static/js/main.") && path_string.ends_with(".js") {
|
||||
main_js_path = path_string;
|
||||
main_js_content = file.data().to_vec();
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ pub async fn downloader_init(
|
||||
disable_cooldown_secs: 600,
|
||||
adaptive_increase_threshold: 5,
|
||||
adaptive_decrease_threshold: 10,
|
||||
user_agent: Some(String::from("SCToolBox/librqbit/1.0")),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//
|
||||
// Do not put code in `mod.rs`, but put in e.g. `simple.rs`.
|
||||
//
|
||||
pub mod applinks_api;
|
||||
pub mod http_api;
|
||||
pub mod rs_process;
|
||||
pub mod win32_api;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user