mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat(shell): startup window mode, --fullscreen switch and F11 toggle (#1514)
Settings > General gains "Window on startup" (normal / maximized / fullscreen), Electron only, mirrored into the main-process config by SETTINGS_UPDATE and applied at the next window creation. `--fullscreen` forces one fullscreen launch (consumed by the first window). F11 toggles OS-level fullscreen through WINDOW:TOGGLE_FULLSCREEN — the exit path on Windows/Linux where the title bar is hidden — and is skipped while the player owns document.fullscreenElement. attachWindowStateEvents tracks native and HTML fullscreen as two flags, since Electron leaves only the HTML state when the window was already natively fullscreen. macOS ignores the constructor `fullscreen` option on a hidden window, so ready-to-show repeats the request after show(). Toggles are decided by an observe-only, event-fed tracker (native-fullscreen-transitions.ts), never against isFullScreen(). Closes #1455 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
078bd07d94
commit
fa9084fca3
57 files changed
+1650
-8
No files matched your search
@@ -270,6 +270,27 @@ describe('RuntimeCapabilitiesService', () => {
|
||||
expect(service.supportsXtreamSqliteDataSource).toBe(false);
|
||||
});
|
||||
|
||||
it('offers the startup window mode only with both the settings mirror and the F11 toggle', () => {
|
||||
testWindow.electron = undefined;
|
||||
const service = new RuntimeCapabilitiesService();
|
||||
|
||||
expect(service.supportsStartupWindowMode).toBe(false);
|
||||
|
||||
// The mirror alone would let a user pick fullscreen with no way out
|
||||
// on Windows/Linux, where the title bar is hidden.
|
||||
testWindow.electron = { updateSettings: jest.fn() };
|
||||
expect(service.supportsStartupWindowMode).toBe(false);
|
||||
|
||||
testWindow.electron = { toggleFullScreenWindow: jest.fn() };
|
||||
expect(service.supportsStartupWindowMode).toBe(false);
|
||||
|
||||
testWindow.electron = {
|
||||
updateSettings: jest.fn(),
|
||||
toggleFullScreenWindow: jest.fn(),
|
||||
};
|
||||
expect(service.supportsStartupWindowMode).toBe(true);
|
||||
});
|
||||
|
||||
it('decouples external player launch support from path-setting support', () => {
|
||||
testWindow.electron = {
|
||||
openInMpv: jest.fn(),
|
||||
|
||||
@@ -69,6 +69,20 @@ export class RuntimeCapabilitiesService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Desktop window mode at launch (normal / maximized / fullscreen) plus
|
||||
* the F11 toggle. The mode reaches the main process through
|
||||
* `updateSettings`, and the toggle is what makes a fullscreen launch
|
||||
* escapable on Windows/Linux, where the title bar is hidden — so the
|
||||
* setting is offered only when both halves exist.
|
||||
*/
|
||||
get supportsStartupWindowMode(): boolean {
|
||||
return (
|
||||
this.hasElectronMethod('updateSettings') &&
|
||||
this.hasElectronMethod('toggleFullScreenWindow')
|
||||
);
|
||||
}
|
||||
|
||||
get supportsEpg(): boolean {
|
||||
return (
|
||||
this.supportsEpgImport &&
|
||||
|
||||
@@ -146,6 +146,36 @@ describe('SettingsStore dashboard rail settings', () => {
|
||||
expect(store.getSettings().stripCountryPrefix).toBe(false);
|
||||
});
|
||||
|
||||
it('defaults the startup window mode to normal when the stored field is missing', async () => {
|
||||
storedSettings = {};
|
||||
const store = injector.get(SettingsStore);
|
||||
|
||||
await store.loadSettings();
|
||||
|
||||
expect(store.getSettings().startupWindowMode).toBe('normal');
|
||||
});
|
||||
|
||||
it('restores a persisted fullscreen startup window mode', async () => {
|
||||
storedSettings = { startupWindowMode: 'fullscreen' };
|
||||
const store = injector.get(SettingsStore);
|
||||
|
||||
await store.loadSettings();
|
||||
|
||||
expect(store.getSettings().startupWindowMode).toBe('fullscreen');
|
||||
});
|
||||
|
||||
it('normalizes a persisted unknown startup window mode to normal', async () => {
|
||||
storedSettings = {
|
||||
startupWindowMode:
|
||||
'kiosk' as unknown as Settings['startupWindowMode'],
|
||||
};
|
||||
const store = injector.get(SettingsStore);
|
||||
|
||||
await store.loadSettings();
|
||||
|
||||
expect(store.getSettings().startupWindowMode).toBe('normal');
|
||||
});
|
||||
|
||||
it('defaults ambient player mode to false when the stored field is missing', async () => {
|
||||
storedSettings = {};
|
||||
const store = injector.get(SettingsStore);
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
Theme,
|
||||
VideoPlayer,
|
||||
normalizeDashboardRailsSettings,
|
||||
normalizeStartupWindowMode,
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
|
||||
const DEFAULT_SETTINGS: Settings = {
|
||||
@@ -37,6 +38,7 @@ const DEFAULT_SETTINGS: Settings = {
|
||||
showCaptions: false,
|
||||
showDashboard: true,
|
||||
startupBehavior: StartupBehavior.FirstView,
|
||||
startupWindowMode: 'normal',
|
||||
showExternalPlaybackBar: true,
|
||||
stripCountryPrefix: false,
|
||||
theme: Theme.SystemTheme,
|
||||
@@ -240,6 +242,9 @@ export const SettingsStore = signalStore(
|
||||
showCaptions: store.showCaptions(),
|
||||
showDashboard: store.showDashboard(),
|
||||
startupBehavior: store.startupBehavior(),
|
||||
startupWindowMode: normalizeStartupWindowMode(
|
||||
store.startupWindowMode?.()
|
||||
),
|
||||
showExternalPlaybackBar:
|
||||
store.showExternalPlaybackBar?.() ??
|
||||
DEFAULT_SETTINGS.showExternalPlaybackBar,
|
||||
|
||||
Reference in new issue
Block a user