添加安装检测和启动应用

This commit is contained in:
柚子
2025-03-07 02:05:30 +08:00
parent f9a6fcbf84
commit 135873a3e7
6 changed files with 111 additions and 50 deletions

View File

@@ -5,3 +5,4 @@ This template should help get you started developing with Tauri, Solid and Types
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
##### 1.2 其他依赖

View File

@@ -0,0 +1,22 @@
use std::process::Command;
#[tauri::command]
pub async fn check_is_installed(pkgname: String) -> Result<bool, String> {
let output = Command::new("/opt/durapps/spark-store/bin/store-helper/check-is-installed")
.arg(&pkgname)
.output()
.map_err(|e| format!("执行命令失败: {}", e))?;
Ok(output.status.success())
}
#[tauri::command]
pub async fn launch_app(pkgname: String) -> Result<(), String> {
Command::new("/opt/durapps/spark-store/bin/store-helper/ss-launcher")
.arg(&pkgname)
.spawn()
.map_err(|e| format!("启动应用失败: {}", e))?;
Ok(())
}

View File

@@ -4,3 +4,4 @@ pub mod app;
pub mod home;
pub mod file;
pub mod download;
pub mod deb;

View File

@@ -30,6 +30,8 @@ pub fn run() {
handlers::download::pause_download,
handlers::download::resume_download,
handlers::download::cancel_download,
handlers::deb::check_is_installed,
handlers::deb::launch_app,
utils::get_user_agent,
])
.on_window_event(|window, event| match event {

View File

@@ -1,4 +1,4 @@
import { Component, createSignal } from 'solid-js';
import { Component, createSignal, onMount } from 'solid-js';
import { useParams } from '@solidjs/router';
import { useAppDetailStore } from './store';
import './AppDetail.css';
@@ -16,6 +16,7 @@ import { useCollectionStore } from '@/features/collection/store';
import { useDownloadsStore } from '@/features/downloads/store';
import { Progress } from '@/components/ui/progress';
import { X } from 'lucide-solid';
import { checkIsInstalled, launchApp } from '@/lib/api/deb';
const AppDetail: Component = () => {
const params = useParams();
@@ -26,6 +27,7 @@ const AppDetail: Component = () => {
const [newCollectionDesc, setNewCollectionDesc] = createSignal('');
const [showNewCollectionDialog, setShowNewCollectionDialog] = createSignal(false);
const [showCollectionDialog, setShowCollectionDialog] = createSignal(false);
const [isInstalled, setIsInstalled] = createSignal(false);
const [selectedCollections, setSelectedCollections] = createSignal<string[]>([]);
const handleCreateCollection = () => {
@@ -45,6 +47,11 @@ const AppDetail: Component = () => {
showToast({ description: '收藏单创建成功', variant: "success" });
};
onMount(async () => {
const installed = await checkIsInstalled(params.pkgname);
setIsInstalled(installed);
});
return (
<div class="w-full h-full">
{loading() ? (
@@ -110,56 +117,75 @@ const AppDetail: Component = () => {
<h2 class="app-name text-2xl font-bold pt-2">{app()?.Name}</h2>
</div>
<div class="flex flex-col gap-2 w-[120px]">
{downloads().some(task => task.category === params.category && task.pkgname === params.pkgname) ? (
<div class="flex flex-col gap-2 w-full pb-2">
{downloads().map(download => {
if (download.category === params.category && download.pkgname === params.pkgname) {
return (
<div class="flex items-center gap-2 group relative">
<Progress value={download.progress} class="flex-1" />
<div class="flex items-center gap-2 group-hover:opacity-0 transition-opacity">
<span class="text-sm text-muted-foreground">{download.progress}%</span>
{download.speed && (
<span class="text-sm text-muted-foreground">{download.speed}</span>
)}
</div>
<button
class="absolute right-1 bg-red-500 rounded-full w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center text-white hover:bg-red-600"
onClick={() => {
cancelDownload(params.category, params.pkgname);
}}
>
<X />
</button>
{(() => {
const downloadTask = downloads().find(task =>
task.category === params.category &&
task.pkgname === params.pkgname
);
if (downloadTask?.status === 'installed' || isInstalled()) {
return (
<Button
size="lg"
class='w-full'
onClick={() => {
launchApp(params.pkgname)
showToast({ description: '正在启动应用...' });
}}
>
</Button>
);
}
if (downloadTask) {
return (
<div class="flex flex-col gap-2 w-full pb-2">
<div class="flex items-center gap-2 group relative">
<Progress value={downloadTask.progress} class="flex-1" />
<div class="flex items-center gap-2 group-hover:opacity-0 transition-opacity">
<span class="text-sm text-muted-foreground">{downloadTask.progress}%</span>
{downloadTask.speed && (
<span class="text-sm text-muted-foreground">{downloadTask.speed}</span>
)}
</div>
);
}
return null;
})}
</div>
) : (
<Button
size="lg"
class='w-full'
onClick={() => {
const currentApp = app();
if (!currentApp) {
showToast({ description: '获取应用信息失败', variant: "error" });
return;
}
<button
class="absolute right-1 bg-red-500 rounded-full w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center text-white hover:bg-red-600"
onClick={() => {
cancelDownload(params.category, params.pkgname);
}}
>
<X />
</button>
</div>
</div>
);
}
if (!currentApp.Filename) {
showToast({ description: '获取应用下载信息失败', variant: "error" });
return;
}
return (
<Button
size="lg"
class='w-full'
onClick={() => {
const currentApp = app();
if (!currentApp) {
showToast({ description: '获取应用信息失败', variant: "error" });
return;
}
addDownload(params.category, params.pkgname, currentApp.Filename, currentApp.Name || '');
showToast({ description: '已添加到下载队列', variant: "success" });
}}
>
</Button>
)}
if (!currentApp.Filename) {
showToast({ description: '获取应用下载信息失败', variant: "error" });
return;
}
addDownload(params.category, params.pkgname, currentApp.Filename, currentApp.Name || '');
showToast({ description: '已添加到下载队列', variant: "success" });
}}
>
</Button>
);
})()}
<Dialog open={showCollectionDialog()} onOpenChange={setShowCollectionDialog}>
<DialogTrigger>
<Button variant="secondary" size="lg" class='w-full'></Button>

9
src/lib/api/deb.ts Normal file
View File

@@ -0,0 +1,9 @@
import { invoke } from "@tauri-apps/api/core";
export async function checkIsInstalled(pkgname: string): Promise<boolean> {
return await invoke('check_is_installed', { pkgname });
}
export async function launchApp(pkgname: string) {
await invoke('launch_app', { pkgname });
}