Stage 1: extract the skin-agnostic UI layer into app/core/
First step of splitting the UI into two skin trees. All 12 services plus platform.ts, format.ts, file-icons.ts, icons.ts and app.config.ts move to ui/src/app/core/ — the layer both skins will share. This is a pure move: git records all 17 as renames, and no file content changed beyond import paths. The premise holds because `git diff main...feat/7css-skin` touches none of these files — the service layer was already skin-agnostic, so there is nothing to untangle, only to relocate. Components now reach it through a new `@core/*` tsconfig alias rather than a relative path. That is deliberate and load-bearing for the next stage: skin components are about to move under app/skins/<skin>/ at varying depths, and an alias keeps every one of these 67 imports correct wherever its file ends up. `@shared/*` (the bun-side src/shared) already set the precedent. Intra-core imports needed no edits at all — every ./sibling reference among the moved files points at another moved file. Verified: tsc clean, `bun run build:ui` clean (AOT resolves every import and template symbol), and the running window's opaque interior is pixel-identical to a pre-refactor capture. Note on that comparison: the Aero frame and title bar do NOT compare equal between launches, and that is not a regression — .window.glass::before runs at opacity .6, so the chrome composites over whatever desktop is behind the window and shifts by a uniform ~8% brightness. The check therefore diffs the opaque interior (inset 30px sides, 80px top), where anything this refactor could break would show. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { Injectable, inject, signal } from '@angular/core';
|
||||
import { RpcService } from './rpc.service';
|
||||
|
||||
export type UpdaterState = 'idle' | 'available' | 'downloading' | 'ready' | 'error';
|
||||
|
||||
/**
|
||||
* Drives the tab-bar update pill. The backend pushes updateStatus events
|
||||
* (available / downloading progress / error); "ready" is derived locally when
|
||||
* downloadUpdate resolves ok. Two-step UX: available -> download -> ready ->
|
||||
* apply (relaunch).
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class UpdaterService {
|
||||
private rpc = inject(RpcService);
|
||||
|
||||
readonly state = signal<UpdaterState>('idle');
|
||||
readonly version = signal('');
|
||||
readonly progress = signal(0);
|
||||
|
||||
constructor() {
|
||||
if (!this.rpc.available) return;
|
||||
this.rpc.onUpdateStatus((s) => {
|
||||
if (s.phase === 'available') {
|
||||
this.version.set(s.version ?? '');
|
||||
this.state.set('available');
|
||||
} else if (s.phase === 'downloading') {
|
||||
this.state.set('downloading');
|
||||
this.progress.set(s.progress ?? 0);
|
||||
} else if (s.phase === 'error') {
|
||||
this.state.set('error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async download(): Promise<void> {
|
||||
if (this.state() !== 'available') return;
|
||||
this.state.set('downloading');
|
||||
this.progress.set(0);
|
||||
const r = await this.rpc.request.downloadUpdate({});
|
||||
this.state.set(r?.ok ? 'ready' : 'error');
|
||||
}
|
||||
|
||||
apply(): void {
|
||||
if (this.state() !== 'ready') return;
|
||||
void this.rpc.request.applyUpdate({}); // quits + relaunches
|
||||
}
|
||||
|
||||
/** Manual re-check (menu item). */
|
||||
async check(): Promise<void> {
|
||||
if (!this.rpc.available) return;
|
||||
const r = await this.rpc.request.checkForUpdate({});
|
||||
if (r?.ok && r.updateAvailable) {
|
||||
this.version.set(r.version);
|
||||
this.state.set('available');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user