Add: Check-for-Updates Button in Electron App
- Manueller Update-Check per Button im Header - Modal-Zustaende: checking, downloading, ready, uptodate, error - IPC: check-for-updates, update-not-available Events
This commit is contained in:
parent
c2942737bd
commit
ce2a26ddeb
4 changed files with 65 additions and 1 deletions
|
|
@ -39,6 +39,12 @@ function setupAutoUpdater() {
|
||||||
|
|
||||||
autoUpdater.on('update-not-available', () => {
|
autoUpdater.on('update-not-available', () => {
|
||||||
console.log('[AutoUpdater] App is up to date.');
|
console.log('[AutoUpdater] App is up to date.');
|
||||||
|
if (mainWindow) mainWindow.webContents.send('update-not-available');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manual check from renderer
|
||||||
|
ipcMain.on('check-for-updates', () => {
|
||||||
|
try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
version: '1.5.0',
|
version: '1.5.0',
|
||||||
onUpdateAvailable: (callback) => ipcRenderer.on('update-available', callback),
|
onUpdateAvailable: (callback) => ipcRenderer.on('update-available', callback),
|
||||||
onUpdateReady: (callback) => ipcRenderer.on('update-ready', callback),
|
onUpdateReady: (callback) => ipcRenderer.on('update-ready', callback),
|
||||||
|
onUpdateNotAvailable: (callback) => ipcRenderer.on('update-not-available', callback),
|
||||||
onUpdateError: (callback) => ipcRenderer.on('update-error', (_e, msg) => callback(msg)),
|
onUpdateError: (callback) => ipcRenderer.on('update-error', (_e, msg) => callback(msg)),
|
||||||
|
checkForUpdates: () => ipcRenderer.send('check-for-updates'),
|
||||||
installUpdate: () => ipcRenderer.send('install-update'),
|
installUpdate: () => ipcRenderer.send('install-update'),
|
||||||
setStreaming: (active) => ipcRenderer.send('streaming-status', active),
|
setStreaming: (active) => ipcRenderer.send('streaming-status', active),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export function registerTab(pluginName: string, component: React.FC<{ data: any
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [connected, setConnected] = useState(false);
|
const [connected, setConnected] = useState(false);
|
||||||
const [plugins, setPlugins] = useState<PluginInfo[]>([]);
|
const [plugins, setPlugins] = useState<PluginInfo[]>([]);
|
||||||
const [updateState, setUpdateState] = useState<'idle' | 'downloading' | 'ready' | 'error'>('idle');
|
const [updateState, setUpdateState] = useState<'idle' | 'checking' | 'downloading' | 'ready' | 'uptodate' | 'error'>('idle');
|
||||||
const [activeTab, setActiveTabRaw] = useState<string>(() => localStorage.getItem('hub_activeTab') ?? '');
|
const [activeTab, setActiveTabRaw] = useState<string>(() => localStorage.getItem('hub_activeTab') ?? '');
|
||||||
|
|
||||||
const setActiveTab = (tab: string) => {
|
const setActiveTab = (tab: string) => {
|
||||||
|
|
@ -100,9 +100,15 @@ export default function App() {
|
||||||
if (!api?.onUpdateAvailable) return;
|
if (!api?.onUpdateAvailable) return;
|
||||||
api.onUpdateAvailable(() => setUpdateState('downloading'));
|
api.onUpdateAvailable(() => setUpdateState('downloading'));
|
||||||
api.onUpdateReady(() => setUpdateState('ready'));
|
api.onUpdateReady(() => setUpdateState('ready'));
|
||||||
|
api.onUpdateNotAvailable?.(() => setUpdateState('uptodate'));
|
||||||
api.onUpdateError?.(() => setUpdateState('error'));
|
api.onUpdateError?.(() => setUpdateState('error'));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleCheckForUpdates = () => {
|
||||||
|
setUpdateState('checking');
|
||||||
|
(window as any).electronAPI?.checkForUpdates();
|
||||||
|
};
|
||||||
|
|
||||||
// Tab icon mapping
|
// Tab icon mapping
|
||||||
const tabIcons: Record<string, string> = {
|
const tabIcons: Record<string, string> = {
|
||||||
radio: '\u{1F30D}',
|
radio: '\u{1F30D}',
|
||||||
|
|
@ -151,6 +157,16 @@ export default function App() {
|
||||||
<span className="hub-download-label">Desktop App</span>
|
<span className="hub-download-label">Desktop App</span>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
{(window as any).electronAPI && (
|
||||||
|
<button
|
||||||
|
className="hub-check-update-btn"
|
||||||
|
onClick={handleCheckForUpdates}
|
||||||
|
disabled={updateState !== 'idle'}
|
||||||
|
title="Nach Updates suchen"
|
||||||
|
>
|
||||||
|
{'\u{1F504}'}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<span className="hub-version">v{version}</span>
|
<span className="hub-version">v{version}</span>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
@ -158,6 +174,15 @@ export default function App() {
|
||||||
{updateState !== 'idle' && (
|
{updateState !== 'idle' && (
|
||||||
<div className="hub-update-overlay">
|
<div className="hub-update-overlay">
|
||||||
<div className="hub-update-modal">
|
<div className="hub-update-modal">
|
||||||
|
{updateState === 'checking' && (
|
||||||
|
<>
|
||||||
|
<div className="hub-update-icon">{'\u{1F50D}'}</div>
|
||||||
|
<h2>Suche nach Updates...</h2>
|
||||||
|
<div className="hub-update-progress">
|
||||||
|
<div className="hub-update-progress-bar" />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{updateState === 'downloading' && (
|
{updateState === 'downloading' && (
|
||||||
<>
|
<>
|
||||||
<div className="hub-update-icon">{'\u2B07\uFE0F'}</div>
|
<div className="hub-update-icon">{'\u2B07\uFE0F'}</div>
|
||||||
|
|
@ -178,6 +203,16 @@ export default function App() {
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{updateState === 'uptodate' && (
|
||||||
|
<>
|
||||||
|
<div className="hub-update-icon">{'\u2705'}</div>
|
||||||
|
<h2>Alles aktuell!</h2>
|
||||||
|
<p>Du verwendest bereits die neueste Version (v{version}).</p>
|
||||||
|
<button className="hub-update-btn" onClick={() => setUpdateState('idle')}>
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{updateState === 'error' && (
|
{updateState === 'error' && (
|
||||||
<>
|
<>
|
||||||
<div className="hub-update-icon">{'\u274C'}</div>
|
<div className="hub-update-icon">{'\u274C'}</div>
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,27 @@ html, body {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Check for Updates Button ── */
|
||||||
|
.hub-check-update-btn {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all var(--transition);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.hub-check-update-btn:hover:not(:disabled) {
|
||||||
|
color: var(--accent);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
.hub-check-update-btn:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Update Modal ── */
|
/* ── Update Modal ── */
|
||||||
.hub-update-overlay {
|
.hub-update-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue