diff --git a/libs/services/src/lib/runtime-capabilities.service.spec.ts b/libs/services/src/lib/runtime-capabilities.service.spec.ts index 3a4ba2373..aaf014d13 100644 --- a/libs/services/src/lib/runtime-capabilities.service.spec.ts +++ b/libs/services/src/lib/runtime-capabilities.service.spec.ts @@ -18,6 +18,8 @@ describe('RuntimeCapabilitiesService', () => { expect(service.environment).toBe('pwa'); expect(service.isPwa).toBe(true); expect(service.isElectron).toBe(false); + expect(service.platform).toBeUndefined(); + expect(service.isMacOS).toBe(false); expect(service.supportsEpg).toBe(false); expect(service.supportsSqlite).toBe(false); expect(service.supportsDownloads).toBe(false); @@ -29,6 +31,7 @@ describe('RuntimeCapabilitiesService', () => { it('reports Electron capabilities from the available preload bridge methods', () => { testWindow.electron = { + platform: 'darwin', dbGetAppPlaylists: jest.fn(), dbUpsertAppPlaylist: jest.fn(), dbGetAppState: jest.fn(), @@ -47,6 +50,8 @@ describe('RuntimeCapabilitiesService', () => { expect(service.environment).toBe('electron'); expect(service.isElectron).toBe(true); expect(service.isPwa).toBe(false); + expect(service.platform).toBe('darwin'); + expect(service.isMacOS).toBe(true); expect(service.supportsEpg).toBe(true); expect(service.supportsSqlite).toBe(true); expect(service.supportsDownloads).toBe(true); @@ -64,6 +69,8 @@ describe('RuntimeCapabilitiesService', () => { const service = new RuntimeCapabilitiesService(); expect(service.environment).toBe('electron'); + expect(service.platform).toBeUndefined(); + expect(service.isMacOS).toBe(false); expect(service.supportsEpg).toBe(true); expect(service.supportsSqlite).toBe(false); expect(service.supportsDownloads).toBe(false); diff --git a/libs/services/src/lib/runtime-capabilities.service.ts b/libs/services/src/lib/runtime-capabilities.service.ts index b530d4dc0..d7a6ebf7c 100644 --- a/libs/services/src/lib/runtime-capabilities.service.ts +++ b/libs/services/src/lib/runtime-capabilities.service.ts @@ -22,6 +22,15 @@ export class RuntimeCapabilitiesService { return !this.isElectron; } + get platform(): string | undefined { + const platform = this.electronBridge?.['platform']; + return typeof platform === 'string' ? platform : undefined; + } + + get isMacOS(): boolean { + return this.platform === 'darwin'; + } + get supportsEpg(): boolean { return this.isElectron; } diff --git a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell-xtream-import.service.ts b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell-xtream-import.service.ts index 7ae8127d5..b8c63a7ed 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell-xtream-import.service.ts +++ b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell-xtream-import.service.ts @@ -4,6 +4,7 @@ import { TranslateService } from '@ngx-translate/core'; import { startWith } from 'rxjs'; import { PlaylistRefreshActionService } from '@iptvnator/playlist/shared/ui'; import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { RuntimeCapabilitiesService } from '@iptvnator/services'; import type { XtreamImportPhaseTone } from './helpers/workspace-shell-constants'; import { buildXtreamImportDetailLabel, @@ -23,14 +24,18 @@ export class WorkspaceShellXtreamImportService { private readonly playlistRefreshAction = inject( PlaylistRefreshActionService ); + private readonly runtime = inject(RuntimeCapabilitiesService); private readonly translate = inject(TranslateService); - private readonly isElectron = !!window.electron; private readonly languageTick = toSignal( this.translate.onLangChange.pipe(startWith(null)), { initialValue: null } ); + private get isElectron(): boolean { + return this.runtime.isElectron; + } + private readonly translateText = ( key: string, params?: Record diff --git a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.spec.ts b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.spec.ts index 7f4983b50..11c2b7507 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.spec.ts +++ b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.spec.ts @@ -17,7 +17,11 @@ import { } from '@iptvnator/portal/shared/util'; import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; -import { PlaylistsService, SettingsStore } from '@iptvnator/services'; +import { + PlaylistsService, + RuntimeCapabilitiesService, + SettingsStore, +} from '@iptvnator/services'; import { PlaylistMeta } from '@iptvnator/shared/interfaces'; import { WorkspaceStartupPreferencesService, @@ -135,10 +139,17 @@ describe('WorkspaceShellFacade', () => { persistLastRestorablePath: jest.Mock; showDashboard: jest.Mock; }; + let runtime: { + isElectron: boolean; + isMacOS: boolean; + }; beforeEach(() => { - window.electron = { platform: 'darwin' } as typeof window.electron; showDashboardSignal = signal(true); + runtime = { + isElectron: true, + isMacOS: true, + }; activePlaylistSignal = signal({ _id: 'pl-1', @@ -254,6 +265,10 @@ describe('WorkspaceShellFacade', () => { showExternalPlaybackBar: signal(true), }, }, + { + provide: RuntimeCapabilitiesService, + useValue: runtime, + }, { provide: PlaylistsService, useValue: playlistsService, @@ -322,6 +337,17 @@ describe('WorkspaceShellFacade', () => { facade = TestBed.inject(WorkspaceShellFacade); }); + it('derives desktop shell flags from runtime capabilities', () => { + expect(facade.isElectron).toBe(true); + expect(facade.isMacOS).toBe(true); + + runtime.isElectron = false; + runtime.isMacOS = false; + + expect(facade.isElectron).toBe(false); + expect(facade.isMacOS).toBe(false); + }); + it('routes dashboard search Enter into the active Xtream playlist search', () => { const xtreamStore = TestBed.inject( XtreamStore diff --git a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts index 2fa3c7418..0d874a50f 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts +++ b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts @@ -36,6 +36,7 @@ import { import { DownloadsService, PlaylistsService, + RuntimeCapabilitiesService, SettingsStore, } from '@iptvnator/services'; import { PlaylistActions, selectAllPlaylistsMeta } from '@iptvnator/m3u-state'; @@ -96,6 +97,7 @@ export class WorkspaceShellFacade { private readonly playlistRefreshAction = inject( PlaylistRefreshActionService ); + private readonly runtime = inject(RuntimeCapabilitiesService); private readonly downloadsService = inject(DownloadsService); readonly hasActiveDownloads = computed( () => this.isElectron && this.downloadsService.activeCount() > 0 @@ -137,8 +139,13 @@ export class WorkspaceShellFacade { readonly searchQuery = signal(''); readonly appliedSearchQuery = signal(''); - readonly isElectron = !!window.electron; - readonly isMacOS = window.electron?.platform === 'darwin'; + get isElectron(): boolean { + return this.runtime.isElectron; + } + + get isMacOS(): boolean { + return this.runtime.isMacOS; + } readonly currentUrl = signal(this.router.url); readonly currentRoute = computed(() => parseWorkspaceShellRoute(this.currentUrl())