mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 09:20:18 +08:00
feat: add app launching functionality and update related components
This commit is contained in:
@@ -396,4 +396,15 @@ ipcMain.handle('uninstall-installed', async (_event, pkgname: string) => {
|
|||||||
success,
|
success,
|
||||||
message: success ? '卸载完成' : (stderr || stdout || `卸载失败,退出码 ${code}`)
|
message: success ? '卸载完成' : (stderr || stdout || `卸载失败,退出码 ${code}`)
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('launch-app', async (_event, pkgname: string) => {
|
||||||
|
if (!pkgname) {
|
||||||
|
logger.warn('No pkgname provided for launch-app');
|
||||||
|
}
|
||||||
|
|
||||||
|
const execCommand = 'dbus-launch';
|
||||||
|
const execParams = ['/opt/apm-app-store/extras/apm-launcher', 'start', pkgname];
|
||||||
|
|
||||||
|
await runCommandCapture(execCommand, execParams);
|
||||||
});
|
});
|
||||||
105
extras/apm-launcher
Executable file
105
extras/apm-launcher
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ===== 日志函数(简化版)=====
|
||||||
|
log.info() { echo "INFO: $*"; }
|
||||||
|
log.warn() { echo "WARN: $*"; }
|
||||||
|
log.error() { echo "ERROR: $*"; }
|
||||||
|
log.debug() { :; } # APM 场景下可禁用 debug 日志
|
||||||
|
|
||||||
|
# ===== APM 专用桌面文件扫描(单文件)=====
|
||||||
|
function scan_apm_desktop_log() {
|
||||||
|
unset desktop_file_path
|
||||||
|
local pkg_name="$1"
|
||||||
|
local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications"
|
||||||
|
|
||||||
|
[ -d "$desktop_dir" ] || return 1
|
||||||
|
|
||||||
|
while IFS= read -r -d '' path; do
|
||||||
|
[ -f "$path" ] || continue
|
||||||
|
if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then
|
||||||
|
log.info "Found valid APM desktop file: $path"
|
||||||
|
export desktop_file_path="$path"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== APM 专用桌面文件扫描(多文件列表)=====
|
||||||
|
function scan_apm_desktop_list() {
|
||||||
|
local pkg_name="$1"
|
||||||
|
local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications"
|
||||||
|
local result=""
|
||||||
|
|
||||||
|
[ -d "$desktop_dir" ] || { echo ""; return; }
|
||||||
|
|
||||||
|
while IFS= read -r -d '' path; do
|
||||||
|
[ -f "$path" ] || continue
|
||||||
|
if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then
|
||||||
|
result+="${path},"
|
||||||
|
fi
|
||||||
|
done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null)
|
||||||
|
|
||||||
|
echo "${result%,}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== 启动应用 =====
|
||||||
|
function launch_app() {
|
||||||
|
local desktop_path="${1#file://}"
|
||||||
|
local exec_cmd
|
||||||
|
|
||||||
|
# 提取并清理 Exec 行(移除字段代码如 %f %u 等)
|
||||||
|
exec_cmd=$(grep -m1 '^Exec=' "$desktop_path" | cut -d= -f2- | sed 's/%[fFuUdDnNickvm]*//g; s/^[[:space:]]*//; s/[[:space:]]*$//')
|
||||||
|
[ -z "$exec_cmd" ] && return 1
|
||||||
|
|
||||||
|
# ACE 环境内使用 host-spawn 在宿主显示图形界面
|
||||||
|
[ -n "$IS_ACE_ENV" ] && exec_cmd="host-spawn $exec_cmd"
|
||||||
|
|
||||||
|
log.info "Launching: $exec_cmd"
|
||||||
|
${SHELL:-bash} -c "$exec_cmd" &
|
||||||
|
}
|
||||||
|
|
||||||
|
# 导出函数供 ACE 环境调用
|
||||||
|
export -f launch_app scan_apm_desktop_log scan_apm_desktop_list log.info log.error
|
||||||
|
|
||||||
|
# ===== 主逻辑 =====
|
||||||
|
[ $# -lt 2 ] && {
|
||||||
|
log.error "Usage: $0 {check|list|launch|start} <apm-package-name>"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
action="$1"
|
||||||
|
pkg_name="$2"
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
check)
|
||||||
|
if scan_apm_desktop_log "$pkg_name"; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
list)
|
||||||
|
if result=$(scan_apm_desktop_list "$pkg_name"); [ -n "$result" ]; then
|
||||||
|
echo "$result"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
launch|start)
|
||||||
|
if scan_apm_desktop_log "$pkg_name" && launch_app "$desktop_file_path"; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
log.error "Invalid command: $action (supported: check|list|launch|start)"
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
13
src/App.vue
13
src/App.vue
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<AppDetailModal data-app-modal="detail" :show="showModal" :app="currentApp" :screenshots="screenshots"
|
<AppDetailModal data-app-modal="detail" :show="showModal" :app="currentApp" :screenshots="screenshots"
|
||||||
:isinstalled="currentAppIsInstalled" @close="closeDetail" @install="handleInstall" @remove="requestUninstallFromDetail"
|
:isinstalled="currentAppIsInstalled" @close="closeDetail" @install="handleInstall" @remove="requestUninstallFromDetail"
|
||||||
@open-preview="openScreenPreview" />
|
@open-preview="openScreenPreview" @open-app="openDownloadedApp" />
|
||||||
|
|
||||||
<ScreenPreview :show="showPreview" :screenshots="screenshots" :current-screen-index="currentScreenIndex"
|
<ScreenPreview :show="showPreview" :screenshots="screenshots" :current-screen-index="currentScreenIndex"
|
||||||
@close="closeScreenPreview" @prev="prevScreen" @next="nextScreen" />
|
@close="closeScreenPreview" @prev="prevScreen" @next="nextScreen" />
|
||||||
@@ -536,11 +536,12 @@ const closeDownloadDetail = () => {
|
|||||||
currentDownload.value = null;
|
currentDownload.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDownloadedApp = (download: DownloadItem) => {
|
const openDownloadedApp = (pkgname: string) => {
|
||||||
const encodedPkg = encodeURIComponent(download.pkgname);
|
// const encodedPkg = encodeURIComponent(download.pkgname);
|
||||||
openApmStoreUrl(`apmstore://launch?pkg=${encodedPkg}`, {
|
// openApmStoreUrl(`apmstore://launch?pkg=${encodedPkg}`, {
|
||||||
fallbackText: `打开应用: ${download.pkgname}`
|
// fallbackText: `打开应用: ${download.pkgname}`
|
||||||
});
|
// });
|
||||||
|
window.ipcRenderer.invoke('launch-app', pkgname);
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadCategories = async () => {
|
const loadCategories = async () => {
|
||||||
|
|||||||
@@ -29,12 +29,20 @@
|
|||||||
<i class="fas" :class="installFeedback ? 'fa-check' : 'fa-download'"></i>
|
<i class="fas" :class="installFeedback ? 'fa-check' : 'fa-download'"></i>
|
||||||
<span>{{ installFeedback ? '已加入队列' : '安装' }}</span>
|
<span>{{ installFeedback ? '已加入队列' : '安装' }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button v-else type="button"
|
<template v-else>
|
||||||
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-rose-500 to-rose-600 px-4 py-2 text-sm font-semibold text-white shadow-lg shadow-rose-500/30 disabled:opacity-40 transition hover:-translate-y-0.5"
|
<button type="button"
|
||||||
@click="handleRemove">
|
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-brand to-brand-dark px-4 py-2 text-sm font-semibold text-white shadow-lg transition hover:-translate-y-0.5"
|
||||||
<i class="fas fa-trash"></i>
|
@click="emit('open-app', app?.pkgname || '')">
|
||||||
<span>卸载</span>
|
<i class="fas fa-external-link-alt"></i>
|
||||||
</button>
|
<span>打开</span>
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-rose-500 to-rose-600 px-4 py-2 text-sm font-semibold text-white shadow-lg shadow-rose-500/30 disabled:opacity-40 transition hover:-translate-y-0.5"
|
||||||
|
@click="handleRemove">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
<span>卸载</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-200/70 text-slate-500 transition hover:text-slate-900 dark:border-slate-700"
|
class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-200/70 text-slate-500 transition hover:text-slate-900 dark:border-slate-700"
|
||||||
@click="closeModal" aria-label="关闭">
|
@click="closeModal" aria-label="关闭">
|
||||||
@@ -119,6 +127,7 @@ const emit = defineEmits<{
|
|||||||
(e: 'install'): void;
|
(e: 'install'): void;
|
||||||
(e: 'remove'): void;
|
(e: 'remove'): void;
|
||||||
(e: 'open-preview', index: number): void;
|
(e: 'open-preview', index: number): void;
|
||||||
|
(e: 'open-app', pkgname: string ): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ const emit = defineEmits<{
|
|||||||
(e: 'resume', download: DownloadItem): void;
|
(e: 'resume', download: DownloadItem): void;
|
||||||
(e: 'cancel', download: DownloadItem): void;
|
(e: 'cancel', download: DownloadItem): void;
|
||||||
(e: 'retry', download: DownloadItem): void;
|
(e: 'retry', download: DownloadItem): void;
|
||||||
(e: 'open-app', download: DownloadItem): void;
|
(e: 'open-app', download: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ const retry = () => {
|
|||||||
|
|
||||||
const openApp = () => {
|
const openApp = () => {
|
||||||
if (props.download) {
|
if (props.download) {
|
||||||
emit('open-app', props.download);
|
emit('open-app', props.download.pkgname);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user