diff --git a/desktop/app/argument.parser.ts b/desktop/app/argument.parser.ts index 123f64213..ed9cd21e4 100644 --- a/desktop/app/argument.parser.ts +++ b/desktop/app/argument.parser.ts @@ -8,6 +8,7 @@ export class ParsedArgument { readonly mode: ApplicationMode, readonly host: string, readonly port: number, + readonly paths: string[], ) {} get uiMode() { @@ -56,6 +57,6 @@ export class ArgumentParser { const host = parsed.values.host || 'localhost' const port = parseInt(parsed.values.port || '0') || (serve ? 7000 : 0) - return new ParsedArgument(serve, mode, host, port) + return new ParsedArgument(serve, mode, host, port, parsed.positionals) } } diff --git a/desktop/app/window.manager.ts b/desktop/app/window.manager.ts index 710c26764..c2504e3b5 100644 --- a/desktop/app/window.manager.ts +++ b/desktop/app/window.manager.ts @@ -1,11 +1,12 @@ import type { Rectangle } from 'electron' -import { BrowserWindow, Notification, dialog, screen, shell } from 'electron' +import { BrowserWindow, Notification, app, dialog, screen, shell } from 'electron' import Store from 'electron-store' import type { ChildProcessWithoutNullStreams } from 'node:child_process' +import { existsSync, statSync } from 'node:fs' import { join } from 'path' import { WebSocket } from 'ws' -import type { MessageEvent } from '../src/shared/types/api.types' -import type { CloseWindow, ConfirmationEvent, FullscreenWindow, NotificationEvent, OpenDirectory, OpenFile, OpenWindow, ResizeWindow, WindowCommand } from '../src/shared/types/app.types' +import type { ConfirmationEvent, MessageEvent, NotificationEvent } from '../src/shared/types/api.types' +import type { CloseWindow, FullscreenWindow, OpenDirectory, OpenFile, OpenWindow, ResizeWindow, WindowCommand } from '../src/shared/types/app.types' import type { Nullable } from '../src/shared/utils/types' import type { ParsedArgument } from './argument.parser' @@ -67,6 +68,10 @@ export class ApplicationWindow { sendMessage(event: MessageEvent) { this.browserWindow.webContents.send(event.eventName, event) } + + openImage(path: string) { + this.sendMessage({ eventName: 'IMAGE.OPEN', path } as never) + } } export function isNotificationEvent(event: MessageEvent): event is NotificationEvent { @@ -257,6 +262,15 @@ export class WindowManager { this.createWebSocket(host, port, (webSocket) => (appWindow.webSocket = webSocket)) appWindow.apiProcess = apiProcess + + if (app.isPackaged) { + for (const path of this.args.paths) { + if (path !== '.' && existsSync(path) && statSync(path).isFile()) { + console.info('opening image at', path) + appWindow.openImage(path) + } + } + } } async createSplashWindow() { diff --git a/desktop/src/app/home/home.component.ts b/desktop/src/app/home/home.component.ts index 250ef58dd..550813421 100644 --- a/desktop/src/app/home/home.component.ts +++ b/desktop/src/app/home/home.component.ts @@ -305,6 +305,12 @@ export class HomeComponent implements AfterContentInit { }) } }) + + electronService.on('IMAGE.OPEN', (event) => { + return ngZone.run(() => { + return this.browserWindowService.openImage({ path: event.path, source: 'PATH' }) + }) + }) } async ngAfterContentInit() { diff --git a/desktop/src/shared/services/confirmation.service.ts b/desktop/src/shared/services/confirmation.service.ts index 509c5a14b..dc7d26317 100644 --- a/desktop/src/shared/services/confirmation.service.ts +++ b/desktop/src/shared/services/confirmation.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { ConfirmEventType } from 'primeng/api' -import { ConfirmationEvent } from '../types/app.types' +import { ConfirmationEvent } from '../types/api.types' import { AngularService } from './angular.service' import { ApiService } from './api.service' diff --git a/desktop/src/shared/services/electron.service.ts b/desktop/src/shared/services/electron.service.ts index 5673d5915..243dc640d 100644 --- a/desktop/src/shared/services/electron.service.ts +++ b/desktop/src/shared/services/electron.service.ts @@ -5,8 +5,8 @@ import { Injectable } from '@angular/core' // look as if you never imported the module at all. import { DARVEvent, TPPAEvent } from '../types/alignment.types' -import { DeviceMessageEvent } from '../types/api.types' -import { CloseWindow, ConfirmationEvent, FullscreenWindow, JsonFile, NotificationEvent, OpenDirectory, OpenFile, ResizeWindow, SaveJson, WindowCommand } from '../types/app.types' +import { ConfirmationEvent, DeviceMessageEvent, NotificationEvent, OpenImageEvent } from '../types/api.types' +import { CloseWindow, FullscreenWindow, JsonFile, OpenDirectory, OpenFile, ResizeWindow, SaveJson, WindowCommand } from '../types/app.types' import { Location } from '../types/atlas.types' import { AutoFocusEvent } from '../types/autofocus.type' import { Camera, CameraCaptureEvent } from '../types/camera.types' @@ -95,6 +95,7 @@ export interface EventMap { 'WHEEL.RENAMED': WheelRenamed 'ROI.SELECTED': ROISelected 'AUTO_FOCUS.ELAPSED': AutoFocusEvent + 'IMAGE.OPEN': OpenImageEvent } @Injectable({ providedIn: 'root' }) diff --git a/desktop/src/shared/types/api.types.ts b/desktop/src/shared/types/api.types.ts index aea0aa242..247b0c945 100644 --- a/desktop/src/shared/types/api.types.ts +++ b/desktop/src/shared/types/api.types.ts @@ -1,3 +1,4 @@ +import type { Severity } from './angular.types' import type { Device } from './device.types' export type ApiEventType = (typeof API_EVENT_TYPES)[number] @@ -6,10 +7,26 @@ export interface MessageEvent { eventName: string } -export interface DeviceMessageEvent { +export interface OpenImageEvent extends MessageEvent { + path: string +} + +export interface DeviceMessageEvent extends MessageEvent { device: T } +export interface NotificationEvent extends MessageEvent { + target?: string + severity: Severity + title?: string + body: string +} + +export interface ConfirmationEvent extends MessageEvent { + message: string + idempotencyKey: string +} + export const API_EVENT_TYPES = [ // Device. 'DEVICE.PROPERTY_CHANGED', @@ -55,3 +72,11 @@ export const API_EVENT_TYPES = [ // Auto Focus. 'AUTO_FOCUS.ELAPSED', ] as const + +export function isNotificationEvent(event: MessageEvent): event is NotificationEvent { + return event.eventName === 'NOTIFICATION' +} + +export function isConfirmationEvent(event: MessageEvent): event is ConfirmationEvent { + return event.eventName === 'CONFIRMATION' +} diff --git a/desktop/src/shared/types/app.types.ts b/desktop/src/shared/types/app.types.ts index 742b3181f..01667726f 100644 --- a/desktop/src/shared/types/app.types.ts +++ b/desktop/src/shared/types/app.types.ts @@ -1,22 +1,7 @@ -import type { Severity } from './angular.types' -import type { MessageEvent } from './api.types' - export type InternalEventType = (typeof INTERNAL_EVENT_TYPES)[number] export type SaveJson = OpenFile & JsonFile -export interface NotificationEvent extends MessageEvent { - target?: string - severity: Severity - title?: string - body: string -} - -export interface ConfirmationEvent extends MessageEvent { - message: string - idempotencyKey: string -} - export interface WindowPreference { modal?: boolean autoResizable?: boolean