feat: deeplinks

This commit is contained in:
neoapps-dev 2026-06-16 19:20:50 +03:00
parent 6312fb4540
commit 38fca607fd
18 changed files with 1003 additions and 392 deletions

View file

@ -1,7 +1,9 @@
[Desktop Entry]
Name=Emerald Legacy Launcher
Comment=FOSS cross-platform launcher for Minecraft Legacy Console Edition
Exec=emerald-legacy-launcher
Exec=emerald-legacy-launcher %u
Icon=io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher
Type=Application
Categories=Game;
Categories=Game;
MimeType=x-scheme-handler/emerald;x-scheme-handler/emeraldlauncher;x-scheme-handler/discord-1482504445152460871;
StartupNotify=true

View file

@ -16,6 +16,9 @@ finish-args:
- --filesystem=xdg-data
- --socket=pulseaudio
- --filesystem=xdg-run/pipewire-0
- --socket=session-bus
- --talk-name=org.freedesktop.portal.Desktop
- --talk-name=org.freedesktop.portal.OpenURI
modules:
- shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json

View file

@ -14,6 +14,7 @@
},
"dependencies": {
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-deep-link": "~2.4.9",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-process": "~2.3.1",
"@tauri-apps/plugin-updater": "~2.10.1",

View file

@ -11,6 +11,9 @@ importers:
'@tauri-apps/api':
specifier: ^2
version: 2.10.1
'@tauri-apps/plugin-deep-link':
specifier: ~2.4.9
version: 2.4.9
'@tauri-apps/plugin-opener':
specifier: ^2
version: 2.5.3
@ -585,6 +588,9 @@ packages:
'@tauri-apps/api@2.10.1':
resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==}
'@tauri-apps/api@2.11.0':
resolution: {integrity: sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==}
'@tauri-apps/cli-darwin-arm64@2.10.1':
resolution: {integrity: sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==}
engines: {node: '>= 10'}
@ -656,6 +662,9 @@ packages:
engines: {node: '>= 10'}
hasBin: true
'@tauri-apps/plugin-deep-link@2.4.9':
resolution: {integrity: sha512-u0SKOUHnJ1wqeqXsDFq2+kASCBj9xxbG0g9XZWPy9SOmU4wXtp6b/wiYpm6oH6/5fBTQsLqnLhIvqLBRpgHJlA==}
'@tauri-apps/plugin-opener@2.5.3':
resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==}
@ -1833,6 +1842,8 @@ snapshots:
'@tauri-apps/api@2.10.1': {}
'@tauri-apps/api@2.11.0': {}
'@tauri-apps/cli-darwin-arm64@2.10.1':
optional: true
@ -1880,6 +1891,10 @@ snapshots:
'@tauri-apps/cli-win32-ia32-msvc': 2.10.1
'@tauri-apps/cli-win32-x64-msvc': 2.10.1
'@tauri-apps/plugin-deep-link@2.4.9':
dependencies:
'@tauri-apps/api': 2.11.0
'@tauri-apps/plugin-opener@2.5.3':
dependencies:
'@tauri-apps/api': 2.10.1

113
src-tauri/Cargo.lock generated
View file

