From b51cbcae15f453f93e9e9036f893f0a20f49f7a2 Mon Sep 17 00:00:00 2001 From: 4gray Date: Fri, 22 May 2026 03:23:34 +0300 Subject: [PATCH] refactor(app): use runtime capabilities for shell gates --- apps/web/src/app/app.component.spec.ts | 28 +++++++++++++++++++++++++- apps/web/src/app/app.component.ts | 15 ++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/app.component.spec.ts b/apps/web/src/app/app.component.spec.ts index 2c32e2d6c..9df495935 100644 --- a/apps/web/src/app/app.component.spec.ts +++ b/apps/web/src/app/app.component.spec.ts @@ -8,7 +8,7 @@ import { EpgService } from '@iptvnator/epg/data-access'; import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util'; import { MockProvider } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; -import { DataService } from '@iptvnator/services'; +import { DataService, RuntimeCapabilitiesService } from '@iptvnator/services'; import { Language, Settings, @@ -64,9 +64,16 @@ describe('AppComponent', () => { let snackBar: MatSnackBar; let store: MockStore; let translateService: TranslateService; + let runtimeCapabilities: Partial; const originalElectron = window.electron; beforeEach(waitForAsync(() => { + runtimeCapabilities = { + isElectron: true, + isMacOS: false, + supportsEpg: true, + }; + TestBed.configureTestingModule({ imports: [AppComponent], providers: [ @@ -83,6 +90,10 @@ describe('AppComponent', () => { provide: SettingsService, useClass: MockSettingsService, }, + { + provide: RuntimeCapabilitiesService, + useValue: runtimeCapabilities as RuntimeCapabilitiesService, + }, MockProvider(EpgService, { fetchEpg: jest.fn(), }), @@ -212,4 +223,19 @@ describe('AppComponent', () => { expect(epgService.fetchEpg).toHaveBeenCalledWith(settings.epgUrl); expect(snackBar.open).not.toHaveBeenCalled(); }); + + it('does not fetch EPG settings when runtime does not support EPG', async () => { + const settings: Settings = { + ...DEFAULT_SETTINGS, + epgUrl: ['https://example.com/epg.xml'], + }; + Object.assign(runtimeCapabilities, { supportsEpg: false }); + settingsService.getValueFromLocalStorage.mockReturnValue(of(settings)); + + component.initSettings(); + await fixture.whenStable(); + + expect(window.electron?.checkEpgFreshness).not.toHaveBeenCalled(); + expect(epgService.fetchEpg).not.toHaveBeenCalled(); + }); }); diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index 2183b900c..6c0bc7410 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -9,7 +9,11 @@ import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util'; import { EpgProgressPanelComponent } from '@iptvnator/ui/epg/progress-panel'; import { PlaylistActions, selectAllPlaylistsMeta } from '@iptvnator/m3u-state'; import { filter, take } from 'rxjs'; -import { DataService, SettingsStore } from '@iptvnator/services'; +import { + DataService, + RuntimeCapabilitiesService, + SettingsStore, +} from '@iptvnator/services'; import { AUTO_UPDATE_PLAYLISTS, Language, @@ -30,9 +34,7 @@ const debugAppComponent = createDevLogger('AppComponent'); }) export class AppComponent implements OnInit { @HostBinding('class.macos-platform') get isMacOS() { - return ( - window.electron && navigator.platform.toLowerCase().includes('mac') - ); + return this.runtime.isMacOS; } private actions$ = inject(Actions); private dataService = inject(DataService); @@ -43,6 +45,7 @@ export class AppComponent implements OnInit { private translate = inject(TranslateService); private settingsService = inject(SettingsService); private settingsStore = inject(SettingsStore); + private runtime = inject(RuntimeCapabilitiesService); private readonly workspaceShellActions = inject(WORKSPACE_SHELL_ACTIONS); /** Default language as fallback */ @@ -75,7 +78,7 @@ export class AppComponent implements OnInit { document.documentElement.dataset.coverSize = size; }); - if (window.electron) { + if (this.runtime.isElectron) { document.addEventListener('keydown', (event) => { if (event.ctrlKey || event.metaKey) { if (event.key === 'f') { @@ -128,7 +131,7 @@ export class AppComponent implements OnInit { // Fetch EPG if URLs are configured (only fetch stale data) if ( - window.electron && + this.runtime.supportsEpg && settings.epgUrl?.length > 0 && settings.epgUrl?.some((u) => u !== '') ) {