mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-01-14 04:00:27 +00:00
feat: Replace desktop_webview_window with tao&wry , from tauri
This commit is contained in:
parent
125fedbc84
commit
6f0c760ab4
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"dart.flutterSdkPath": ".fvm/versions/stable"
|
"dart.flutterSdkPath": ".fvm/versions/stable",
|
||||||
|
"cmake.ignoreCMakeListsMissing": true
|
||||||
}
|
}
|
||||||
@ -10,7 +10,7 @@
|
|||||||
font-family: 'Material Icons';
|
font-family: 'Material Icons';
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-size: 24px;
|
font-size: 1.5rem; /* 24px */
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
|
|||||||
@ -207,7 +207,7 @@ function ReportUnTranslate(k, v) {
|
|||||||
const jsRegex = /(?:^|[^<])<script[^>]*>[\s\S]*?<\/script>(?:[^>]|$)/i;
|
const jsRegex = /(?:^|[^<])<script[^>]*>[\s\S]*?<\/script>(?:[^>]|$)/i;
|
||||||
if (k.trim() !== "" && !cnPattern.test(k) && !htmlPattern.test(k) && !cssRegex.test(k) && !jsRegex.test(k)
|
if (k.trim() !== "" && !cnPattern.test(k) && !htmlPattern.test(k) && !cssRegex.test(k) && !jsRegex.test(k)
|
||||||
&& enPattern.test(k) && !k.startsWith("http://") && !k.startsWith("https://")) {
|
&& enPattern.test(k) && !k.startsWith("http://") && !k.startsWith("https://")) {
|
||||||
window.chrome.webview.postMessage({ action: 'webview_localization_capture', key: k, value: v });
|
window.ipc.postMessage(JSON.stringify({ action: 'webview_localization_capture', key: k, value: v }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,93 +217,149 @@ InitWebLocalization();
|
|||||||
|
|
||||||
/// ----- Login Script ----
|
/// ----- Login Script ----
|
||||||
async function getRSILauncherToken(channelId) {
|
async function getRSILauncherToken(channelId) {
|
||||||
if (!window.location.href.includes("robertsspaceindustries.com")) return;
|
console.log('[SCToolbox] getRSILauncherToken called with channel:', channelId);
|
||||||
|
|
||||||
// check if logged in and fix redirect
|
try {
|
||||||
if (window.location.href.endsWith('/connect?jumpto=/account/dashboard')) {
|
if (!window.location.href.includes("robertsspaceindustries.com")) {
|
||||||
if (document.body.textContent.trim() === "/account/dashboard") {
|
console.log('[SCToolbox] Not on RSI site, skipping');
|
||||||
window.location.href = "https://robertsspaceindustries.com/account/dashboard";
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let loginBodyElement = $(".c-form authenticationForm sign_in");
|
|
||||||
loginBodyElement.show();
|
|
||||||
// wait login
|
|
||||||
window.chrome.webview.postMessage({ action: 'webview_rsi_login_show_window' });
|
|
||||||
|
|
||||||
// get claims
|
|
||||||
let claimsR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/claims", {
|
|
||||||
method: 'POST', headers: {
|
|
||||||
'x-rsi-token': $.cookie('Rsi-Token'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (claimsR.status !== 200) return;
|
|
||||||
|
|
||||||
loginBodyElement.hide();
|
|
||||||
SCTShowToast("登录游戏中...");
|
|
||||||
|
|
||||||
let claimsData = (await claimsR.json())["data"];
|
|
||||||
|
|
||||||
let tokenFormData = new FormData();
|
|
||||||
tokenFormData.append('claims', claimsData);
|
|
||||||
tokenFormData.append('gameId', 'SC');
|
|
||||||
let tokenR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/token", {
|
|
||||||
method: 'POST', headers: {
|
|
||||||
'x-rsi-token': $.cookie('Rsi-Token'),
|
|
||||||
},
|
|
||||||
body: tokenFormData
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tokenR.status !== 200) return;
|
|
||||||
let TokenData = (await tokenR.json())["data"]["token"];
|
|
||||||
console.log(TokenData);
|
|
||||||
|
|
||||||
// get release Data
|
|
||||||
let releaseFormData = new FormData();
|
|
||||||
releaseFormData.append("channelId", channelId);
|
|
||||||
releaseFormData.append("claims", claimsData);
|
|
||||||
releaseFormData.append("gameId", "SC");
|
|
||||||
releaseFormData.append("platformId", "prod");
|
|
||||||
let releaseR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/release", {
|
|
||||||
method: 'POST', headers: {
|
|
||||||
'x-rsi-token': $.cookie('Rsi-Token'),
|
|
||||||
},
|
|
||||||
body: releaseFormData
|
|
||||||
});
|
|
||||||
if (releaseR.status !== 200) return;
|
|
||||||
let releaseDataJson = (await releaseR.json())['data'];
|
|
||||||
console.log(releaseDataJson);
|
|
||||||
// get game library
|
|
||||||
let libraryR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/library", {
|
|
||||||
method: 'POST', headers: {
|
|
||||||
'x-rsi-token': $.cookie('Rsi-Token'),
|
|
||||||
},
|
|
||||||
body: releaseFormData
|
|
||||||
});
|
|
||||||
|
|
||||||
let libraryData = (await libraryR.json())["data"]
|
|
||||||
|
|
||||||
// get user avatar
|
|
||||||
let avatarUrl = $(".orion-c-avatar__image").attr("src");
|
|
||||||
|
|
||||||
//post message
|
|
||||||
window.chrome.webview.postMessage({
|
|
||||||
action: 'webview_rsi_login_success', data: {
|
|
||||||
'webToken': $.cookie('Rsi-Token'),
|
|
||||||
'claims': claimsData,
|
|
||||||
'authToken': TokenData,
|
|
||||||
'releaseInfo': releaseDataJson,
|
|
||||||
"avatar": avatarUrl,
|
|
||||||
'libraryData': libraryData,
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
// check if logged in and fix redirect
|
||||||
|
if (window.location.href.endsWith('/connect?jumpto=/account/dashboard')) {
|
||||||
|
if (document.body.textContent.trim() === "/account/dashboard") {
|
||||||
|
window.location.href = "https://robertsspaceindustries.com/account/dashboard";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for jQuery to be ready
|
||||||
|
let waitCount = 0;
|
||||||
|
while (typeof $ === 'undefined' && waitCount < 50) {
|
||||||
|
console.log('[SCToolbox] Waiting for jQuery... attempt', waitCount);
|
||||||
|
await new Promise(r => setTimeout(r, 100));
|
||||||
|
waitCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof $ === 'undefined') {
|
||||||
|
console.error('[SCToolbox] jQuery not available after waiting');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get RSI token from cookie (don't rely on $.cookie plugin)
|
||||||
|
function getCookie(name) {
|
||||||
|
const value = `; ${document.cookie}`;
|
||||||
|
const parts = value.split(`; ${name}=`);
|
||||||
|
if (parts.length === 2) return parts.pop().split(';').shift();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rsiToken = getCookie('Rsi-Token');
|
||||||
|
console.log('[SCToolbox] RSI Token available:', !!rsiToken);
|
||||||
|
|
||||||
|
if (!rsiToken) {
|
||||||
|
console.log('[SCToolbox] No RSI token, showing login window');
|
||||||
|
let loginBodyElement = $(".c-form authenticationForm sign_in");
|
||||||
|
loginBodyElement.show();
|
||||||
|
window.ipc.postMessage(JSON.stringify({ action: 'webview_rsi_login_show_window' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get claims
|
||||||
|
console.log('[SCToolbox] Fetching claims...');
|
||||||
|
let claimsR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/claims", {
|
||||||
|
method: 'POST', headers: {
|
||||||
|
'x-rsi-token': rsiToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[SCToolbox] Claims response status:', claimsR.status);
|
||||||
|
if (claimsR.status !== 200) {
|
||||||
|
console.error('[SCToolbox] Claims request failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCTShowToast("登录游戏中...");
|
||||||
|
|
||||||
|
let claimsData = (await claimsR.json())["data"];
|
||||||
|
console.log('[SCToolbox] Claims data received');
|
||||||
|
|
||||||
|
let tokenFormData = new FormData();
|
||||||
|
tokenFormData.append('claims', claimsData);
|
||||||
|
tokenFormData.append('gameId', 'SC');
|
||||||
|
let tokenR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/token", {
|
||||||
|
method: 'POST', headers: {
|
||||||
|
'x-rsi-token': rsiToken,
|
||||||
|
},
|
||||||
|
body: tokenFormData
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[SCToolbox] Token response status:', tokenR.status);
|
||||||
|
if (tokenR.status !== 200) {
|
||||||
|
console.error('[SCToolbox] Token request failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let TokenData = (await tokenR.json())["data"]["token"];
|
||||||
|
console.log('[SCToolbox] Token received');
|
||||||
|
|
||||||
|
// get release Data
|
||||||
|
let releaseFormData = new FormData();
|
||||||
|
releaseFormData.append("channelId", channelId);
|
||||||
|
releaseFormData.append("claims", claimsData);
|
||||||
|
releaseFormData.append("gameId", "SC");
|
||||||
|
releaseFormData.append("platformId", "prod");
|
||||||
|
let releaseR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/release", {
|
||||||
|
method: 'POST', headers: {
|
||||||
|
'x-rsi-token': rsiToken,
|
||||||
|
},
|
||||||
|
body: releaseFormData
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[SCToolbox] Release response status:', releaseR.status);
|
||||||
|
if (releaseR.status !== 200) {
|
||||||
|
console.error('[SCToolbox] Release request failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let releaseDataJson = (await releaseR.json())['data'];
|
||||||
|
console.log('[SCToolbox] Release data received');
|
||||||
|
|
||||||
|
// get game library
|
||||||
|
let libraryR = await fetch("https://robertsspaceindustries.com/api/launcher/v3/games/library", {
|
||||||
|
method: 'POST', headers: {
|
||||||
|
'x-rsi-token': rsiToken,
|
||||||
|
},
|
||||||
|
body: releaseFormData
|
||||||
|
});
|
||||||
|
|
||||||
|
let libraryData = (await libraryR.json())["data"];
|
||||||
|
console.log('[SCToolbox] Library data received');
|
||||||
|
|
||||||
|
// get user avatar
|
||||||
|
let avatarUrl = $(".orion-c-avatar__image").attr("src") || '';
|
||||||
|
console.log('[SCToolbox] Avatar URL:', avatarUrl);
|
||||||
|
|
||||||
|
//post message
|
||||||
|
console.log('[SCToolbox] Sending login success message...');
|
||||||
|
window.ipc.postMessage(JSON.stringify({
|
||||||
|
action: 'webview_rsi_login_success', data: {
|
||||||
|
'webToken': rsiToken,
|
||||||
|
'claims': claimsData,
|
||||||
|
'authToken': TokenData,
|
||||||
|
'releaseInfo': releaseDataJson,
|
||||||
|
"avatar": avatarUrl,
|
||||||
|
'libraryData': libraryData,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
console.log('[SCToolbox] Login success message sent');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[SCToolbox] Error in getRSILauncherToken:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function SCTShowToast(message) {
|
function SCTShowToast(message) {
|
||||||
let m = document.createElement('div');
|
let m = document.createElement('div');
|
||||||
m.innerHTML = message;
|
m.innerHTML = message;
|
||||||
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
|
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 9.375rem;padding:0 0.875rem;height: 2.5rem;color: rgb(255, 255, 255);line-height: 2.5rem;text-align: center;border-radius: 0.25rem;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 1rem;";
|
||||||
document.body.appendChild(m);
|
document.body.appendChild(m);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
let d = 0.5;
|
let d = 0.5;
|
||||||
|
|||||||
142
lib/common/rust/api/webview_api.dart
Normal file
142
lib/common/rust/api/webview_api.dart
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.11.1.
|
||||||
|
|
||||||
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||||
|
|
||||||
|
import '../frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
|
||||||
|
part 'webview_api.freezed.dart';
|
||||||
|
|
||||||
|
// These functions are ignored because they are not marked as `pub`: `handle_command`, `load_app_icon`, `run_webview_loop`, `send_command`
|
||||||
|
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `UserEvent`, `WebViewCommand`, `WebViewInstance`
|
||||||
|
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`
|
||||||
|
|
||||||
|
/// Create a new WebView window and return its ID
|
||||||
|
String webviewCreate({required WebViewConfiguration config}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewCreate(config: config);
|
||||||
|
|
||||||
|
/// Navigate to a URL
|
||||||
|
void webviewNavigate({required String id, required String url}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewNavigate(id: id, url: url);
|
||||||
|
|
||||||
|
/// Go back in history
|
||||||
|
void webviewGoBack({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewGoBack(id: id);
|
||||||
|
|
||||||
|
/// Go forward in history
|
||||||
|
void webviewGoForward({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewGoForward(id: id);
|
||||||
|
|
||||||
|
/// Reload the current page
|
||||||
|
void webviewReload({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewReload(id: id);
|
||||||
|
|
||||||
|
/// Stop loading
|
||||||
|
void webviewStop({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewStop(id: id);
|
||||||
|
|
||||||
|
/// Execute JavaScript in the WebView
|
||||||
|
void webviewExecuteScript({required String id, required String script}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewExecuteScript(
|
||||||
|
id: id,
|
||||||
|
script: script,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Set window visibility
|
||||||
|
void webviewSetVisibility({required String id, required bool visible}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewSetVisibility(
|
||||||
|
id: id,
|
||||||
|
visible: visible,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Close the WebView window
|
||||||
|
void webviewClose({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewClose(id: id);
|
||||||
|
|
||||||
|
/// Set window size
|
||||||
|
void webviewSetWindowSize({
|
||||||
|
required String id,
|
||||||
|
required int width,
|
||||||
|
required int height,
|
||||||
|
}) => RustLib.instance.api.crateApiWebviewApiWebviewSetWindowSize(
|
||||||
|
id: id,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Set window position
|
||||||
|
void webviewSetWindowPosition({
|
||||||
|
required String id,
|
||||||
|
required int x,
|
||||||
|
required int y,
|
||||||
|
}) => RustLib.instance.api.crateApiWebviewApiWebviewSetWindowPosition(
|
||||||
|
id: id,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Get the current navigation state
|
||||||
|
WebViewNavigationState webviewGetState({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewGetState(id: id);
|
||||||
|
|
||||||
|
/// Check if the WebView is closed
|
||||||
|
bool webviewIsClosed({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewIsClosed(id: id);
|
||||||
|
|
||||||
|
/// Poll for events from the WebView (non-blocking)
|
||||||
|
List<WebViewEvent> webviewPollEvents({required String id}) =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewPollEvents(id: id);
|
||||||
|
|
||||||
|
/// Get a list of all active WebView IDs
|
||||||
|
List<String> webviewListAll() =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebviewListAll();
|
||||||
|
|
||||||
|
/// WebView window configuration
|
||||||
|
@freezed
|
||||||
|
sealed class WebViewConfiguration with _$WebViewConfiguration {
|
||||||
|
const WebViewConfiguration._();
|
||||||
|
const factory WebViewConfiguration({
|
||||||
|
required String title,
|
||||||
|
required int width,
|
||||||
|
required int height,
|
||||||
|
String? userDataFolder,
|
||||||
|
required bool enableDevtools,
|
||||||
|
required bool transparent,
|
||||||
|
String? userAgent,
|
||||||
|
}) = _WebViewConfiguration;
|
||||||
|
static Future<WebViewConfiguration> default_() =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebViewConfigurationDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class WebViewEvent with _$WebViewEvent {
|
||||||
|
const WebViewEvent._();
|
||||||
|
|
||||||
|
const factory WebViewEvent.navigationStarted({required String url}) =
|
||||||
|
WebViewEvent_NavigationStarted;
|
||||||
|
const factory WebViewEvent.navigationCompleted({required String url}) =
|
||||||
|
WebViewEvent_NavigationCompleted;
|
||||||
|
const factory WebViewEvent.titleChanged({required String title}) =
|
||||||
|
WebViewEvent_TitleChanged;
|
||||||
|
const factory WebViewEvent.webMessage({required String message}) =
|
||||||
|
WebViewEvent_WebMessage;
|
||||||
|
const factory WebViewEvent.windowClosed() = WebViewEvent_WindowClosed;
|
||||||
|
const factory WebViewEvent.error({required String message}) =
|
||||||
|
WebViewEvent_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Navigation state of the WebView
|
||||||
|
@freezed
|
||||||
|
sealed class WebViewNavigationState with _$WebViewNavigationState {
|
||||||
|
const WebViewNavigationState._();
|
||||||
|
const factory WebViewNavigationState({
|
||||||
|
required String url,
|
||||||
|
required String title,
|
||||||
|
required bool canGoBack,
|
||||||
|
required bool canGoForward,
|
||||||
|
required bool isLoading,
|
||||||
|
}) = _WebViewNavigationState;
|
||||||
|
static Future<WebViewNavigationState> default_() =>
|
||||||
|
RustLib.instance.api.crateApiWebviewApiWebViewNavigationStateDefault();
|
||||||
|
}
|
||||||
1092
lib/common/rust/api/webview_api.freezed.dart
Normal file
1092
lib/common/rust/api/webview_api.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,7 @@
|
|||||||
import '../frb_generated.dart';
|
import '../frb_generated.dart';
|
||||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_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`, `fmt`
|
// 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`
|
||||||
|
|
||||||
Future<void> sendNotify({
|
Future<void> sendNotify({
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'api/http_api.dart';
|
|||||||
import 'api/ort_api.dart';
|
import 'api/ort_api.dart';
|
||||||
import 'api/rs_process.dart';
|
import 'api/rs_process.dart';
|
||||||
import 'api/unp4k_api.dart';
|
import 'api/unp4k_api.dart';
|
||||||
|
import 'api/webview_api.dart';
|
||||||
import 'api/win32_api.dart';
|
import 'api/win32_api.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@ -70,7 +71,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
|||||||
String get codegenVersion => '2.11.1';
|
String get codegenVersion => '2.11.1';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get rustContentHash => 1801517256;
|
int get rustContentHash => -1082688871;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig =
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
ExternalLibraryLoaderConfig(
|
ExternalLibraryLoaderConfig(
|
||||||
@ -175,6 +176,62 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
|
|
||||||
Future<void> crateApiOrtApiUnloadTranslationModel({required String modelKey});
|
Future<void> crateApiOrtApiUnloadTranslationModel({required String modelKey});
|
||||||
|
|
||||||
|
Future<WebViewConfiguration> crateApiWebviewApiWebViewConfigurationDefault();
|
||||||
|
|
||||||
|
Future<WebViewNavigationState>
|
||||||
|
crateApiWebviewApiWebViewNavigationStateDefault();
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewClose({required String id});
|
||||||
|
|
||||||
|
String crateApiWebviewApiWebviewCreate({
|
||||||
|
required WebViewConfiguration config,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewExecuteScript({
|
||||||
|
required String id,
|
||||||
|
required String script,
|
||||||
|
});
|
||||||
|
|
||||||
|
WebViewNavigationState crateApiWebviewApiWebviewGetState({
|
||||||
|
required String id,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewGoBack({required String id});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewGoForward({required String id});
|
||||||
|
|
||||||
|
bool crateApiWebviewApiWebviewIsClosed({required String id});
|
||||||
|
|
||||||
|
List<String> crateApiWebviewApiWebviewListAll();
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewNavigate({
|
||||||
|
required String id,
|
||||||
|
required String url,
|
||||||
|
});
|
||||||
|
|
||||||
|
List<WebViewEvent> crateApiWebviewApiWebviewPollEvents({required String id});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewReload({required String id});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewSetVisibility({
|
||||||
|
required String id,
|
||||||
|
required bool visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewSetWindowPosition({
|
||||||
|
required String id,
|
||||||
|
required int x,
|
||||||
|
required int y,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewSetWindowSize({
|
||||||
|
required String id,
|
||||||
|
required int width,
|
||||||
|
required int height,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiWebviewApiWebviewStop({required String id});
|
||||||
|
|
||||||
Future<void> crateApiRsProcessWrite({
|
Future<void> crateApiRsProcessWrite({
|
||||||
required int rsPid,
|
required int rsPid,
|
||||||
required String data,
|
required String data,
|
||||||
@ -893,6 +950,451 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
argNames: ["modelKey"],
|
argNames: ["modelKey"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WebViewConfiguration> crateApiWebviewApiWebViewConfigurationDefault() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__webview_api__web_view_configuration_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_web_view_configuration,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebViewConfigurationDefaultConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebViewConfigurationDefaultConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "web_view_configuration_default",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WebViewNavigationState>
|
||||||
|
crateApiWebviewApiWebViewNavigationStateDefault() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__webview_api__web_view_navigation_state_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_web_view_navigation_state,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebViewNavigationStateDefaultConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebViewNavigationStateDefaultConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "web_view_navigation_state_default",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewClose({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_close(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewCloseConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewCloseConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_close", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String crateApiWebviewApiWebviewCreate({
|
||||||
|
required WebViewConfiguration config,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_box_autoadd_web_view_configuration(config);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_create(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_String,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewCreateConstMeta,
|
||||||
|
argValues: [config],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewCreateConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_create", argNames: ["config"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewExecuteScript({
|
||||||
|
required String id,
|
||||||
|
required String script,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
var arg1 = cst_encode_String(script);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_execute_script(
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewExecuteScriptConstMeta,
|
||||||
|
argValues: [id, script],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewExecuteScriptConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "webview_execute_script",
|
||||||
|
argNames: ["id", "script"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebViewNavigationState crateApiWebviewApiWebviewGetState({
|
||||||
|
required String id,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_get_state(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_web_view_navigation_state,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewGetStateConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewGetStateConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_get_state", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewGoBack({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_go_back(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewGoBackConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewGoBackConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_go_back", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewGoForward({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_go_forward(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewGoForwardConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewGoForwardConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_go_forward", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool crateApiWebviewApiWebviewIsClosed({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_is_closed(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_bool,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewIsClosedConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewIsClosedConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_is_closed", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> crateApiWebviewApiWebviewListAll() {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
return wire.wire__crate__api__webview_api__webview_list_all();
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_list_String,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewListAllConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewListAllConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_list_all", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewNavigate({
|
||||||
|
required String id,
|
||||||
|
required String url,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
var arg1 = cst_encode_String(url);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_navigate(
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewNavigateConstMeta,
|
||||||
|
argValues: [id, url],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewNavigateConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "webview_navigate",
|
||||||
|
argNames: ["id", "url"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<WebViewEvent> crateApiWebviewApiWebviewPollEvents({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_poll_events(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_list_web_view_event,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewPollEventsConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewPollEventsConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_poll_events", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewReload({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_reload(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewReloadConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewReloadConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_reload", argNames: ["id"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewSetVisibility({
|
||||||
|
required String id,
|
||||||
|
required bool visible,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
var arg1 = cst_encode_bool(visible);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_set_visibility(
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewSetVisibilityConstMeta,
|
||||||
|
argValues: [id, visible],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewSetVisibilityConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "webview_set_visibility",
|
||||||
|
argNames: ["id", "visible"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewSetWindowPosition({
|
||||||
|
required String id,
|
||||||
|
required int x,
|
||||||
|
required int y,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
var arg1 = cst_encode_i_32(x);
|
||||||
|
var arg2 = cst_encode_i_32(y);
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__webview_api__webview_set_window_position(
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewSetWindowPositionConstMeta,
|
||||||
|
argValues: [id, x, y],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewSetWindowPositionConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "webview_set_window_position",
|
||||||
|
argNames: ["id", "x", "y"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewSetWindowSize({
|
||||||
|
required String id,
|
||||||
|
required int width,
|
||||||
|
required int height,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
var arg1 = cst_encode_u_32(width);
|
||||||
|
var arg2 = cst_encode_u_32(height);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_set_window_size(
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewSetWindowSizeConstMeta,
|
||||||
|
argValues: [id, width, height],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewSetWindowSizeConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "webview_set_window_size",
|
||||||
|
argNames: ["id", "width", "height"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiWebviewApiWebviewStop({required String id}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(id);
|
||||||
|
return wire.wire__crate__api__webview_api__webview_stop(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_String,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiWebviewApiWebviewStopConstMeta,
|
||||||
|
argValues: [id],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiWebviewApiWebviewStopConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "webview_stop", argNames: ["id"]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> crateApiRsProcessWrite({
|
Future<void> crateApiRsProcessWrite({
|
||||||
required int rsPid,
|
required int rsPid,
|
||||||
@ -974,6 +1476,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return dco_decode_u_64(raw);
|
return dco_decode_u_64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration dco_decode_box_autoadd_web_view_configuration(
|
||||||
|
dynamic raw,
|
||||||
|
) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return dco_decode_web_view_configuration(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw) {
|
int dco_decode_i_32(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -1022,6 +1532,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return (raw as List<dynamic>).map(dco_decode_record_string_string).toList();
|
return (raw as List<dynamic>).map(dco_decode_record_string_string).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<WebViewEvent> dco_decode_list_web_view_event(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return (raw as List<dynamic>).map(dco_decode_web_view_event).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MyHttpVersion dco_decode_my_http_version(dynamic raw) {
|
MyHttpVersion dco_decode_my_http_version(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -1187,6 +1703,59 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return dcoDecodeU64(raw);
|
return dcoDecodeU64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration dco_decode_web_view_configuration(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 7)
|
||||||
|
throw Exception('unexpected arr length: expect 7 but see ${arr.length}');
|
||||||
|
return WebViewConfiguration(
|
||||||
|
title: dco_decode_String(arr[0]),
|
||||||
|
width: dco_decode_u_32(arr[1]),
|
||||||
|
height: dco_decode_u_32(arr[2]),
|
||||||
|
userDataFolder: dco_decode_opt_String(arr[3]),
|
||||||
|
enableDevtools: dco_decode_bool(arr[4]),
|
||||||
|
transparent: dco_decode_bool(arr[5]),
|
||||||
|
userAgent: dco_decode_opt_String(arr[6]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewEvent dco_decode_web_view_event(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
switch (raw[0]) {
|
||||||
|
case 0:
|
||||||
|
return WebViewEvent_NavigationStarted(url: dco_decode_String(raw[1]));
|
||||||
|
case 1:
|
||||||
|
return WebViewEvent_NavigationCompleted(url: dco_decode_String(raw[1]));
|
||||||
|
case 2:
|
||||||
|
return WebViewEvent_TitleChanged(title: dco_decode_String(raw[1]));
|
||||||
|
case 3:
|
||||||
|
return WebViewEvent_WebMessage(message: dco_decode_String(raw[1]));
|
||||||
|
case 4:
|
||||||
|
return WebViewEvent_WindowClosed();
|
||||||
|
case 5:
|
||||||
|
return WebViewEvent_Error(message: dco_decode_String(raw[1]));
|
||||||
|
default:
|
||||||
|
throw Exception("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewNavigationState dco_decode_web_view_navigation_state(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 5)
|
||||||
|
throw Exception('unexpected arr length: expect 5 but see ${arr.length}');
|
||||||
|
return WebViewNavigationState(
|
||||||
|
url: dco_decode_String(arr[0]),
|
||||||
|
title: dco_decode_String(arr[1]),
|
||||||
|
canGoBack: dco_decode_bool(arr[2]),
|
||||||
|
canGoForward: dco_decode_bool(arr[3]),
|
||||||
|
isLoading: dco_decode_bool(arr[4]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) {
|
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -1245,6 +1814,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return (sse_decode_u_64(deserializer));
|
return (sse_decode_u_64(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration sse_decode_box_autoadd_web_view_configuration(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return (sse_decode_web_view_configuration(deserializer));
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer) {
|
int sse_decode_i_32(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -1323,6 +1900,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return ans_;
|
return ans_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<WebViewEvent> sse_decode_list_web_view_event(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
var ans_ = <WebViewEvent>[];
|
||||||
|
for (var idx_ = 0; idx_ < len_; ++idx_) {
|
||||||
|
ans_.add(sse_decode_web_view_event(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MyHttpVersion sse_decode_my_http_version(SseDeserializer deserializer) {
|
MyHttpVersion sse_decode_my_http_version(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -1525,6 +2116,76 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return deserializer.buffer.getBigUint64();
|
return deserializer.buffer.getBigUint64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration sse_decode_web_view_configuration(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_title = sse_decode_String(deserializer);
|
||||||
|
var var_width = sse_decode_u_32(deserializer);
|
||||||
|
var var_height = sse_decode_u_32(deserializer);
|
||||||
|
var var_userDataFolder = sse_decode_opt_String(deserializer);
|
||||||
|
var var_enableDevtools = sse_decode_bool(deserializer);
|
||||||
|
var var_transparent = sse_decode_bool(deserializer);
|
||||||
|
var var_userAgent = sse_decode_opt_String(deserializer);
|
||||||
|
return WebViewConfiguration(
|
||||||
|
title: var_title,
|
||||||
|
width: var_width,
|
||||||
|
height: var_height,
|
||||||
|
userDataFolder: var_userDataFolder,
|
||||||
|
enableDevtools: var_enableDevtools,
|
||||||
|
transparent: var_transparent,
|
||||||
|
userAgent: var_userAgent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewEvent sse_decode_web_view_event(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
var tag_ = sse_decode_i_32(deserializer);
|
||||||
|
switch (tag_) {
|
||||||
|
case 0:
|
||||||
|
var var_url = sse_decode_String(deserializer);
|
||||||
|
return WebViewEvent_NavigationStarted(url: var_url);
|
||||||
|
case 1:
|
||||||
|
var var_url = sse_decode_String(deserializer);
|
||||||
|
return WebViewEvent_NavigationCompleted(url: var_url);
|
||||||
|
case 2:
|
||||||
|
var var_title = sse_decode_String(deserializer);
|
||||||
|
return WebViewEvent_TitleChanged(title: var_title);
|
||||||
|
case 3:
|
||||||
|
var var_message = sse_decode_String(deserializer);
|
||||||
|
return WebViewEvent_WebMessage(message: var_message);
|
||||||
|
case 4:
|
||||||
|
return WebViewEvent_WindowClosed();
|
||||||
|
case 5:
|
||||||
|
var var_message = sse_decode_String(deserializer);
|
||||||
|
return WebViewEvent_Error(message: var_message);
|
||||||
|
default:
|
||||||
|
throw UnimplementedError('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewNavigationState sse_decode_web_view_navigation_state(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_url = sse_decode_String(deserializer);
|
||||||
|
var var_title = sse_decode_String(deserializer);
|
||||||
|
var var_canGoBack = sse_decode_bool(deserializer);
|
||||||
|
var var_canGoForward = sse_decode_bool(deserializer);
|
||||||
|
var var_isLoading = sse_decode_bool(deserializer);
|
||||||
|
return WebViewNavigationState(
|
||||||
|
url: var_url,
|
||||||
|
title: var_title,
|
||||||
|
canGoBack: var_canGoBack,
|
||||||
|
canGoForward: var_canGoForward,
|
||||||
|
isLoading: var_isLoading,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
bool cst_encode_bool(bool raw) {
|
bool cst_encode_bool(bool raw) {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
@ -1650,6 +2311,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
sse_encode_u_64(self, serializer);
|
sse_encode_u_64(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_web_view_configuration(
|
||||||
|
WebViewConfiguration self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_web_view_configuration(self, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer) {
|
void sse_encode_i_32(int self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -1729,6 +2399,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_web_view_event(
|
||||||
|
List<WebViewEvent> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
for (final item in self) {
|
||||||
|
sse_encode_web_view_event(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_my_http_version(
|
void sse_encode_my_http_version(
|
||||||
MyHttpVersion self,
|
MyHttpVersion self,
|
||||||
@ -1908,4 +2590,56 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
serializer.buffer.putBigUint64(self);
|
serializer.buffer.putBigUint64(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_configuration(
|
||||||
|
WebViewConfiguration self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_String(self.title, serializer);
|
||||||
|
sse_encode_u_32(self.width, serializer);
|
||||||
|
sse_encode_u_32(self.height, serializer);
|
||||||
|
sse_encode_opt_String(self.userDataFolder, serializer);
|
||||||
|
sse_encode_bool(self.enableDevtools, serializer);
|
||||||
|
sse_encode_bool(self.transparent, serializer);
|
||||||
|
sse_encode_opt_String(self.userAgent, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_event(WebViewEvent self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
switch (self) {
|
||||||
|
case WebViewEvent_NavigationStarted(url: final url):
|
||||||
|
sse_encode_i_32(0, serializer);
|
||||||
|
sse_encode_String(url, serializer);
|
||||||
|
case WebViewEvent_NavigationCompleted(url: final url):
|
||||||
|
sse_encode_i_32(1, serializer);
|
||||||
|
sse_encode_String(url, serializer);
|
||||||
|
case WebViewEvent_TitleChanged(title: final title):
|
||||||
|
sse_encode_i_32(2, serializer);
|
||||||
|
sse_encode_String(title, serializer);
|
||||||
|
case WebViewEvent_WebMessage(message: final message):
|
||||||
|
sse_encode_i_32(3, serializer);
|
||||||
|
sse_encode_String(message, serializer);
|
||||||
|
case WebViewEvent_WindowClosed():
|
||||||
|
sse_encode_i_32(4, serializer);
|
||||||
|
case WebViewEvent_Error(message: final message):
|
||||||
|
sse_encode_i_32(5, serializer);
|
||||||
|
sse_encode_String(message, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_navigation_state(
|
||||||
|
WebViewNavigationState self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_String(self.url, serializer);
|
||||||
|
sse_encode_String(self.title, serializer);
|
||||||
|
sse_encode_bool(self.canGoBack, serializer);
|
||||||
|
sse_encode_bool(self.canGoForward, serializer);
|
||||||
|
sse_encode_bool(self.isLoading, serializer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'api/http_api.dart';
|
|||||||
import 'api/ort_api.dart';
|
import 'api/ort_api.dart';
|
||||||
import 'api/rs_process.dart';
|
import 'api/rs_process.dart';
|
||||||
import 'api/unp4k_api.dart';
|
import 'api/unp4k_api.dart';
|
||||||
|
import 'api/webview_api.dart';
|
||||||
import 'api/win32_api.dart';
|
import 'api/win32_api.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@ -51,6 +52,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt dco_decode_box_autoadd_u_64(dynamic raw);
|
BigInt dco_decode_box_autoadd_u_64(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration dco_decode_box_autoadd_web_view_configuration(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw);
|
int dco_decode_i_32(dynamic raw);
|
||||||
|
|
||||||
@ -75,6 +81,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
List<(String, String)> dco_decode_list_record_string_string(dynamic raw);
|
List<(String, String)> dco_decode_list_record_string_string(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<WebViewEvent> dco_decode_list_web_view_event(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MyHttpVersion dco_decode_my_http_version(dynamic raw);
|
MyHttpVersion dco_decode_my_http_version(dynamic raw);
|
||||||
|
|
||||||
@ -135,6 +144,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt dco_decode_usize(dynamic raw);
|
BigInt dco_decode_usize(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration dco_decode_web_view_configuration(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewEvent dco_decode_web_view_event(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewNavigationState dco_decode_web_view_navigation_state(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
|
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -166,6 +184,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
|
BigInt sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration sse_decode_box_autoadd_web_view_configuration(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer);
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -194,6 +217,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<WebViewEvent> sse_decode_list_web_view_event(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
MyHttpVersion sse_decode_my_http_version(SseDeserializer deserializer);
|
MyHttpVersion sse_decode_my_http_version(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -264,6 +292,19 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt sse_decode_usize(SseDeserializer deserializer);
|
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewConfiguration sse_decode_web_view_configuration(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewEvent sse_decode_web_view_event(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
WebViewNavigationState sse_decode_web_view_navigation_state(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_encode_AnyhowException(
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_encode_AnyhowException(
|
||||||
AnyhowException raw,
|
AnyhowException raw,
|
||||||
@ -324,6 +365,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return wire.cst_new_box_autoadd_u_64(cst_encode_u_64(raw));
|
return wire.cst_new_box_autoadd_u_64(cst_encode_u_64(raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration>
|
||||||
|
cst_encode_box_autoadd_web_view_configuration(WebViewConfiguration raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
final ptr = wire.cst_new_box_autoadd_web_view_configuration();
|
||||||
|
cst_api_fill_to_wire_web_view_configuration(raw, ptr.ref);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int cst_encode_i_64(PlatformInt64 raw) {
|
int cst_encode_i_64(PlatformInt64 raw) {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
@ -395,6 +445,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_list_web_view_event> cst_encode_list_web_view_event(
|
||||||
|
List<WebViewEvent> raw,
|
||||||
|
) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
final ans = wire.cst_new_list_web_view_event(raw.length);
|
||||||
|
for (var i = 0; i < raw.length; ++i) {
|
||||||
|
cst_api_fill_to_wire_web_view_event(raw[i], ans.ref.ptr[i]);
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_list_record_string_string>
|
ffi.Pointer<wire_cst_list_record_string_string>
|
||||||
cst_encode_opt_Map_String_String_None(Map<String, String>? raw) {
|
cst_encode_opt_Map_String_String_None(Map<String, String>? raw) {
|
||||||
@ -449,6 +511,14 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
cst_api_fill_to_wire_rsi_launcher_asar_data(apiObj, wireObj.ref);
|
cst_api_fill_to_wire_rsi_launcher_asar_data(apiObj, wireObj.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_box_autoadd_web_view_configuration(
|
||||||
|
WebViewConfiguration apiObj,
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration> wireObj,
|
||||||
|
) {
|
||||||
|
cst_api_fill_to_wire_web_view_configuration(apiObj, wireObj.ref);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_p_4_k_file_item(
|
void cst_api_fill_to_wire_p_4_k_file_item(
|
||||||
P4kFileItem apiObj,
|
P4kFileItem apiObj,
|
||||||
@ -518,6 +588,73 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
wireObj.data = cst_encode_opt_list_prim_u_8_strict(apiObj.data);
|
wireObj.data = cst_encode_opt_list_prim_u_8_strict(apiObj.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_web_view_configuration(
|
||||||
|
WebViewConfiguration apiObj,
|
||||||
|
wire_cst_web_view_configuration wireObj,
|
||||||
|
) {
|
||||||
|
wireObj.title = cst_encode_String(apiObj.title);
|
||||||
|
wireObj.width = cst_encode_u_32(apiObj.width);
|
||||||
|
wireObj.height = cst_encode_u_32(apiObj.height);
|
||||||
|
wireObj.user_data_folder = cst_encode_opt_String(apiObj.userDataFolder);
|
||||||
|
wireObj.enable_devtools = cst_encode_bool(apiObj.enableDevtools);
|
||||||
|
wireObj.transparent = cst_encode_bool(apiObj.transparent);
|
||||||
|
wireObj.user_agent = cst_encode_opt_String(apiObj.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_web_view_event(
|
||||||
|
WebViewEvent apiObj,
|
||||||
|
wire_cst_web_view_event wireObj,
|
||||||
|
) {
|
||||||
|
if (apiObj is WebViewEvent_NavigationStarted) {
|
||||||
|
var pre_url = cst_encode_String(apiObj.url);
|
||||||
|
wireObj.tag = 0;
|
||||||
|
wireObj.kind.NavigationStarted.url = pre_url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiObj is WebViewEvent_NavigationCompleted) {
|
||||||
|
var pre_url = cst_encode_String(apiObj.url);
|
||||||
|
wireObj.tag = 1;
|
||||||
|
wireObj.kind.NavigationCompleted.url = pre_url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiObj is WebViewEvent_TitleChanged) {
|
||||||
|
var pre_title = cst_encode_String(apiObj.title);
|
||||||
|
wireObj.tag = 2;
|
||||||
|
wireObj.kind.TitleChanged.title = pre_title;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiObj is WebViewEvent_WebMessage) {
|
||||||
|
var pre_message = cst_encode_String(apiObj.message);
|
||||||
|
wireObj.tag = 3;
|
||||||
|
wireObj.kind.WebMessage.message = pre_message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiObj is WebViewEvent_WindowClosed) {
|
||||||
|
wireObj.tag = 4;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiObj is WebViewEvent_Error) {
|
||||||
|
var pre_message = cst_encode_String(apiObj.message);
|
||||||
|
wireObj.tag = 5;
|
||||||
|
wireObj.kind.Error.message = pre_message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_web_view_navigation_state(
|
||||||
|
WebViewNavigationState apiObj,
|
||||||
|
wire_cst_web_view_navigation_state wireObj,
|
||||||
|
) {
|
||||||
|
wireObj.url = cst_encode_String(apiObj.url);
|
||||||
|
wireObj.title = cst_encode_String(apiObj.title);
|
||||||
|
wireObj.can_go_back = cst_encode_bool(apiObj.canGoBack);
|
||||||
|
wireObj.can_go_forward = cst_encode_bool(apiObj.canGoForward);
|
||||||
|
wireObj.is_loading = cst_encode_bool(apiObj.isLoading);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
bool cst_encode_bool(bool raw);
|
bool cst_encode_bool(bool raw);
|
||||||
|
|
||||||
@ -581,6 +718,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_u_64(BigInt self, SseSerializer serializer);
|
void sse_encode_box_autoadd_u_64(BigInt self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_web_view_configuration(
|
||||||
|
WebViewConfiguration self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer);
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
@ -617,6 +760,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_web_view_event(
|
||||||
|
List<WebViewEvent> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_my_http_version(MyHttpVersion self, SseSerializer serializer);
|
void sse_encode_my_http_version(MyHttpVersion self, SseSerializer serializer);
|
||||||
|
|
||||||
@ -697,6 +846,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_configuration(
|
||||||
|
WebViewConfiguration self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_event(WebViewEvent self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_web_view_navigation_state(
|
||||||
|
WebViewNavigationState self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section: wire_class
|
// Section: wire_class
|
||||||
@ -1368,6 +1532,416 @@ class RustLibWire implements BaseWire {
|
|||||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__webview_api__web_view_configuration_default(
|
||||||
|
int port_,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__web_view_configuration_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__web_view_configuration_defaultPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__web_view_configuration_default',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__web_view_configuration_default =
|
||||||
|
_wire__crate__api__webview_api__web_view_configuration_defaultPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__webview_api__web_view_navigation_state_default(
|
||||||
|
int port_,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__web_view_navigation_state_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__web_view_navigation_state_defaultPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__web_view_navigation_state_default',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__web_view_navigation_state_default =
|
||||||
|
_wire__crate__api__webview_api__web_view_navigation_state_defaultPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_close(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_close(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_closePtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_close',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_close =
|
||||||
|
_wire__crate__api__webview_api__webview_closePtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_create(
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration> config,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_create(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_createPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_create',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_create =
|
||||||
|
_wire__crate__api__webview_api__webview_createPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_execute_script(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> script,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_execute_script(id, script);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_execute_scriptPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_execute_script',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_execute_script =
|
||||||
|
_wire__crate__api__webview_api__webview_execute_scriptPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_get_state(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_get_state(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_get_statePtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_get_state',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_get_state =
|
||||||
|
_wire__crate__api__webview_api__webview_get_statePtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_go_back(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_go_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_go_backPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_go_back',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_go_back =
|
||||||
|
_wire__crate__api__webview_api__webview_go_backPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_go_forward(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_go_forward(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_go_forwardPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_go_forward',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_go_forward =
|
||||||
|
_wire__crate__api__webview_api__webview_go_forwardPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_is_closed(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_is_closed(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_is_closedPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_is_closed',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_is_closed =
|
||||||
|
_wire__crate__api__webview_api__webview_is_closedPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_list_all() {
|
||||||
|
return _wire__crate__api__webview_api__webview_list_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_list_allPtr =
|
||||||
|
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function()>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_list_all',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_list_all =
|
||||||
|
_wire__crate__api__webview_api__webview_list_allPtr
|
||||||
|
.asFunction<WireSyncRust2DartDco Function()>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_navigate(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> url,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_navigate(id, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_navigatePtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_navigate',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_navigate =
|
||||||
|
_wire__crate__api__webview_api__webview_navigatePtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_poll_events(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_poll_events(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_poll_eventsPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_poll_events',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_poll_events =
|
||||||
|
_wire__crate__api__webview_api__webview_poll_eventsPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_reload(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_reload(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_reloadPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_reload',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_reload =
|
||||||
|
_wire__crate__api__webview_api__webview_reloadPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_set_visibility(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
bool visible,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_set_visibility(id, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_visibilityPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Bool,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_set_visibility',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_visibility =
|
||||||
|
_wire__crate__api__webview_api__webview_set_visibilityPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
bool,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco
|
||||||
|
wire__crate__api__webview_api__webview_set_window_position(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_set_window_position(
|
||||||
|
id,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_window_positionPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Int32,
|
||||||
|
ffi.Int32,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_set_window_position',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_window_position =
|
||||||
|
_wire__crate__api__webview_api__webview_set_window_positionPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_set_window_size(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_set_window_size(
|
||||||
|
id,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_window_sizePtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Uint32,
|
||||||
|
ffi.Uint32,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_set_window_size',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_set_window_size =
|
||||||
|
_wire__crate__api__webview_api__webview_set_window_sizePtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__webview_api__webview_stop(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__webview_api__webview_stop(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__webview_api__webview_stopPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__webview_api__webview_stop',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__webview_api__webview_stop =
|
||||||
|
_wire__crate__api__webview_api__webview_stopPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
void wire__crate__api__rs_process__write(
|
void wire__crate__api__rs_process__write(
|
||||||
int port_,
|
int port_,
|
||||||
int rs_pid,
|
int rs_pid,
|
||||||
@ -1431,6 +2005,23 @@ class RustLibWire implements BaseWire {
|
|||||||
late final _cst_new_box_autoadd_u_64 = _cst_new_box_autoadd_u_64Ptr
|
late final _cst_new_box_autoadd_u_64 = _cst_new_box_autoadd_u_64Ptr
|
||||||
.asFunction<ffi.Pointer<ffi.Uint64> Function(int)>();
|
.asFunction<ffi.Pointer<ffi.Uint64> Function(int)>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration>
|
||||||
|
cst_new_box_autoadd_web_view_configuration() {
|
||||||
|
return _cst_new_box_autoadd_web_view_configuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _cst_new_box_autoadd_web_view_configurationPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration> Function()
|
||||||
|
>
|
||||||
|
>('frbgen_starcitizen_doctor_cst_new_box_autoadd_web_view_configuration');
|
||||||
|
late final _cst_new_box_autoadd_web_view_configuration =
|
||||||
|
_cst_new_box_autoadd_web_view_configurationPtr
|
||||||
|
.asFunction<
|
||||||
|
ffi.Pointer<wire_cst_web_view_configuration> Function()
|
||||||
|
>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_list_String> cst_new_list_String(int len) {
|
ffi.Pointer<wire_cst_list_String> cst_new_list_String(int len) {
|
||||||
return _cst_new_list_String(len);
|
return _cst_new_list_String(len);
|
||||||
}
|
}
|
||||||
@ -1519,6 +2110,21 @@ class RustLibWire implements BaseWire {
|
|||||||
ffi.Pointer<wire_cst_list_record_string_string> Function(int)
|
ffi.Pointer<wire_cst_list_record_string_string> Function(int)
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_list_web_view_event> cst_new_list_web_view_event(
|
||||||
|
int len,
|
||||||
|
) {
|
||||||
|
return _cst_new_list_web_view_event(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _cst_new_list_web_view_eventPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Pointer<wire_cst_list_web_view_event> Function(ffi.Int32)
|
||||||
|
>
|
||||||
|
>('frbgen_starcitizen_doctor_cst_new_list_web_view_event');
|
||||||
|
late final _cst_new_list_web_view_event = _cst_new_list_web_view_eventPtr
|
||||||
|
.asFunction<ffi.Pointer<wire_cst_list_web_view_event> Function(int)>();
|
||||||
|
|
||||||
int dummy_method_to_enforce_bundling() {
|
int dummy_method_to_enforce_bundling() {
|
||||||
return _dummy_method_to_enforce_bundling();
|
return _dummy_method_to_enforce_bundling();
|
||||||
}
|
}
|
||||||
@ -1582,6 +2188,26 @@ final class wire_cst_list_prim_u_8_loose extends ffi.Struct {
|
|||||||
external int len;
|
external int len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_web_view_configuration extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> title;
|
||||||
|
|
||||||
|
@ffi.Uint32()
|
||||||
|
external int width;
|
||||||
|
|
||||||
|
@ffi.Uint32()
|
||||||
|
external int height;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> user_data_folder;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool enable_devtools;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool transparent;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_p_4_k_file_item extends ffi.Struct {
|
final class wire_cst_p_4_k_file_item extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> name;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> name;
|
||||||
|
|
||||||
@ -1621,6 +2247,52 @@ final class wire_cst_list_process_info extends ffi.Struct {
|
|||||||
external int len;
|
external int len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_WebViewEvent_NavigationStarted extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> url;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_WebViewEvent_NavigationCompleted extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> url;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_WebViewEvent_TitleChanged extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> title;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_WebViewEvent_WebMessage extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> message;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_WebViewEvent_Error extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> message;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class WebViewEventKind extends ffi.Union {
|
||||||
|
external wire_cst_WebViewEvent_NavigationStarted NavigationStarted;
|
||||||
|
|
||||||
|
external wire_cst_WebViewEvent_NavigationCompleted NavigationCompleted;
|
||||||
|
|
||||||
|
external wire_cst_WebViewEvent_TitleChanged TitleChanged;
|
||||||
|
|
||||||
|
external wire_cst_WebViewEvent_WebMessage WebMessage;
|
||||||
|
|
||||||
|
external wire_cst_WebViewEvent_Error Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_web_view_event extends ffi.Struct {
|
||||||
|
@ffi.Int32()
|
||||||
|
external int tag;
|
||||||
|
|
||||||
|
external WebViewEventKind kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_list_web_view_event extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_web_view_event> ptr;
|
||||||
|
|
||||||
|
@ffi.Int32()
|
||||||
|
external int len;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_rs_process_stream_data extends ffi.Struct {
|
final class wire_cst_rs_process_stream_data extends ffi.Struct {
|
||||||
@ffi.Int32()
|
@ffi.Int32()
|
||||||
external int data_type;
|
external int data_type;
|
||||||
@ -1648,3 +2320,18 @@ final class wire_cst_rust_http_response extends ffi.Struct {
|
|||||||
|
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> data;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_web_view_navigation_state extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> url;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> title;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool can_go_back;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool can_go_forward;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool is_loading;
|
||||||
|
}
|
||||||
|
|||||||
350
lib/common/rust/rust_webview_controller.dart
Normal file
350
lib/common/rust/rust_webview_controller.dart
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
// Rust WebView 管理器
|
||||||
|
// 使用 wry + tao 实现的 WebView 窗口管理
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/api/webview_api.dart'
|
||||||
|
as rust_webview;
|
||||||
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
|
|
||||||
|
typedef OnWebMessageCallback = void Function(String message);
|
||||||
|
typedef OnNavigationCallback = void Function(String url);
|
||||||
|
typedef OnNavigationCompletedCallback = void Function(String url);
|
||||||
|
typedef OnWindowClosedCallback = void Function();
|
||||||
|
|
||||||
|
/// Rust WebView 控制器
|
||||||
|
/// 封装 Rust wry + tao WebView 的业务逻辑
|
||||||
|
class RustWebViewController {
|
||||||
|
final String id;
|
||||||
|
final List<OnWebMessageCallback> _messageCallbacks = [];
|
||||||
|
final List<OnNavigationCallback> _navigationCallbacks = [];
|
||||||
|
final List<OnNavigationCompletedCallback> _navigationCompletedCallbacks = [];
|
||||||
|
final List<OnWindowClosedCallback> _closeCallbacks = [];
|
||||||
|
|
||||||
|
Timer? _pollTimer;
|
||||||
|
bool _isDisposed = false;
|
||||||
|
|
||||||
|
/// 本地化脚本(从 assets 加载)
|
||||||
|
String _localizationScript = "";
|
||||||
|
|
||||||
|
/// 请求拦截器脚本
|
||||||
|
String _requestInterceptorScript = "";
|
||||||
|
|
||||||
|
/// 当前 URL
|
||||||
|
String _currentUrl = "";
|
||||||
|
String get currentUrl => _currentUrl;
|
||||||
|
|
||||||
|
RustWebViewController._(this.id);
|
||||||
|
|
||||||
|
/// 创建新的 WebView 窗口
|
||||||
|
static Future<RustWebViewController> create({
|
||||||
|
String title = "WebView",
|
||||||
|
int width = 1280,
|
||||||
|
int height = 720,
|
||||||
|
String? userDataFolder,
|
||||||
|
bool enableDevtools = false,
|
||||||
|
bool transparent = false,
|
||||||
|
String? userAgent,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final config = rust_webview.WebViewConfiguration(
|
||||||
|
title: title,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
userDataFolder: userDataFolder,
|
||||||
|
enableDevtools: enableDevtools,
|
||||||
|
transparent: transparent,
|
||||||
|
userAgent: userAgent,
|
||||||
|
);
|
||||||
|
|
||||||
|
final id = rust_webview.webviewCreate(config: config);
|
||||||
|
final controller = RustWebViewController._(id);
|
||||||
|
|
||||||
|
// 加载脚本资源
|
||||||
|
await controller._loadScripts();
|
||||||
|
|
||||||
|
// 启动事件轮询
|
||||||
|
controller._startEventPolling();
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception("Failed to create WebView: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 加载本地化和拦截器脚本
|
||||||
|
Future<void> _loadScripts() async {
|
||||||
|
try {
|
||||||
|
_localizationScript = await rootBundle.loadString('assets/web_script.js');
|
||||||
|
_requestInterceptorScript = await rootBundle.loadString(
|
||||||
|
'assets/request_interceptor.js',
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
dPrint("Failed to load scripts: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 启动事件轮询
|
||||||
|
void _startEventPolling() {
|
||||||
|
_pollTimer = Timer.periodic(const Duration(milliseconds: 50), (_) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
_pollEvents();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 轮询事件
|
||||||
|
void _pollEvents() {
|
||||||
|
try {
|
||||||
|
final events = rust_webview.webviewPollEvents(id: id);
|
||||||
|
for (final event in events) {
|
||||||
|
_handleEvent(event);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// WebView 可能已关闭
|
||||||
|
if (!_isDisposed) {
|
||||||
|
dPrint("Error polling events: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 处理事件
|
||||||
|
void _handleEvent(rust_webview.WebViewEvent event) {
|
||||||
|
switch (event) {
|
||||||
|
case rust_webview.WebViewEvent_NavigationStarted(:final url):
|
||||||
|
dPrint("Navigation started: $url");
|
||||||
|
_currentUrl = url;
|
||||||
|
// 导航开始时通知
|
||||||
|
for (final callback in _navigationCallbacks) {
|
||||||
|
callback(url);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rust_webview.WebViewEvent_NavigationCompleted(:final url):
|
||||||
|
dPrint("Navigation completed: $url");
|
||||||
|
_currentUrl = url;
|
||||||
|
// 注入请求拦截器
|
||||||
|
if (_requestInterceptorScript.isNotEmpty) {
|
||||||
|
executeScript(_requestInterceptorScript);
|
||||||
|
}
|
||||||
|
// 导航完成回调(用于注入脚本)
|
||||||
|
for (final callback in _navigationCompletedCallbacks) {
|
||||||
|
callback(url);
|
||||||
|
}
|
||||||
|
for (final callback in _navigationCallbacks) {
|
||||||
|
callback(url);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rust_webview.WebViewEvent_TitleChanged(:final title):
|
||||||
|
dPrint("Title changed: $title");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rust_webview.WebViewEvent_WebMessage(:final message):
|
||||||
|
_handleWebMessage(message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rust_webview.WebViewEvent_WindowClosed():
|
||||||
|
dPrint("Window closed");
|
||||||
|
for (final callback in _closeCallbacks) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
dispose();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rust_webview.WebViewEvent_Error(:final message):
|
||||||
|
dPrint("WebView error: $message");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 处理来自 WebView 的消息
|
||||||
|
void _handleWebMessage(String message) {
|
||||||
|
dPrint("Web message: $message");
|
||||||
|
try {
|
||||||
|
final data = json.decode(message);
|
||||||
|
final action = data["action"];
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case "navigation_state":
|
||||||
|
// 从 JS 获取导航状态更新
|
||||||
|
final url = data["url"] ?? "";
|
||||||
|
final isLoading = data["isLoading"] ?? false;
|
||||||
|
_currentUrl = url;
|
||||||
|
if (!isLoading) {
|
||||||
|
for (final callback in _navigationCallbacks) {
|
||||||
|
callback(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "close_window":
|
||||||
|
// 处理来自导航栏的关闭请求
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 转发其他消息给回调
|
||||||
|
for (final callback in _messageCallbacks) {
|
||||||
|
callback(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 非 JSON 消息,直接转发
|
||||||
|
for (final callback in _messageCallbacks) {
|
||||||
|
callback(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 导航到 URL
|
||||||
|
void navigate(String url) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
_currentUrl = url;
|
||||||
|
rust_webview.webviewNavigate(id: id, url: url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 后退
|
||||||
|
void goBack() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewGoBack(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 前进
|
||||||
|
void goForward() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewGoForward(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 刷新
|
||||||
|
void reload() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewReload(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 停止加载
|
||||||
|
void stop() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewStop(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 执行 JavaScript
|
||||||
|
void executeScript(String script) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewExecuteScript(id: id, script: script);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置窗口可见性
|
||||||
|
void setVisible(bool visible) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewSetVisibility(id: id, visible: visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 关闭窗口
|
||||||
|
void close() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewClose(id: id);
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置窗口大小
|
||||||
|
void setWindowSize(int width, int height) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewSetWindowSize(id: id, width: width, height: height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置窗口位置
|
||||||
|
void setWindowPosition(int x, int y) {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
rust_webview.webviewSetWindowPosition(id: id, x: x, y: y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取当前导航状态
|
||||||
|
rust_webview.WebViewNavigationState getState() {
|
||||||
|
return rust_webview.webviewGetState(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检查窗口是否已关闭
|
||||||
|
bool get isClosed {
|
||||||
|
if (_isDisposed) return true;
|
||||||
|
return rust_webview.webviewIsClosed(id: id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加消息回调
|
||||||
|
void addOnWebMessageCallback(OnWebMessageCallback callback) {
|
||||||
|
_messageCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 移除消息回调
|
||||||
|
void removeOnWebMessageCallback(OnWebMessageCallback callback) {
|
||||||
|
_messageCallbacks.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加导航回调
|
||||||
|
void addOnNavigationCallback(OnNavigationCallback callback) {
|
||||||
|
_navigationCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 移除导航回调
|
||||||
|
void removeOnNavigationCallback(OnNavigationCallback callback) {
|
||||||
|
_navigationCallbacks.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加导航完成回调(用于在页面加载完成后注入脚本)
|
||||||
|
void addOnNavigationCompletedCallback(
|
||||||
|
OnNavigationCompletedCallback callback,
|
||||||
|
) {
|
||||||
|
_navigationCompletedCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 移除导航完成回调
|
||||||
|
void removeOnNavigationCompletedCallback(
|
||||||
|
OnNavigationCompletedCallback callback,
|
||||||
|
) {
|
||||||
|
_navigationCompletedCallbacks.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加关闭回调
|
||||||
|
void addOnCloseCallback(OnWindowClosedCallback callback) {
|
||||||
|
_closeCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 移除关闭回调
|
||||||
|
void removeOnCloseCallback(OnWindowClosedCallback callback) {
|
||||||
|
_closeCallbacks.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 注入本地化脚本
|
||||||
|
void injectLocalizationScript() {
|
||||||
|
if (_localizationScript.isNotEmpty) {
|
||||||
|
executeScript(_localizationScript);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 初始化网页本地化
|
||||||
|
void initWebLocalization() {
|
||||||
|
executeScript("InitWebLocalization()");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 更新翻译词典
|
||||||
|
void updateReplaceWords(List<Map<String, String>> words, bool enableCapture) {
|
||||||
|
final jsonWords = json.encode(words);
|
||||||
|
executeScript(
|
||||||
|
"WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 执行 RSI 登录脚本
|
||||||
|
void executeRsiLogin(String channel) {
|
||||||
|
executeScript('getRSILauncherToken("$channel");');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 释放资源
|
||||||
|
void dispose() {
|
||||||
|
if (_isDisposed) return;
|
||||||
|
_isDisposed = true;
|
||||||
|
_pollTimer?.cancel();
|
||||||
|
_messageCallbacks.clear();
|
||||||
|
_navigationCallbacks.clear();
|
||||||
|
_navigationCompletedCallbacks.clear();
|
||||||
|
_closeCallbacks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@ -12,15 +11,6 @@ import 'app.dart';
|
|||||||
import 'common/utils/multi_window_manager.dart';
|
import 'common/utils/multi_window_manager.dart';
|
||||||
|
|
||||||
Future<void> main(List<String> args) async {
|
Future<void> main(List<String> args) async {
|
||||||
// webview window
|
|
||||||
if (runWebViewTitleBarWidget(
|
|
||||||
args,
|
|
||||||
backgroundColor: const Color.fromRGBO(19, 36, 49, 1),
|
|
||||||
builder: _defaultWebviewTitleBar,
|
|
||||||
)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
|
|
||||||
@ -133,33 +123,3 @@ class App extends HookConsumerWidget with WindowListener {
|
|||||||
super.onWindowClose();
|
super.onWindowClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _defaultWebviewTitleBar(BuildContext context) {
|
|
||||||
final state = TitleBarWebViewState.of(context);
|
|
||||||
final controller = TitleBarWebViewController.of(context);
|
|
||||||
return FluentTheme(
|
|
||||||
data: FluentThemeData.dark(),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
if (Platform.isMacOS) const SizedBox(width: 96),
|
|
||||||
IconButton(onPressed: !state.canGoBack ? null : controller.back, icon: const Icon(FluentIcons.chevron_left)),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
IconButton(
|
|
||||||
onPressed: !state.canGoForward ? null : controller.forward,
|
|
||||||
icon: const Icon(FluentIcons.chevron_right),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
if (state.isLoading)
|
|
||||||
IconButton(onPressed: controller.stop, icon: const Icon(FluentIcons.chrome_close))
|
|
||||||
else
|
|
||||||
IconButton(onPressed: controller.reload, icon: const Icon(FluentIcons.refresh)),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
(state.isLoading) ? const SizedBox(width: 24, height: 24, child: ProgressRing()) : const SizedBox(width: 24),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
SelectableText(state.url ?? ""),
|
|
||||||
const Spacer(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class Unp4kCModelProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$unp4kCModelHash() => r'b46274b1409dc904db2d96acf692869edf034b9f';
|
String _$unp4kCModelHash() => r'72ee23ad9864cdfb73a588ea1a0509b083e7dee8';
|
||||||
|
|
||||||
abstract class _$Unp4kCModel extends $Notifier<Unp4kcState> {
|
abstract class _$Unp4kCModel extends $Notifier<Unp4kcState> {
|
||||||
Unp4kcState build();
|
Unp4kcState build();
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import 'package:fluent_ui/fluent_ui.dart';
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:hive_ce/hive.dart';
|
import 'package:hive_ce/hive.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
||||||
import 'package:jwt_decode/jwt_decode.dart';
|
import 'package:jwt_decode/jwt_decode.dart';
|
||||||
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||||
@ -14,7 +13,6 @@ import 'package:starcitizen_doctor/common/utils/provider.dart';
|
|||||||
import 'package:starcitizen_doctor/data/rsi_game_library_data.dart';
|
import 'package:starcitizen_doctor/data/rsi_game_library_data.dart';
|
||||||
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
|
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
|
||||||
import 'package:starcitizen_doctor/ui/webview/webview.dart';
|
import 'package:starcitizen_doctor/ui/webview/webview.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
part 'home_game_login_dialog_ui_model.freezed.dart';
|
part 'home_game_login_dialog_ui_model.freezed.dart';
|
||||||
@ -47,82 +45,87 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
|||||||
Future<void> launchWebLogin(BuildContext context) async {
|
Future<void> launchWebLogin(BuildContext context) async {
|
||||||
final homeState = ref.read(homeUIModelProvider);
|
final homeState = ref.read(homeUIModelProvider);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
goWebView(context, S.current.home_action_login_rsi_account,
|
goWebView(
|
||||||
"https://robertsspaceindustries.com/en/connect?jumpto=/account/dashboard",
|
context,
|
||||||
loginMode: true, rsiLoginCallback: (message, ok) async {
|
S.current.home_action_login_rsi_account,
|
||||||
// dPrint(
|
"https://robertsspaceindustries.com/en/connect?jumpto=/account/dashboard",
|
||||||
// "======rsiLoginCallback=== $ok ===== data==\n${json.encode(message)}");
|
loginMode: true,
|
||||||
if (message == null || !ok) {
|
rsiLoginCallback: (message, ok) async {
|
||||||
Navigator.pop(context);
|
// dPrint(
|
||||||
return;
|
// "======rsiLoginCallback=== $ok ===== data==\n${json.encode(message)}");
|
||||||
}
|
if (message == null || !ok) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// final emailBox = await Hive.openBox("quick_login_email");
|
// final emailBox = await Hive.openBox("quick_login_email");
|
||||||
final data = message["data"];
|
final data = message["data"];
|
||||||
final authToken = data["authToken"];
|
final authToken = data["authToken"];
|
||||||
final webToken = data["webToken"];
|
final webToken = data["webToken"];
|
||||||
final releaseInfo = data["releaseInfo"];
|
final releaseInfo = data["releaseInfo"];
|
||||||
final libraryData = RsiGameLibraryData.fromJson(data["libraryData"]);
|
final libraryData = RsiGameLibraryData.fromJson(data["libraryData"]);
|
||||||
var avatarUrl = data["avatar"]
|
var avatarUrl = data["avatar"]?.toString().replaceAll("url(\"", "").replaceAll("\")", "");
|
||||||
?.toString()
|
if (avatarUrl?.startsWith("/") ?? false) {
|
||||||
.replaceAll("url(\"", "")
|
avatarUrl = "https://robertsspaceindustries.com$avatarUrl";
|
||||||
.replaceAll("\")", "");
|
}
|
||||||
if (avatarUrl?.startsWith("/") ?? false) {
|
final Map<String, dynamic> payload = Jwt.parseJwt(authToken!);
|
||||||
avatarUrl = "https://robertsspaceindustries.com$avatarUrl";
|
final nickname = payload["nickname"] ?? "";
|
||||||
}
|
|
||||||
final Map<String, dynamic> payload = Jwt.parseJwt(authToken!);
|
|
||||||
final nickname = payload["nickname"] ?? "";
|
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
nickname: nickname,
|
nickname: nickname,
|
||||||
avatarUrl: avatarUrl,
|
avatarUrl: avatarUrl,
|
||||||
authToken: authToken,
|
authToken: authToken,
|
||||||
webToken: webToken,
|
webToken: webToken,
|
||||||
releaseInfo: releaseInfo,
|
releaseInfo: releaseInfo,
|
||||||
libraryData: libraryData,
|
libraryData: libraryData,
|
||||||
);
|
);
|
||||||
|
|
||||||
final buildInfoFile =
|
final buildInfoFile = File("${homeState.scInstalledPath}\\build_manifest.id");
|
||||||
File("${homeState.scInstalledPath}\\build_manifest.id");
|
if (await buildInfoFile.exists()) {
|
||||||
if (await buildInfoFile.exists()) {
|
final buildInfo = json.decode(await buildInfoFile.readAsString())["Data"];
|
||||||
final buildInfo =
|
|
||||||
json.decode(await buildInfoFile.readAsString())["Data"];
|
|
||||||
|
|
||||||
if (releaseInfo?["versionLabel"] != null &&
|
if (releaseInfo?["versionLabel"] != null && buildInfo["RequestedP4ChangeNum"] != null) {
|
||||||
buildInfo["RequestedP4ChangeNum"] != null) {
|
if (!(releaseInfo!["versionLabel"]!.toString().endsWith(buildInfo["RequestedP4ChangeNum"]!.toString()))) {
|
||||||
if (!(releaseInfo!["versionLabel"]!
|
if (!context.mounted) return;
|
||||||
.toString()
|
final ok = await showConfirmDialogs(
|
||||||
.endsWith(buildInfo["RequestedP4ChangeNum"]!.toString()))) {
|
|
||||||
if (!context.mounted) return;
|
|
||||||
final ok = await showConfirmDialogs(
|
|
||||||
context,
|
context,
|
||||||
S.current.home_login_info_game_version_outdated,
|
S.current.home_login_info_game_version_outdated,
|
||||||
Text(S.current.home_login_info_rsi_server_report(
|
Text(
|
||||||
|
S.current.home_login_info_rsi_server_report(
|
||||||
releaseInfo?["versionLabel"],
|
releaseInfo?["versionLabel"],
|
||||||
buildInfo["RequestedP4ChangeNum"])),
|
buildInfo["RequestedP4ChangeNum"],
|
||||||
constraints: BoxConstraints(
|
),
|
||||||
maxWidth: MediaQuery.of(context).size.width * .4),
|
),
|
||||||
cancel: S.current.home_login_info_action_ignore);
|
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .4),
|
||||||
if (ok == true) {
|
cancel: S.current.home_login_info_action_ignore,
|
||||||
if (!context.mounted) return;
|
);
|
||||||
Navigator.pop(context);
|
if (ok == true) {
|
||||||
return;
|
if (!context.mounted) return;
|
||||||
|
Navigator.pop(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
_readyForLaunch(homeState, context);
|
_readyForLaunch(homeState, context);
|
||||||
}, useLocalization: true, homeState: homeState);
|
},
|
||||||
|
useLocalization: true,
|
||||||
|
homeState: homeState,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: avoid_build_context_in_providers
|
// ignore: avoid_build_context_in_providers
|
||||||
Future<void> goWebView(BuildContext context, String title, String url,
|
Future<void> goWebView(
|
||||||
{bool useLocalization = false,
|
BuildContext context,
|
||||||
bool loginMode = false,
|
String title,
|
||||||
RsiLoginCallback? rsiLoginCallback,
|
String url, {
|
||||||
required HomeUIModelState homeState}) async {
|
bool useLocalization = false,
|
||||||
|
bool loginMode = false,
|
||||||
|
RsiLoginCallback? rsiLoginCallback,
|
||||||
|
required HomeUIModelState homeState,
|
||||||
|
}) async {
|
||||||
if (useLocalization) {
|
if (useLocalization) {
|
||||||
const tipVersion = 2;
|
const tipVersion = 2;
|
||||||
final box = await Hive.openBox("app_conf");
|
final box = await Hive.openBox("app_conf");
|
||||||
@ -130,14 +133,11 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
|||||||
if (skip != tipVersion) {
|
if (skip != tipVersion) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final ok = await showConfirmDialogs(
|
final ok = await showConfirmDialogs(
|
||||||
context,
|
context,
|
||||||
S.current.home_login_action_title_box_one_click_launch,
|
S.current.home_login_action_title_box_one_click_launch,
|
||||||
Text(
|
Text(S.current.home_login_info_one_click_launch_description, style: const TextStyle(fontSize: 16)),
|
||||||
S.current.home_login_info_one_click_launch_description,
|
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .6),
|
||||||
style: const TextStyle(fontSize: 16),
|
);
|
||||||
),
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: MediaQuery.of(context).size.width * .6));
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
if (loginMode) {
|
if (loginMode) {
|
||||||
rsiLoginCallback?.call(null, false);
|
rsiLoginCallback?.call(null, false);
|
||||||
@ -147,26 +147,17 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
|||||||
await box.put("skip_web_login_version", tipVersion);
|
await box.put("skip_web_login_version", tipVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!await WebviewWindow.isWebviewAvailable()) {
|
// Rust WebView using wry + tao - no WebView2 runtime check needed as wry handles it internally
|
||||||
if (!context.mounted) return;
|
|
||||||
await showToast(
|
|
||||||
context, S.current.home_login_action_title_need_webview2_runtime);
|
|
||||||
if (!context.mounted) return;
|
|
||||||
await launchUrlString(
|
|
||||||
"https://developer.microsoft.com/en-us/microsoft-edge/webview2/");
|
|
||||||
if (!context.mounted) return;
|
|
||||||
Navigator.pop(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final webViewModel = WebViewModel(context,
|
final webViewModel = WebViewModel(
|
||||||
loginMode: loginMode,
|
context,
|
||||||
loginCallback: rsiLoginCallback,
|
loginMode: loginMode,
|
||||||
loginChannel: getChannelID(homeState.scInstalledPath!));
|
loginCallback: rsiLoginCallback,
|
||||||
|
loginChannel: getChannelID(homeState.scInstalledPath!),
|
||||||
|
);
|
||||||
if (useLocalization) {
|
if (useLocalization) {
|
||||||
try {
|
try {
|
||||||
await webViewModel
|
await webViewModel.initLocalization(homeState.webLocalizationVersionsData!);
|
||||||
.initLocalization(homeState.webLocalizationVersionsData!);
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
@ -179,9 +170,10 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _readyForLaunch(
|
Future<void> _readyForLaunch(
|
||||||
HomeUIModelState homeState,
|
HomeUIModelState homeState,
|
||||||
// ignore: avoid_build_context_in_providers
|
// ignore: avoid_build_context_in_providers
|
||||||
BuildContext context) async {
|
BuildContext context,
|
||||||
|
) async {
|
||||||
final userBox = await Hive.openBox("rsi_account_data");
|
final userBox = await Hive.openBox("rsi_account_data");
|
||||||
state = state.copyWith(loginStatus: 2);
|
state = state.copyWith(loginStatus: 2);
|
||||||
final launchData = {
|
final launchData = {
|
||||||
@ -211,11 +203,12 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
|
|||||||
final homeUIModel = ref.read(homeUIModelProvider.notifier);
|
final homeUIModel = ref.read(homeUIModelProvider.notifier);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
homeUIModel.doLaunchGame(
|
homeUIModel.doLaunchGame(
|
||||||
context,
|
context,
|
||||||
'${homeState.scInstalledPath}\\$executable',
|
'${homeState.scInstalledPath}\\$executable',
|
||||||
["-no_login_dialog", ...launchOptions.toString().split(" ")],
|
["-no_login_dialog", ...launchOptions.toString().split(" ")],
|
||||||
homeState.scInstalledPath!,
|
homeState.scInstalledPath!,
|
||||||
processorAffinity);
|
processorAffinity,
|
||||||
|
);
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class HomeGameLoginUIModelProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$homeGameLoginUIModelHash() =>
|
String _$homeGameLoginUIModelHash() =>
|
||||||
r'c9e9ec2e85f2459b6bfc1518406b091ff4675a85';
|
r'217a57f797b37f3467be2e7711f220610e9e67d8';
|
||||||
|
|
||||||
abstract class _$HomeGameLoginUIModel extends $Notifier<HomeGameLoginState> {
|
abstract class _$HomeGameLoginUIModel extends $Notifier<HomeGameLoginState> {
|
||||||
HomeGameLoginState build();
|
HomeGameLoginState build();
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:hive_ce/hive.dart';
|
import 'package:hive_ce/hive.dart';
|
||||||
@ -164,12 +163,7 @@ class HomeUIModel extends _$HomeUIModel {
|
|||||||
await box.put("skip_web_localization_tip_version", tipVersion);
|
await box.put("skip_web_localization_tip_version", tipVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!await WebviewWindow.isWebviewAvailable()) {
|
// Rust WebView using wry + tao - no WebView2 runtime check needed as wry handles it internally
|
||||||
if (!context.mounted) return;
|
|
||||||
showToast(context, S.current.home_login_action_title_need_webview2_runtime);
|
|
||||||
launchUrlString("https://developer.microsoft.com/en-us/microsoft-edge/webview2/");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final webViewModel = WebViewModel(context, loginMode: loginMode, loginCallback: rsiLoginCallback);
|
final webViewModel = WebViewModel(context, loginMode: loginMode, loginCallback: rsiLoginCallback);
|
||||||
if (useLocalization) {
|
if (useLocalization) {
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class HomeUIModelProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$homeUIModelHash() => r'7dfe73383f7be2e520a42d176e199a8db208f008';
|
String _$homeUIModelHash() => r'cc795e27213d02993459dd711de4a897c8491575';
|
||||||
|
|
||||||
abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> {
|
abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> {
|
||||||
HomeUIModelState build();
|
HomeUIModelState build();
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class ToolsUIModelProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$toolsUIModelHash() => r'78732ff16e87cc9f92174bda43d0fafadba51146';
|
String _$toolsUIModelHash() => r'ee1de3d555443f72b4fbb395a5728b2de1e8aaf4';
|
||||||
|
|
||||||
abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
||||||
ToolsUIState build();
|
ToolsUIState build();
|
||||||
|
|||||||
@ -4,22 +4,24 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hive_ce/hive.dart';
|
import 'package:hive_ce/hive.dart';
|
||||||
import 'package:starcitizen_doctor/api/analytics.dart';
|
import 'package:starcitizen_doctor/api/analytics.dart';
|
||||||
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
|
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
|
||||||
import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/rust_webview_controller.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/data/app_version_data.dart';
|
import 'package:starcitizen_doctor/data/app_version_data.dart';
|
||||||
import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart';
|
import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart';
|
||||||
|
|
||||||
typedef RsiLoginCallback = void Function(Map? data, bool success);
|
typedef RsiLoginCallback = void Function(Map? data, bool success);
|
||||||
|
typedef OnWebMessageReceivedCallback = void Function(String message);
|
||||||
|
|
||||||
class WebViewModel {
|
class WebViewModel {
|
||||||
late Webview webview;
|
late RustWebViewController webview;
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
|
||||||
bool _isClosed = false;
|
bool _isClosed = false;
|
||||||
@ -51,6 +53,8 @@ class WebViewModel {
|
|||||||
|
|
||||||
final RsiLoginCallback? loginCallback;
|
final RsiLoginCallback? loginCallback;
|
||||||
|
|
||||||
|
late AppVersionData _appVersionData;
|
||||||
|
|
||||||
Future<void> initWebView({
|
Future<void> initWebView({
|
||||||
String title = "",
|
String title = "",
|
||||||
required String applicationSupportDir,
|
required String applicationSupportDir,
|
||||||
@ -59,114 +63,35 @@ class WebViewModel {
|
|||||||
try {
|
try {
|
||||||
final userBox = await Hive.openBox("app_conf");
|
final userBox = await Hive.openBox("app_conf");
|
||||||
isEnableToolSiteMirrors = userBox.get("isEnableToolSiteMirrors", defaultValue: false);
|
isEnableToolSiteMirrors = userBox.get("isEnableToolSiteMirrors", defaultValue: false);
|
||||||
webview = await WebviewWindow.create(
|
_appVersionData = appVersionData;
|
||||||
configuration: CreateConfiguration(
|
|
||||||
windowWidth: loginMode ? 960 : 1920,
|
webview = await RustWebViewController.create(
|
||||||
windowHeight: loginMode ? 720 : 1080,
|
title: Platform.isMacOS ? "" : title,
|
||||||
userDataFolderWindows: "$applicationSupportDir/webview_data",
|
width: loginMode ? 960 : 1920,
|
||||||
title: Platform.isMacOS ? "" : title,
|
height: loginMode ? 720 : 1080,
|
||||||
),
|
userDataFolder: "$applicationSupportDir/webview_data",
|
||||||
|
enableDevtools: kDebugMode,
|
||||||
);
|
);
|
||||||
// webview.openDevToolsWindow();
|
|
||||||
webview.isNavigating.addListener(() async {
|
|
||||||
if (!webview.isNavigating.value && localizationResource.isNotEmpty) {
|
|
||||||
dPrint("webview Navigating url === $url");
|
|
||||||
if (url.contains("robertsspaceindustries.com")) {
|
|
||||||
// SC 官网
|
|
||||||
final replaceWords = _getLocalizationResource("zh-CN");
|
|
||||||
const org = "https://robertsspaceindustries.com/orgs";
|
|
||||||
const citizens = "https://robertsspaceindustries.com/citizens";
|
|
||||||
const organization = "https://robertsspaceindustries.com/account/organization";
|
|
||||||
const concierge = "https://robertsspaceindustries.com/account/concierge";
|
|
||||||
const referral = "https://robertsspaceindustries.com/account/referral-program";
|
|
||||||
const address = "https://robertsspaceindustries.com/account/addresses";
|
|
||||||
|
|
||||||
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
// 添加导航完成回调(用于注入脚本)
|
||||||
|
webview.addOnNavigationCompletedCallback(_onNavigationCompleted);
|
||||||
|
|
||||||
const spectrum = "https://robertsspaceindustries.com/spectrum";
|
// 添加关闭回调
|
||||||
// 跳过光谱论坛 https://github.com/StarCitizenToolBox/StarCitizenBoxBrowserEx/issues/1
|
webview.addOnCloseCallback(dispose);
|
||||||
if (url.startsWith(spectrum)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dPrint("load script");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
|
||||||
|
|
||||||
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
|
||||||
replaceWords.add({"word": 'members', "replacement": S.current.webview_localization_name_member});
|
|
||||||
replaceWords.addAll(_getLocalizationResource("orgs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address.startsWith(address)) {
|
|
||||||
replaceWords.addAll(_getLocalizationResource("address"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.startsWith(referral)) {
|
|
||||||
replaceWords.addAll([
|
|
||||||
{"word": 'Total recruits: ', "replacement": S.current.webview_localization_total_invitations},
|
|
||||||
{"word": 'Prospects ', "replacement": S.current.webview_localization_unfinished_invitations},
|
|
||||||
{"word": 'Recruits', "replacement": S.current.webview_localization_finished_invitations},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.startsWith(concierge)) {
|
|
||||||
replaceWords.clear();
|
|
||||||
replaceWords.addAll(_getLocalizationResource("concierge"));
|
|
||||||
}
|
|
||||||
if (url.startsWith(hangar)) {
|
|
||||||
replaceWords.addAll(_getLocalizationResource("hangar"));
|
|
||||||
}
|
|
||||||
|
|
||||||
_curReplaceWords = {};
|
|
||||||
for (var element in replaceWords) {
|
|
||||||
_curReplaceWords?[element["word"] ?? ""] = element["replacement"] ?? "";
|
|
||||||
}
|
|
||||||
await webview.evaluateJavaScript("InitWebLocalization()");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
dPrint("update replaceWords");
|
|
||||||
await webview.evaluateJavaScript(
|
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
|
||||||
);
|
|
||||||
|
|
||||||
/// loginMode
|
|
||||||
if (loginMode) {
|
|
||||||
dPrint("--- do rsi login ---\n run === getRSILauncherToken(\"$loginChannel\");");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 200));
|
|
||||||
webview.evaluateJavaScript("getRSILauncherToken(\"$loginChannel\");");
|
|
||||||
}
|
|
||||||
} else if (url.startsWith(await _handleMirrorsUrl("https://www.erkul.games", appVersionData))) {
|
|
||||||
dPrint("load script");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
|
||||||
dPrint("update replaceWords");
|
|
||||||
final replaceWords = _getLocalizationResource("DPS");
|
|
||||||
await webview.evaluateJavaScript(
|
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
|
||||||
);
|
|
||||||
} else if (url.startsWith(await _handleMirrorsUrl("https://uexcorp.space", appVersionData))) {
|
|
||||||
dPrint("load script");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
|
||||||
dPrint("update replaceWords");
|
|
||||||
final replaceWords = _getLocalizationResource("UEX");
|
|
||||||
await webview.evaluateJavaScript(
|
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
webview.addOnUrlRequestCallback(_onUrlRequest);
|
|
||||||
webview.onClose.whenComplete(dispose);
|
|
||||||
if (loginMode) {
|
if (loginMode) {
|
||||||
webview.addOnWebMessageReceivedCallback((messageString) {
|
webview.addOnWebMessageCallback((messageString) {
|
||||||
final message = json.decode(messageString);
|
try {
|
||||||
if (message["action"] == "webview_rsi_login_show_window") {
|
final message = json.decode(messageString);
|
||||||
webview.setWebviewWindowVisibility(true);
|
if (message["action"] == "webview_rsi_login_show_window") {
|
||||||
} else if (message["action"] == "webview_rsi_login_success") {
|
webview.setVisible(true);
|
||||||
_loginModeSuccess = true;
|
} else if (message["action"] == "webview_rsi_login_success") {
|
||||||
loginCallback?.call(message, true);
|
_loginModeSuccess = true;
|
||||||
webview.close();
|
loginCallback?.call(message, true);
|
||||||
|
webview.close();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
dPrint("Error parsing login message: $e");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -175,6 +100,98 @@ class WebViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onNavigationCompleted(String newUrl) async {
|
||||||
|
dPrint("Navigation completed: $newUrl");
|
||||||
|
url = newUrl;
|
||||||
|
|
||||||
|
// 在页面加载时注入拦截器
|
||||||
|
if (requestInterceptorScript.isNotEmpty) {
|
||||||
|
dPrint("Injecting request interceptor for: $url");
|
||||||
|
webview.executeScript(requestInterceptorScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localizationResource.isEmpty) return;
|
||||||
|
|
||||||
|
dPrint("webview Navigating url === $url");
|
||||||
|
if (url.contains("robertsspaceindustries.com")) {
|
||||||
|
// SC 官网
|
||||||
|
final replaceWords = _getLocalizationResource("zh-CN");
|
||||||
|
const org = "https://robertsspaceindustries.com/orgs";
|
||||||
|
const citizens = "https://robertsspaceindustries.com/citizens";
|
||||||
|
const organization = "https://robertsspaceindustries.com/account/organization";
|
||||||
|
const concierge = "https://robertsspaceindustries.com/account/concierge";
|
||||||
|
const referral = "https://robertsspaceindustries.com/account/referral-program";
|
||||||
|
const address = "https://robertsspaceindustries.com/account/addresses";
|
||||||
|
|
||||||
|
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
||||||
|
|
||||||
|
const spectrum = "https://robertsspaceindustries.com/spectrum";
|
||||||
|
// 跳过光谱论坛 https://github.com/StarCitizenToolBox/StarCitizenBoxBrowserEx/issues/1
|
||||||
|
if (url.startsWith(spectrum)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dPrint("load script");
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
webview.injectLocalizationScript();
|
||||||
|
|
||||||
|
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
||||||
|
replaceWords.add({"word": 'members', "replacement": S.current.webview_localization_name_member});
|
||||||
|
replaceWords.addAll(_getLocalizationResource("orgs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.startsWith(address)) {
|
||||||
|
replaceWords.addAll(_getLocalizationResource("address"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.startsWith(referral)) {
|
||||||
|
replaceWords.addAll([
|
||||||
|
{"word": 'Total recruits: ', "replacement": S.current.webview_localization_total_invitations},
|
||||||
|
{"word": 'Prospects ', "replacement": S.current.webview_localization_unfinished_invitations},
|
||||||
|
{"word": 'Recruits', "replacement": S.current.webview_localization_finished_invitations},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.startsWith(concierge)) {
|
||||||
|
replaceWords.clear();
|
||||||
|
replaceWords.addAll(_getLocalizationResource("concierge"));
|
||||||
|
}
|
||||||
|
if (url.startsWith(hangar)) {
|
||||||
|
replaceWords.addAll(_getLocalizationResource("hangar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_curReplaceWords = {};
|
||||||
|
for (var element in replaceWords) {
|
||||||
|
_curReplaceWords?[element["word"] ?? ""] = element["replacement"] ?? "";
|
||||||
|
}
|
||||||
|
webview.initWebLocalization();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
dPrint("update replaceWords");
|
||||||
|
webview.updateReplaceWords(replaceWords, enableCapture);
|
||||||
|
|
||||||
|
/// loginMode
|
||||||
|
if (loginMode) {
|
||||||
|
dPrint("--- do rsi login ---\n run === getRSILauncherToken(\"$loginChannel\");");
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
webview.executeRsiLogin(loginChannel);
|
||||||
|
}
|
||||||
|
} else if (url.startsWith(await _handleMirrorsUrl("https://www.erkul.games", _appVersionData))) {
|
||||||
|
dPrint("load script");
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
webview.injectLocalizationScript();
|
||||||
|
dPrint("update replaceWords");
|
||||||
|
final replaceWords = _getLocalizationResource("DPS");
|
||||||
|
webview.updateReplaceWords(replaceWords, enableCapture);
|
||||||
|
} else if (url.startsWith(await _handleMirrorsUrl("https://uexcorp.space", _appVersionData))) {
|
||||||
|
dPrint("load script");
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
webview.injectLocalizationScript();
|
||||||
|
dPrint("update replaceWords");
|
||||||
|
final replaceWords = _getLocalizationResource("UEX");
|
||||||
|
webview.updateReplaceWords(replaceWords, enableCapture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> _handleMirrorsUrl(String url, AppVersionData appVersionData) async {
|
Future<String> _handleMirrorsUrl(String url, AppVersionData appVersionData) async {
|
||||||
var finalUrl = url;
|
var finalUrl = url;
|
||||||
if (isEnableToolSiteMirrors) {
|
if (isEnableToolSiteMirrors) {
|
||||||
@ -189,7 +206,7 @@ class WebViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> launch(String url, AppVersionData appVersionData) async {
|
Future<void> launch(String url, AppVersionData appVersionData) async {
|
||||||
webview.launch(await _handleMirrorsUrl(url, appVersionData));
|
webview.navigate(await _handleMirrorsUrl(url, appVersionData));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initLocalization(AppWebLocalizationVersionsData v) async {
|
Future<void> initLocalization(AppWebLocalizationVersionsData v) async {
|
||||||
@ -259,29 +276,19 @@ class WebViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
|
void addOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
|
||||||
webview.addOnWebMessageReceivedCallback(callback);
|
webview.addOnWebMessageCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
|
void removeOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
|
||||||
webview.removeOnWebMessageReceivedCallback(callback);
|
webview.removeOnWebMessageCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> dispose() {
|
FutureOr<void> dispose() {
|
||||||
webview.removeOnUrlRequestCallback(_onUrlRequest);
|
webview.removeOnNavigationCompletedCallback(_onNavigationCompleted);
|
||||||
if (loginMode && !_loginModeSuccess) {
|
if (loginMode && !_loginModeSuccess) {
|
||||||
loginCallback?.call(null, false);
|
loginCallback?.call(null, false);
|
||||||
}
|
}
|
||||||
_isClosed = true;
|
_isClosed = true;
|
||||||
}
|
webview.dispose();
|
||||||
|
|
||||||
void _onUrlRequest(String url) {
|
|
||||||
dPrint("OnUrlRequestCallback === $url");
|
|
||||||
this.url = url;
|
|
||||||
|
|
||||||
// 在页面开始加载时立即注入拦截器
|
|
||||||
if (requestInterceptorScript.isNotEmpty) {
|
|
||||||
dPrint("Injecting request interceptor for: $url");
|
|
||||||
webview.evaluateJavaScript(requestInterceptorScript);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <desktop_multi_window/desktop_multi_window_plugin.h>
|
#include <desktop_multi_window/desktop_multi_window_plugin.h>
|
||||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
|
||||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||||
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
@ -17,9 +16,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) desktop_multi_window_registrar =
|
g_autoptr(FlPluginRegistrar) desktop_multi_window_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopMultiWindowPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopMultiWindowPlugin");
|
||||||
desktop_multi_window_plugin_register_with_registrar(desktop_multi_window_registrar);
|
desktop_multi_window_plugin_register_with_registrar(desktop_multi_window_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
|
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
|
|
||||||
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
|
|
||||||
g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar =
|
g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin");
|
||||||
flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar);
|
flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar);
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
desktop_multi_window
|
desktop_multi_window
|
||||||
desktop_webview_window
|
|
||||||
flutter_acrylic
|
flutter_acrylic
|
||||||
screen_retriever_linux
|
screen_retriever_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
|
|||||||
@ -6,20 +6,20 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import desktop_multi_window
|
import desktop_multi_window
|
||||||
import desktop_webview_window
|
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import file_picker
|
import file_picker
|
||||||
import macos_window_utils
|
import macos_window_utils
|
||||||
|
import path_provider_foundation
|
||||||
import screen_retriever_macos
|
import screen_retriever_macos
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import window_manager
|
import window_manager
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FlutterMultiWindowPlugin.register(with: registry.registrar(forPlugin: "FlutterMultiWindowPlugin"))
|
FlutterMultiWindowPlugin.register(with: registry.registrar(forPlugin: "FlutterMultiWindowPlugin"))
|
||||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||||
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
|
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
|
||||||
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||||
|
|||||||
24
pubspec.lock
24
pubspec.lock
@ -322,14 +322,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.3.0"
|
||||||
desktop_webview_window:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: desktop_webview_window
|
|
||||||
sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.3"
|
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -934,14 +926,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
objective_c:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: objective_c
|
|
||||||
sha256: "1f81ed9e41909d44162d7ec8663b2c647c202317cc0b56d3d56f6a13146a0b64"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "9.1.0"
|
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -986,10 +970,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "6192e477f34018ef1ea790c56fffc7302e3bc3efede9e798b934c252c8c105ba"
|
sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.5.1"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1646,10 +1630,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: yaml_edit
|
name: yaml_edit
|
||||||
sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
|
sha256: ec709065bb2c911b336853b67f3732dd13e0336bd065cc2f1061d7610ddf45e3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.9.0 <4.0.0"
|
dart: ">=3.9.0 <4.0.0"
|
||||||
flutter: ">=3.35.0"
|
flutter: ">=3.35.0"
|
||||||
|
|||||||
@ -40,7 +40,6 @@ dependencies:
|
|||||||
device_info_plus: ^12.3.0
|
device_info_plus: ^12.3.0
|
||||||
file_picker: ^10.3.7
|
file_picker: ^10.3.7
|
||||||
file_sizes: ^1.0.6
|
file_sizes: ^1.0.6
|
||||||
desktop_webview_window: ^0.2.3
|
|
||||||
flutter_svg: ^2.2.3
|
flutter_svg: ^2.2.3
|
||||||
archive: ^4.0.7
|
archive: ^4.0.7
|
||||||
jwt_decode: ^0.3.1
|
jwt_decode: ^0.3.1
|
||||||
|
|||||||
1765
rust/Cargo.lock
generated
1765
rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -15,22 +15,29 @@ crate-type = ["cdylib", "staticlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
flutter_rust_bridge = "=2.11.1"
|
flutter_rust_bridge = "=2.11.1"
|
||||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "process"] }
|
tokio = { version = "1.48.0", features = ["rt", "rt-multi-thread", "macros", "process", "sync"] }
|
||||||
futures = { version = "0.3", default-features = false, features = ["executor"] }
|
futures = { version = "0.3.31", default-features = false, features = ["executor"] }
|
||||||
url = "2.5"
|
url = "2.5.7"
|
||||||
once_cell = "1.21"
|
once_cell = "1.21.3"
|
||||||
reqwest = { version = "0.12", features = ["rustls-tls-webpki-roots", "cookies", "gzip", "json", "stream"] }
|
reqwest = { version = "0.12.24", features = ["rustls-tls-webpki-roots", "cookies", "gzip", "json", "stream"] }
|
||||||
hickory-resolver = { version = "0.25" }
|
hickory-resolver = { version = "0.25.2" }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0.100"
|
||||||
scopeguard = "1.2"
|
scopeguard = "1.2.0"
|
||||||
notify-rust = "4"
|
notify-rust = "4.11.7"
|
||||||
asar = "0.3.0"
|
asar = "0.3.0"
|
||||||
walkdir = "2.5.0"
|
walkdir = "2.5.0"
|
||||||
ort = { version = "2.0.0-rc.10", features = ["xnnpack", "download-binaries", "ndarray"] }
|
ort = { version = "2.0.0-rc.10", features = ["xnnpack", "download-binaries", "ndarray"] }
|
||||||
tokenizers = { version = "0.22", default-features = false, features = ["onig"] }
|
tokenizers = { version = "0.22.2", default-features = false, features = ["onig"] }
|
||||||
ndarray = "0.17"
|
ndarray = "0.17.1"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0.145"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
unp4k_rs = { git = "https://github.com/StarCitizenToolBox/unp4k_rs", tag = "V0.0.2" }
|
unp4k_rs = { git = "https://github.com/StarCitizenToolBox/unp4k_rs", tag = "V0.0.2" }
|
||||||
|
wry = "0.53.5"
|
||||||
|
tao = { version = "0.34.5", features = ["serde"] }
|
||||||
|
uuid = { version = "1.19.0", features = ["v4"] }
|
||||||
|
parking_lot = "0.12.5"
|
||||||
|
crossbeam-channel = "0.5.15"
|
||||||
|
image = { version = "0.25.9", default-features = false, features = ["ico"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows = { version = "0.62.2", features = [
|
windows = { version = "0.62.2", features = [
|
||||||
@ -39,7 +46,7 @@ windows = { version = "0.62.2", features = [
|
|||||||
"Win32_System_Threading",
|
"Win32_System_Threading",
|
||||||
"Win32_Foundation"
|
"Win32_Foundation"
|
||||||
] }
|
] }
|
||||||
win32job = "2"
|
win32job = "2.0.3"
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }
|
||||||
|
|||||||
@ -7,3 +7,4 @@ pub mod win32_api;
|
|||||||
pub mod asar_api;
|
pub mod asar_api;
|
||||||
pub mod ort_api;
|
pub mod ort_api;
|
||||||
pub mod unp4k_api;
|
pub mod unp4k_api;
|
||||||
|
pub mod webview_api;
|
||||||
|
|||||||
533
rust/src/api/webview_api.rs
Normal file
533
rust/src/api/webview_api.rs
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
// WebView API using wry + tao
|
||||||
|
// This module provides a cross-platform WebView implementation for Flutter
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crossbeam_channel::{bounded, Receiver, Sender};
|
||||||
|
use flutter_rust_bridge::frb;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tao::dpi::{LogicalPosition, LogicalSize};
|
||||||
|
use tao::event::{Event, WindowEvent};
|
||||||
|
use tao::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
|
||||||
|
use tao::platform::run_return::EventLoopExtRunReturn;
|
||||||
|
use tao::window::{Icon, Window, WindowBuilder};
|
||||||
|
use wry::{PageLoadEvent, WebView, WebViewBuilder};
|
||||||
|
|
||||||
|
// Platform-specific imports for running event loop on any thread
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use tao::platform::windows::EventLoopBuilderExtWindows;
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
// Embed the app icon at compile time
|
||||||
|
static APP_ICON_DATA: &[u8] = include_bytes!("../../../windows/runner/resources/app_icon.ico");
|
||||||
|
|
||||||
|
// Embed the init script at compile time
|
||||||
|
static INIT_SCRIPT: &str = include_str!("../assets/webview_init_script.js");
|
||||||
|
|
||||||
|
// ============ Data Structures ============
|
||||||
|
|
||||||
|
/// WebView window configuration
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[frb(dart_metadata = ("freezed"))]
|
||||||
|
pub struct WebViewConfiguration {
|
||||||
|
pub title: String,
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub user_data_folder: Option<String>,
|
||||||
|
pub enable_devtools: bool,
|
||||||
|
pub transparent: bool,
|
||||||
|
pub user_agent: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WebViewConfiguration {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
title: "WebView".to_string(),
|
||||||
|
width: 1280,
|
||||||
|
height: 720,
|
||||||
|
user_data_folder: None,
|
||||||
|
enable_devtools: false,
|
||||||
|
transparent: false,
|
||||||
|
user_agent: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Navigation state of the WebView
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[frb(dart_metadata = ("freezed"))]
|
||||||
|
pub struct WebViewNavigationState {
|
||||||
|
pub url: String,
|
||||||
|
pub title: String,
|
||||||
|
pub can_go_back: bool,
|
||||||
|
pub can_go_forward: bool,
|
||||||
|
pub is_loading: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WebViewNavigationState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
url: String::new(),
|
||||||
|
title: String::new(),
|
||||||
|
can_go_back: false,
|
||||||
|
can_go_forward: false,
|
||||||
|
is_loading: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Events from WebView to Dart
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[frb(dart_metadata = ("freezed"))]
|
||||||
|
pub enum WebViewEvent {
|
||||||
|
NavigationStarted { url: String },
|
||||||
|
NavigationCompleted { url: String },
|
||||||
|
TitleChanged { title: String },
|
||||||
|
WebMessage { message: String },
|
||||||
|
WindowClosed,
|
||||||
|
Error { message: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Commands from Dart to WebView
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum WebViewCommand {
|
||||||
|
Navigate(String),
|
||||||
|
GoBack,
|
||||||
|
GoForward,
|
||||||
|
Reload,
|
||||||
|
Stop,
|
||||||
|
ExecuteScript(String),
|
||||||
|
SetVisibility(bool),
|
||||||
|
Close,
|
||||||
|
SetWindowSize(u32, u32),
|
||||||
|
SetWindowPosition(i32, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Global State ============
|
||||||
|
|
||||||
|
type WebViewId = String;
|
||||||
|
|
||||||
|
struct WebViewInstance {
|
||||||
|
command_sender: Sender<WebViewCommand>,
|
||||||
|
event_receiver: Receiver<WebViewEvent>,
|
||||||
|
state: Arc<RwLock<WebViewNavigationState>>,
|
||||||
|
is_closed: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBVIEW_INSTANCES: Lazy<RwLock<HashMap<WebViewId, WebViewInstance>>> =
|
||||||
|
Lazy::new(|| RwLock::new(HashMap::new()));
|
||||||
|
|
||||||
|
// Custom event type for the event loop
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum UserEvent {
|
||||||
|
Command(WebViewCommand),
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Public API ============
|
||||||
|
|
||||||
|
/// Create a new WebView window and return its ID
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_create(config: WebViewConfiguration) -> Result<String, String> {
|
||||||
|
let id = uuid::Uuid::new_v4().to_string();
|
||||||
|
let id_clone = id.clone();
|
||||||
|
|
||||||
|
let (cmd_tx, cmd_rx) = bounded::<WebViewCommand>(100);
|
||||||
|
let (event_tx, event_rx) = bounded::<WebViewEvent>(100);
|
||||||
|
let state = Arc::new(RwLock::new(WebViewNavigationState::default()));
|
||||||
|
let state_clone = Arc::clone(&state);
|
||||||
|
let is_closed = Arc::new(AtomicBool::new(false));
|
||||||
|
let is_closed_clone = Arc::clone(&is_closed);
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
run_webview_loop(id_clone, config, cmd_rx, event_tx, state_clone, is_closed_clone);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait a moment for the window to be created
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
|
||||||
|
let instance = WebViewInstance {
|
||||||
|
command_sender: cmd_tx,
|
||||||
|
event_receiver: event_rx,
|
||||||
|
state,
|
||||||
|
is_closed,
|
||||||
|
};
|
||||||
|
|
||||||
|
WEBVIEW_INSTANCES.write().insert(id.clone(), instance);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Navigate to a URL
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_navigate(id: String, url: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::Navigate(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Go back in history
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_go_back(id: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::GoBack)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Go forward in history
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_go_forward(id: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::GoForward)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reload the current page
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_reload(id: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::Reload)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop loading
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_stop(id: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::Stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute JavaScript in the WebView
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_execute_script(id: String, script: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::ExecuteScript(script))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set window visibility
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_set_visibility(id: String, visible: bool) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::SetVisibility(visible))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Close the WebView window
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_close(id: String) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::Close)?;
|
||||||
|
// Remove from instances after a short delay
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||||
|
WEBVIEW_INSTANCES.write().remove(&id);
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set window size
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_set_window_size(id: String, width: u32, height: u32) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::SetWindowSize(width, height))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set window position
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_set_window_position(id: String, x: i32, y: i32) -> Result<(), String> {
|
||||||
|
send_command(&id, WebViewCommand::SetWindowPosition(x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current navigation state
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_get_state(id: String) -> Result<WebViewNavigationState, String> {
|
||||||
|
let instances = WEBVIEW_INSTANCES.read();
|
||||||
|
let instance = instances
|
||||||
|
.get(&id)
|
||||||
|
.ok_or_else(|| format!("WebView instance not found: {}", id))?;
|
||||||
|
let state = instance.state.read().clone();
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the WebView is closed
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_is_closed(id: String) -> bool {
|
||||||
|
let instances = WEBVIEW_INSTANCES.read();
|
||||||
|
let result = instances
|
||||||
|
.get(&id)
|
||||||
|
.map(|i| i.is_closed.load(Ordering::SeqCst))
|
||||||
|
.unwrap_or(true);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Poll for events from the WebView (non-blocking)
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_poll_events(id: String) -> Vec<WebViewEvent> {
|
||||||
|
let instances = WEBVIEW_INSTANCES.read();
|
||||||
|
if let Some(instance) = instances.get(&id) {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
while let Ok(event) = instance.event_receiver.try_recv() {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
drop(instances);
|
||||||
|
events
|
||||||
|
} else {
|
||||||
|
drop(instances);
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a list of all active WebView IDs
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn webview_list_all() -> Vec<String> {
|
||||||
|
let instances = WEBVIEW_INSTANCES.read();
|
||||||
|
let keys: Vec<String> = instances.keys().cloned().collect();
|
||||||
|
drop(instances);
|
||||||
|
keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Internal Implementation ============
|
||||||
|
|
||||||
|
fn send_command(id: &str, command: WebViewCommand) -> Result<(), String> {
|
||||||
|
let instances = WEBVIEW_INSTANCES.read();
|
||||||
|
let instance = instances
|
||||||
|
.get(id)
|
||||||
|
.ok_or_else(|| format!("WebView instance not found: {}", id))?;
|
||||||
|
|
||||||
|
if instance.is_closed.load(Ordering::SeqCst) {
|
||||||
|
return Err("WebView is closed".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
instance
|
||||||
|
.command_sender
|
||||||
|
.send(command)
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_webview_loop(
|
||||||
|
_id: String,
|
||||||
|
config: WebViewConfiguration,
|
||||||
|
cmd_rx: Receiver<WebViewCommand>,
|
||||||
|
event_tx: Sender<WebViewEvent>,
|
||||||
|
state: Arc<RwLock<WebViewNavigationState>>,
|
||||||
|
is_closed: Arc<AtomicBool>,
|
||||||
|
) {
|
||||||
|
// Create event loop with any_thread support for non-main thread execution
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let mut event_loop: EventLoop<UserEvent> = EventLoopBuilder::with_user_event()
|
||||||
|
.with_any_thread(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
let mut event_loop: EventLoop<UserEvent> = EventLoopBuilder::with_user_event().build();
|
||||||
|
|
||||||
|
let proxy = event_loop.create_proxy();
|
||||||
|
|
||||||
|
// Load window icon from embedded ICO file
|
||||||
|
let window_icon = load_app_icon();
|
||||||
|
|
||||||
|
// Build the window with decorations (title bar provided by OS)
|
||||||
|
// Set dark background color matching app theme (#1a1a1a)
|
||||||
|
let mut window_builder = WindowBuilder::new()
|
||||||
|
.with_title(&config.title)
|
||||||
|
.with_inner_size(LogicalSize::new(config.width, config.height))
|
||||||
|
.with_visible(true);
|
||||||
|
|
||||||
|
// Set window icon if loaded successfully
|
||||||
|
if let Some(icon) = window_icon {
|
||||||
|
window_builder = window_builder.with_window_icon(Some(icon));
|
||||||
|
}
|
||||||
|
|
||||||
|
let window = window_builder.build(&event_loop)
|
||||||
|
.expect("Failed to create window");
|
||||||
|
|
||||||
|
let window = Arc::new(window);
|
||||||
|
|
||||||
|
let event_tx_clone = event_tx.clone();
|
||||||
|
|
||||||
|
// Create web context with custom data directory if provided
|
||||||
|
let mut web_context = config
|
||||||
|
.user_data_folder
|
||||||
|
.as_ref()
|
||||||
|
.map(|path| wry::WebContext::new(Some(std::path::PathBuf::from(path))))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut builder = WebViewBuilder::new_with_web_context(&mut web_context)
|
||||||
|
.with_url("about:blank")
|
||||||
|
.with_devtools(config.enable_devtools)
|
||||||
|
.with_transparent(config.transparent)
|
||||||
|
.with_background_color((26, 26, 26, 255)) // Dark background #1a1a1a
|
||||||
|
.with_initialization_script(INIT_SCRIPT);
|
||||||
|
|
||||||
|
// Set user agent if provided
|
||||||
|
if let Some(ref user_agent) = config.user_agent {
|
||||||
|
builder = builder.with_user_agent(user_agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
let webview = builder
|
||||||
|
.with_ipc_handler(move |message| {
|
||||||
|
let msg = message.body().to_string();
|
||||||
|
// Forward all messages to Dart
|
||||||
|
let _ = event_tx_clone.send(WebViewEvent::WebMessage { message: msg });
|
||||||
|
})
|
||||||
|
.with_navigation_handler({
|
||||||
|
let event_tx = event_tx.clone();
|
||||||
|
let state = Arc::clone(&state);
|
||||||
|
move |uri| {
|
||||||
|
{
|
||||||
|
let mut state_guard = state.write();
|
||||||
|
state_guard.url = uri.clone();
|
||||||
|
state_guard.is_loading = true;
|
||||||
|
}
|
||||||
|
let _ = event_tx.send(WebViewEvent::NavigationStarted { url: uri });
|
||||||
|
true // Allow navigation
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.with_on_page_load_handler({
|
||||||
|
let event_tx = event_tx.clone();
|
||||||
|
let state = Arc::clone(&state);
|
||||||
|
move |event, url| {
|
||||||
|
match event {
|
||||||
|
PageLoadEvent::Started => {
|
||||||
|
let mut state_guard = state.write();
|
||||||
|
state_guard.url = url.clone();
|
||||||
|
state_guard.is_loading = true;
|
||||||
|
}
|
||||||
|
PageLoadEvent::Finished => {
|
||||||
|
{
|
||||||
|
let mut state_guard = state.write();
|
||||||
|
state_guard.url = url.clone();
|
||||||
|
state_guard.is_loading = false;
|
||||||
|
}
|
||||||
|
let _ = event_tx.send(WebViewEvent::NavigationCompleted { url });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build(&window)
|
||||||
|
.expect("Failed to create webview");
|
||||||
|
|
||||||
|
let webview = Arc::new(webview);
|
||||||
|
let webview_cmd = Arc::clone(&webview);
|
||||||
|
|
||||||
|
// Spawn command handler thread
|
||||||
|
let proxy_cmd = proxy.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
while let Ok(cmd) = cmd_rx.recv() {
|
||||||
|
if proxy_cmd.send_event(UserEvent::Command(cmd)).is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run the event loop with run_return so we can properly cleanup
|
||||||
|
event_loop.run_return(|event, _, control_flow| {
|
||||||
|
*control_flow = ControlFlow::Wait;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
is_closed.store(true, Ordering::SeqCst);
|
||||||
|
let _ = event_tx.send(WebViewEvent::WindowClosed);
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
Event::UserEvent(user_event) => match user_event {
|
||||||
|
UserEvent::Command(cmd) => {
|
||||||
|
handle_command(&webview_cmd, &window, cmd, &state, &event_tx, &is_closed, control_flow);
|
||||||
|
}
|
||||||
|
UserEvent::Quit => {
|
||||||
|
is_closed.store(true, Ordering::SeqCst);
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Explicitly drop in correct order: webview first, then web_context, then window
|
||||||
|
drop(webview_cmd);
|
||||||
|
drop(web_context);
|
||||||
|
drop(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_command(
|
||||||
|
webview: &Arc<WebView>,
|
||||||
|
window: &Arc<Window>,
|
||||||
|
command: WebViewCommand,
|
||||||
|
state: &Arc<RwLock<WebViewNavigationState>>,
|
||||||
|
event_tx: &Sender<WebViewEvent>,
|
||||||
|
is_closed: &Arc<AtomicBool>,
|
||||||
|
control_flow: &mut ControlFlow,
|
||||||
|
) {
|
||||||
|
match command {
|
||||||
|
WebViewCommand::Navigate(url) => {
|
||||||
|
{
|
||||||
|
let mut s = state.write();
|
||||||
|
s.url = url.clone();
|
||||||
|
s.is_loading = true;
|
||||||
|
}
|
||||||
|
let _ = webview.load_url(&url);
|
||||||
|
let _ = event_tx.send(WebViewEvent::NavigationStarted { url });
|
||||||
|
}
|
||||||
|
WebViewCommand::GoBack => {
|
||||||
|
let _ = webview.evaluate_script("history.back()");
|
||||||
|
}
|
||||||
|
WebViewCommand::GoForward => {
|
||||||
|
let _ = webview.evaluate_script("history.forward()");
|
||||||
|
}
|
||||||
|
WebViewCommand::Reload => {
|
||||||
|
let _ = webview.evaluate_script("location.reload()");
|
||||||
|
}
|
||||||
|
WebViewCommand::Stop => {
|
||||||
|
let _ = webview.evaluate_script("window.stop()");
|
||||||
|
}
|
||||||
|
WebViewCommand::ExecuteScript(script) => {
|
||||||
|
let _ = webview.evaluate_script(&script);
|
||||||
|
}
|
||||||
|
WebViewCommand::SetVisibility(visible) => {
|
||||||
|
window.set_visible(visible);
|
||||||
|
}
|
||||||
|
WebViewCommand::Close => {
|
||||||
|
// Properly close the window and exit the event loop
|
||||||
|
is_closed.store(true, Ordering::SeqCst);
|
||||||
|
let _ = event_tx.send(WebViewEvent::WindowClosed);
|
||||||
|
// Exit the event loop - this will cause cleanup
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
WebViewCommand::SetWindowSize(width, height) => {
|
||||||
|
let _ = window.set_inner_size(LogicalSize::new(width, height));
|
||||||
|
}
|
||||||
|
WebViewCommand::SetWindowPosition(x, y) => {
|
||||||
|
window.set_outer_position(LogicalPosition::new(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the application icon from embedded ICO data
|
||||||
|
fn load_app_icon() -> Option<Icon> {
|
||||||
|
use std::io::Cursor;
|
||||||
|
use image::ImageReader;
|
||||||
|
|
||||||
|
// Parse the ICO file from embedded bytes
|
||||||
|
let cursor = Cursor::new(APP_ICON_DATA);
|
||||||
|
let reader = match ImageReader::new(cursor).with_guessed_format() {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[SCToolbox] Failed to create image reader: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let img = match reader.decode() {
|
||||||
|
Ok(img) => img,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[SCToolbox] Failed to decode icon: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert to RGBA8
|
||||||
|
let rgba = img.to_rgba8();
|
||||||
|
let (width, height) = rgba.dimensions();
|
||||||
|
let raw_data = rgba.into_raw();
|
||||||
|
|
||||||
|
match Icon::from_rgba(raw_data, width, height) {
|
||||||
|
Ok(icon) => Some(icon),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[SCToolbox] Failed to create icon: {:?}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
266
rust/src/assets/webview_init_script.js
Normal file
266
rust/src/assets/webview_init_script.js
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
// SCToolbox WebView initialization script
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (window._sctInitialized) return;
|
||||||
|
window._sctInitialized = true;
|
||||||
|
|
||||||
|
// ========== 导航栏 UI ==========
|
||||||
|
const icons = {
|
||||||
|
back: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
||||||
|
forward: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
||||||
|
reload: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.5 8C13.5 11.0376 11.0376 13.5 8 13.5C4.96243 13.5 2.5 11.0376 2.5 8C2.5 4.96243 4.96243 2.5 8 2.5C10.1012 2.5 11.9254 3.67022 12.8169 5.4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><path d="M10.5 5.5H13V3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>'
|
||||||
|
};
|
||||||
|
|
||||||
|
function createNavBar() {
|
||||||
|
if (window.location.href === 'about:blank') return;
|
||||||
|
if (document.getElementById('sct-navbar')) return;
|
||||||
|
if (!document.body) {
|
||||||
|
setTimeout(createNavBar, 50);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nav = document.createElement('div');
|
||||||
|
nav.id = 'sct-navbar';
|
||||||
|
nav.innerHTML = `
|
||||||
|
<style>
|
||||||
|
#sct-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0.5rem; /* 8px */
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
height: 2.25rem; /* 36px */
|
||||||
|
background: rgba(19, 36, 49, 0.95);
|
||||||
|
backdrop-filter: blur(0.75rem); /* 12px */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 0.5rem; /* 0 8px */
|
||||||
|
z-index: 2147483647;
|
||||||
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
||||||
|
box-shadow: 0 0.125rem 0.75rem rgba(0,0,0,0.4); /* 0 2px 12px */
|
||||||
|
user-select: none;
|
||||||
|
border-radius: 0.5rem; /* 8px */
|
||||||
|
gap: 0.125rem; /* 2px */
|
||||||
|
border: 0.0625rem solid rgba(10, 49, 66, 0.8); /* 1px */
|
||||||
|
}
|
||||||
|
#sct-navbar button {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: rgba(255,255,255,0.85);
|
||||||
|
width: 2rem; /* 32px */
|
||||||
|
height: 1.75rem; /* 28px */
|
||||||
|
border-radius: 0.25rem; /* 4px */
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#sct-navbar button:hover { background: rgba(10, 49, 66, 0.9); color: #fff; }
|
||||||
|
#sct-navbar button:active { background: rgba(10, 49, 66, 1); transform: scale(0.95); }
|
||||||
|
#sct-navbar button:disabled { opacity: 0.35; cursor: not-allowed; }
|
||||||
|
#sct-navbar button svg { display: block; }
|
||||||
|
#sct-navbar-url {
|
||||||
|
width: 16.25rem; /* 260px */
|
||||||
|
height: 1.625rem; /* 26px */
|
||||||
|
padding: 0 0.625rem; /* 0 10px */
|
||||||
|
border: 0.0625rem solid rgba(10, 49, 66, 0.6); /* 1px */
|
||||||
|
border-radius: 0.25rem; /* 4px */
|
||||||
|
background: rgba(0,0,0,0.25);
|
||||||
|
color: rgba(255,255,255,0.9);
|
||||||
|
font-size: 0.75rem; /* 12px */
|
||||||
|
outline: none;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-left: 0.25rem; /* 4px */
|
||||||
|
}
|
||||||
|
#sct-navbar-url:focus { border-color: rgba(10, 49, 66, 1); background: rgba(0,0,0,0.35); }
|
||||||
|
/* ---------- Spinner & Favicon Slot ---------- */
|
||||||
|
#sct-spinner {
|
||||||
|
display: block; /* default: show spinner during loading */
|
||||||
|
width: 1.125rem; /* 18px */
|
||||||
|
height: 1.125rem; /* 18px */
|
||||||
|
border: 0.125rem solid rgba(255, 255, 255, 0.16); /* ~2px */
|
||||||
|
border-top-color: rgba(255, 255, 255, 0.92);
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
-webkit-animation: sct-spin 0.8s linear infinite;
|
||||||
|
animation: sct-spin 0.8s linear infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
align-self: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
#sct-favicon-slot {
|
||||||
|
display: none; /* hidden until page ready */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 1.125rem; /* 18px - same as spinner */
|
||||||
|
height: 1.125rem; /* 18px - same as spinner */
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
pointer-events: none;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
#sct-favicon {
|
||||||
|
width: 1.125rem; /* 18px */
|
||||||
|
height: 1.125rem; /* 18px */
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 0.25rem; /* 4px */
|
||||||
|
}
|
||||||
|
@-webkit-keyframes sct-spin { to { -webkit-transform: rotate(360deg); } }
|
||||||
|
@keyframes sct-spin { to { transform: rotate(360deg); } }
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
#sct-spinner { -webkit-animation: none; animation: none; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<button id="sct-back" title="Back">${icons.back}</button>
|
||||||
|
<button id="sct-forward" title="Forward">${icons.forward}</button>
|
||||||
|
<button id="sct-reload" title="Reload">${icons.reload}</button>
|
||||||
|
<div id="sct-spinner" role="progressbar" aria-hidden="false" aria-valuetext="Loading" title="Loading"></div>
|
||||||
|
<div id="sct-favicon-slot"><img id="sct-favicon" src="" alt="Page icon" /></div>
|
||||||
|
<input type="text" id="sct-navbar-url" readonly value="${window.location.href}" />
|
||||||
|
`;
|
||||||
|
document.body.insertBefore(nav, document.body.firstChild);
|
||||||
|
|
||||||
|
document.getElementById('sct-back').onclick = () => {
|
||||||
|
// Check if going back would result in about:blank
|
||||||
|
// If so, skip this entry and go back further
|
||||||
|
const beforeBackUrl = window.location.href;
|
||||||
|
history.back();
|
||||||
|
|
||||||
|
// After a short delay, if we landed on about:blank, go back again
|
||||||
|
setTimeout(() => {
|
||||||
|
if (window.location.href === 'about:blank' && beforeBackUrl !== 'about:blank') {
|
||||||
|
history.back();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
document.getElementById('sct-forward').onclick = () => history.forward();
|
||||||
|
document.getElementById('sct-reload').onclick = () => location.reload();
|
||||||
|
|
||||||
|
// Update back button state and URL display on navigation
|
||||||
|
function updateNavBarState() {
|
||||||
|
const backBtn = document.getElementById('sct-back');
|
||||||
|
const urlEl = document.getElementById('sct-navbar-url');
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
|
||||||
|
if (backBtn) {
|
||||||
|
// Disable back button if at start of history or at about:blank
|
||||||
|
backBtn.disabled = window.history.length <= 1 || currentUrl === 'about:blank';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlEl) {
|
||||||
|
urlEl.value = currentUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen to popstate and hashchange to update nav bar
|
||||||
|
window.addEventListener('popstate', updateNavBarState);
|
||||||
|
window.addEventListener('hashchange', updateNavBarState);
|
||||||
|
|
||||||
|
// Initial state
|
||||||
|
updateNavBarState();
|
||||||
|
|
||||||
|
// Spinner and favicon show/hide helpers
|
||||||
|
const spinner = document.getElementById('sct-spinner');
|
||||||
|
const faviconSlot = document.getElementById('sct-favicon-slot');
|
||||||
|
const faviconImg = document.getElementById('sct-favicon');
|
||||||
|
|
||||||
|
function showSpinner() {
|
||||||
|
if (spinner) {
|
||||||
|
spinner.style.display = 'block';
|
||||||
|
spinner.setAttribute('aria-hidden', 'false');
|
||||||
|
spinner.setAttribute('aria-busy', 'true');
|
||||||
|
}
|
||||||
|
if (faviconSlot) {
|
||||||
|
faviconSlot.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSpin() {
|
||||||
|
if (spinner) {
|
||||||
|
spinner.style.display = 'none';
|
||||||
|
spinner.setAttribute('aria-hidden', 'true');
|
||||||
|
spinner.setAttribute('aria-busy', 'false');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract favicon from page and show it when ready
|
||||||
|
function showFaviconWhenReady() {
|
||||||
|
hideSpin();
|
||||||
|
|
||||||
|
// Try to find favicon from page
|
||||||
|
let faviconUrl = null;
|
||||||
|
|
||||||
|
// 1. Look for link[rel="icon"] or link[rel="shortcut icon"]
|
||||||
|
const linkIcon = document.querySelector('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]');
|
||||||
|
if (linkIcon && linkIcon.href) {
|
||||||
|
faviconUrl = linkIcon.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Look for og:image in meta tags (fallback)
|
||||||
|
if (!faviconUrl) {
|
||||||
|
const ogImage = document.querySelector('meta[property="og:image"]');
|
||||||
|
if (ogImage && ogImage.content) {
|
||||||
|
faviconUrl = ogImage.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check page's existing favicon from document.head or body elements
|
||||||
|
if (!faviconUrl) {
|
||||||
|
const existingFavicon = document.querySelector('img[src*="favicon"], img[src*="icon"]');
|
||||||
|
if (existingFavicon && existingFavicon.src) {
|
||||||
|
faviconUrl = existingFavicon.src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display favicon if found, otherwise hide slot
|
||||||
|
if (faviconUrl) {
|
||||||
|
if (faviconImg) {
|
||||||
|
faviconImg.src = faviconUrl;
|
||||||
|
faviconImg.onerror = () => {
|
||||||
|
if (faviconSlot) faviconSlot.style.display = 'none';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (faviconSlot) {
|
||||||
|
faviconSlot.style.display = 'flex';
|
||||||
|
}
|
||||||
|
} else if (faviconSlot) {
|
||||||
|
faviconSlot.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monitor document readyState to show favicon when page is ready
|
||||||
|
document.addEventListener('readystatechange', function () {
|
||||||
|
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
||||||
|
setTimeout(showFaviconWhenReady, 150);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also trigger favicon display on load event
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
setTimeout(showFaviconWhenReady, 150);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在 DOM 准备好时创建导航栏
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', createNavBar);
|
||||||
|
} else {
|
||||||
|
createNavBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL 变化时:进入加载状态,显示 spinner
|
||||||
|
window.addEventListener('popstate', () => {
|
||||||
|
// Show spinner when navigating via popstate (URL change)
|
||||||
|
const spinner = document.getElementById('sct-spinner');
|
||||||
|
const faviconSlot = document.getElementById('sct-favicon-slot');
|
||||||
|
if (spinner) {
|
||||||
|
spinner.style.display = 'block';
|
||||||
|
spinner.setAttribute('aria-hidden', 'false');
|
||||||
|
spinner.setAttribute('aria-busy', 'true');
|
||||||
|
}
|
||||||
|
if (faviconSlot) {
|
||||||
|
faviconSlot.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
File diff suppressed because it is too large
Load Diff
@ -37,18 +37,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.13.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: boolean_selector
|
name: boolean_selector
|
||||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
|
cli_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_config
|
||||||
|
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -69,10 +77,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: coverage
|
name: coverage
|
||||||
sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76"
|
sha256: "802bd084fb82e55df091ec8ad1553a7331b61c08251eef19a508b6f3f3a9858d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.7.2"
|
version: "1.13.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -101,18 +109,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fixnum
|
name: fixnum
|
||||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: frontend_server_client
|
name: frontend_server_client
|
||||||
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "4.0.0"
|
||||||
github:
|
github:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -125,10 +133,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
hex:
|
hex:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -149,10 +157,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_multi_server
|
name: http_multi_server
|
||||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.2"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -165,26 +173,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: io
|
name: io
|
||||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: js
|
name: js
|
||||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.2"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.9.0"
|
||||||
lints:
|
lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -205,26 +213,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16+1"
|
version: "0.12.17"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.0"
|
version: "1.17.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "2.0.0"
|
||||||
node_preamble:
|
node_preamble:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -237,10 +245,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_config
|
name: package_config
|
||||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -261,18 +269,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pool
|
name: pool
|
||||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -293,34 +301,34 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_static
|
name: shelf_static
|
||||||
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_web_socket
|
name: shelf_web_socket
|
||||||
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
|
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "3.0.0"
|
||||||
source_map_stack_trace:
|
source_map_stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_map_stack_trace
|
name: source_map_stack_trace
|
||||||
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
|
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
source_maps:
|
source_maps:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_maps
|
name: source_maps
|
||||||
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.12"
|
version: "0.10.13"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -333,58 +341,58 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.1"
|
version: "1.12.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.4"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.4.1"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
test:
|
test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073"
|
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.25.2"
|
version: "1.26.3"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.7"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4"
|
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.12"
|
||||||
toml:
|
toml:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -397,10 +405,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: typed_data
|
name: typed_data
|
||||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.4.0"
|
||||||
version:
|
version:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -413,34 +421,42 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0
|
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.1.0"
|
version: "15.0.2"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.4"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "1.1.1"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2"
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.4"
|
version: "3.0.3"
|
||||||
webkit_inspection_protocol:
|
webkit_inspection_protocol:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -458,4 +474,4 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.7.0-0 <4.0.0"
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <desktop_multi_window/desktop_multi_window_plugin.h>
|
#include <desktop_multi_window/desktop_multi_window_plugin.h>
|
||||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
|
||||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||||
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
@ -16,8 +15,6 @@
|
|||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
DesktopMultiWindowPluginRegisterWithRegistrar(
|
DesktopMultiWindowPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin"));
|
registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin"));
|
||||||
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
|
||||||
FlutterAcrylicPluginRegisterWithRegistrar(
|
FlutterAcrylicPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterAcrylicPlugin"));
|
registry->GetRegistrarForPlugin("FlutterAcrylicPlugin"));
|
||||||
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
desktop_multi_window
|
desktop_multi_window
|
||||||
desktop_webview_window
|
|
||||||
flutter_acrylic
|
flutter_acrylic
|
||||||
screen_retriever_windows
|
screen_retriever_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user