mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-08-20 04:27:29 +00:00
fix: screenshots on windows and android
This commit is contained in:
parent
bef3532c93
commit
8c4e36b23a
7
src-tauri/Cargo.lock
generated
7
src-tauri/Cargo.lock
generated
|
|
@ -1913,6 +1913,12 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
|
|
@ -4742,6 +4748,7 @@ dependencies = [
|
|||
"gtk",
|
||||
"heck 0.5.0",
|
||||
"http 1.4.0",
|
||||
"http-range",
|
||||
"image 0.25.10",
|
||||
"jni",
|
||||
"libc",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
|||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = ["tray-icon", "image-png"] }
|
||||
tauri = { version = "2", features = ["protocol-asset", "tray-icon", "image-png"] }
|
||||
tauri-plugin-opener = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@
|
|||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"assetProtocol": {
|
||||
"enable": true,
|
||||
"scope": {
|
||||
"allow": ["**"],
|
||||
"requireLiteralLeadingDot": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"label": "main",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect, useRef } from "react";
|
||||
import { TauriService } from "../../services/TauriService";
|
||||
import { useState } from "react";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
interface ScreenshotImageProps {
|
||||
path: string;
|
||||
className?: string;
|
||||
|
|
@ -9,50 +9,6 @@ interface ScreenshotImageProps {
|
|||
fallbackSrc?: string;
|
||||
}
|
||||
|
||||
const imgCache = new Map<string, string>();
|
||||
let activeLoads = 0;
|
||||
const MAX_CONCURRENT = 4;
|
||||
const loadQueue: Array<() => void> = [];
|
||||
function dequeue() {
|
||||
while (activeLoads < MAX_CONCURRENT && loadQueue.length > 0) {
|
||||
const next = loadQueue.shift()!;
|
||||
activeLoads++;
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
function enqueueLoad(
|
||||
path: string,
|
||||
onLoad: (url: string) => void,
|
||||
onError: () => void,
|
||||
) {
|
||||
const cached = imgCache.get(path);
|
||||
if (cached) {
|
||||
onLoad(cached);
|
||||
return;
|
||||
}
|
||||
|
||||
const run = () => {
|
||||
TauriService.readScreenshotAsDataUrl(path)
|
||||
.then((url) => {
|
||||
imgCache.set(path, url);
|
||||
onLoad(url);
|
||||
})
|
||||
.catch(() => onError())
|
||||
.finally(() => {
|
||||
activeLoads--;
|
||||
dequeue();
|
||||
});
|
||||
};
|
||||
|
||||
if (activeLoads < MAX_CONCURRENT) {
|
||||
activeLoads++;
|
||||
run();
|
||||
} else {
|
||||
loadQueue.push(run);
|
||||
}
|
||||
}
|
||||
|
||||
export function ScreenshotImage({
|
||||
path,
|
||||
className,
|
||||
|
|
@ -61,62 +17,18 @@ export function ScreenshotImage({
|
|||
style,
|
||||
fallbackSrc,
|
||||
}: ScreenshotImageProps) {
|
||||
const [src, setSrc] = useState<string | undefined>(fallbackSrc);
|
||||
const imgRef = useRef<HTMLImageElement>(null);
|
||||
const loadedRef = useRef(false);
|
||||
useEffect(() => {
|
||||
const el = imgRef.current?.parentElement || imgRef.current;
|
||||
if (!el) return;
|
||||
let cancelled = false;
|
||||
const doLoad = () => {
|
||||
if (loadedRef.current) return;
|
||||
loadedRef.current = true;
|
||||
enqueueLoad(
|
||||
path,
|
||||
(url) => {
|
||||
if (!cancelled) setSrc(url);
|
||||
},
|
||||
() => {
|
||||
if (!cancelled && fallbackSrc) setSrc(fallbackSrc);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
if (loading === "eager") {
|
||||
doLoad();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
observer.disconnect();
|
||||
doLoad();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "800px" },
|
||||
);
|
||||
observer.observe(el);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [path, fallbackSrc, loading]);
|
||||
const handleError = () => {
|
||||
if (fallbackSrc) setSrc(fallbackSrc);
|
||||
};
|
||||
const [hasError, setHasError] = useState(false);
|
||||
|
||||
return (
|
||||
<img
|
||||
ref={imgRef}
|
||||
src={src}
|
||||
src={hasError && fallbackSrc ? fallbackSrc : convertFileSrc(path)}
|
||||
className={className}
|
||||
alt={alt}
|
||||
loading={loading}
|
||||
style={style}
|
||||
onError={handleError}
|
||||
onError={() => {
|
||||
if (fallbackSrc) setHasError(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-[200] bg-black/90 flex flex-col items-center justify-center p-8 backdrop-blur-md"
|
||||
className="fixed inset-0 z-[200] bg-black/90 flex flex-col items-center justify-center p-4 sm:p-8 backdrop-blur-md"
|
||||
onClick={() => setSelectedScreenshot(null)}
|
||||
>
|
||||
<motion.div
|
||||
|
|
@ -282,7 +282,7 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
animate={{ scale: 1, opacity: 1, y: 0 }}
|
||||
exit={{ scale: 0.9, opacity: 0, y: 20 }}
|
||||
transition={{ type: "spring", damping: 25, stiffness: 300 }}
|
||||
className="relative max-w-5xl w-full flex flex-col items-center border-2 border-[#555] rounded-sm p-2"
|
||||
className="relative max-w-5xl w-full max-h-[92vh] overflow-y-auto flex flex-col items-center border-2 border-[#555] rounded-sm p-2"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
|
|
@ -290,11 +290,11 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="relative w-full aspect-video bg-black/60 overflow-hidden border border-[#444] rounded-sm">
|
||||
<div className="relative w-full aspect-video max-h-[55vh] bg-black/60 overflow-hidden border border-[#444] rounded-sm">
|
||||
<ScreenshotImage
|
||||
path={selectedScreenshot.path}
|
||||
className="w-full h-full object-contain"
|
||||
fallbackSrc="/images/Pack_Icon.png"
|
||||
fallbackSrc="/images/Folder_Icon.png"
|
||||
/>
|
||||
<div className="absolute bottom-4 left-6 right-6 flex items-end justify-between pointer-events-none">
|
||||
<div className="flex flex-col gap-1">
|
||||
|
|
@ -318,7 +318,7 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-6 mt-6 mb-2 w-full justify-center px-6">
|
||||
<div className="flex flex-wrap gap-4 sm:gap-6 mt-4 sm:mt-6 mb-2 w-full justify-center px-4 sm:px-6">
|
||||
<button
|
||||
onMouseEnter={() => setModalFocusIndex(0)}
|
||||
onClick={() => handleOpenFolder(selectedScreenshot)}
|
||||
|
|
@ -395,7 +395,7 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
initial={{ scale: 0.9, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.9, opacity: 0 }}
|
||||
className="w-[420px] p-6 border-2 border-[#555] rounded-sm flex flex-col items-center"
|
||||
className="w-[420px] max-w-[92vw] p-4 sm:p-6 border-2 border-[#555] rounded-sm flex flex-col items-center"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
|
|
|
|||
Loading…
Reference in a new issue