summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxXJSONDeruloXx <danielhimebauch@gmail.com>2025-07-16 17:11:00 -0400
committerxXJSONDeruloXx <danielhimebauch@gmail.com>2025-07-16 17:11:00 -0400
commit2811ba4e29cd27b5893fba676278f29b155068cb (patch)
tree5eaab7f419b277196ed4c22939ce0ea74555f4ce /src
parent44393f6e126c3dff196283a2079162e3eb9245a2 (diff)
downloaddecky-lsfg-vk-2811ba4e29cd27b5893fba676278f29b155068cb.tar.gz
decky-lsfg-vk-2811ba4e29cd27b5893fba676278f29b155068cb.zip
non modal updater
Diffstat (limited to 'src')
-rw-r--r--src/api/lsfgApi.ts21
-rw-r--r--src/components/Content.tsx4
-rw-r--r--src/components/PluginUpdateChecker.tsx187
-rw-r--r--src/components/index.ts1
4 files changed, 213 insertions, 0 deletions
diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts
index 2e7964c..f7363c1 100644
--- a/src/api/lsfgApi.ts
+++ b/src/api/lsfgApi.ts
@@ -49,6 +49,23 @@ export interface ConfigSchemaResult {
defaults: ConfigurationData;
}
+export interface UpdateCheckResult {
+ success: boolean;
+ update_available: boolean;
+ current_version: string;
+ latest_version: string;
+ release_notes: string;
+ release_date: string;
+ download_url: string;
+ error?: string;
+}
+
+export interface UpdateDownloadResult {
+ success: boolean;
+ download_path?: string;
+ error?: string;
+}
+
// API functions
export const installLsfgVk = callable<[], InstallationResult>("install_lsfg_vk");
export const uninstallLsfgVk = callable<[], InstallationResult>("uninstall_lsfg_vk");
@@ -68,3 +85,7 @@ export const updateLsfgConfigFromObject = async (config: ConfigurationData): Pro
const args = ConfigurationManager.createArgsFromConfig(config);
return updateLsfgConfig(...args as [boolean, number, number, boolean, boolean, boolean, boolean, number]);
};
+
+// Self-updater API functions
+export const checkForPluginUpdate = callable<[], UpdateCheckResult>("check_for_plugin_update");
+export const downloadPluginUpdate = callable<[string], UpdateDownloadResult>("download_plugin_update");
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
index ba651d4..ea3f3c1 100644
--- a/src/components/Content.tsx
+++ b/src/components/Content.tsx
@@ -8,6 +8,7 @@ import { ConfigurationSection } from "./ConfigurationSection";
import { UsageInstructions } from "./UsageInstructions";
import { WikiButton } from "./WikiButton";
import { ClipboardButton } from "./ClipboardButton";
+import { PluginUpdateChecker } from "./PluginUpdateChecker";
import { ConfigurationData } from "../config/configSchema";
export function Content() {
@@ -77,6 +78,9 @@ export function Content() {
<WikiButton />
<ClipboardButton />
+
+ {/* Plugin Update Checker */}
+ <PluginUpdateChecker />
</PanelSection>
);
}
diff --git a/src/components/PluginUpdateChecker.tsx b/src/components/PluginUpdateChecker.tsx
new file mode 100644
index 0000000..0028a79
--- /dev/null
+++ b/src/components/PluginUpdateChecker.tsx
@@ -0,0 +1,187 @@
+import React, { useState, useEffect } from 'react';
+import {
+ ButtonItem,
+ PanelSection
+} from '@decky/ui';
+import { checkForPluginUpdate, downloadPluginUpdate, UpdateCheckResult, UpdateDownloadResult } from '../api/lsfgApi';
+
+interface PluginUpdateCheckerProps {
+ // Add any props if needed
+}
+
+interface UpdateInfo {
+ updateAvailable: boolean;
+ currentVersion: string;
+ latestVersion: string;
+ releaseNotes: string;
+ releaseDate: string;
+ downloadUrl: string;
+}
+
+export const PluginUpdateChecker: React.FC<PluginUpdateCheckerProps> = () => {
+ const [checkingUpdate, setCheckingUpdate] = useState(false);
+ const [downloadingUpdate, setDownloadingUpdate] = useState(false);
+ const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);
+ const [updateError, setUpdateError] = useState<string | null>(null);
+ const [downloadResult, setDownloadResult] = useState<UpdateDownloadResult | null>(null);
+
+ // Auto-hide error messages after 5 seconds
+ useEffect(() => {
+ if (updateError) {
+ const timer = setTimeout(() => {
+ setUpdateError(null);
+ }, 5000);
+ return () => clearTimeout(timer);
+ }
+ return undefined;
+ }, [updateError]);
+
+ const handleCheckForUpdate = async () => {
+ setCheckingUpdate(true);
+ setUpdateError(null);
+ setUpdateInfo(null);
+ setDownloadResult(null); // Clear previous download result
+
+ try {
+ const result: UpdateCheckResult = await checkForPluginUpdate();
+
+ if (result.success) {
+ setUpdateInfo({
+ updateAvailable: result.update_available,
+ currentVersion: result.current_version,
+ latestVersion: result.latest_version,
+ releaseNotes: result.release_notes,
+ releaseDate: result.release_date,
+ downloadUrl: result.download_url
+ });
+
+ // Simple console log instead of toast since showToast may not be available
+ if (result.update_available) {
+ console.log("Update available!", `Version ${result.latest_version} is now available.`);
+ } else {
+ console.log("Up to date!", "You have the latest version installed.");
+ }
+ } else {
+ setUpdateError(result.error || "Failed to check for updates");
+ }
+ } catch (error) {
+ setUpdateError(`Error checking for updates: ${error}`);
+ } finally {
+ setCheckingUpdate(false);
+ }
+ };
+
+ const handleDownloadUpdate = async () => {
+ if (!updateInfo?.downloadUrl) return;
+
+ setDownloadingUpdate(true);
+ setUpdateError(null);
+ setDownloadResult(null);
+
+ try {
+ const result: UpdateDownloadResult = await downloadPluginUpdate(updateInfo.downloadUrl);
+
+ if (result.success) {
+ setDownloadResult(result);
+ console.log("✓ Download complete!", `Plugin downloaded to ${result.download_path}`);
+ } else {
+ setUpdateError(result.error || "Failed to download update");
+ }
+ } catch (error) {
+ setUpdateError(`Error downloading update: ${error}`);
+ } finally {
+ setDownloadingUpdate(false);
+ }
+ };
+
+ const getStatusMessage = () => {
+ if (!updateInfo) return null;
+
+ if (updateInfo.updateAvailable) {
+ if (downloadResult?.success) {
+ return (
+ <div style={{ color: 'lightgreen', marginTop: '5px' }}>
+ ✓ v{updateInfo.latestVersion} downloaded - ready to install
+ </div>
+ );
+ } else {
+ return (
+ <div style={{ color: 'orange', marginTop: '5px' }}>
+ Update available: v{updateInfo.latestVersion}
+ </div>
+ );
+ }
+ } else {
+ return (
+ <div style={{ color: 'lightgreen', marginTop: '5px' }}>
+ Up to date (v{updateInfo.currentVersion})
+ </div>
+ );
+ }
+ };
+
+ return (
+ <PanelSection title="Plugin Updates">
+ <ButtonItem
+ layout="below"
+ onClick={handleCheckForUpdate}
+ disabled={checkingUpdate}
+ description={getStatusMessage()}
+ >
+ {checkingUpdate ? 'Checking for updates...' : 'Check for Updates'}
+ </ButtonItem>
+
+ {updateInfo && updateInfo.updateAvailable && !downloadResult?.success && (
+ <ButtonItem
+ layout="below"
+ onClick={handleDownloadUpdate}
+ disabled={downloadingUpdate}
+ description={`Download version ${updateInfo.latestVersion}`}
+ >
+ {downloadingUpdate ? 'Downloading...' : 'Download Update'}
+ </ButtonItem>
+ )}
+
+ {downloadResult?.success && (
+ <div style={{
+ marginTop: '10px',
+ padding: '10px',
+ backgroundColor: 'rgba(0, 255, 0, 0.1)',
+ borderRadius: '4px',
+ border: '1px solid rgba(0, 255, 0, 0.3)'
+ }}>
+ <div style={{ color: 'lightgreen', fontWeight: 'bold', marginBottom: '5px' }}>
+ ✓ Download Complete!
+ </div>
+ <div style={{ fontSize: '12px', marginBottom: '10px' }}>
+ File saved to: {downloadResult.download_path}
+ </div>
+ <div style={{ fontSize: '12px' }}>
+ <strong>Installation Instructions:</strong>
+ <ol style={{ paddingLeft: '20px', marginTop: '5px' }}>
+ <li>Go to Decky Loader settings</li>
+ <li>Click "Developer" tab</li>
+ <li>Click "Uninstall" next to "Lossless Scaling"</li>
+ <li>Click "Install from ZIP"</li>
+ <li>Select the downloaded file</li>
+ <li>Restart Steam or reload plugins</li>
+ </ol>
+ </div>
+ </div>
+ )}
+
+ {updateError && (
+ <div style={{
+ color: 'red',
+ marginTop: '10px',
+ padding: '8px',
+ backgroundColor: 'rgba(255, 0, 0, 0.1)',
+ borderRadius: '4px',
+ fontSize: '12px'
+ }}>
+ {updateError}
+ </div>
+ )}
+ </PanelSection>
+ );
+};
diff --git a/src/components/index.ts b/src/components/index.ts
index 7304ca9..d26159d 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -5,3 +5,4 @@ export { ConfigurationSection } from "./ConfigurationSection";
export { UsageInstructions } from "./UsageInstructions";
export { WikiButton } from "./WikiButton";
export { ClipboardButton } from "./ClipboardButton";
+export { PluginUpdateChecker } from "./PluginUpdateChecker";