mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-27 17:31:36 -06:00
SDA-4049 Taking screenshot - hiding fullscreen window (#1690)
This commit is contained in:
parent
20f0d92152
commit
3fbe9a9e63
2
package-lock.json
generated
2
package-lock.json
generated
@ -36499,4 +36499,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import {
|
||||
clipboard,
|
||||
dialog,
|
||||
ipcMain,
|
||||
NativeImage,
|
||||
nativeImage,
|
||||
WebContents,
|
||||
} from 'electron';
|
||||
@ -161,6 +162,7 @@ class ScreenSnippet {
|
||||
await this.execCmd(this.captureUtil, this.captureUtilArgs);
|
||||
|
||||
if (windowHandler.isMana) {
|
||||
winStore.restoreWindows(hideOnCapture);
|
||||
logger.info(
|
||||
'screen-snippet-handler: Attempting to extract image dimensions from: ' +
|
||||
this.outputFilePath,
|
||||
@ -177,7 +179,6 @@ class ScreenSnippet {
|
||||
|
||||
if (dimensions.width === 0 && dimensions.height === 0) {
|
||||
logger.info('screen-snippet-handler: no screen capture picture');
|
||||
winStore.restoreWindowsOnCapturing(hideOnCapture);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -356,7 +357,7 @@ class ScreenSnippet {
|
||||
'screen-snippet-handler: Snippet uploaded correctly, sending payload to SFE',
|
||||
);
|
||||
webContents.send('screen-snippet-data', payload);
|
||||
winStore.focusWindowsSnippingFinished(hideOnCapture);
|
||||
winStore.restoreWindows(hideOnCapture);
|
||||
await this.verifyAndUpdateAlwaysOnTop();
|
||||
} catch (error) {
|
||||
await this.verifyAndUpdateAlwaysOnTop();
|
||||
@ -432,6 +433,9 @@ class ScreenSnippet {
|
||||
clipboard: string;
|
||||
},
|
||||
) => {
|
||||
if (isMac) {
|
||||
windowHandler.closeSnippingToolWindow();
|
||||
}
|
||||
const filePath = path.join(
|
||||
app.getPath('downloads'),
|
||||
'symphonyImage-' + Date.now() + '.png',
|
||||
@ -439,46 +443,11 @@ class ScreenSnippet {
|
||||
const [, data] = saveAsData.clipboard.split(',');
|
||||
const buffer = Buffer.from(data, 'base64');
|
||||
const img = nativeImage.createFromBuffer(buffer);
|
||||
|
||||
const dialogResult = await dialog
|
||||
.showSaveDialog(BrowserWindow.getFocusedWindow() as BrowserWindow, {
|
||||
title: 'Select place to store your file',
|
||||
defaultPath: filePath,
|
||||
// defaultPath: path.join(__dirname, '../assets/'),
|
||||
buttonLabel: 'Save',
|
||||
// Restricting the user to only Text Files.
|
||||
filters: [
|
||||
{
|
||||
name: 'Image file',
|
||||
extensions: ['png'],
|
||||
},
|
||||
],
|
||||
properties: [],
|
||||
})
|
||||
.then((file) => {
|
||||
// Stating whether dialog operation was cancelled or not.
|
||||
if (!file.canceled && file.filePath) {
|
||||
// Creating and Writing to the sample.txt file
|
||||
fs.writeFile(file.filePath.toString(), img.toPNG(), (err) => {
|
||||
if (err) {
|
||||
throw logger.error(
|
||||
`screen-snippet-handler: cannot save file, failed with error: ${err}!`,
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(`screen-snippet-handler: modal save opened!`);
|
||||
});
|
||||
}
|
||||
|
||||
return file;
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(
|
||||
`screen-snippet-handler: cannot save file, failed with error: ${err}!`,
|
||||
);
|
||||
|
||||
return undefined;
|
||||
});
|
||||
const dialogResult = await this.saveFile(
|
||||
filePath,
|
||||
img,
|
||||
BrowserWindow.getFocusedWindow(),
|
||||
);
|
||||
if (dialogResult?.filePath) {
|
||||
windowHandler.closeSnippingToolWindow();
|
||||
}
|
||||
@ -496,7 +465,6 @@ class ScreenSnippet {
|
||||
const windowObj = winStore.getWindowStore();
|
||||
const currentWindowName = (currentWindowObj as ICustomBrowserWindow)
|
||||
?.winName;
|
||||
|
||||
if (windowObj.windows.length < 1) {
|
||||
const allWindows = BrowserWindow.getAllWindows();
|
||||
let windowsArr: IWindowState[] = [];
|
||||
@ -531,12 +499,67 @@ class ScreenSnippet {
|
||||
} else {
|
||||
windowsArr = windowsArr.concat(mainArr);
|
||||
}
|
||||
|
||||
winStore.setWindowStore({
|
||||
windows: windowsArr,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Save image in a given location
|
||||
* @param filePath where the image should be stored
|
||||
* @param img the image
|
||||
* @param parent parent window to attach save dialog
|
||||
*/
|
||||
private saveFile = (
|
||||
filePath: string,
|
||||
img: NativeImage,
|
||||
parentWindow: BrowserWindow | null,
|
||||
) => {
|
||||
const saveOptions = {
|
||||
title: 'Select place to store your file',
|
||||
defaultPath: filePath,
|
||||
// defaultPath: path.join(__dirname, '../assets/'),
|
||||
buttonLabel: 'Save',
|
||||
// Restricting the user to only Text Files.
|
||||
filters: [
|
||||
{
|
||||
name: 'Image file',
|
||||
extensions: ['png'],
|
||||
},
|
||||
],
|
||||
properties: [],
|
||||
};
|
||||
const saveDialog =
|
||||
!isMac && parentWindow
|
||||
? dialog.showSaveDialog(parentWindow, saveOptions)
|
||||
: dialog.showSaveDialog(saveOptions);
|
||||
return saveDialog
|
||||
.then((file) => {
|
||||
// Stating whether dialog operation was cancelled or not.
|
||||
if (!file.canceled && file.filePath) {
|
||||
// Creating and Writing to the sample.txt file
|
||||
fs.writeFile(file.filePath.toString(), img.toPNG(), (err) => {
|
||||
if (err) {
|
||||
throw logger.error(
|
||||
`screen-snippet-handler: cannot save file, failed with error: ${err}!`,
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(`screen-snippet-handler: modal save opened!`);
|
||||
});
|
||||
}
|
||||
|
||||
return file;
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(
|
||||
`screen-snippet-handler: cannot save file, failed with error: ${err}!`,
|
||||
);
|
||||
|
||||
return undefined;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const screenSnippet = new ScreenSnippet();
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { isMac, isWindowsOS } from '../../common/env';
|
||||
import { ICustomBrowserWindow, windowHandler } from '../window-handler';
|
||||
import { getWindowByName } from '../window-utils';
|
||||
|
||||
export interface IWindowObject {
|
||||
@ -9,9 +11,11 @@ export interface IWindowState {
|
||||
id: string;
|
||||
minimized?: boolean;
|
||||
focused?: boolean;
|
||||
isFullScreen?: boolean;
|
||||
}
|
||||
|
||||
export class WindowStore {
|
||||
public windowsRestored: boolean = true;
|
||||
private windowVariable: IWindowObject = {
|
||||
windows: [],
|
||||
};
|
||||
@ -35,47 +39,112 @@ export class WindowStore {
|
||||
|
||||
public hideWindowsOnCapturing = (hideOnCapture?: boolean) => {
|
||||
if (hideOnCapture) {
|
||||
this.windowsRestored = false;
|
||||
const currentWindows = BrowserWindow.getAllWindows();
|
||||
|
||||
currentWindows.forEach((currentWindow) => {
|
||||
currentWindow?.hide();
|
||||
const isFullScreen = currentWindow.isFullScreen();
|
||||
if (isFullScreen) {
|
||||
this.hideFullscreenWindow(currentWindow);
|
||||
} else {
|
||||
currentWindow?.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
public focusWindowsSnippingFinished = (hideOnCapture?: boolean) => {
|
||||
public restoreWindows = (hideOnCapture?: boolean) => {
|
||||
if (hideOnCapture) {
|
||||
const currentWindows = this.getWindowStore();
|
||||
const currentWindow = currentWindows.windows.find(
|
||||
const storedWindows = this.getWindowStore();
|
||||
let currentWindow = storedWindows.windows.find(
|
||||
(currentWindow) => currentWindow.focused,
|
||||
);
|
||||
|
||||
if (currentWindow) {
|
||||
if (!currentWindow.minimized) {
|
||||
getWindowByName(currentWindow.id || '')?.show();
|
||||
}
|
||||
|
||||
if (currentWindow.focused) {
|
||||
getWindowByName(currentWindow.id || '')?.focus();
|
||||
}
|
||||
if (!currentWindow) {
|
||||
// In case there is no window focused, we automatically focus on the main one.
|
||||
currentWindow = storedWindows.windows.find(
|
||||
(currentWindow) => currentWindow.id === 'main',
|
||||
);
|
||||
currentWindow!.focused = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public restoreWindowsOnCapturing = (hideOnCapture?: boolean) => {
|
||||
if (hideOnCapture) {
|
||||
const currentWindows = this.getWindowStore();
|
||||
currentWindows.windows.forEach((currentWindow) => {
|
||||
if (!currentWindow.minimized) {
|
||||
getWindowByName(currentWindow.id || '')?.show();
|
||||
}
|
||||
let focusedWindowToRestore: ICustomBrowserWindow | undefined;
|
||||
|
||||
if (currentWindow.focused) {
|
||||
getWindowByName(currentWindow.id || '')?.focus();
|
||||
const fullscreenedWindows: IWindowState[] = [];
|
||||
// Restoring all windows except focused one
|
||||
storedWindows.windows.forEach((currentWindow) => {
|
||||
if (currentWindow) {
|
||||
const window: ICustomBrowserWindow | undefined = getWindowByName(
|
||||
currentWindow.id || '',
|
||||
) as ICustomBrowserWindow;
|
||||
if (window) {
|
||||
if (currentWindow.isFullScreen) {
|
||||
fullscreenedWindows.push(currentWindow);
|
||||
// Window should be shown before putting it in fullscreen on Windows
|
||||
if (isWindowsOS) {
|
||||
window.show();
|
||||
}
|
||||
} else if (!currentWindow.minimized && !currentWindow.focused) {
|
||||
window.showInactive();
|
||||
}
|
||||
if (currentWindow.focused) {
|
||||
focusedWindowToRestore = window;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// First item in array should be the focused window
|
||||
fullscreenedWindows.sort((x: IWindowState, y: IWindowState) =>
|
||||
x.focused === y.focused ? 0 : x.focused ? -1 : 1,
|
||||
);
|
||||
this.putWindowInFullScreenAndFocus(
|
||||
fullscreenedWindows,
|
||||
focusedWindowToRestore,
|
||||
);
|
||||
|
||||
// Store reset
|
||||
this.destroyWindowStore();
|
||||
}
|
||||
};
|
||||
|
||||
private hideFullscreenWindow = (window: BrowserWindow) => {
|
||||
window.once('leave-full-screen', () => {
|
||||
if (isMac) {
|
||||
window.hide();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
window.hide();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
window.setFullScreen(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Restores windows that are in fullscreen and focus on the right window
|
||||
* On macOS, windows in fullscreen need to be restore one by one
|
||||
* @param windowsNames
|
||||
*/
|
||||
private putWindowInFullScreenAndFocus(
|
||||
windows: IWindowState[],
|
||||
windowToFocus?: BrowserWindow,
|
||||
) {
|
||||
if (windows.length) {
|
||||
const windowDetails = windows[windows.length - 1];
|
||||
const window: ICustomBrowserWindow | undefined = getWindowByName(
|
||||
windowDetails.id || '',
|
||||
) as ICustomBrowserWindow;
|
||||
window.once('enter-full-screen', () => {
|
||||
windows.pop();
|
||||
this.putWindowInFullScreenAndFocus(windows, windowToFocus);
|
||||
});
|
||||
window.setFullScreen(true);
|
||||
} else {
|
||||
if (windowToFocus) {
|
||||
windowToFocus?.show();
|
||||
windowHandler.moveSnippingToolWindow(windowToFocus);
|
||||
}
|
||||
this.windowsRestored = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1057,11 +1057,18 @@ export class WindowHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Move window to the same screen as main window
|
||||
* Move window to the same screen as main window or provided parent window
|
||||
*/
|
||||
public moveWindow(windowToMove: BrowserWindow, fixedYPosition?: number) {
|
||||
public moveWindow(
|
||||
windowToMove: BrowserWindow,
|
||||
fixedYPosition?: number,
|
||||
parentWindow?: BrowserWindow,
|
||||
) {
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
const display = screen.getDisplayMatching(this.mainWindow.getBounds());
|
||||
let display = screen.getDisplayMatching(this.mainWindow.getBounds());
|
||||
if (parentWindow && windowExists(parentWindow)) {
|
||||
display = screen.getDisplayMatching(parentWindow.getBounds());
|
||||
}
|
||||
|
||||
logger.info(
|
||||
'window-handler: moveWindow, display: ' +
|
||||
@ -1238,7 +1245,7 @@ export class WindowHandler {
|
||||
this.hideOnCapture = !!hideOnCapture;
|
||||
|
||||
logger.info(
|
||||
'window-handler, createSnippingToolWindow: Receiving snippet props: ' +
|
||||
'window-handler: createSnippingToolWindow: Receiving snippet props: ' +
|
||||
JSON.stringify({
|
||||
snipImage,
|
||||
snipDimensions,
|
||||
@ -1247,7 +1254,7 @@ export class WindowHandler {
|
||||
|
||||
const allDisplays = screen.getAllDisplays();
|
||||
logger.info(
|
||||
'window-handler, createSnippingToolWindow: User has these displays: ' +
|
||||
'window-handler: createSnippingToolWindow: User has these displays: ' +
|
||||
JSON.stringify(allDisplays),
|
||||
);
|
||||
|
||||
@ -1263,7 +1270,10 @@ export class WindowHandler {
|
||||
const BUTTON_BAR_BOTTOM_HEIGHT = 72;
|
||||
const BUTTON_BARS_HEIGHT = BUTTON_BAR_TOP_HEIGHT + BUTTON_BAR_BOTTOM_HEIGHT;
|
||||
|
||||
const display = screen.getDisplayMatching(this.mainWindow.getBounds());
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
const display = screen.getDisplayMatching(
|
||||
focusedWindow ? focusedWindow.getBounds() : this.mainWindow.getBounds(),
|
||||
);
|
||||
const workAreaSize = display.workAreaSize;
|
||||
// Snipping tool height shouldn't be greater than min of screen width and height (screen orientation can be portrait or landscape)
|
||||
const minSize = Math.min(workAreaSize.width, workAreaSize.height);
|
||||
@ -1277,7 +1287,7 @@ export class WindowHandler {
|
||||
width: Math.floor(snipDimensions.width / scaleFactor),
|
||||
};
|
||||
logger.info(
|
||||
'window-handler, createSnippingToolWindow: Image will open with scaled dimensions: ' +
|
||||
'window-handler: createSnippingToolWindow: Image will open with scaled dimensions: ' +
|
||||
JSON.stringify(scaledImageDimensions),
|
||||
);
|
||||
|
||||
@ -1314,12 +1324,12 @@ export class WindowHandler {
|
||||
}
|
||||
|
||||
this.currentWindow = currentWindow || '';
|
||||
const parentWindow = getWindowByName(this.currentWindow);
|
||||
const opts: ICustomBrowserWindowConstructorOpts = this.getWindowOpts(
|
||||
{
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
parent: getWindowByName(this.currentWindow),
|
||||
modal: true,
|
||||
modal: isWindowsOS,
|
||||
alwaysOnTop: this.hideOnCapture,
|
||||
resizable: false,
|
||||
fullscreenable: false,
|
||||
@ -1337,8 +1347,16 @@ export class WindowHandler {
|
||||
opts.alwaysOnTop = true;
|
||||
}
|
||||
|
||||
const areWindowsRestoredPostHide =
|
||||
(winStore.windowsRestored && this.hideOnCapture) || !this.hideOnCapture;
|
||||
|
||||
if (isWindowsOS || (isMac && areWindowsRestoredPostHide)) {
|
||||
opts.parent = parentWindow;
|
||||
opts.modal = true;
|
||||
}
|
||||
|
||||
this.snippingToolWindow = createComponentWindow('snipping-tool', opts);
|
||||
this.moveWindow(this.snippingToolWindow);
|
||||
this.moveWindow(this.snippingToolWindow, undefined, parentWindow);
|
||||
this.snippingToolWindow.setVisibleOnAllWorkspaces(true);
|
||||
|
||||
this.snippingToolWindow.webContents.once('did-finish-load', async () => {
|
||||
@ -1391,12 +1409,11 @@ export class WindowHandler {
|
||||
'snipping-tool-data',
|
||||
snippingToolInfo,
|
||||
);
|
||||
winStore.restoreWindowsOnCapturing(this.hideOnCapture);
|
||||
}
|
||||
});
|
||||
this.snippingToolWindow.once('close', () => {
|
||||
logger.info(
|
||||
'window-handler, createSnippingToolWindow: Closing snipping window, attempting to delete temp snip image',
|
||||
'window-handler: createSnippingToolWindow: Closing snipping window, attempting to delete temp snip image',
|
||||
);
|
||||
ipcMain.removeAllListeners(ScreenShotAnnotation.COPY_TO_CLIPBOARD);
|
||||
ipcMain.removeAllListeners(ScreenShotAnnotation.SAVE_AS);
|
||||
@ -1404,7 +1421,6 @@ export class WindowHandler {
|
||||
this.deleteFile(snipImage);
|
||||
this.removeWindow(opts.winKey);
|
||||
this.screenPickerWindow = null;
|
||||
winStore.focusWindowsSnippingFinished(this.hideOnCapture);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2215,6 +2231,18 @@ export class WindowHandler {
|
||||
exportLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves snipping tool to the right place after restoring all hidden windows
|
||||
* @param focusedWindow Focused window where snipping tool window should be moved
|
||||
*/
|
||||
public moveSnippingToolWindow(focusedWindow: BrowserWindow): void {
|
||||
if (this.snippingToolWindow && !this.snippingToolWindow.isDestroyed()) {
|
||||
this.snippingToolWindow.setAlwaysOnTop(true);
|
||||
this.snippingToolWindow.setParentWindow(focusedWindow);
|
||||
this.moveWindow(this.snippingToolWindow, undefined, focusedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for app load timeouts and reloads if required
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user