mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 06:03:49 +08:00
fix(favorites): refresh installed apps across origins
This commit is contained in:
+91
-1
@@ -322,6 +322,7 @@ import type {
|
|||||||
ReviewTags,
|
ReviewTags,
|
||||||
FavoriteFolder,
|
FavoriteFolder,
|
||||||
FavoriteItem,
|
FavoriteItem,
|
||||||
|
InstalledAppInfo,
|
||||||
ResolvedFavoriteItem,
|
ResolvedFavoriteItem,
|
||||||
} from "./global/typedefinition";
|
} from "./global/typedefinition";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
@@ -1134,6 +1135,95 @@ const refreshInstalledApps = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapInstalledAppToCatalogApp = (
|
||||||
|
app: InstalledAppInfo,
|
||||||
|
origin: "spark" | "apm",
|
||||||
|
): App | null => {
|
||||||
|
let appInfo = apps.value.find(
|
||||||
|
(catalogApp) =>
|
||||||
|
catalogApp.pkgname === app.pkgname && catalogApp.origin === origin,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (origin === "spark" && !appInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appInfo) {
|
||||||
|
appInfo.flags = app.flags;
|
||||||
|
appInfo.arch = app.arch;
|
||||||
|
appInfo.currentStatus = "installed";
|
||||||
|
appInfo.isDependency = app.isDependency;
|
||||||
|
return appInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: app.name || app.pkgname,
|
||||||
|
pkgname: app.pkgname,
|
||||||
|
version: app.version,
|
||||||
|
category: "unknown",
|
||||||
|
tags: "",
|
||||||
|
more: "",
|
||||||
|
filename: "",
|
||||||
|
torrent_address: "",
|
||||||
|
author: "",
|
||||||
|
contributor: "",
|
||||||
|
website: "",
|
||||||
|
update: "",
|
||||||
|
size: "",
|
||||||
|
img_urls: [],
|
||||||
|
icons: app.icon || "",
|
||||||
|
origin: app.origin || (app.arch?.includes("apm") ? "apm" : "spark"),
|
||||||
|
currentStatus: "installed",
|
||||||
|
arch: app.arch,
|
||||||
|
flags: app.flags,
|
||||||
|
isDependency: app.isDependency,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshFavoriteInstalledApps = async (): Promise<void> => {
|
||||||
|
const origins: Array<"spark" | "apm"> = [];
|
||||||
|
if (isOriginEnabled(storeFilter.value, "spark") && sparkAvailable.value) {
|
||||||
|
origins.push("spark");
|
||||||
|
}
|
||||||
|
if (isOriginEnabled(storeFilter.value, "apm") && apmAvailable.value) {
|
||||||
|
origins.push("apm");
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshedApps: App[] = [];
|
||||||
|
await Promise.all(
|
||||||
|
origins.map(async (origin) => {
|
||||||
|
const pkgnameList =
|
||||||
|
origin === "spark"
|
||||||
|
? apps.value
|
||||||
|
.filter((app) => app.origin === "spark")
|
||||||
|
.map((app) => app.pkgname)
|
||||||
|
: undefined;
|
||||||
|
const result = await window.ipcRenderer.invoke("list-installed", {
|
||||||
|
origin,
|
||||||
|
pkgnameList,
|
||||||
|
});
|
||||||
|
if (!result?.success) return;
|
||||||
|
|
||||||
|
for (const app of result.apps as InstalledAppInfo[]) {
|
||||||
|
const appInfo = mapInstalledAppToCatalogApp(app, origin);
|
||||||
|
if (appInfo) refreshedApps.push(appInfo);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const refreshedKeys = new Set(
|
||||||
|
refreshedApps.map((app) => `${app.origin}:${app.pkgname}`),
|
||||||
|
);
|
||||||
|
installedApps.value = [
|
||||||
|
...installedApps.value.filter(
|
||||||
|
(app) =>
|
||||||
|
!origins.includes(app.origin) &&
|
||||||
|
!refreshedKeys.has(`${app.origin}:${app.pkgname}`),
|
||||||
|
),
|
||||||
|
...refreshedApps,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
const requestUninstall = (app: App) => {
|
const requestUninstall = (app: App) => {
|
||||||
uninstallTargetApp.value = app;
|
uninstallTargetApp.value = app;
|
||||||
showUninstallModal.value = true;
|
showUninstallModal.value = true;
|
||||||
@@ -1274,7 +1364,7 @@ const refreshFavorites = async (): Promise<void> => {
|
|||||||
favoriteLoading.value = true;
|
favoriteLoading.value = true;
|
||||||
favoriteError.value = "";
|
favoriteError.value = "";
|
||||||
try {
|
try {
|
||||||
await Promise.all([refreshInstalledApps(), loadFavoriteFolders()]);
|
await Promise.all([refreshFavoriteInstalledApps(), loadFavoriteFolders()]);
|
||||||
await loadActiveFavoriteItems();
|
await loadActiveFavoriteItems();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
favoriteError.value = (error as Error)?.message || "读取收藏夹失败";
|
favoriteError.value = (error as Error)?.message || "读取收藏夹失败";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { fireEvent, render, screen } from "@testing-library/vue";
|
import { fireEvent, render, screen, waitFor } from "@testing-library/vue";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import App from "@/App.vue";
|
import App from "@/App.vue";
|
||||||
@@ -197,6 +197,10 @@ describe("App account placeholders", () => {
|
|||||||
});
|
});
|
||||||
render(App);
|
render(App);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("2")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
||||||
await fireEvent.click(screen.getByText("我的收藏"));
|
await fireEvent.click(screen.getByText("我的收藏"));
|
||||||
|
|
||||||
@@ -209,4 +213,50 @@ describe("App account placeholders", () => {
|
|||||||
pkgnameList: undefined,
|
pkgnameList: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("refreshes Spark installed state for favorites in both mode", async () => {
|
||||||
|
invoke.mockImplementation(async (channel: string, payload?: unknown) => {
|
||||||
|
if (channel === "get-store-filter") return "both";
|
||||||
|
if (channel === "check-spark-available") return true;
|
||||||
|
if (channel === "check-apm-available") return true;
|
||||||
|
if (channel === "get-app-version") return "5.0.0";
|
||||||
|
if (channel === "list-installed") {
|
||||||
|
const request = payload as { origin?: string };
|
||||||
|
if (request.origin === "spark") {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
pkgname: "wps",
|
||||||
|
name: "WPS",
|
||||||
|
version: "1.0.0",
|
||||||
|
arch: "amd64",
|
||||||
|
flags: "installed",
|
||||||
|
origin: "spark",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { success: true, apps: [] };
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
render(App);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("2")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
||||||
|
await fireEvent.click(screen.getByText("我的收藏"));
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByRole("heading", { name: "我的收藏" }),
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(await screen.findByText("已安装")).toBeTruthy();
|
||||||
|
expect(invoke).toHaveBeenCalledWith("list-installed", {
|
||||||
|
origin: "spark",
|
||||||
|
pkgnameList: ["wps"],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -112,4 +112,15 @@ describe("favoriteAvailability", () => {
|
|||||||
)[0];
|
)[0];
|
||||||
expect(resolved.status).toBe("installed");
|
expect(resolved.status).toBe("installed");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("marks installed favorites from all-category catalog matches", () => {
|
||||||
|
const resolved = resolveFavoriteItems(
|
||||||
|
[favorite],
|
||||||
|
[app("spark")],
|
||||||
|
[app("spark", { category: "all", currentStatus: "installed" })],
|
||||||
|
{ spark: true, apm: true },
|
||||||
|
"both",
|
||||||
|
)[0];
|
||||||
|
expect(resolved.status).toBe("installed");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ const appMatchesFavorite = (app: App, item: FavoriteItem): boolean =>
|
|||||||
|
|
||||||
const installedAppMatchesFavorite = (app: App, item: FavoriteItem): boolean =>
|
const installedAppMatchesFavorite = (app: App, item: FavoriteItem): boolean =>
|
||||||
app.pkgname === item.pkgname &&
|
app.pkgname === item.pkgname &&
|
||||||
(app.category === item.category || app.category === "unknown");
|
(app.category === item.category ||
|
||||||
|
app.category === "all" ||
|
||||||
|
app.category === "unknown");
|
||||||
|
|
||||||
const appMatchesClientArch = (app: App, clientArch: string): boolean => {
|
const appMatchesClientArch = (app: App, clientArch: string): boolean => {
|
||||||
if (!app.arch) return true;
|
if (!app.arch) return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user