[MM-51874] Migrate loading screen to singleton (#2655)
* Migrate loadingScreen to singleton * REVERT ME when MainWindow singleton changes are merged * Revert "REVERT ME when MainWindow singleton changes are merged" This reverts commit 2de5520117b9aefb8eeb161d493de7cb275f7a5b.
This commit is contained in:
@@ -44,6 +44,7 @@ jest.mock('main/badge', () => ({
|
|||||||
jest.mock('main/tray/tray', () => ({
|
jest.mock('main/tray/tray', () => ({
|
||||||
refreshTrayImages: jest.fn(),
|
refreshTrayImages: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/loadingScreen', () => ({}));
|
||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
handleUpdateConfig: jest.fn(),
|
handleUpdateConfig: jest.fn(),
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
|
@@ -12,6 +12,7 @@ import Config from 'common/config';
|
|||||||
import AutoLauncher from 'main/AutoLauncher';
|
import AutoLauncher from 'main/AutoLauncher';
|
||||||
import {setUnreadBadgeSetting} from 'main/badge';
|
import {setUnreadBadgeSetting} from 'main/badge';
|
||||||
import {refreshTrayImages} from 'main/tray/tray';
|
import {refreshTrayImages} from 'main/tray/tray';
|
||||||
|
import LoadingScreen from 'main/views/loadingScreen';
|
||||||
import WindowManager from 'main/windows/windowManager';
|
import WindowManager from 'main/windows/windowManager';
|
||||||
|
|
||||||
import {handleMainWindowIsShown} from './intercom';
|
import {handleMainWindowIsShown} from './intercom';
|
||||||
@@ -80,7 +81,7 @@ export function handleDarkModeChange(darkMode: boolean) {
|
|||||||
|
|
||||||
refreshTrayImages(Config.trayIconTheme);
|
refreshTrayImages(Config.trayIconTheme);
|
||||||
WindowManager.sendToRenderer(DARK_MODE_CHANGE, darkMode);
|
WindowManager.sendToRenderer(DARK_MODE_CHANGE, darkMode);
|
||||||
WindowManager.updateLoadingScreenDarkMode(darkMode);
|
LoadingScreen.setDarkMode(darkMode);
|
||||||
|
|
||||||
ipcMain.emit(EMIT_CONFIGURATION, true, Config.data);
|
ipcMain.emit(EMIT_CONFIGURATION, true, Config.data);
|
||||||
}
|
}
|
||||||
|
56
src/main/views/loadingScreen.test.js
Normal file
56
src/main/views/loadingScreen.test.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
|
import {LoadingScreen} from './loadingScreen';
|
||||||
|
|
||||||
|
jest.mock('electron', () => ({
|
||||||
|
ipcMain: {
|
||||||
|
on: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('main/windows/mainWindow', () => ({
|
||||||
|
get: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('main/views/loadingScreen', () => {
|
||||||
|
describe('show', () => {
|
||||||
|
const mainWindow = {
|
||||||
|
getBrowserViews: jest.fn(),
|
||||||
|
setTopBrowserView: jest.fn(),
|
||||||
|
addBrowserView: jest.fn(),
|
||||||
|
};
|
||||||
|
const loadingScreen = new LoadingScreen();
|
||||||
|
loadingScreen.create = jest.fn();
|
||||||
|
loadingScreen.setBounds = jest.fn();
|
||||||
|
const view = {webContents: {send: jest.fn(), isLoading: () => false}};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mainWindow.getBrowserViews.mockImplementation(() => []);
|
||||||
|
MainWindow.get.mockReturnValue(mainWindow);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
delete loadingScreen.view;
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create new loading screen if one doesnt exist and add it to the window', () => {
|
||||||
|
loadingScreen.create.mockImplementation(() => {
|
||||||
|
loadingScreen.view = view;
|
||||||
|
});
|
||||||
|
loadingScreen.show();
|
||||||
|
expect(loadingScreen.create).toHaveBeenCalled();
|
||||||
|
expect(mainWindow.addBrowserView).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the browser view as top if already exists and needs to be shown', () => {
|
||||||
|
loadingScreen.view = view;
|
||||||
|
mainWindow.getBrowserViews.mockImplementation(() => [view]);
|
||||||
|
loadingScreen.show();
|
||||||
|
expect(mainWindow.setTopBrowserView).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
115
src/main/views/loadingScreen.ts
Normal file
115
src/main/views/loadingScreen.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {BrowserView, app, ipcMain} from 'electron';
|
||||||
|
import log from 'electron-log';
|
||||||
|
|
||||||
|
import {DARK_MODE_CHANGE, LOADING_SCREEN_ANIMATION_FINISHED, TOGGLE_LOADING_SCREEN_VISIBILITY} from 'common/communication';
|
||||||
|
|
||||||
|
import {getLocalPreload, getLocalURLString, getWindowBoundaries} from 'main/utils';
|
||||||
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
|
enum LoadingScreenState {
|
||||||
|
VISIBLE = 1,
|
||||||
|
FADING = 2,
|
||||||
|
HIDDEN = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LoadingScreen {
|
||||||
|
private view?: BrowserView;
|
||||||
|
private state: LoadingScreenState;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.state = LoadingScreenState.HIDDEN;
|
||||||
|
|
||||||
|
ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, this.handleAnimationFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loading Screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
setBounds = () => {
|
||||||
|
if (this.view) {
|
||||||
|
const mainWindow = MainWindow.get();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.view.setBounds(getWindowBoundaries(mainWindow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDarkMode = (darkMode: boolean) => {
|
||||||
|
this.view?.webContents.send(DARK_MODE_CHANGE, darkMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
isHidden = () => {
|
||||||
|
return this.state === LoadingScreenState.HIDDEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
show = () => {
|
||||||
|
const mainWindow = MainWindow.get();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.view) {
|
||||||
|
this.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = LoadingScreenState.VISIBLE;
|
||||||
|
|
||||||
|
if (this.view?.webContents.isLoading()) {
|
||||||
|
this.view.webContents.once('did-finish-load', () => {
|
||||||
|
this.view!.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.view!.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainWindow.getBrowserViews().includes(this.view!)) {
|
||||||
|
mainWindow.setTopBrowserView(this.view!);
|
||||||
|
} else {
|
||||||
|
mainWindow.addBrowserView(this.view!);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
fade = () => {
|
||||||
|
if (this.view && this.state === LoadingScreenState.VISIBLE) {
|
||||||
|
this.state = LoadingScreenState.FADING;
|
||||||
|
this.view.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private create = () => {
|
||||||
|
const preload = getLocalPreload('desktopAPI.js');
|
||||||
|
this.view = new BrowserView({webPreferences: {
|
||||||
|
preload,
|
||||||
|
|
||||||
|
// Workaround for this issue: https://github.com/electron/electron/issues/30993
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
transparent: true,
|
||||||
|
}});
|
||||||
|
const localURL = getLocalURLString('loadingScreen.html');
|
||||||
|
this.view.webContents.loadURL(localURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleAnimationFinished = () => {
|
||||||
|
log.debug('handleLoadingScreenAnimationFinished');
|
||||||
|
|
||||||
|
if (this.view && this.state !== LoadingScreenState.HIDDEN) {
|
||||||
|
this.state = LoadingScreenState.HIDDEN;
|
||||||
|
MainWindow.get()?.removeBrowserView(this.view);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'test') {
|
||||||
|
app.emit('e2e-app-loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingScreen = new LoadingScreen();
|
||||||
|
export default loadingScreen;
|
@@ -16,6 +16,7 @@ import MainWindow from 'main/windows/mainWindow';
|
|||||||
|
|
||||||
import {MattermostView} from './MattermostView';
|
import {MattermostView} from './MattermostView';
|
||||||
import {ViewManager} from './viewManager';
|
import {ViewManager} from './viewManager';
|
||||||
|
import LoadingScreen from './loadingScreen';
|
||||||
|
|
||||||
jest.mock('electron', () => ({
|
jest.mock('electron', () => ({
|
||||||
app: {
|
app: {
|
||||||
@@ -57,7 +58,10 @@ jest.mock('main/i18nManager', () => ({
|
|||||||
jest.mock('main/server/serverInfo', () => ({
|
jest.mock('main/server/serverInfo', () => ({
|
||||||
ServerInfo: jest.fn(),
|
ServerInfo: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('main/views/loadingScreen', () => ({
|
||||||
|
show: jest.fn(),
|
||||||
|
fade: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('main/windows/mainWindow', () => ({
|
jest.mock('main/windows/mainWindow', () => ({
|
||||||
get: jest.fn(),
|
get: jest.fn(),
|
||||||
}));
|
}));
|
||||||
@@ -78,7 +82,6 @@ describe('main/views/viewManager', () => {
|
|||||||
const destroyFn = jest.fn();
|
const destroyFn = jest.fn();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
viewManager.createLoadingScreen = jest.fn();
|
|
||||||
viewManager.showByName = jest.fn();
|
viewManager.showByName = jest.fn();
|
||||||
viewManager.getServerView = jest.fn().mockImplementation((srv, tabName) => ({name: `${srv.name}-${tabName}`}));
|
viewManager.getServerView = jest.fn().mockImplementation((srv, tabName) => ({name: `${srv.name}-${tabName}`}));
|
||||||
MattermostView.mockImplementation((tab) => ({
|
MattermostView.mockImplementation((tab) => ({
|
||||||
@@ -92,7 +95,6 @@ describe('main/views/viewManager', () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
viewManager.loadingScreen = undefined;
|
|
||||||
viewManager.closedViews = new Map();
|
viewManager.closedViews = new Map();
|
||||||
viewManager.views = new Map();
|
viewManager.views = new Map();
|
||||||
});
|
});
|
||||||
@@ -112,7 +114,6 @@ describe('main/views/viewManager', () => {
|
|||||||
it('should add view to views map and add listeners', () => {
|
it('should add view to views map and add listeners', () => {
|
||||||
viewManager.loadView({name: 'server1'}, {}, {name: 'tab1', isOpen: true}, 'http://server-1.com/subpath');
|
viewManager.loadView({name: 'server1'}, {}, {name: 'tab1', isOpen: true}, 'http://server-1.com/subpath');
|
||||||
expect(viewManager.views.has('server1-tab1')).toBe(true);
|
expect(viewManager.views.has('server1-tab1')).toBe(true);
|
||||||
expect(viewManager.createLoadingScreen).toHaveBeenCalled();
|
|
||||||
expect(onceFn).toHaveBeenCalledWith(LOAD_SUCCESS, viewManager.activateView);
|
expect(onceFn).toHaveBeenCalledWith(LOAD_SUCCESS, viewManager.activateView);
|
||||||
expect(loadFn).toHaveBeenCalledWith('http://server-1.com/subpath');
|
expect(loadFn).toHaveBeenCalledWith('http://server-1.com/subpath');
|
||||||
});
|
});
|
||||||
@@ -218,7 +219,6 @@ describe('main/views/viewManager', () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
delete viewManager.loadingScreen;
|
|
||||||
delete viewManager.currentView;
|
delete viewManager.currentView;
|
||||||
viewManager.closedViews = new Map();
|
viewManager.closedViews = new Map();
|
||||||
viewManager.views = new Map();
|
viewManager.views = new Map();
|
||||||
@@ -582,8 +582,6 @@ describe('main/views/viewManager', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
viewManager.getCurrentView = jest.fn();
|
viewManager.getCurrentView = jest.fn();
|
||||||
viewManager.showLoadingScreen = jest.fn();
|
|
||||||
viewManager.fadeLoadingScreen = jest.fn();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -641,7 +639,7 @@ describe('main/views/viewManager', () => {
|
|||||||
view.needsLoadingScreen.mockImplementation(() => true);
|
view.needsLoadingScreen.mockImplementation(() => true);
|
||||||
viewManager.views.set('view1', view);
|
viewManager.views.set('view1', view);
|
||||||
viewManager.showByName('view1');
|
viewManager.showByName('view1');
|
||||||
expect(viewManager.showLoadingScreen).toHaveBeenCalled();
|
expect(LoadingScreen.show).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the view when not errored', () => {
|
it('should show the view when not errored', () => {
|
||||||
@@ -655,44 +653,6 @@ describe('main/views/viewManager', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('showLoadingScreen', () => {
|
|
||||||
const window = {
|
|
||||||
getBrowserViews: jest.fn(),
|
|
||||||
setTopBrowserView: jest.fn(),
|
|
||||||
addBrowserView: jest.fn(),
|
|
||||||
};
|
|
||||||
const viewManager = new ViewManager();
|
|
||||||
const loadingScreen = {webContents: {send: jest.fn(), isLoading: () => false}};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
MainWindow.get.mockReturnValue(window);
|
|
||||||
viewManager.createLoadingScreen = jest.fn();
|
|
||||||
viewManager.setLoadingScreenBounds = jest.fn();
|
|
||||||
window.getBrowserViews.mockImplementation(() => []);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
delete viewManager.loadingScreen;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create new loading screen if one doesnt exist and add it to the window', () => {
|
|
||||||
viewManager.createLoadingScreen.mockImplementation(() => {
|
|
||||||
viewManager.loadingScreen = loadingScreen;
|
|
||||||
});
|
|
||||||
viewManager.showLoadingScreen();
|
|
||||||
expect(viewManager.createLoadingScreen).toHaveBeenCalled();
|
|
||||||
expect(window.addBrowserView).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set the browser view as top if already exists and needs to be shown', () => {
|
|
||||||
viewManager.loadingScreen = loadingScreen;
|
|
||||||
window.getBrowserViews.mockImplementation(() => [loadingScreen]);
|
|
||||||
viewManager.showLoadingScreen();
|
|
||||||
expect(window.setTopBrowserView).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getViewByURL', () => {
|
describe('getViewByURL', () => {
|
||||||
const viewManager = new ViewManager({});
|
const viewManager = new ViewManager({});
|
||||||
viewManager.getServers = () => [
|
viewManager.getServers = () => [
|
||||||
|
@@ -14,7 +14,6 @@ import {
|
|||||||
UPDATE_TARGET_URL,
|
UPDATE_TARGET_URL,
|
||||||
LOAD_SUCCESS,
|
LOAD_SUCCESS,
|
||||||
LOAD_FAILED,
|
LOAD_FAILED,
|
||||||
TOGGLE_LOADING_SCREEN_VISIBILITY,
|
|
||||||
LOADSCREEN_END,
|
LOADSCREEN_END,
|
||||||
SET_ACTIVE_VIEW,
|
SET_ACTIVE_VIEW,
|
||||||
OPEN_TAB,
|
OPEN_TAB,
|
||||||
@@ -22,7 +21,6 @@ import {
|
|||||||
UPDATE_LAST_ACTIVE,
|
UPDATE_LAST_ACTIVE,
|
||||||
UPDATE_URL_VIEW_WIDTH,
|
UPDATE_URL_VIEW_WIDTH,
|
||||||
MAIN_WINDOW_SHOWN,
|
MAIN_WINDOW_SHOWN,
|
||||||
DARK_MODE_CHANGE,
|
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import urlUtils, {equalUrlsIgnoringSubpath} from 'common/utils/url';
|
import urlUtils, {equalUrlsIgnoringSubpath} from 'common/utils/url';
|
||||||
@@ -37,21 +35,16 @@ import {localizeMessage} from 'main/i18nManager';
|
|||||||
import {ServerInfo} from 'main/server/serverInfo';
|
import {ServerInfo} from 'main/server/serverInfo';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
|
|
||||||
import {getLocalURLString, getLocalPreload, getWindowBoundaries} from '../utils';
|
import {getLocalURLString, getLocalPreload} from '../utils';
|
||||||
|
|
||||||
import {MattermostView} from './MattermostView';
|
import {MattermostView} from './MattermostView';
|
||||||
import modalManager from './modalManager';
|
import modalManager from './modalManager';
|
||||||
import WebContentsEventManager from './webContentEvents';
|
import WebContentsEventManager from './webContentEvents';
|
||||||
|
import LoadingScreen from './loadingScreen';
|
||||||
|
|
||||||
const URL_VIEW_DURATION = 10 * SECOND;
|
const URL_VIEW_DURATION = 10 * SECOND;
|
||||||
const URL_VIEW_HEIGHT = 20;
|
const URL_VIEW_HEIGHT = 20;
|
||||||
|
|
||||||
export enum LoadingScreenState {
|
|
||||||
VISIBLE = 1,
|
|
||||||
FADING = 2,
|
|
||||||
HIDDEN = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ViewManager {
|
export class ViewManager {
|
||||||
lastActiveServer?: number;
|
lastActiveServer?: number;
|
||||||
viewOptions: BrowserViewConstructorOptions;
|
viewOptions: BrowserViewConstructorOptions;
|
||||||
@@ -60,15 +53,12 @@ export class ViewManager {
|
|||||||
currentView?: string;
|
currentView?: string;
|
||||||
urlView?: BrowserView;
|
urlView?: BrowserView;
|
||||||
urlViewCancel?: () => void;
|
urlViewCancel?: () => void;
|
||||||
loadingScreen?: BrowserView;
|
|
||||||
loadingScreenState: LoadingScreenState;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.lastActiveServer = Config.lastActiveTeam;
|
this.lastActiveServer = Config.lastActiveTeam;
|
||||||
this.viewOptions = {webPreferences: {spellcheck: Config.useSpellChecker}};
|
this.viewOptions = {webPreferences: {spellcheck: Config.useSpellChecker}};
|
||||||
this.views = new Map(); // keep in mind that this doesn't need to hold server order, only tabs on the renderer need that.
|
this.views = new Map(); // keep in mind that this doesn't need to hold server order, only tabs on the renderer need that.
|
||||||
this.closedViews = new Map();
|
this.closedViews = new Map();
|
||||||
this.loadingScreenState = LoadingScreenState.HIDDEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getServers = () => {
|
getServers = () => {
|
||||||
@@ -97,9 +87,6 @@ export class ViewManager {
|
|||||||
if (this.closedViews.has(view.name)) {
|
if (this.closedViews.has(view.name)) {
|
||||||
this.closedViews.delete(view.name);
|
this.closedViews.delete(view.name);
|
||||||
}
|
}
|
||||||
if (!this.loadingScreen) {
|
|
||||||
this.createLoadingScreen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string) => {
|
loadView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string) => {
|
||||||
@@ -242,7 +229,7 @@ export class ViewManager {
|
|||||||
if (!newView.isErrored()) {
|
if (!newView.isErrored()) {
|
||||||
newView.show();
|
newView.show();
|
||||||
if (newView.needsLoadingScreen()) {
|
if (newView.needsLoadingScreen()) {
|
||||||
this.showLoadingScreen();
|
LoadingScreen.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.name, newView.tab.type);
|
MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.name, newView.tab.type);
|
||||||
@@ -290,7 +277,7 @@ export class ViewManager {
|
|||||||
const view = this.views.get(server);
|
const view = this.views.get(server);
|
||||||
if (view && this.getCurrentView() === view) {
|
if (view && this.getCurrentView() === view) {
|
||||||
this.showByName(this.currentView!);
|
this.showByName(this.currentView!);
|
||||||
this.fadeLoadingScreen();
|
LoadingScreen.fade();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +301,7 @@ export class ViewManager {
|
|||||||
failLoading = (tabName: string) => {
|
failLoading = (tabName: string) => {
|
||||||
log.debug('viewManager.failLoading', tabName);
|
log.debug('viewManager.failLoading', tabName);
|
||||||
|
|
||||||
this.fadeLoadingScreen();
|
LoadingScreen.fade();
|
||||||
if (this.currentView === tabName) {
|
if (this.currentView === tabName) {
|
||||||
this.getCurrentView()?.hide();
|
this.getCurrentView()?.hide();
|
||||||
}
|
}
|
||||||
@@ -417,87 +404,16 @@ export class ViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoadingScreenBounds = () => {
|
|
||||||
const mainWindow = MainWindow.get();
|
|
||||||
if (!mainWindow) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loadingScreen?.setBounds(getWindowBoundaries(mainWindow));
|
|
||||||
}
|
|
||||||
|
|
||||||
createLoadingScreen = () => {
|
|
||||||
const preload = getLocalPreload('desktopAPI.js');
|
|
||||||
this.loadingScreen = new BrowserView({webPreferences: {
|
|
||||||
preload,
|
|
||||||
|
|
||||||
// Workaround for this issue: https://github.com/electron/electron/issues/30993
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
transparent: true,
|
|
||||||
}});
|
|
||||||
const localURL = getLocalURLString('loadingScreen.html');
|
|
||||||
this.loadingScreen.webContents.loadURL(localURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
showLoadingScreen = () => {
|
|
||||||
const mainWindow = MainWindow.get();
|
|
||||||
if (!mainWindow) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.loadingScreen) {
|
|
||||||
this.createLoadingScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadingScreenState = LoadingScreenState.VISIBLE;
|
|
||||||
|
|
||||||
if (this.loadingScreen?.webContents.isLoading()) {
|
|
||||||
this.loadingScreen.webContents.once('did-finish-load', () => {
|
|
||||||
this.loadingScreen!.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, true);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.loadingScreen!.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainWindow.getBrowserViews().includes(this.loadingScreen!)) {
|
|
||||||
mainWindow.setTopBrowserView(this.loadingScreen!);
|
|
||||||
} else {
|
|
||||||
mainWindow.addBrowserView(this.loadingScreen!);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setLoadingScreenBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
fadeLoadingScreen = () => {
|
|
||||||
if (this.loadingScreen && this.loadingScreenState === LoadingScreenState.VISIBLE) {
|
|
||||||
this.loadingScreenState = LoadingScreenState.FADING;
|
|
||||||
this.loadingScreen.webContents.send(TOGGLE_LOADING_SCREEN_VISIBILITY, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hideLoadingScreen = () => {
|
|
||||||
if (this.loadingScreen && this.loadingScreenState !== LoadingScreenState.HIDDEN) {
|
|
||||||
this.loadingScreenState = LoadingScreenState.HIDDEN;
|
|
||||||
MainWindow.get()?.removeBrowserView(this.loadingScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setServerInitialized = (server: string) => {
|
setServerInitialized = (server: string) => {
|
||||||
const view = this.views.get(server);
|
const view = this.views.get(server);
|
||||||
if (view) {
|
if (view) {
|
||||||
view.setInitialized();
|
view.setInitialized();
|
||||||
if (this.getCurrentView() === view) {
|
if (this.getCurrentView() === view) {
|
||||||
this.fadeLoadingScreen();
|
LoadingScreen.fade();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLoadingScreenDarkMode = (darkMode: boolean) => {
|
|
||||||
if (this.loadingScreen) {
|
|
||||||
this.loadingScreen.webContents.send(DARK_MODE_CHANGE, darkMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deeplinkSuccess = (viewName: string) => {
|
deeplinkSuccess = (viewName: string) => {
|
||||||
log.debug('viewManager.deeplinkSuccess', viewName);
|
log.debug('viewManager.deeplinkSuccess', viewName);
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import {
|
|||||||
MINIMUM_CALLS_WIDGET_HEIGHT,
|
MINIMUM_CALLS_WIDGET_HEIGHT,
|
||||||
CALLS_PLUGIN_ID,
|
CALLS_PLUGIN_ID,
|
||||||
} from 'common/utils/constants';
|
} from 'common/utils/constants';
|
||||||
|
|
||||||
import WebContentsEventManager from '../views/webContentEvents';
|
import WebContentsEventManager from '../views/webContentEvents';
|
||||||
|
|
||||||
import CallsWidgetWindow from './callsWidgetWindow';
|
import CallsWidgetWindow from './callsWidgetWindow';
|
||||||
|
@@ -14,6 +14,7 @@ import * as Validator from 'common/Validator';
|
|||||||
|
|
||||||
import ContextMenu from '../contextMenu';
|
import ContextMenu from '../contextMenu';
|
||||||
import {isInsideRectangle} from '../utils';
|
import {isInsideRectangle} from '../utils';
|
||||||
|
|
||||||
import {MainWindow} from './mainWindow';
|
import {MainWindow} from './mainWindow';
|
||||||
|
|
||||||
jest.mock('path', () => ({
|
jest.mock('path', () => ({
|
||||||
|
@@ -15,6 +15,7 @@ import {
|
|||||||
resetScreensharePermissionsMacOS,
|
resetScreensharePermissionsMacOS,
|
||||||
openScreensharePermissionsSettingsMacOS,
|
openScreensharePermissionsSettingsMacOS,
|
||||||
} from 'main/utils';
|
} from 'main/utils';
|
||||||
|
import LoadingScreen from '../views/loadingScreen';
|
||||||
|
|
||||||
import {WindowManager} from './windowManager';
|
import {WindowManager} from './windowManager';
|
||||||
import MainWindow from './mainWindow';
|
import MainWindow from './mainWindow';
|
||||||
@@ -68,11 +69,12 @@ jest.mock('../utils', () => ({
|
|||||||
}));
|
}));
|
||||||
jest.mock('../views/viewManager', () => ({
|
jest.mock('../views/viewManager', () => ({
|
||||||
ViewManager: jest.fn(),
|
ViewManager: jest.fn(),
|
||||||
LoadingScreenState: {
|
|
||||||
HIDDEN: 3,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
jest.mock('../CriticalErrorHandler', () => jest.fn());
|
jest.mock('../CriticalErrorHandler', () => jest.fn());
|
||||||
|
jest.mock('../views/loadingScreen', () => ({
|
||||||
|
isHidden: jest.fn(),
|
||||||
|
setBounds: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('../views/teamDropdownView', () => jest.fn());
|
jest.mock('../views/teamDropdownView', () => jest.fn());
|
||||||
jest.mock('../views/downloadsDropdownView', () => jest.fn());
|
jest.mock('../views/downloadsDropdownView', () => jest.fn());
|
||||||
jest.mock('../views/downloadsDropdownMenuView', () => jest.fn());
|
jest.mock('../views/downloadsDropdownMenuView', () => jest.fn());
|
||||||
@@ -193,7 +195,7 @@ describe('main/windows/windowManager', () => {
|
|||||||
|
|
||||||
it('should update loading screen and team dropdown bounds', () => {
|
it('should update loading screen and team dropdown bounds', () => {
|
||||||
windowManager.handleResizeMainWindow();
|
windowManager.handleResizeMainWindow();
|
||||||
expect(windowManager.viewManager.setLoadingScreenBounds).toHaveBeenCalled();
|
expect(LoadingScreen.setBounds).toHaveBeenCalled();
|
||||||
expect(windowManager.teamDropdown.updateWindowBounds).toHaveBeenCalled();
|
expect(windowManager.teamDropdown.updateWindowBounds).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -254,12 +256,13 @@ describe('main/windows/windowManager', () => {
|
|||||||
it('should update loading screen and team dropdown bounds', () => {
|
it('should update loading screen and team dropdown bounds', () => {
|
||||||
const event = {preventDefault: jest.fn()};
|
const event = {preventDefault: jest.fn()};
|
||||||
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
||||||
expect(windowManager.viewManager.setLoadingScreenBounds).toHaveBeenCalled();
|
expect(LoadingScreen.setBounds).toHaveBeenCalled();
|
||||||
expect(windowManager.teamDropdown.updateWindowBounds).toHaveBeenCalled();
|
expect(windowManager.teamDropdown.updateWindowBounds).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not resize if the app is already resizing', () => {
|
it('should not resize if the app is already resizing', () => {
|
||||||
windowManager.isResizing = true;
|
windowManager.isResizing = true;
|
||||||
|
LoadingScreen.isHidden.mockReturnValue(true);
|
||||||
const event = {preventDefault: jest.fn()};
|
const event = {preventDefault: jest.fn()};
|
||||||
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
windowManager.handleWillResizeMainWindow(event, {width: 800, height: 600});
|
||||||
expect(view.setBounds).not.toHaveBeenCalled();
|
expect(view.setBounds).not.toHaveBeenCalled();
|
||||||
|
@@ -18,7 +18,6 @@ import {
|
|||||||
MAXIMIZE_CHANGE,
|
MAXIMIZE_CHANGE,
|
||||||
HISTORY,
|
HISTORY,
|
||||||
REACT_APP_INITIALIZED,
|
REACT_APP_INITIALIZED,
|
||||||
LOADING_SCREEN_ANIMATION_FINISHED,
|
|
||||||
FOCUS_THREE_DOT_MENU,
|
FOCUS_THREE_DOT_MENU,
|
||||||
GET_DARK_MODE,
|
GET_DARK_MODE,
|
||||||
UPDATE_SHORTCUT_MENU,
|
UPDATE_SHORTCUT_MENU,
|
||||||
@@ -45,6 +44,7 @@ import {SECOND} from 'common/utils/constants';
|
|||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {getTabViewName, TAB_MESSAGING} from 'common/tabs/TabView';
|
import {getTabViewName, TAB_MESSAGING} from 'common/tabs/TabView';
|
||||||
|
|
||||||
|
import downloadsManager from 'main/downloadsManager';
|
||||||
import {MattermostView} from 'main/views/MattermostView';
|
import {MattermostView} from 'main/views/MattermostView';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -54,14 +54,12 @@ import {
|
|||||||
openScreensharePermissionsSettingsMacOS,
|
openScreensharePermissionsSettingsMacOS,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
import {ViewManager, LoadingScreenState} from '../views/viewManager';
|
import {ViewManager} from '../views/viewManager';
|
||||||
|
import LoadingScreen from '../views/loadingScreen';
|
||||||
import TeamDropdownView from '../views/teamDropdownView';
|
import TeamDropdownView from '../views/teamDropdownView';
|
||||||
import DownloadsDropdownView from '../views/downloadsDropdownView';
|
import DownloadsDropdownView from '../views/downloadsDropdownView';
|
||||||
import DownloadsDropdownMenuView from '../views/downloadsDropdownMenuView';
|
import DownloadsDropdownMenuView from '../views/downloadsDropdownMenuView';
|
||||||
|
|
||||||
import downloadsManager from 'main/downloadsManager';
|
|
||||||
|
|
||||||
import MainWindow from './mainWindow';
|
import MainWindow from './mainWindow';
|
||||||
|
|
||||||
import CallsWidgetWindow from './callsWidgetWindow';
|
import CallsWidgetWindow from './callsWidgetWindow';
|
||||||
@@ -86,7 +84,6 @@ export class WindowManager {
|
|||||||
ipcMain.on(HISTORY, this.handleHistory);
|
ipcMain.on(HISTORY, this.handleHistory);
|
||||||
ipcMain.handle(GET_DARK_MODE, this.handleGetDarkMode);
|
ipcMain.handle(GET_DARK_MODE, this.handleGetDarkMode);
|
||||||
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
|
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
|
||||||
ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, this.handleLoadingScreenAnimationFinished);
|
|
||||||
ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush);
|
ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush);
|
||||||
ipcMain.on(BROWSER_HISTORY_BUTTON, this.handleBrowserHistoryButton);
|
ipcMain.on(BROWSER_HISTORY_BUTTON, this.handleBrowserHistoryButton);
|
||||||
ipcMain.on(APP_LOGGED_IN, this.handleAppLoggedIn);
|
ipcMain.on(APP_LOGGED_IN, this.handleAppLoggedIn);
|
||||||
@@ -270,14 +267,14 @@ export class WindowManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isResizing && this.viewManager.loadingScreenState === LoadingScreenState.HIDDEN && this.viewManager.getCurrentView()) {
|
if (this.isResizing && LoadingScreen.isHidden() && this.viewManager.getCurrentView()) {
|
||||||
log.debug('prevented resize');
|
log.debug('prevented resize');
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.throttledWillResize(newBounds);
|
this.throttledWillResize(newBounds);
|
||||||
this.viewManager?.setLoadingScreenBounds();
|
LoadingScreen.setBounds();
|
||||||
this.teamDropdown?.updateWindowBounds();
|
this.teamDropdown?.updateWindowBounds();
|
||||||
this.downloadsDropdown?.updateWindowBounds();
|
this.downloadsDropdown?.updateWindowBounds();
|
||||||
this.downloadsDropdownMenu?.updateWindowBounds();
|
this.downloadsDropdownMenu?.updateWindowBounds();
|
||||||
@@ -324,7 +321,8 @@ export class WindowManager {
|
|||||||
// Another workaround since the window doesn't update properly under Linux for some reason
|
// Another workaround since the window doesn't update properly under Linux for some reason
|
||||||
// See above comment
|
// See above comment
|
||||||
setTimeout(this.setCurrentViewBounds, 10, bounds);
|
setTimeout(this.setCurrentViewBounds, 10, bounds);
|
||||||
this.viewManager.setLoadingScreenBounds();
|
|
||||||
|
LoadingScreen.setBounds();
|
||||||
this.teamDropdown?.updateWindowBounds();
|
this.teamDropdown?.updateWindowBounds();
|
||||||
this.downloadsDropdown?.updateWindowBounds();
|
this.downloadsDropdown?.updateWindowBounds();
|
||||||
this.downloadsDropdownMenu?.updateWindowBounds();
|
this.downloadsDropdownMenu?.updateWindowBounds();
|
||||||
@@ -542,24 +540,6 @@ export class WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLoadingScreenAnimationFinished = () => {
|
|
||||||
log.debug('WindowManager.handleLoadingScreenAnimationFinished');
|
|
||||||
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.hideLoadingScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'test') {
|
|
||||||
app.emit('e2e-app-loaded');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateLoadingScreenDarkMode = (darkMode: boolean) => {
|
|
||||||
if (this.viewManager) {
|
|
||||||
this.viewManager.updateLoadingScreenDarkMode(darkMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getViewNameByWebContentsId = (webContentsId: number) => {
|
getViewNameByWebContentsId = (webContentsId: number) => {
|
||||||
const view = this.viewManager?.findViewByWebContent(webContentsId);
|
const view = this.viewManager?.findViewByWebContent(webContentsId);
|
||||||
return view?.name;
|
return view?.name;
|
||||||
@@ -599,7 +579,7 @@ export class WindowManager {
|
|||||||
reload = () => {
|
reload = () => {
|
||||||
const currentView = this.viewManager?.getCurrentView();
|
const currentView = this.viewManager?.getCurrentView();
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
this.viewManager?.showLoadingScreen();
|
LoadingScreen.show();
|
||||||
currentView.reload();
|
currentView.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user