Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f1708129a | |||
| e4f014e3b4 | |||
| 2349d6d360 | |||
| acdd761652 | |||
| e08b265ae8 | |||
| 52134c2200 | |||
| 892ea44c17 | |||
| ca612797ee | |||
| 787962c6d0 | |||
| 09434fcc5b |
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Firefly Shelter
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
5
Makefile
@@ -22,6 +22,11 @@ build:
|
||||
wails3 build
|
||||
@echo Done!
|
||||
|
||||
generate:
|
||||
@echo Generating bindings...
|
||||
wails3 generate bindings -ts
|
||||
@echo Done!
|
||||
|
||||
release:
|
||||
@echo Building release application...
|
||||
wails3 package
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
@@ -28,9 +28,30 @@ export function GetCurrentLauncherVersion() {
|
||||
return $Call.ByID(3575133982);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function HideApp() {
|
||||
return $Call.ByID(88003266);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function MaximizeApp() {
|
||||
return $Call.ByID(1257306588);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function MinimizeApp() {
|
||||
return $Call.ByID(3434614194);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function RestoreApp() {
|
||||
return $Call.ByID(3115625834);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,22 @@ export function FileExistsInZip(archivePath, fileInside) {
|
||||
return $Call.ByID(2509699047, archivePath, fileInside);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {$CancellablePromise<string>}
|
||||
*/
|
||||
export function GetDir(path) {
|
||||
return $Call.ByID(1744445742, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} paths
|
||||
* @returns {$CancellablePromise<string>}
|
||||
*/
|
||||
export function Join(...paths) {
|
||||
return $Call.ByID(2460588289, paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
@@ -56,7 +72,15 @@ export function PickFolder() {
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {$CancellablePromise<boolean>}
|
||||
* @returns {$CancellablePromise<void>}
|
||||
*/
|
||||
export function RemoveFile(path) {
|
||||
return $Call.ByID(3206735043, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function StartApp(path) {
|
||||
return $Call.ByID(1267568402, path);
|
||||
@@ -64,7 +88,7 @@ export function StartApp(path) {
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {$CancellablePromise<boolean>}
|
||||
* @returns {$CancellablePromise<[boolean, string]>}
|
||||
*/
|
||||
export function StartWithConsole(path) {
|
||||
return $Call.ByID(3249271428, path);
|
||||
|
||||
@@ -43,13 +43,6 @@ export function GetLatestServerVersion() {
|
||||
return $Call.ByID(2918980975);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<void>}
|
||||
*/
|
||||
export function UnzipProxy() {
|
||||
return $Call.ByID(2563246729);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {$CancellablePromise<void>}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//@ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import { Create as $Create } from "@wailsio/runtime";
|
||||
|
||||
Object.freeze($Create.Events);
|
||||
2
frontend/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" data-theme="dracula">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
2219
frontend/package-lock.json
generated
@@ -11,33 +11,34 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@tanstack/react-router": "^1.131.27",
|
||||
"@tanstack/react-router-devtools": "^1.131.27",
|
||||
"lucide-react": "^0.541.0",
|
||||
"motion": "^12.23.12",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@tanstack/react-router": "^1.149.3",
|
||||
"@tanstack/react-router-devtools": "^1.149.3",
|
||||
"lucide-react": "^0.562.0",
|
||||
"motion": "^12.26.2",
|
||||
"path-browserify": "^1.0.1",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-easy-crop": "^5.5.6",
|
||||
"react-toastify": "^11.0.5",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"zustand": "^5.0.8"
|
||||
"tailwindcss": "^4.1.18",
|
||||
"zustand": "^5.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tanstack/router-plugin": "^1.131.27",
|
||||
"@types/node": "^24.3.0",
|
||||
"@tanstack/router-plugin": "^1.149.3",
|
||||
"@types/node": "^25.0.8",
|
||||
"@types/path-browserify": "^1.0.3",
|
||||
"@types/react": "^19.1.11",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
||||
"@typescript-eslint/parser": "^8.40.0",
|
||||
"@vitejs/plugin-react": "^5.0.1",
|
||||
"@wailsio/runtime": "^3.0.0-alpha.66",
|
||||
"daisyui": "^5.1.27",
|
||||
"eslint": "^9.34.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.1.3"
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
||||
"@typescript-eslint/parser": "^8.53.0",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"@wailsio/runtime": "^3.0.0-alpha.78",
|
||||
"daisyui": "^5.5.14",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
frontend/public/bg-1.jpeg
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
frontend/public/bg-10.jpg
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
frontend/public/bg-11.jpeg
Normal file
|
After Width: | Height: | Size: 386 KiB |
BIN
frontend/public/bg-12.jpg
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
frontend/public/bg-13.jpg
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
frontend/public/bg-16.jpg
Normal file
|
After Width: | Height: | Size: 270 KiB |
BIN
frontend/public/bg-2.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
frontend/public/bg-3.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
frontend/public/bg-5.jpeg
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
frontend/public/bg-6.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
frontend/public/bg-7.jpeg
Normal file
|
After Width: | Height: | Size: 349 KiB |
BIN
frontend/public/bg-8.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
frontend/public/bg-9.jpeg
Normal file
|
After Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
frontend/public/heart-hsr.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
180
frontend/src/components/backgroudModal/index.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useRef } from 'react'
|
||||
import { X, Image as ImageIcon, Plus, Upload, Check } from 'lucide-react'
|
||||
import useSettingStore from '@/stores/settingStore'
|
||||
import Cropper from 'react-easy-crop'
|
||||
import getCroppedImg from '@/utils/cropImage'
|
||||
|
||||
const initialImages = {
|
||||
"bg-1": "bg-1.jpeg",
|
||||
"bg-2": "bg-2.png",
|
||||
"bg-3": "bg-3.png",
|
||||
"bg-6": "bg-6.png",
|
||||
"bg-7": "bg-7.jpeg",
|
||||
"bg-8": "bg-8.png",
|
||||
"bg-9": "bg-9.jpeg",
|
||||
"bg-10": "bg-10.jpg",
|
||||
"bg-11": "bg-11.jpeg",
|
||||
"bg-12": "bg-12.jpg",
|
||||
"bg-13": "bg-13.jpg",
|
||||
"bg-16": "bg-16.jpg",
|
||||
}
|
||||
|
||||
export const BackgroundSelector = () => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [newUrl, setNewUrl] = useState('')
|
||||
const [croppingImage, setCroppingImage] = useState<string | null>(null)
|
||||
const [crop, setCrop] = useState({ x: 0, y: 0 })
|
||||
const [zoom, setZoom] = useState(1)
|
||||
const [croppedAreaPixels, setCroppedAreaPixels] = useState<any>(null)
|
||||
const { background, setBackground, extraBackgrounds, setExtraBackgrounds } = useSettingStore()
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const handleSelect = (img: string) => {
|
||||
setIsOpen(false)
|
||||
setBackground(img)
|
||||
}
|
||||
|
||||
const handleAddUrl = () => {
|
||||
if (!newUrl.trim()) return setCroppingImage(newUrl)
|
||||
setNewUrl('')
|
||||
}
|
||||
|
||||
const handleRemoveExtra = (url: string) => {
|
||||
setExtraBackgrounds(extraBackgrounds.filter(bg => bg !== url))
|
||||
}
|
||||
|
||||
const handleUploadFile = (file: File) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => setCroppingImage(reader.result as string)
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
const handleCropComplete = async () => {
|
||||
if (!croppingImage || !croppedAreaPixels) return
|
||||
const croppedBase64 = await getCroppedImg(croppingImage, croppedAreaPixels)
|
||||
setExtraBackgrounds([croppedBase64, ...extraBackgrounds])
|
||||
setCroppingImage(null)
|
||||
}
|
||||
|
||||
const allBackgrounds = [...extraBackgrounds, ...Object.values(initialImages)]
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center gap-4">
|
||||
<div className="tooltip tooltip-right" data-tip="Select Background">
|
||||
<button
|
||||
className="group btn btn-primary btn-circle flex items-center justify-center shadow-md transition-all duration-300 hover:scale-110 hover:shadow-lg hover:bg-primary/80"
|
||||
onClick={() => setIsOpen(true)}
|
||||
>
|
||||
<ImageIcon size={22} className="text-white transition-all duration-300 group-hover:rotate-6 group-hover:scale-110 group-hover:text-yellow-300" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<div className="fixed inset-0 z-40 flex items-center justify-center bg-base-200/60 pt-10">
|
||||
<div className="bg-base-200 text-white rounded-xl shadow-xl p-6 w-[90%] max-w-2xl relative">
|
||||
<button className="btn btn-ghost btn-circle absolute top-3 right-3" onClick={() => setIsOpen(false)}>
|
||||
<X size={20} />
|
||||
</button>
|
||||
|
||||
<h2 className="text-lg font-semibold mb-4">Choose Background</h2>
|
||||
|
||||
{/* Add via URL */}
|
||||
<div className="flex gap-2 mb-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Paste image URL (https://...)"
|
||||
className="input input-bordered w-full text-info"
|
||||
value={newUrl}
|
||||
onChange={(e) => setNewUrl(e.target.value)}
|
||||
/>
|
||||
<button className="btn btn-success flex items-center gap-1" onClick={handleAddUrl}>
|
||||
<Plus size={16} /> Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Upload from computer */}
|
||||
<div className="flex mb-4">
|
||||
<button
|
||||
className="btn btn-warning flex items-center gap-1"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<Upload size={16} /> Upload from computer
|
||||
</button>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="hidden"
|
||||
ref={fileInputRef}
|
||||
onChange={(e) => {
|
||||
const file = e.target.files?.[0]
|
||||
if (file) handleUploadFile(file)
|
||||
e.target.value = ''
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Crop Modal */}
|
||||
{croppingImage && (
|
||||
<div className="fixed inset-0 z-60 flex flex-col items-center justify-center bg-black/70 p-4">
|
||||
<div className="relative w-full max-w-3xl h-[400px] bg-gray-800 rounded-lg">
|
||||
<Cropper
|
||||
image={croppingImage}
|
||||
crop={crop}
|
||||
zoom={zoom}
|
||||
aspect={16 / 9}
|
||||
onCropChange={setCrop}
|
||||
onZoomChange={setZoom}
|
||||
onCropComplete={(_, croppedAreaPixels) => setCroppedAreaPixels(croppedAreaPixels)}
|
||||
/>
|
||||
<button
|
||||
className="absolute bottom-4 left-1/2 -translate-x-1/2 btn btn-success"
|
||||
onClick={handleCropComplete}
|
||||
>
|
||||
<Check size={20} /> Done
|
||||
</button>
|
||||
<button
|
||||
className="absolute top-2 right-2 btn btn-ghost btn-circle"
|
||||
onClick={() => setCroppingImage(null)}
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 max-h-[60vh] overflow-y-auto">
|
||||
{allBackgrounds.map((value, i) => {
|
||||
const isExtra = i < extraBackgrounds.length
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`relative rounded-lg overflow-hidden cursor-pointer border-2 transition-all duration-200 ${
|
||||
value === background ? 'border-blue-500' : 'border-transparent hover:border-gray-500'
|
||||
}`}
|
||||
onClick={() => handleSelect(value)}
|
||||
>
|
||||
<img src={value} alt={`bg-${i}`} loading="lazy" className="w-full h-28 object-cover" />
|
||||
{isExtra && (
|
||||
<button
|
||||
className="absolute top-1 right-1 bg-black/50 hover:bg-black/70 text-white rounded-full p-1"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
handleRemoveExtra(value)
|
||||
}}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function CloseModal({
|
||||
className="btn btn-warning"
|
||||
onClick={async () => {
|
||||
onClose()
|
||||
const [success, message] = await AppService.MinimizeApp()
|
||||
const [success, message] = await AppService.HideApp()
|
||||
if (!success) toast.error(message)
|
||||
if (!closingOption.isAsk) {
|
||||
setClosingOption({ isMinimize: true, isAsk: false })
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import ThemeController from "../themeController";
|
||||
import useModalStore from "@/stores/modalStore";
|
||||
import { Settings2 } from "lucide-react";
|
||||
import { Blend, BookOpen, Diff, Home, Info, Languages, Minus, Puzzle, Settings, TrendingUpDown, Wrench, X } from "lucide-react";
|
||||
import { AppService } from "@bindings/firefly-launcher/internal/app-service";
|
||||
|
||||
export default function Header() {
|
||||
const { setIsOpenSettingModal } = useModalStore()
|
||||
|
||||
const controlButtons = [
|
||||
{
|
||||
icon: <Settings className="w-5 h-5" />,
|
||||
action: () => setIsOpenSettingModal(true),
|
||||
tip: "Settings",
|
||||
},
|
||||
{
|
||||
icon: <Minus className="w-5 h-5" />,
|
||||
action: () => AppService.MinimizeApp(),
|
||||
tip: "Minimize",
|
||||
},
|
||||
{
|
||||
icon: <X className="w-5 h-5" />,
|
||||
action: () => AppService.CloseApp(),
|
||||
tip: "Close",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="navbar bg-base-100 shadow-sm sticky top-0 z-50 px-3">
|
||||
<div className="navbar sticky top-0 z-50 px-3" style={{ '--wails-draggable': 'drag' } as any}>
|
||||
<div className="navbar-start">
|
||||
<div className="dropdown">
|
||||
<div tabIndex={0} role="button" className="btn btn-ghost md:hidden">
|
||||
@@ -14,7 +33,7 @@ export default function Header() {
|
||||
</div>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
|
||||
className="menu menu-sm dropdown-content bg-black/50 backdrop-blur-md rounded-box z-1 mt-3 w-52 p-2 shadow">
|
||||
<li><Link to="/">Home</Link></li>
|
||||
|
||||
<li>
|
||||
@@ -35,52 +54,110 @@ export default function Header() {
|
||||
<li><Link to="/about">About</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<Link to="/" className="grid grid-cols-1 items-start text-left gap-0 hover:scale-105 px-2">
|
||||
<Link to="/" className="grid grid-cols-1 items-start text-left gap-0">
|
||||
<div className="flex items-center justify-center">
|
||||
<img src="/appicon.png" alt="Logo" className='w-13 h-13 rounded-lg mx-2' />
|
||||
<div className="flex flex-col justify-center items-start">
|
||||
<h1 className="text-xl font-bold">
|
||||
<span className="text-emerald-500">Firefly </span>
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-emerald-400 via-orange-500 to-red-500">
|
||||
<span className="text-emerald-500"
|
||||
style={{
|
||||
textShadow: '0 1px 2px rgba(255, 255, 255, 0.2)',
|
||||
}}
|
||||
>Firefly </span>
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-emerald-400 via-orange-500 to-red-500"
|
||||
style={{
|
||||
textShadow: '0 1px 2px rgba(255, 255, 255, 0.2)',
|
||||
}}
|
||||
>
|
||||
Launcher
|
||||
</span>
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">By Kain</p>
|
||||
<p
|
||||
className="text-white text-sm"
|
||||
style={{
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.8)',
|
||||
}}
|
||||
>
|
||||
By Kain
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="navbar-center hidden md:flex">
|
||||
<ul className="menu menu-horizontal px-1 gap-4">
|
||||
<li><Link to="/">Home</Link></li>
|
||||
<div className="navbar-center hidden md:flex bg-black/40 backdrop-blur-sm rounded-lg shadow-lg">
|
||||
<ul className="menu menu-horizontal px-1 gap-4 text-white">
|
||||
<li>
|
||||
<Link to="/" className="flex items-center gap-2 hover:text-cyan-300 transition-colors">
|
||||
<Home size={18} /> Home
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>Tools</summary>
|
||||
<ul className="p-2">
|
||||
<li><Link to="/language">Language</Link></li>
|
||||
<li><Link to="/diff">Diff</Link></li>
|
||||
<summary className="flex items-center gap-2 cursor-pointer hover:text-cyan-300 transition-colors">
|
||||
<Wrench size={18} /> Tools
|
||||
</summary>
|
||||
<ul className="p-2 bg-black/75 text-white rounded-lg">
|
||||
<li>
|
||||
<Link to="/language" className="flex items-center gap-2 hover:text-cyan-300">
|
||||
<Languages size={18} /> Language
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/diff" className="flex items-center gap-2 hover:text-cyan-300">
|
||||
<Diff size={18} /> Client update
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>Plugins</summary>
|
||||
<ul className="p-2">
|
||||
<li><Link to="/analysis">Analysis (Veritas)</Link></li>
|
||||
<li><Link to="/srtools">Firefly Tools</Link></li>
|
||||
<summary className="flex items-center gap-2 cursor-pointer hover:text-cyan-300 transition-colors">
|
||||
<Puzzle size={18} /> Plugins
|
||||
</summary>
|
||||
<ul className="p-2 bg-black/75 text-white rounded-lg">
|
||||
<li>
|
||||
<Link to="/analysis" className="flex items-center gap-2 hover:text-cyan-300">
|
||||
<TrendingUpDown size={18} /> Analysis (Veritas)
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/srtools" className="flex items-center gap-2 hover:text-cyan-300">
|
||||
<Blend size={18} /> Firefly Tools
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
<li><Link to="/howto">How to?</Link></li>
|
||||
<li><Link to="/about">About</Link></li>
|
||||
<li>
|
||||
<Link to="/howto" className="flex items-center gap-2 hover:text-cyan-300 transition-colors">
|
||||
<BookOpen size={18} /> How to?
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/about" className="flex items-center gap-2 hover:text-cyan-300 transition-colors">
|
||||
<Info size={18} /> About
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="navbar-end flex gap-2">
|
||||
<ThemeController />
|
||||
<button className="btn btn-ghost btn-circle" onClick={() => setIsOpenSettingModal(true)}>
|
||||
<Settings2 className="w-5 h-5" />
|
||||
|
||||
<div className="navbar-end flex gap-2 z-52">
|
||||
<div className="flex items-center gap-2 bg-black/40 backdrop-blur-sm rounded-lg">
|
||||
{controlButtons.map((btn, i) => (
|
||||
<div key={i} className="tooltip tooltip-bottom" data-tip={btn.tip}>
|
||||
<button
|
||||
onClick={btn.action}
|
||||
className="btn btn-ghost btn-circle bg-transparent border-none flex items-center justify-center"
|
||||
>
|
||||
<div className="hover:text-cyan-300 transition-colors">
|
||||
{btn.icon}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -14,8 +14,9 @@ export default function SettingModal({
|
||||
if (!isOpen) return null
|
||||
|
||||
const { setIsOpenSelfUpdateModal } = useModalStore()
|
||||
const { closingOption, setClosingOption } = useSettingStore()
|
||||
const { setUpdateData, updateData } = useLauncherStore()
|
||||
const { closingOption, setClosingOption, serverVersion,
|
||||
proxyVersion, } = useSettingStore()
|
||||
const { setUpdateData, updateData, launcherVersion } = useLauncherStore()
|
||||
const CheckUpdate = async () => {
|
||||
const launcherData = await CheckUpdateLauncher()
|
||||
if (!launcherData.isUpdate) {
|
||||
@@ -32,7 +33,7 @@ export default function SettingModal({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm">
|
||||
<div className="fixed inset-0 z-10 flex items-center justify-center bg-black/40 backdrop-blur-sm">
|
||||
<div className="relative w-[90%] max-w-md bg-base-100 text-base-content rounded-2xl border border-purple-500/30 shadow-2xl shadow-purple-500/30 p-6">
|
||||
{/* Header */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
@@ -72,7 +73,6 @@ export default function SettingModal({
|
||||
className="checkbox checkbox-primary w-5 h-5 mt-1"
|
||||
checked={!closingOption.isAsk}
|
||||
onChange={(e) => {
|
||||
console.log(!e.target.checked)
|
||||
setClosingOption({
|
||||
isMinimize: closingOption.isMinimize,
|
||||
isAsk: !e.target.checked
|
||||
@@ -83,7 +83,7 @@ export default function SettingModal({
|
||||
<span className="text-base font-medium text-info">
|
||||
Set do not ask again
|
||||
</span>
|
||||
<span className="text-sm text-warning">
|
||||
<span className="text-sm text-accent">
|
||||
Next time you close the app, it will automatically{" "}
|
||||
{closingOption.isMinimize ? "minimize to system tray" : "quit the app"}{" "}
|
||||
without asking.
|
||||
@@ -91,6 +91,24 @@ export default function SettingModal({
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Section 3: Launcher Version */}
|
||||
<div className="p-4 bg-base-200 rounded-xl border border-purple-300 shadow-sm">
|
||||
<h4 className="font-bold text-lg mb-2">Version</h4>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<p className="text-base text-info">
|
||||
Server: {serverVersion}
|
||||
</p>
|
||||
<p className="text-base text-info">
|
||||
Proxy: {proxyVersion}
|
||||
</p>
|
||||
|
||||
<p className="text-base text-info">
|
||||
Launcher: {launcherVersion}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function ThemeController() {
|
||||
const [theme, setTheme] = useState(localStorage.getItem("theme") ?? "night");
|
||||
|
||||
const handleToggle = (e: any) => {
|
||||
if (e.target.checked) {
|
||||
setTheme("cupcake");
|
||||
} else {
|
||||
setTheme("night");
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('theme', theme!)
|
||||
const localTheme = localStorage.getItem('theme')
|
||||
document.querySelector('html')?.setAttribute('data-theme', localTheme!)
|
||||
}, [theme]);
|
||||
|
||||
|
||||
return (
|
||||
<label className="toggle text-base-content">
|
||||
<input type="checkbox" onChange={handleToggle} className="theme-controller" />
|
||||
|
||||
<svg aria-label="moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g strokeLinejoin="round" strokeLinecap="round" strokeWidth="2" fill="none" stroke="currentColor"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></g></svg>
|
||||
<svg aria-label="sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g strokeLinejoin="round" strokeLinecap="round" strokeWidth="2" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></g></svg>
|
||||
|
||||
</label>
|
||||
)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export default function UpdateModal({ isOpen, title, message, buttons, onClose }
|
||||
|
||||
<div className="px-6 pb-6">
|
||||
<div className="mb-6">
|
||||
<p className="text-warning text-lg">{message}</p>
|
||||
<p className="text-accent text-lg">{message}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
|
||||
@@ -23,11 +23,9 @@ export async function UpdateProxy(proxyVersion: string) : Promise<void> {
|
||||
setDownloadType("Downloading proxy...")
|
||||
const [ok, error] = await GitService.DownloadProxyProgress(proxyVersion)
|
||||
if (ok) {
|
||||
setDownloadType("Unzipping proxy...")
|
||||
GitService.UnzipProxy()
|
||||
setDownloadType("Download proxy successfully")
|
||||
setProxyVersion(proxyVersion)
|
||||
setProxyPath("./proxy/FireflyProxy.exe")
|
||||
setProxyPath("./proxy/firefly-go-proxy.exe")
|
||||
} else {
|
||||
toast.error(error)
|
||||
setDownloadType("Download proxy failed")
|
||||
|
||||
@@ -19,24 +19,25 @@ export function useGlobalEvents() {
|
||||
const onProxyExit = () => setProxyRunning(false);
|
||||
|
||||
const onDownload = (event: any) => {
|
||||
const { percent, speed } = event.data[0];
|
||||
const { percent, speed } = event.data;
|
||||
setProgressDownload(Number(percent));
|
||||
setDownloadSpeed(speed);
|
||||
};
|
||||
|
||||
const onUpdateProgress = (event: any) => {
|
||||
const { progress, maxProgress } = event.data[0];
|
||||
console.log(event)
|
||||
const { progress, maxProgress } = event.data;
|
||||
setProgressUpdate(Number(progress));
|
||||
setMaxProgressUpdate(Number(maxProgress));
|
||||
};
|
||||
|
||||
const onMessageUpdate = (event: any) => {
|
||||
const { message } = event.data[0];
|
||||
const { message } = event.data;
|
||||
setMessageUpdate(message);
|
||||
};
|
||||
|
||||
const onStageUpdate = (event: any) => {
|
||||
const { stage } = event.data[0];
|
||||
const { stage } = event.data;
|
||||
setStageType(stage);
|
||||
};
|
||||
|
||||
@@ -49,7 +50,7 @@ export function useGlobalEvents() {
|
||||
Events.On("diff:message", onMessageUpdate);
|
||||
Events.On("diff:stage", onStageUpdate);
|
||||
Events.On("diff:error", (event: any) => {
|
||||
const { message } = event.data[0];
|
||||
const { message } = event.data;
|
||||
toast.error(message);
|
||||
});
|
||||
Events.On("window:close", async () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function AboutPage() {
|
||||
I created a lightweight and modern <span className="font-semibold text-success">Game Launcher</span> to help users easily launch and manage their games with better performance and simplicity.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed">
|
||||
The launcher is built using <span className="font-mono text-info">Go + Wails3</span>, with a clean and responsive interface styled with <span className="text-warning">Tailwind CSS</span> and <span className="text-warning">DaisyUI</span>.
|
||||
The launcher is built using <span className="font-mono text-info">Go + Wails3</span>, with a clean and responsive interface styled with <span className="text-accent">Tailwind CSS</span> and <span className="text-accent">DaisyUI</span>.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed">
|
||||
My goal is to make tools that are fast, efficient, and enjoyable to use — and this launcher is just the beginning.
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function AnalysisPage() {
|
||||
</div>
|
||||
<a
|
||||
href="https://sranalysis.kain.id.vn/"
|
||||
className="link link-warning font-mono text-sm break-all"
|
||||
className="link link-accent font-mono text-sm break-all"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -79,7 +79,7 @@ export default function AnalysisPage() {
|
||||
</div>
|
||||
<a
|
||||
href="https://firefly-sranalysis.vercel.app/"
|
||||
className="link link-warning font-mono text-sm break-all"
|
||||
className="link link-accent font-mono text-sm break-all"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -309,7 +309,7 @@ export default function DiffPage() {
|
||||
<div className="w-full p-4">
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-center items-center text-sm text-white/80">
|
||||
<span className="font-bold text-lg text-warning">{stageType}:</span>
|
||||
<span className="font-bold text-lg text-accent">{stageType}:</span>
|
||||
<div className="flex items-center gap-4 ml-2">
|
||||
{stageType !== 'Cut Data' && <span className="text-white font-bold">{progressUpdate.toFixed(0)} / {maxProgressUpdate.toFixed(0)}</span>}
|
||||
{stageType === 'Cut Data' && <span className="text-white font-bold truncate max-w-full overflow-hidden whitespace-nowrap">{messageUpdate}</span>}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function FireflyToolsPage() {
|
||||
This site is a another version of {" "}
|
||||
<span className="font-semibold text-success">Firefly Tools {" "}</span>
|
||||
developed by {" "}
|
||||
<span className="font-semibold text-warning">Me {"(Kain)"}</span>
|
||||
<span className="font-semibold text-accent">Me {"(Kain)"}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
@@ -30,7 +30,7 @@ export default function FireflyToolsPage() {
|
||||
</div>
|
||||
<a
|
||||
href="https://srtools.kain.id.vn/"
|
||||
className="link link-warning font-mono text-sm break-all"
|
||||
className="link link-accent font-mono text-sm break-all"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -45,7 +45,7 @@ export default function FireflyToolsPage() {
|
||||
</div>
|
||||
<a
|
||||
href="https://firefly-srtools.vercel.app/"
|
||||
className="link link-warning font-mono text-sm break-all"
|
||||
className="link link-accent font-mono text-sm break-all"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -55,14 +55,14 @@ export default function FireflyToolsPage() {
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="text-blue-600 text-lg">👨💻</div>
|
||||
<p>The original tool was created by a third-party developer named <span className="font-semibold text-warning">Amazing</span>. This version is directly based on that work, without modification to core logic.</p>
|
||||
<p>The original tool was created by a third-party developer named <span className="font-semibold text-accent">Amazing</span>. This version is directly based on that work, without modification to core logic.</p>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="text-blue-600 text-lg">🔗</div>
|
||||
<p>There is also a more modern version by the same author available at{" "}
|
||||
<a
|
||||
href="https://srtools.neonteam.dev/"
|
||||
className="link link-warning"
|
||||
className="link link-accent"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -71,7 +71,7 @@ export default function FireflyToolsPage() {
|
||||
{" "}and the original version at{" "}
|
||||
<a
|
||||
href="https://srtools.pages.dev/"
|
||||
className="link link-warning"
|
||||
className="link link-accent"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -95,14 +95,14 @@ export default function FireflyToolsPage() {
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="text-green-600 text-lg">🔌</div>
|
||||
<p>Instantly apply setups to <span className="font-semibold text-warning">Firefly GO Server</span> using <span className="font-semibold">Connect PS</span> — no manual file uploads required.</p>
|
||||
<p>Instantly apply setups to <span className="font-semibold text-accent">Firefly GO Server</span> using <span className="font-semibold">Connect PS</span> — no manual file uploads required.</p>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="text-green-600 text-2xl">✨</div>
|
||||
<div>
|
||||
<h4 className="font-semibold text-green-800 text-lg">Extra Settings</h4>
|
||||
<p className="text-green-700 mt-1">
|
||||
Enhance your <span className="font-semibold text-warning">Firefly GO Server</span> experience with extra features:
|
||||
Enhance your <span className="font-semibold text-accent">Firefly GO Server</span> experience with extra features:
|
||||
</p>
|
||||
<ul className="list-disc list-inside mt-2 space-y-1 text-green-700">
|
||||
<li>🎭 <span className="font-medium">Hidden Game UI</span> — remove the entire game interface.</li>
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function HowToPage() {
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="text-green-600 text-lg">🌐</div>
|
||||
<p>Support switching in-game language (e.g., EN, JP, ZH, KR) via{" "}
|
||||
<a href="/language" className="link link-info font-mono">Language Tools</a>
|
||||
<Link to="/language" className="link link-info font-mono">Language Tools</Link>
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
@@ -35,7 +35,7 @@ export default function HowToPage() {
|
||||
</p>
|
||||
<p className="text-green-700">
|
||||
Use the{" "}
|
||||
<a href="/diff" className="link link-info font-mono">Diff Tool</a>{" "}
|
||||
<Link to="/diff" className="link link-info font-mono">Diff Tool</Link>{" "}
|
||||
(<span className="font-medium">DiffPatch</span>) for fast & lightweight incremental updates.
|
||||
</p>
|
||||
<p className="text-green-700 mt-1">
|
||||
@@ -56,7 +56,7 @@ export default function HowToPage() {
|
||||
|
||||
<p className="text-blue-700 mb-4">
|
||||
Below are in-game chat commands you can use. Some commands require you to enable{" "}
|
||||
<span className="font-semibold text-warning">Theorycraft Mode</span>.
|
||||
<span className="font-semibold text-accent">Theorycraft Mode</span>.
|
||||
</p>
|
||||
|
||||
{/* Theorycraft Mode Warning */}
|
||||
|
||||
@@ -208,10 +208,10 @@ export default function LanguagePage() {
|
||||
|
||||
<div className="bg-warning/5 rounded-lg p-2 border border-warning/30">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<Mic size={20} className="text-warning" />
|
||||
<span className="font-bold text-warning">Voice Language</span>
|
||||
<Mic size={20} className="text-accent" />
|
||||
<span className="font-bold text-accent">Voice Language</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-warning">
|
||||
<p className="text-2xl font-bold text-accent">
|
||||
{getLanguageLabel(voiceLang)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -250,7 +250,7 @@ export default function LanguagePage() {
|
||||
|
||||
{/* Voice Language */}
|
||||
<div className="space-y-3">
|
||||
<label className="flex text-sm font-medium text-warning items-center gap-2">
|
||||
<label className="flex text-sm font-medium text-accent items-center gap-2">
|
||||
<Mic size={16} />
|
||||
Voice Language
|
||||
</label>
|
||||
|
||||
@@ -11,9 +11,12 @@ import { motion } from 'motion/react';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import { CheckUpdateLauncher, CheckUpdateProxy, CheckUpdateServer, sleep, UpdateLauncher, UpdateProxy, UpdateServer } from '@/helper';
|
||||
import UpdateModal from '@/components/updateModal';
|
||||
import { BackgroundSelector } from '@/components/backgroudModal';
|
||||
|
||||
|
||||
export default function LauncherPage() {
|
||||
const { gamePath,
|
||||
const {
|
||||
gamePath,
|
||||
setGamePath,
|
||||
setGameDir,
|
||||
serverPath,
|
||||
@@ -21,6 +24,7 @@ export default function LauncherPage() {
|
||||
gameDir,
|
||||
serverVersion,
|
||||
proxyVersion,
|
||||
background
|
||||
} = useSettingStore()
|
||||
|
||||
const {
|
||||
@@ -44,7 +48,7 @@ export default function LauncherPage() {
|
||||
progressDownload,
|
||||
downloadSpeed,
|
||||
updateData,
|
||||
launcherVersion,
|
||||
// launcherVersion,
|
||||
setLauncherVersion,
|
||||
setIsLoading,
|
||||
setDownloadType,
|
||||
@@ -174,8 +178,6 @@ export default function LauncherPage() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const handleStartGame = async () => {
|
||||
if (!gamePath) {
|
||||
return
|
||||
@@ -186,39 +188,46 @@ export default function LauncherPage() {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
if (!proxyRunning && !gamePath.endsWith("launcher.exe")) {
|
||||
const resultProxy = await FSService.StartWithConsole(proxyPath)
|
||||
const [resultProxy, error] = await FSService.StartWithConsole(proxyPath)
|
||||
if (!resultProxy) {
|
||||
toast.error('Failed to start proxy')
|
||||
toast.error('Failed to start proxy: ' + error)
|
||||
return
|
||||
}
|
||||
setProxyRunning(true)
|
||||
}
|
||||
await sleep(500)
|
||||
if (!serverRunning) {
|
||||
const resultServer = await FSService.StartWithConsole(serverPath)
|
||||
const [resultServer, error] = await FSService.StartWithConsole(serverPath)
|
||||
if (!resultServer) {
|
||||
toast.error('Failed to start server')
|
||||
toast.error('Failed to start server: ' + error)
|
||||
return
|
||||
}
|
||||
setServerRunning(true)
|
||||
}
|
||||
await sleep(2000)
|
||||
await sleep(1000)
|
||||
const gameFolder = await FSService.GetDir(gamePath)
|
||||
const fileNeedRemove = await FSService.Join(gameFolder, "StarRail_Data", "Plugins", "x86_64", "AccountPlatNative.dll")
|
||||
const fileExists = await FSService.FileExists(fileNeedRemove)
|
||||
if (fileExists) {
|
||||
await FSService.RemoveFile(fileNeedRemove)
|
||||
}
|
||||
if (gamePath.endsWith("launcher.exe")) {
|
||||
const resultGame = await FSService.StartWithConsole(gamePath)
|
||||
const [resultGame, error] = await FSService.StartWithConsole(gamePath)
|
||||
if (!resultGame) {
|
||||
toast.error('Failed to start game')
|
||||
toast.error('Failed to start game: ' + error)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
const resultGame = await FSService.StartApp(gamePath)
|
||||
const [resultGame, error] = await FSService.StartApp(gamePath)
|
||||
if (!resultGame) {
|
||||
toast.error('Failed to start game')
|
||||
toast.error('Failed to start game: ' + error)
|
||||
return
|
||||
}
|
||||
}
|
||||
setGameRunning(true)
|
||||
|
||||
} catch (err: any) {
|
||||
console.log(err)
|
||||
toast.error('StartGame error:', err)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
@@ -265,24 +274,24 @@ export default function LauncherPage() {
|
||||
|
||||
return (
|
||||
<div className="relative min-h-fit overflow-hidden">
|
||||
<div
|
||||
className="fixed inset-0 z-0 w-full h-full"
|
||||
style={{
|
||||
backgroundImage: "url('/bg.jpg')",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat"
|
||||
<img
|
||||
src={background}
|
||||
alt="background"
|
||||
className="fixed inset-0 w-full h-full object-cover z-0"
|
||||
onError={(e) => {
|
||||
const target = e.currentTarget as HTMLImageElement
|
||||
target.src = "bg-12.jpg"
|
||||
}}
|
||||
></div>
|
||||
/>
|
||||
|
||||
{/* Header */}
|
||||
<header className="hidden sm:flex fixed z-10 items-center justify-between p-6">
|
||||
<div className="text-2xl font-bold text-white">Firefly GO</div>
|
||||
<header className="hidden sm:flex fixed z-10 items-center justify-between py-6 px-4 ">
|
||||
<div className="text-2xl font-bold text-white bg-gray-500/5 rounded-full p-1">Firefly GO</div>
|
||||
</header>
|
||||
|
||||
<div className="hidden sm:flex fixed top-1/4 left-4 z-10 flex-col space-y-3 bg-black/30 backdrop-blur-md rounded-xl p-3 shadow-lg">
|
||||
<div className="hidden sm:flex fixed top-1/4 right-4 z-10 flex-col space-y-3 bg-white/5 rounded-xl p-3 shadow-lg">
|
||||
{widgetLinks.map((link, idx) => (
|
||||
<div key={idx} className="tooltip tooltip-right" data-tip={link.tooltip}>
|
||||
<div key={idx} className="tooltip tooltip-left" data-tip={link.tooltip}>
|
||||
<a
|
||||
className={`btn btn-circle ${link.btnClass}`}
|
||||
target="_blank"
|
||||
@@ -297,7 +306,7 @@ export default function LauncherPage() {
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="tooltip tooltip-right" data-tip="How to use all tools & commands">
|
||||
<div className="tooltip tooltip-left" data-tip="How to use all tools & commands">
|
||||
<Link
|
||||
to="/howto"
|
||||
className="btn btn-warning btn-circle"
|
||||
@@ -307,6 +316,9 @@ export default function LauncherPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden sm:flex fixed top-1/2 left-5 z-10 ">
|
||||
<BackgroundSelector />
|
||||
</div>
|
||||
|
||||
{/* Bottom Panel */}
|
||||
{serverReady && proxyReady && !isDownloading && (
|
||||
@@ -459,15 +471,11 @@ export default function LauncherPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Version Info */}
|
||||
{serverReady && proxyReady && !isDownloading && (
|
||||
<div className="hidden md:block fixed bottom-4 left-4 z-10 text-sm font-bold bg-black/20 backdrop-blur-sm rounded-lg p-2 shadow">
|
||||
<p className="text-primary">Version server: {serverVersion}</p>
|
||||
<p className="mt-2 text-secondary">Version proxy: {proxyVersion}</p>
|
||||
<p className="mt-2 text-success">Version launcher: {launcherVersion}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="hidden md:block fixed bottom-4 left-5 z-10">
|
||||
|
||||
<img src="/heart-hsr.gif" alt="firefly animation" className="rounded-lg w-24 h-24" />
|
||||
|
||||
</div>
|
||||
{/* Modal */}
|
||||
<UpdateModal
|
||||
isOpen={isOpenUpdateDataModal}
|
||||
|
||||
@@ -14,6 +14,10 @@ interface SettingState {
|
||||
isMinimize: boolean;
|
||||
isAsk: boolean;
|
||||
}
|
||||
background: string;
|
||||
extraBackgrounds: string[];
|
||||
setExtraBackgrounds: (newExtraBackgrounds: string[]) => void;
|
||||
setBackground: (newBackground: string) => void;
|
||||
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => void;
|
||||
setLocale: (newLocale: string) => void;
|
||||
setGamePath: (newGamePath: string) => void;
|
||||
@@ -38,6 +42,10 @@ const useSettingStore = create<SettingState>()(
|
||||
isMinimize: false,
|
||||
isAsk: true,
|
||||
},
|
||||
background: "bg-12.jpg",
|
||||
extraBackgrounds: [],
|
||||
setExtraBackgrounds: (newExtraBackgrounds: string[]) => set({ extraBackgrounds: newExtraBackgrounds }),
|
||||
setBackground: (newBackground: string) => set({ background: newBackground }),
|
||||
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => set({ closingOption: newClosingOption }),
|
||||
setLocale: (newLocale: string) => set({ locale: newLocale }),
|
||||
setGamePath: (newGamePath: string) => set({ gamePath: newGamePath }),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "daisyui"{
|
||||
themes: night --default, night --prefersdark, cupcake;
|
||||
themes: dracula --default;
|
||||
}
|
||||
|
||||
25
frontend/src/utils/cropImage.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
export default function getCroppedImg(imageSrc: string, crop: any): Promise<string> {
|
||||
const image = new Image()
|
||||
image.src = imageSrc
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')!
|
||||
canvas.width = crop.width
|
||||
canvas.height = crop.height
|
||||
return new Promise((resolve) => {
|
||||
image.onload = () => {
|
||||
ctx.drawImage(
|
||||
image,
|
||||
crop.x,
|
||||
crop.y,
|
||||
crop.width,
|
||||
crop.height,
|
||||
0,
|
||||
0,
|
||||
crop.width,
|
||||
crop.height
|
||||
)
|
||||
resolve(canvas.toDataURL('image/jpeg'))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -13,10 +13,9 @@
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@bindings/*": ["bindings/*"],
|
||||
"@/*": ["src/*"]
|
||||
"@bindings/*": ["./bindings/*"],
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
|
||||
56
go.mod
@@ -1,55 +1,53 @@
|
||||
module firefly-launcher
|
||||
|
||||
go 1.25
|
||||
go 1.25.5
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.18.0
|
||||
github.com/klauspost/compress v1.18.2
|
||||
github.com/minio/selfupdate v0.6.0
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/sys v0.31.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.59
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96
|
||||
golang.org/x/sys v0.40.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require (
|
||||
aead.dev/minisign v0.2.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
aead.dev/minisign v0.3.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||
github.com/adrg/xdg v0.5.3 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
github.com/cloudflare/circl v1.6.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||
github.com/ebitengine/purego v0.9.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.7.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.16.4 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect
|
||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||
github.com/leaanthony/u v1.1.1 // indirect
|
||||
github.com/lmittmann/tint v1.0.7 // indirect
|
||||
github.com/lmittmann/tint v1.1.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/samber/lo v1.49.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.21 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/samber/lo v1.52.0 // indirect
|
||||
github.com/sergi/go-diff v1.4.0 // indirect
|
||||
github.com/skeema/knownhosts v1.3.2 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.23 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
golang.org/x/crypto v0.47.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
124
go.sum
@@ -1,12 +1,13 @@
|
||||
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
|
||||
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
aead.dev/minisign v0.3.0 h1:8Xafzy5PEVZqYDNP60yJHARlW1eOQtsKNp/Ph2c0vRA=
|
||||
aead.dev/minisign v0.3.0/go.mod h1:NLvG3Uoq3skkRMDuc3YHpWUTMTrSExqm+Ij73W13F6Y=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
|
||||
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
@@ -15,33 +16,35 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ=
|
||||
github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
||||
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM=
|
||||
github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
|
||||
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
|
||||
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
|
||||
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e h1:Lf/gRkoycfOBPa42vU2bbgPurFong6zXeFtPoxholzU=
|
||||
github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -50,12 +53,14 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 h1:njuLRcjAuMKr7kI3D85AXWkw6/+v9PwtV6M6o11sWHQ=
|
||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
@@ -67,8 +72,8 @@ github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
||||
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||
github.com/lmittmann/tint v1.0.7 h1:D/0OqWZ0YOGZ6AyC+5Y2kD8PBEzBk6rFHVSfOqCkF9Y=
|
||||
github.com/lmittmann/tint v1.0.7/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
|
||||
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
@@ -80,8 +85,8 @@ github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDw
|
||||
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
||||
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -91,41 +96,38 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
|
||||
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
|
||||
github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/wailsapp/go-webview2 v1.0.21 h1:k3dtoZU4KCoN/AEIbWiPln3P2661GtA2oEgA2Pb+maA=
|
||||
github.com/wailsapp/go-webview2 v1.0.21/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34 h1:t6NwHOLJzXuESb3YSXarSd1C/U1h2CpXF+BLr0ekj2g=
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34/go.mod h1:UZpnhYuju4saspCJrIHAvC0H5XjtKnqd26FRxJLrQ0M=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/wailsapp/go-webview2 v1.0.23 h1:jmv8qhz1lHibCc79bMM/a/FqOnnzOGEisLav+a0b9P0=
|
||||
github.com/wailsapp/go-webview2 v1.0.23/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.59 h1:L1d59J+TuLBRBXX0pdMSOior5JwMrM7gtSshKXzHM90=
|
||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.59/go.mod h1:ynGPamjQDXoaWjOGKAHJ6vw94PUDbeIxtbapunWcDjk=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -137,25 +139,23 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -26,7 +26,7 @@ func (a *AppService) CloseApp() (bool, string) {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (a *AppService) MinimizeApp() (bool, string) {
|
||||
func (a *AppService) HideApp() (bool, string) {
|
||||
window := application.Get().Window.Current()
|
||||
if window == nil {
|
||||
return false, "not found window"
|
||||
@@ -35,3 +35,29 @@ func (a *AppService) MinimizeApp() (bool, string) {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (a *AppService) MinimizeApp() (bool, string) {
|
||||
window := application.Get().Window.Current()
|
||||
if window == nil {
|
||||
return false, "not found window"
|
||||
}
|
||||
window.Minimise()
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (a *AppService) MaximizeApp() (bool, string) {
|
||||
window := application.Get().Window.Current()
|
||||
if window == nil {
|
||||
return false, "not found window"
|
||||
}
|
||||
window.Maximise()
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (a *AppService) RestoreApp() (bool, string) {
|
||||
window := application.Get().Window.Current()
|
||||
if window == nil {
|
||||
return false, "not found window"
|
||||
}
|
||||
window.Restore()
|
||||
return true, ""
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (h *DiffService) CheckTypeHDiff(patchPath string) (bool, string, string) {
|
||||
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdifffiles.txt"); err == nil && ok {
|
||||
return true, "hdifffiles.txt", ""
|
||||
}
|
||||
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdifffiles.txt"); err == nil && ok {
|
||||
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdifffiles.json"); err == nil && ok {
|
||||
return true, "hdifffiles.json", ""
|
||||
}
|
||||
if ok, err := sevenzip.IsFileIn7z(patchPath, "hdiffmap.json"); err == nil && ok {
|
||||
@@ -68,9 +68,11 @@ func (h *DiffService) VersionValidate(gamePath, patchPath string) (bool, string)
|
||||
if err := sevenzip.ExtractAFileFromZip(patchPath, "StarRail_Data\\StreamingAssets\\BinaryVersion.bytes.hdiff", constant.TempUrl); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
patchBinFile := filepath.Join(constant.TempUrl, "BinaryVersion.bytes.hdiff")
|
||||
sourceBinFile := oldBinPath
|
||||
tempBinFile = filepath.Join(constant.TempUrl, "BinaryVersion.bytes")
|
||||
|
||||
if err := hpatchz.ApplyPatch(sourceBinFile, patchBinFile, tempBinFile); err != nil {
|
||||
os.Remove(patchBinFile)
|
||||
return false, err.Error()
|
||||
@@ -172,9 +174,11 @@ func (h *DiffService) HDiffPatchData(gamePath string) (bool, string) {
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
if err := json.Unmarshal(data, &jsonData); err != nil {
|
||||
var hdiffJson []*models.HDiffData
|
||||
if err := json.Unmarshal(data, &hdiffJson); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
jsonData.DiffMap = append(jsonData.DiffMap, hdiffJson...)
|
||||
} else if _, err := os.Stat(hdiffFilesPath); err == nil {
|
||||
files, err := models.LoadHDiffFiles(hdiffFilesPath)
|
||||
if err != nil {
|
||||
@@ -188,6 +192,7 @@ func (h *DiffService) HDiffPatchData(gamePath string) (bool, string) {
|
||||
}
|
||||
|
||||
application.Get().Event.Emit("diff:stage", map[string]string{"stage": "Patching HDiff"})
|
||||
|
||||
for i, entry := range jsonData.DiffMap {
|
||||
application.Get().Event.Emit(
|
||||
"diff:progress", map[string]int{
|
||||
|
||||
@@ -2,12 +2,12 @@ package fsService
|
||||
|
||||
import (
|
||||
"firefly-launcher/pkg/sevenzip"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
type FSService struct{}
|
||||
|
||||
func (f *FSService) PickFolder() (string, error) {
|
||||
dialog := application.OpenFileDialog().
|
||||
dialog := application.Get().Dialog.OpenFile().
|
||||
CanChooseDirectories(true).
|
||||
CanCreateDirectories(true).
|
||||
ResolvesAliases(true)
|
||||
@@ -31,7 +31,7 @@ func (f *FSService) PickFolder() (string, error) {
|
||||
}
|
||||
|
||||
func (f *FSService) PickFile(filter string) (string, error) {
|
||||
dialog := application.OpenFileDialog().
|
||||
dialog := application.Get().Dialog.OpenFile().
|
||||
CanChooseFiles(true).
|
||||
ResolvesAliases(true)
|
||||
if runtime.GOOS == "darwin" {
|
||||
@@ -63,12 +63,25 @@ func (f *FSService) FileExists(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *FSService) StartApp(path string) (bool, error) {
|
||||
func (f *FSService) GetDir(path string) string {
|
||||
return filepath.Dir(path)
|
||||
}
|
||||
|
||||
func (f *FSService) Join(paths ...string) string {
|
||||
return filepath.Join(paths...)
|
||||
}
|
||||
|
||||
func (f *FSService) RemoveFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
func (f *FSService) StartApp(path string) (bool, string) {
|
||||
cmd := exec.Command(path)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, "StarRail.exe") {
|
||||
go func() {
|
||||
_ = cmd.Wait()
|
||||
@@ -76,17 +89,17 @@ func (f *FSService) StartApp(path string) (bool, error) {
|
||||
}()
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (f *FSService) StartWithConsole(path string) (bool, error) {
|
||||
func (f *FSService) StartWithConsole(path string) (bool, string) {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
if _, err := os.Stat(absPath); os.IsNotExist(err) {
|
||||
return false, fmt.Errorf("file not found: %s", absPath)
|
||||
return false, "file not found: " + absPath
|
||||
}
|
||||
cmd := exec.Command(absPath)
|
||||
cmd.Dir = filepath.Dir(absPath)
|
||||
@@ -103,7 +116,7 @@ func (f *FSService) StartWithConsole(path string) (bool, error) {
|
||||
err = cmd.Start()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -112,11 +125,11 @@ func (f *FSService) StartWithConsole(path string) (bool, error) {
|
||||
application.Get().Event.Emit("game:exit")
|
||||
} else if strings.HasSuffix(path, "firefly-go_win.exe") {
|
||||
application.Get().Event.Emit("server:exit")
|
||||
} else if strings.HasSuffix(path, "FireflyProxy.exe") {
|
||||
} else if strings.HasSuffix(path, "firefly-go-proxy.exe") {
|
||||
application.Get().Event.Emit("proxy:exit")
|
||||
}
|
||||
}()
|
||||
return true, nil
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (f *FSService) OpenFolder(path string) (bool, string) {
|
||||
@@ -142,4 +155,3 @@ func (f *FSService) FileExistsInZip(archivePath, fileInside string) (bool, strin
|
||||
}
|
||||
return exists, ""
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func (g *GitService) GetLatestProxyVersion() (bool, string, string) {
|
||||
}
|
||||
|
||||
func (g *GitService) DownloadProxyProgress(version string) (bool, string) {
|
||||
asset, ok := g.getReleaseAsset(version, constant.ProxyGitUrl, constant.ProxyZipFile)
|
||||
asset, ok := g.getReleaseAsset(version, constant.ProxyGitUrl, constant.ProxyFile)
|
||||
if !ok {
|
||||
return false, "no release found"
|
||||
}
|
||||
@@ -65,7 +65,3 @@ func (g *GitService) DownloadProxyProgress(version string) (bool, string) {
|
||||
return false, "failed to rename tmp file after retries"
|
||||
}
|
||||
|
||||
func (g *GitService) UnzipProxy() {
|
||||
g.unzipParallel(filepath.Join(constant.ProxyStorageUrl, constant.ProxyZipFile), constant.ProxyStorageUrl)
|
||||
os.Remove(filepath.Join(constant.ProxyStorageUrl, constant.ProxyZipFile))
|
||||
}
|
||||
|
||||
8
main.go
@@ -93,10 +93,12 @@ func main() {
|
||||
TitleBar: application.MacTitleBarHiddenInset,
|
||||
},
|
||||
BackgroundColour: application.NewRGB(27, 38, 54),
|
||||
Width: 1200,
|
||||
Height: 600,
|
||||
Width: 1280,
|
||||
Height: 720,
|
||||
URL: "/",
|
||||
DevToolsEnabled: true,
|
||||
Frameless: true,
|
||||
DisableResize: true,
|
||||
})
|
||||
|
||||
iconBytes, _ := tools.ReadFile("assets/appicon.png")
|
||||
@@ -115,8 +117,6 @@ func main() {
|
||||
|
||||
systemTray.SetMenu(menu)
|
||||
|
||||
|
||||
|
||||
window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
|
||||
app.Event.Emit("window:close")
|
||||
e.Cancel()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package constant
|
||||
|
||||
const ProxyGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/Firefly_Proxy/releases"
|
||||
const ProxyGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Proxy/releases"
|
||||
const ServerGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Local_Archive/releases"
|
||||
const LauncherGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/Firefly_Launcher/releases"
|
||||
const ServerStorageUrl = "./server"
|
||||
const ProxyStorageUrl = "./proxy"
|
||||
const ServerZipFile = "prebuild_win_x86.zip"
|
||||
const ProxyZipFile = "64bit.zip"
|
||||
const ProxyFile = "firefly-go-proxy.exe"
|
||||
const LauncherFile = "firefly-launcher.exe"
|
||||
const TempUrl = "./temp"
|
||||
|
||||
const CurrentLauncherVersion = "2.1.0"
|
||||
const CurrentLauncherVersion = "2.3.5"
|
||||
|
||||
type ToolFile string
|
||||
|
||||
|
||||