Skip to content

Commit

Permalink
feat: electron splash screen (#4119)
Browse files Browse the repository at this point in the history
* splash screen

* Fix css

* Fixes logo

* Fix blank window

* Fixes mac

* fix splash screen flashing on linux

* Added comments

Co-authored-by: Soroush <sorgh@microsoft.com>
Co-authored-by: Chris Whitten <christopher.whitten@microsoft.com>
Co-authored-by: Geoff Cox (Microsoft) <gcox@microsoft.com>
  • Loading branch information
4 people committed Sep 15, 2020
1 parent f5c30f3 commit cf5544b
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
"asarUnpack": [
"build/assets",
"build/templates",
"resources/composerIcon_1024x1024.png"
"resources/composerIcon_1024x1024.png",
"resources/ms_logo.svg"
],
"files": [
"build",
"resources/composerIcon_1024x1024.png"
"resources/composerIcon_1024x1024.png",
"resources/ms_logo.svg"
],
"extraResources": [
{
Expand Down
39 changes: 39 additions & 0 deletions Composer/packages/electron-server/resources/ms_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 36 additions & 14 deletions Composer/packages/electron-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@

import { join, resolve } from 'path';

import { mkdirp } from 'fs-extra';
import { AppUpdaterSettings, UserSettings } from '@bfc/shared';
import { app, ipcMain } from 'electron';
import fixPath from 'fix-path';
import { UpdateInfo } from 'electron-updater';
import { AppUpdaterSettings, UserSettings } from '@bfc/shared';
import fixPath from 'fix-path';
import { mkdirp } from 'fs-extra';

import { initAppMenu } from './appMenu';
import { AppUpdater } from './appUpdater';
import { composerProtocol } from './constants';
import ElectronWindow from './electronWindow';
import { initSplashScreen } from './splash/splashScreen';
import { isDevelopment } from './utility/env';
import { isWindows, isMac } from './utility/platform';
import { getUnpackedAsarPath } from './utility/getUnpackedAsarPath';
import ElectronWindow from './electronWindow';
import log from './utility/logger';
import { AppUpdater } from './appUpdater';
import { parseDeepLinkUrl } from './utility/url';
import { composerProtocol } from './constants';
import { initAppMenu } from './appMenu';
import { getAccessToken, loginAndGetIdToken, OAuthLoginOptions } from './utility/oauthImplicitFlowHelper';
import { isMac, isWindows } from './utility/platform';
import { parseDeepLinkUrl } from './utility/url';

const microsoftLogoPath = join(__dirname, '../resources/ms_logo.svg');

const error = log.extend('error');
let deeplinkUrl = '';
Expand Down Expand Up @@ -150,7 +153,7 @@ async function loadServer() {
log(`Server started at port: ${serverPort}`);
}

async function main() {
async function main(show = false) {
log('Rendering application...');
const mainWindow = ElectronWindow.getInstance().browserWindow;
initAppMenu(mainWindow);
Expand All @@ -165,7 +168,9 @@ async function main() {
}
await mainWindow.webContents.loadURL(getBaseUrl() + deeplinkUrl);

mainWindow.show();
if (show) {
mainWindow.show();
}

mainWindow.on('closed', () => {
ElectronWindow.destroy();
Expand Down Expand Up @@ -200,13 +205,30 @@ async function run() {

app.on('ready', async () => {
log('App ready');
const getMainWindow = () => ElectronWindow.getInstance().browserWindow;
const { startApp, updateStatus } = await initSplashScreen({
getMainWindow,
color: 'rgb(0, 120, 212)',
logo: `file://${microsoftLogoPath}`,
productName: 'Bot Framework Composer',
productFamily: 'Microsoft Azure',
status: 'Initializing...',
website: 'www.botframework.com',
width: 500,
height: 300,
});

updateStatus('Starting server...');
await loadServer();
await main();

setTimeout(startApp, 500);

ipcMain.once('init-user-settings', (_ev, settings: UserSettings) => {
// we can't synchronously call the main process (due to deadlocks)
// so we wait for the initial settings to be loaded from the client
initializeAppUpdater(settings.appUpdater);
});
await loadServer();
await main();
});

// Quit when all windows are closed.
Expand All @@ -222,7 +244,7 @@ async function run() {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (!ElectronWindow.isBrowserWindowCreated) {
main();
main(true);
}
});

Expand Down
92 changes: 92 additions & 0 deletions Composer/packages/electron-server/src/splash/splashScreen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { BrowserWindow, systemPreferences } from 'electron';

import { getSplashScreenContent, statusElmId } from './template';

export type SplashScreenProps = {
getMainWindow: () => BrowserWindow | undefined;
color?: string;
icon?: string;
width?: number;
height?: number;
productName?: string;
productFamily?: string;
logo?: string;
website?: string;
status?: string;
};

export const initSplashScreen = async ({
getMainWindow,
color: initColor,
icon,
width = 600,
height = 400,
productName,
productFamily,
logo,
website,
status,
}: SplashScreenProps) => {
// If no color is provided, uses OS accent color
const color = initColor || (systemPreferences.getAccentColor && `#${systemPreferences.getAccentColor()}`);

const splashScreenWindow = new BrowserWindow({
parent: getMainWindow(),
show: false,
width,
height,
modal: true,
transparent: true,
skipTaskbar: true,
frame: false,
autoHideMenuBar: true,
alwaysOnTop: true,
resizable: false,
movable: false,
icon,
webPreferences: {
// This is necessary to enable loading local images in the url protocol (window.loadURL)
webSecurity: false,
},
});

const args = {
productName,
productFamily,
logo,
website,
color,
status,
};

// This prevents window visual flash
splashScreenWindow.on('ready-to-show', () => {
splashScreenWindow.show();
});

const file = 'data:text/html;charset=UTF-8,' + encodeURIComponent(getSplashScreenContent(args));
await splashScreenWindow.loadURL(file);

/**
* Displays the main windows of the app and destroys the splash screen.
*/
const startApp = () => {
setTimeout(() => splashScreenWindow.destroy(), 500);
getMainWindow()?.show();
};

/**
* Updates the loading status on the splash screen.
* @param status New status text.
*/
const updateStatus = async (status: string) => {
await splashScreenWindow.webContents.executeJavaScript(
`document.querySelector('#${statusElmId}').textContent = '${status}';`
);
};

return { startApp, updateStatus };
};
91 changes: 91 additions & 0 deletions Composer/packages/electron-server/src/splash/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export const statusElmId = 'status-txt';

export const getSplashScreenContent = ({
logo = '',
productName = 'Product',
productFamily = 'Product Family',
text = 'Loading ...',
website = 'www.website.com',
color = '#666',
}) => `
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
html,
body
{
margin: 0;
overflow: hidden;
}
#box {
position: absolute;
user-select: none;
width: 100%;
height: 100%;
overflow: hidden;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column
}
#logo {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
}
#logo img {
height: 60px
}
#box .text {
color: white;
font-weight: 400;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#box h1 {
color: white;
font-size: 36px;
}
#box h2 {
color: white;
font-size: 18px;
}
#box h4 {
font-size: 12px;
font-weight: 400;
opacity: 50%;
}
#${statusElmId} {
position: absolute;
left: 20px;
bottom: 16px;
}
#website-url {
position: absolute;
right: 20px;
bottom: 16px;
}
</style>
</head>
<body style="background-color:${color}">
<div id="box" style="background-color:${color}">
<span id="logo">
<img id="logo-img" src="${logo}" />
</span>
<h1 id="product" class="text">${productName}</h1>
${productFamily ? `<h2 id="product-family" class="text">${productFamily}</h2>` : ''}
<h4 class="text" id="${statusElmId}">${text}</h4>
<h4 class="text" id="website-url">${website}</h4>
</div>
</body>
</html>
`;

0 comments on commit cf5544b

Please sign in to comment.