위젯 추가 팝업 수정
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import DesktopUpdateModal from '@frontend/components/DesktopUpdateModal';
|
||||
import {
|
||||
runStartupAutoUpdate,
|
||||
checkForUpdates,
|
||||
getAppVersion,
|
||||
type DesktopUpdatePhase,
|
||||
type DesktopUpdateProgress,
|
||||
} from './bridge/updater';
|
||||
@@ -27,9 +29,8 @@ function formatBytes(n?: number): string {
|
||||
|
||||
function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | null }) {
|
||||
const phase = progress?.phase ?? 'checking';
|
||||
const isActive = phase === 'checking' || phase === 'downloading' || phase === 'installing' || phase === 'relaunching';
|
||||
const showBar = phase === 'available' || phase === 'downloading' || phase === 'installing';
|
||||
const barPct = phase === 'installing' ? 100 : progress?.downloadPercent;
|
||||
const isActive = phase === 'checking';
|
||||
const showBar = false;
|
||||
|
||||
const panelClass = phase === 'error'
|
||||
? 'desktop-update-progress--failed'
|
||||
@@ -54,9 +55,6 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n
|
||||
<h1 className="desktop-startup-update-title">GoldenChart</h1>
|
||||
<p className="desktop-startup-update-sub">
|
||||
{progress?.currentVersion ? `현재 v${progress.currentVersion}` : '시작 중…'}
|
||||
{progress?.newVersion && progress.newVersion !== progress.currentVersion && (
|
||||
<> → v{progress.newVersion}</>
|
||||
)}
|
||||
</p>
|
||||
|
||||
<div className={`desktop-update-progress ${panelClass}`.trim()}>
|
||||
@@ -65,27 +63,11 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n
|
||||
{isActive && <span className="desktop-update-spinner" aria-hidden />}
|
||||
{PHASE_LABEL[phase]}
|
||||
</span>
|
||||
{phase === 'downloading' && progress?.downloadPercent != null && (
|
||||
<span className="desktop-update-pct">{progress.downloadPercent}%</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{showBar && (
|
||||
<div
|
||||
className="desktop-update-bar"
|
||||
role="progressbar"
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={barPct ?? undefined}
|
||||
>
|
||||
{barPct != null ? (
|
||||
<div
|
||||
className="desktop-update-bar-fill desktop-update-bar-fill--determinate"
|
||||
style={{ width: `${barPct}%` }}
|
||||
/>
|
||||
) : (
|
||||
<div className="desktop-update-bar-fill desktop-update-bar-fill--indeterminate" />
|
||||
)}
|
||||
<div className="desktop-update-bar" role="progressbar" aria-valuemin={0} aria-valuemax={100}>
|
||||
<div className="desktop-update-bar-fill desktop-update-bar-fill--indeterminate" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -94,10 +76,7 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n
|
||||
<span className="desktop-update-step-dot" aria-hidden />
|
||||
서버에서 버전 확인
|
||||
</li>
|
||||
<li className={`desktop-update-step${
|
||||
phase === 'available' || phase === 'downloading' ? ' active'
|
||||
: ['installing', 'relaunching', 'uptodate'].includes(phase) ? ' done' : ''
|
||||
}`}>
|
||||
<li className="desktop-update-step">
|
||||
<span className="desktop-update-step-dot" aria-hidden />
|
||||
업데이트 다운로드
|
||||
{progress?.downloadedBytes && progress.totalBytes ? (
|
||||
@@ -106,9 +85,7 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n
|
||||
</span>
|
||||
) : null}
|
||||
</li>
|
||||
<li className={`desktop-update-step${
|
||||
phase === 'installing' ? ' active' : phase === 'relaunching' || phase === 'uptodate' ? ' done' : ''
|
||||
}`}>
|
||||
<li className="desktop-update-step">
|
||||
<span className="desktop-update-step-dot" aria-hidden />
|
||||
설치 및 재시작
|
||||
</li>
|
||||
@@ -125,44 +102,56 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n
|
||||
);
|
||||
}
|
||||
|
||||
/** StrictMode 이중 실행 방지 — 시작 업데이트는 한 번만 */
|
||||
let startupUpdateTask: ReturnType<typeof runStartupAutoUpdate> | null = null;
|
||||
const startupProgressListeners = new Set<(p: DesktopUpdateProgress) => void>();
|
||||
|
||||
function emitStartupProgress(p: DesktopUpdateProgress) {
|
||||
for (const listener of startupProgressListeners) listener(p);
|
||||
}
|
||||
|
||||
function getStartupUpdateTask() {
|
||||
if (!startupUpdateTask) {
|
||||
startupUpdateTask = runStartupAutoUpdate(emitStartupProgress);
|
||||
}
|
||||
return startupUpdateTask;
|
||||
}
|
||||
|
||||
/** 시작 시 자동 업데이트 후 children(메인 앱) 렌더 */
|
||||
/** 시작 시 버전 확인 후 children(메인 앱) 렌더 — 새 버전 있으면 업데이트 모달 표시 */
|
||||
export function StartupUpdateGate({ children }: { children: React.ReactNode }) {
|
||||
const [ready, setReady] = useState(false);
|
||||
const [startupUpdateOpen, setStartupUpdateOpen] = useState(false);
|
||||
const [progress, setProgress] = useState<DesktopUpdateProgress | null>({
|
||||
phase: 'checking',
|
||||
message: '서버에서 새 버전을 확인하는 중…',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (p: DesktopUpdateProgress) => setProgress(p);
|
||||
startupProgressListeners.add(listener);
|
||||
let cancelled = false;
|
||||
|
||||
void getStartupUpdateTask().then(({ shouldContinue, result }) => {
|
||||
if (!shouldContinue) return;
|
||||
if (result.phase === 'error') {
|
||||
console.warn('[startup-update]', result.message);
|
||||
void (async () => {
|
||||
let currentVersion = '—';
|
||||
try {
|
||||
currentVersion = await getAppVersion();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (cancelled) return;
|
||||
|
||||
setProgress({
|
||||
phase: 'checking',
|
||||
message: '서버에서 새 버전을 확인하는 중…',
|
||||
currentVersion,
|
||||
});
|
||||
|
||||
const result = await checkForUpdates();
|
||||
if (cancelled) return;
|
||||
|
||||
if (result.available) {
|
||||
setProgress({
|
||||
phase: 'available',
|
||||
message: result.message ?? `새 버전 v${result.version}을(를) 사용할 수 있습니다.`,
|
||||
currentVersion,
|
||||
newVersion: result.version,
|
||||
});
|
||||
} else if (result.message?.includes('실패') || result.message?.includes('오류')) {
|
||||
setProgress({ phase: 'error', message: result.message, currentVersion });
|
||||
}
|
||||
|
||||
scheduleMainWindowTitleSync();
|
||||
setReady(true);
|
||||
});
|
||||
if (result.available) {
|
||||
setStartupUpdateOpen(true);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
startupProgressListeners.delete(listener);
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -170,5 +159,14 @@ export function StartupUpdateGate({ children }: { children: React.ReactNode }) {
|
||||
return <StartupUpdateSplash progress={progress} />;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<DesktopUpdateModal
|
||||
open={startupUpdateOpen}
|
||||
onClose={() => setStartupUpdateOpen(false)}
|
||||
autoStart
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user