@ -564,6 +564,26 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom 0.2.17",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "convert_case"
version = "0.4.0"
@ -929,6 +949,15 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "dom_query"
version = "0.27.0"
@ -1033,10 +1062,12 @@ dependencies = [
"steam_shortcuts_util",
"tauri",
"tauri-build",
"tauri-plugin-deep-link",
"tauri-plugin-drpc",
"tauri-plugin-gamepad",
"tauri-plugin-opener",
"tauri-plugin-process",
"tauri-plugin-single-instance",
"tauri-plugin-updater",
"tokio",
"tokio-tungstenite",
@ -1773,6 +1804,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.5"
@ -2993,6 +3030,16 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-multimap"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown 0.14.5",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@ -3851,6 +3898,16 @@ dependencies = [
"uuid 0.8.2",
]
[[package]]
name = "rust-ini"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-hash"
version = "2.1.2"
@ -4809,6 +4866,27 @@ dependencies = [
"walkdir",
]
[[package]]
name = "tauri-plugin-deep-link"
version = "2.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ee75bc5627f77bfdf40c913255ebc258117b10ebe2b2239a1a1cf40b0b58aa"
dependencies = [
"dunce",
"plist",
"rust-ini",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-utils",
"thiserror 2.0.18",
"tracing",
"url",
"windows-registry",
"windows-result 0.3.4",
]
[[package]]
name = "tauri-plugin-drpc"
version = "0.1.6"
@ -4873,6 +4951,21 @@ dependencies = [
"tauri-plugin",
]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8f29386f5e9fdc699182388a33ee80a56de436d91b67459e86afef426282af"
dependencies = [
"serde",
"serde_json",
"tauri",
"thiserror 2.0.18",
"tracing",
"windows-sys 0.60.2",
"zbus",
]
[[package]]
name = "tauri-plugin-updater"
version = "2.10.1"
@ -5122,6 +5215,15 @@ dependencies = [
"time-core",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinystr"
version = "0.8.3"
@ -6165,6 +6267,17 @@ dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-registry"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
"windows-link 0.1.3",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-result"
version = "0.3.4"

View file

@ -38,6 +38,8 @@ flate2 = "1"
once_cell = "1"
lzxd = "0.2.6"
uuid = { version = "1", features = ["v4"] }
tauri-plugin-deep-link = "2"
tauri-plugin-single-instance = "2"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-updater = "2"

View file

@ -35,6 +35,7 @@
}
]
},
"process:default"
"process:default",
"deep-link:default"
]
}

View file

@ -10,6 +10,7 @@
],
"permissions": [
"updater:default",
"process:default"
"process:default",
"deep-link:default"
]
}

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"default":{"identifier":"default","description":"Default permissions","local":true,"windows":["main"],"permissions":["core:default","core:app:default","core:event:default","core:image:default","core:menu:default","core:path:default","core:resources:default","core:tray:default","core:webview:default","core:window:default","opener:default","gamepad:default","drpc:default","updater:default",{"identifier":"opener:allow-open-path","allow":[{"path":"**"}]},{"identifier":"opener:allow-reveal-item-in-dir","allow":[{"path":"**"}]},"process:default"]},"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["updater:default","process:default"],"platforms":["macOS","windows","linux"]}}
{"default":{"identifier":"default","description":"Default permissions","local":true,"windows":["main"],"permissions":["core:default","core:app:default","core:event:default","core:image:default","core:menu:default","core:path:default","core:resources:default","core:tray:default","core:webview:default","core:window:default","opener:default","gamepad:default","drpc:default","updater:default",{"identifier":"opener:allow-open-path","allow":[{"path":"**"}]},{"identifier":"opener:allow-reveal-item-in-dir","allow":[{"path":"**"}]},"process:default","deep-link:default"]},"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["updater:default","process:default","deep-link:default"],"platforms":["macOS","windows","linux"]}}

View file

@ -2312,6 +2312,60 @@
"const": "core:window:deny-unminimize",
"markdownDescription": "Denies the unminimize command without any pre-configured scope."
},
{
"description": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`",
"type": "string",
"const": "deep-link:default",
"markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`"
},
{
"description": "Enables the get_current command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-get-current",
"markdownDescription": "Enables the get_current command without any pre-configured scope."
},
{
"description": "Enables the is_registered command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-is-registered",
"markdownDescription": "Enables the is_registered command without any pre-configured scope."
},
{
"description": "Enables the register command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-register",
"markdownDescription": "Enables the register command without any pre-configured scope."
},
{
"description": "Enables the unregister command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-unregister",
"markdownDescription": "Enables the unregister command without any pre-configured scope."
},
{
"description": "Denies the get_current command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-get-current",
"markdownDescription": "Denies the get_current command without any pre-configured scope."
},
{
"description": "Denies the is_registered command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-is-registered",
"markdownDescription": "Denies the is_registered command without any pre-configured scope."
},
{
"description": "Denies the register command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-register",
"markdownDescription": "Denies the register command without any pre-configured scope."
},
{
"description": "Denies the unregister command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-unregister",
"markdownDescription": "Denies the unregister command without any pre-configured scope."
},
{
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`",
"type": "string",

View file

@ -2312,6 +2312,60 @@
"const": "core:window:deny-unminimize",
"markdownDescription": "Denies the unminimize command without any pre-configured scope."
},
{
"description": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`",
"type": "string",
"const": "deep-link:default",
"markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`"
},
{
"description": "Enables the get_current command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-get-current",
"markdownDescription": "Enables the get_current command without any pre-configured scope."
},
{
"description": "Enables the is_registered command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-is-registered",
"markdownDescription": "Enables the is_registered command without any pre-configured scope."
},
{
"description": "Enables the register command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-register",
"markdownDescription": "Enables the register command without any pre-configured scope."
},
{
"description": "Enables the unregister command without any pre-configured scope.",
"type": "string",
"const": "deep-link:allow-unregister",
"markdownDescription": "Enables the unregister command without any pre-configured scope."
},
{
"description": "Denies the get_current command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-get-current",
"markdownDescription": "Denies the get_current command without any pre-configured scope."
},
{
"description": "Denies the is_registered command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-is-registered",
"markdownDescription": "Denies the is_registered command without any pre-configured scope."
},
{
"description": "Denies the register command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-register",
"markdownDescription": "Denies the register command without any pre-configured scope."
},
{
"description": "Denies the unregister command without any pre-configured scope.",
"type": "string",
"const": "deep-link:deny-unregister",
"markdownDescription": "Denies the unregister command without any pre-configured scope."
},
{
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`",
"type": "string",

View file

@ -10,7 +10,7 @@ mod commands;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use tauri::Manager;
use tauri::{Emitter, Manager};
use commands::config as config_cmds;
use commands::download;
use commands::file_dialogs;
@ -29,6 +29,21 @@ use state::{DownloadState, GameState, ProxyGuard};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
let urls: Vec<String> = args
.iter()
.filter(|a| {
a.starts_with("emerald://")
|| a.starts_with("emeraldlauncher://")
|| a.starts_with("discord-1482504445152460871://")
})
.cloned()
.collect();
if !urls.is_empty() {
let _ = app.emit("deep-link", urls);
}
}))
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.manage(DownloadState {
@ -112,21 +127,27 @@ pub fn run() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 && !args[1].starts_with('-') {
let instance_id = args[1].clone();
let app_handle = app.handle().clone();
tauri::async_runtime::spawn(async move {
if let Some(window) = app_handle.get_webview_window("main") {
let _ = window.hide();
}
let state = app_handle.state::<GameState>();
match game::launch_game(app_handle.clone(), state, instance_id, Vec::new(), vec![]).await {
Ok(_) => app_handle.exit(0),
Err(e) => {
eprintln!("Auto-launch error: {}", e);
app_handle.exit(1);
let first = &args[1];
let is_deep_link = first.starts_with("emerald://")
|| first.starts_with("emeraldlauncher://")
|| first.starts_with("discord-1482504445152460871://");
if !is_deep_link {
let instance_id = first.clone();
let app_handle_clone = app.handle().clone();
tauri::async_runtime::spawn(async move {
if let Some(window) = app_handle_clone.get_webview_window("main") {
let _ = window.hide();
}
}
});
let state = app_handle_clone.state::<GameState>();
match game::launch_game(app_handle_clone.clone(), state, instance_id, Vec::new(), vec![]).await {
Ok(_) => app_handle_clone.exit(0),
Err(e) => {
eprintln!("Auto-launch error: {}", e);
app_handle_clone.exit(1);
}
}
});
}
}
Ok(())
})

View file

@ -27,6 +27,11 @@
]
},
"plugins": {
"deep-link": {
"desktop": {
"schemes": ["emerald", "discord-1482504445152460871", "emeraldlauncher"]
}
},
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1NTk5MjQ4QjMxQjFCQgpSV1M3c1RHTEpKbFZBMEtxMnNUZ3F5V2FmQmQrREY5Z0pkbnJuUlBYL2d1cUtzRkJIeDFkUkR4RQo=",
"endpoints": [

View file

@ -27,6 +27,11 @@
]
},
"plugins": {
"deep-link": {
"desktop": {
"schemes": ["emerald", "discord-1482504445152460871", "emeraldlauncher"]
}
},
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1NTk5MjQ4QjMxQjFCQgpSV1M3c1RHTEpKbFZBMEtxMnNUZ3F5V2FmQmQrREY5Z0pkbnJuUlBYL2d1cUtzRkJIeDFkUkR4RQo=",
"endpoints": [

View file

@ -17,7 +17,14 @@ import { TauriService } from "../../services/TauriService";
import ChooseInstanceModal from "../modals/ChooseInstanceModal";
import QRCode from "qrcode";
const LceLiveView = memo(function LceLiveView() {
interface LceLiveViewProps {
addFriendTarget?: string | null;
onClearAddFriendTarget?: () => void;
}
const LceLiveView = memo(function LceLiveView({
addFriendTarget,
onClearAddFriendTarget,
}: LceLiveViewProps) {
const { setActiveView } = useUI();
const { animationsEnabled } = useConfig();
const { playPressSound, playBackSound } = useAudio();
@ -37,7 +44,7 @@ const LceLiveView = memo(function LceLiveView() {
);
const [linkError, setLinkError] = useState<string | null>(null);
const [isHosting, setIsHosting] = useState(false);
const [hostStatus, setHostStatus] = useState("");
const [_hostStatus, setHostStatus] = useState("");
const [hostIp, setHostIp] = useState("");
const [hostPort, setHostPort] = useState(19132);
const [isDiscovering, setIsDiscovering] = useState(false);
@ -392,6 +399,15 @@ const LceLiveView = memo(function LceLiveView() {
showHostMethodPicker,
]);
useEffect(() => {
if (!addFriendTarget) return;
setCurrentTab("friends");
handleAction(() =>
lceLiveService.sendFriendRequest(addFriendTarget),
);
onClearAddFriendTarget?.();
}, [addFriendTarget, onClearAddFriendTarget]);
const tabs: ("friends" | "requests" | "invites")[] = [
"friends",
"requests",

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
import { useEffect, useState, useMemo, useCallback } from "react";
import { useEffect, useState, useMemo, useCallback, useRef } from "react";
import { motion, AnimatePresence, MotionConfig } from "framer-motion";
import "../css/App.css";
import HomeView from "../components/views/HomeView";
@ -39,6 +39,8 @@ import { PluginViewContainer } from "../components/plugins/PluginViewContainer";
import type { Edition } from "../types/edition";
import type { ToastOptions } from "../plugins/types";
import pkg from "../../package.json";
import { getCurrent, onOpenUrl } from "@tauri-apps/plugin-deep-link";
import { listen } from "@tauri-apps/api/event";
export default function App() {
const ui = useUI();
const {
@ -69,8 +71,14 @@ export default function App() {
} = notifications;
const [showSetup, setShowSetup] = useState(false);
const [isSetupChecked, setIsSetupChecked] = useState(false);
const pendingDeepLinks = useRef<string[]>([]);
const appReadyRef = useRef(false);
const [workshopTarget, setWorkshopTarget] = useState<{
id: string;
type?: string;
} | null>(null);
const [addFriendTarget, setAddFriendTarget] = useState<string | null>(null);
const displayIsDay = config.isDayTime;
const clearError = useCallback(() => game.setError(null), [game]);
const clearGameUpdate = useCallback(
() => game.setGameUpdateMessage(null),
@ -124,6 +132,117 @@ export default function App() {
}
}, [showIntro, config.skipIntro, setShowIntro]);
const processDeepLink = useCallback(
(url: string) => {
try {
const parsed = new URL(url);
const path = parsed.hostname + parsed.pathname;
const parts = path.replace(/^\/+/, "").split("/").filter(Boolean);
if (parts.length === 0) return;
const action = parts[0];
if (action === "launch") {
if (parts.length >= 2) {
let instanceId = decodeURIComponent(parts[1]);
if (instanceId === "neolegacy") instanceId = "legacy_evolved"; //neo: piebot said so
TauriService.launchGame(instanceId, []).catch(console.error);
} else {
setActiveView("main");
game.handleLaunch().catch(console.error);
}
return;
}
if (action === "lcelive" && parts.length >= 2 && parts[1] === "addfriend") {
const username = parsed.searchParams.get("username");
if (username) {
setActiveView("lcelive");
setAddFriendTarget(username);
return;
}
}
if (action === "workshop" && parts.length >= 2) {
const workshopId = decodeURIComponent(parts[1]);
const knownTypes = ["normal", "bytebukkit", "plugin", "version"];
let workshopType: string | undefined;
if (parts.length >= 3) {
workshopType = parts[2];
} else if (parsed.searchParams.get("type")) {
workshopType = parsed.searchParams.get("type")!;
} else {
workshopType = knownTypes.find((t) => parsed.searchParams.has(t));
}
setActiveView("workshop");
setWorkshopTarget({ id: workshopId, type: workshopType });
return;
}
setActiveView(action); //neo: yeah no im not checking if its valid or not.
} catch (e) {
console.error("failed to parse deep link:", e);
}
},
[setActiveView, game.handleLaunch, setWorkshopTarget],
);
const appReady =
config.isLoaded && isSetupChecked && !showSetup && !showIntro;
useEffect(() => {
if (appReady) {
appReadyRef.current = true;
if (pendingDeepLinks.current.length > 0) {
for (const url of pendingDeepLinks.current) {
processDeepLink(url);
}
pendingDeepLinks.current = [];
}
}
}, [appReady, processDeepLink]);
const queueDeepLink = useCallback(
(url: string) => {
if (appReadyRef.current) {
processDeepLink(url);
} else {
pendingDeepLinks.current.push(url);
}
},
[processDeepLink],
);
useEffect(() => {
getCurrent()
.then((urls) => {
if (urls && urls.length > 0) {
queueDeepLink(urls[0]);
}
})
.catch(() => {});
let unlistenOpenUrl: Function;
onOpenUrl((payload) => {
for (const url of payload) {
queueDeepLink(url);
}
}).then((unlistenFn) => {
unlistenOpenUrl = unlistenFn;
});
let unlistenEvent: Function;
listen<string[]>("deep-link", (event) => {
for (const url of event.payload) {
queueDeepLink(url);
}
}).then((unlistenFn) => {
unlistenEvent = unlistenFn;
});
return () => {
if (unlistenOpenUrl) unlistenOpenUrl();
if (unlistenEvent) unlistenEvent();
};
}, [queueDeepLink]);
useEffect(() => {
if (config.isLoaded) {
const setupCompleted =
@ -433,7 +552,11 @@ export default function App() {
<VersionsView key="versions-view" />
)}
{activeView === "workshop" && (
<WorkshopView key="workshop-view" />
<WorkshopView
key="workshop-view"
workshopTarget={workshopTarget}
onClearWorkshopTarget={() => setWorkshopTarget(null)}
/>
)}
{activeView === "devtools" && (
<DevtoolsView key="devtools-view" />
@ -460,7 +583,11 @@ export default function App() {
<SwfView key="swf-editor-view" />
)}
{activeView === "lcelive" && (
<LceLiveView key="lcelive-view" />
<LceLiveView
key="lcelive-view"
addFriendTarget={addFriendTarget}
onClearAddFriendTarget={() => setAddFriendTarget(null)}
/>
)}
{activeView === "skins" && <SkinsView key="skins-view" />}
{activeView === "screenshots" && (