mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
feat: adding freezing backups logic
This commit is contained in:
16
src/main/events/cloud-save/toggle-artifact-freeze.ts
Normal file
16
src/main/events/cloud-save/toggle-artifact-freeze.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const toggleArtifactFreeze = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => {
|
||||
if (freeze) {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/freeze`);
|
||||
} else {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/unfreeze`);
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent("toggleArtifactFreeze", toggleArtifactFreeze);
|
||||
@@ -86,6 +86,7 @@ import "./cloud-save/get-game-backup-preview";
|
||||
import "./cloud-save/upload-save-game";
|
||||
import "./cloud-save/delete-game-artifact";
|
||||
import "./cloud-save/select-game-backup-path";
|
||||
import "./cloud-save/toggle-artifact-freeze";
|
||||
import "./notifications/publish-new-repacks-notification";
|
||||
import "./themes/add-custom-theme";
|
||||
import "./themes/delete-custom-theme";
|
||||
|
||||
@@ -238,6 +238,8 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
downloadOptionTitle: string | null
|
||||
) =>
|
||||
ipcRenderer.invoke("uploadSaveGame", objectId, shop, downloadOptionTitle),
|
||||
toggleArtifactFreeze: (gameArtifactId: string, freeze: boolean) =>
|
||||
ipcRenderer.invoke("toggleArtifactFreeze", gameArtifactId, freeze),
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
|
||||
@@ -30,9 +30,14 @@ export interface CloudSyncContext {
|
||||
setShowCloudSyncFilesModal: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
getGameBackupPreview: () => Promise<void>;
|
||||
getGameArtifacts: () => Promise<void>;
|
||||
toggleArtifactFreeze: (
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => Promise<void>;
|
||||
restoringBackup: boolean;
|
||||
uploadingBackup: boolean;
|
||||
loadingPreview: boolean;
|
||||
freezingArtifact: boolean;
|
||||
}
|
||||
|
||||
export const cloudSyncContext = createContext<CloudSyncContext>({
|
||||
@@ -47,10 +52,12 @@ export const cloudSyncContext = createContext<CloudSyncContext>({
|
||||
showCloudSyncFilesModal: false,
|
||||
setShowCloudSyncFilesModal: () => {},
|
||||
getGameBackupPreview: async () => {},
|
||||
toggleArtifactFreeze: async () => {},
|
||||
getGameArtifacts: async () => {},
|
||||
restoringBackup: false,
|
||||
uploadingBackup: false,
|
||||
loadingPreview: false,
|
||||
freezingArtifact: false,
|
||||
});
|
||||
|
||||
const { Provider } = cloudSyncContext;
|
||||
@@ -78,6 +85,7 @@ export function CloudSyncContextProvider({
|
||||
const [uploadingBackup, setUploadingBackup] = useState(false);
|
||||
const [showCloudSyncFilesModal, setShowCloudSyncFilesModal] = useState(false);
|
||||
const [loadingPreview, setLoadingPreview] = useState(false);
|
||||
const [freezingArtifact, setFreezingArtifact] = useState(false);
|
||||
|
||||
const { showSuccessToast } = useToast();
|
||||
|
||||
@@ -119,6 +127,21 @@ export function CloudSyncContextProvider({
|
||||
[objectId, shop]
|
||||
);
|
||||
|
||||
const toggleArtifactFreeze = useCallback(
|
||||
async (gameArtifactId: string, freeze: boolean) => {
|
||||
setFreezingArtifact(true);
|
||||
try {
|
||||
await window.electron.toggleArtifactFreeze(gameArtifactId, freeze);
|
||||
getGameArtifacts();
|
||||
} catch (err) {
|
||||
logger.error("Failed to toggle artifact freeze", objectId, shop, err);
|
||||
} finally {
|
||||
setFreezingArtifact(false);
|
||||
}
|
||||
},
|
||||
[objectId, shop, getGameArtifacts]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const removeUploadCompleteListener = window.electron.onUploadComplete(
|
||||
objectId,
|
||||
@@ -192,6 +215,7 @@ export function CloudSyncContextProvider({
|
||||
uploadingBackup,
|
||||
showCloudSyncFilesModal,
|
||||
loadingPreview,
|
||||
freezingArtifact,
|
||||
setShowCloudSyncModal,
|
||||
uploadSaveGame,
|
||||
downloadGameArtifact,
|
||||
@@ -199,6 +223,7 @@ export function CloudSyncContextProvider({
|
||||
setShowCloudSyncFilesModal,
|
||||
getGameBackupPreview,
|
||||
getGameArtifacts,
|
||||
toggleArtifactFreeze,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
@@ -202,6 +202,10 @@ declare global {
|
||||
shop: GameShop,
|
||||
downloadOptionTitle: string | null
|
||||
) => Promise<void>;
|
||||
toggleArtifactFreeze: (
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => Promise<void>;
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
|
||||
@@ -7,10 +7,13 @@ import { formatBytes } from "@shared";
|
||||
import {
|
||||
ClockIcon,
|
||||
DeviceDesktopIcon,
|
||||
HistoryIcon,
|
||||
DownloadIcon,
|
||||
InfoIcon,
|
||||
LockIcon,
|
||||
PencilIcon,
|
||||
SyncIcon,
|
||||
TrashIcon,
|
||||
UnlockIcon,
|
||||
UploadIcon,
|
||||
} from "@primer/octicons-react";
|
||||
import { useAppSelector, useDate, useToast } from "@renderer/hooks";
|
||||
@@ -36,9 +39,11 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
uploadingBackup,
|
||||
restoringBackup,
|
||||
loadingPreview,
|
||||
freezingArtifact,
|
||||
uploadSaveGame,
|
||||
downloadGameArtifact,
|
||||
deleteGameArtifact,
|
||||
toggleArtifactFreeze,
|
||||
setShowCloudSyncFilesModal,
|
||||
getGameBackupPreview,
|
||||
} = useContext(cloudSyncContext);
|
||||
@@ -82,6 +87,13 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
downloadGameArtifact(artifactId);
|
||||
};
|
||||
|
||||
const handleFreezeArtifactClick = async (artifactId: string) => {
|
||||
await toggleArtifactFreeze(
|
||||
artifactId,
|
||||
!artifacts.find((artifact) => artifact.id === artifactId)?.isFrozen
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
getGameBackupPreview();
|
||||
@@ -147,7 +159,8 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
t,
|
||||
]);
|
||||
|
||||
const disableActions = uploadingBackup || restoringBackup || deletingArtifact;
|
||||
const disableActions =
|
||||
uploadingBackup || restoringBackup || deletingArtifact || freezingArtifact;
|
||||
const isMissingWinePrefix =
|
||||
window.electron.platform === "linux" && !game?.winePrefixPath;
|
||||
|
||||
@@ -208,12 +221,14 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
<li key={artifact.id} className="cloud-sync-modal__artifact">
|
||||
<div className="cloud-sync-modal__artifact-info">
|
||||
<div className="cloud-sync-modal__artifact-header">
|
||||
<h3>
|
||||
<button type="button">
|
||||
{artifact.label ??
|
||||
t("backup_from", {
|
||||
date: formatDate(artifact.createdAt),
|
||||
})}
|
||||
</h3>
|
||||
|
||||
<PencilIcon />
|
||||
</button>
|
||||
<small>{formatBytes(artifact.artifactLengthInBytes)}</small>
|
||||
</div>
|
||||
|
||||
@@ -234,23 +249,37 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
</div>
|
||||
|
||||
<div className="cloud-sync-modal__artifact-actions">
|
||||
<Button
|
||||
type="button"
|
||||
tooltip={
|
||||
artifact.isFrozen
|
||||
? t("unfreeze_backup")
|
||||
: t("freeze_backup")
|
||||
}
|
||||
theme={artifact.isFrozen ? "danger" : "outline"}
|
||||
onClick={() => handleFreezeArtifactClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{artifact.isFrozen ? <UnlockIcon /> : <LockIcon />}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
tooltip={t("install_backup")}
|
||||
theme="outline"
|
||||
>
|
||||
{restoringBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<HistoryIcon />
|
||||
<DownloadIcon />
|
||||
)}
|
||||
{t("install_backup")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||
theme="danger"
|
||||
disabled={disableActions}
|
||||
disabled={disableActions || artifact.isFrozen}
|
||||
>
|
||||
<TrashIcon />
|
||||
{t("delete_backup")}
|
||||
|
||||
@@ -272,6 +272,7 @@ export interface GameArtifact {
|
||||
hostname: string;
|
||||
downloadCount: number;
|
||||
label?: string;
|
||||
isFrozen: boolean;
|
||||
}
|
||||
|
||||
export interface ComparedAchievements {
|
||||
|
||||
Reference in New Issue
Block a user