-
Notifications
You must be signed in to change notification settings - Fork 374
feat: electron splash screen #4119
Changes from 8 commits
6aedf17
868c357
2bf3b80
fc348aa
40adc97
1eb7304
0157c88
1ae085f
4fb3248
7327e25
bd628a5
69d7cc0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 = ''; | ||
|
|
@@ -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); | ||
|
|
@@ -165,7 +168,9 @@ async function main() { | |
| } | ||
| await mainWindow.webContents.loadURL(getBaseUrl() + deeplinkUrl); | ||
|
|
||
| mainWindow.show(); | ||
| if (show) { | ||
| mainWindow.show(); | ||
| } | ||
|
|
||
| mainWindow.on('closed', () => { | ||
| ElectronWindow.destroy(); | ||
|
|
@@ -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...'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Messages like this should be localized, since the app menu was not localized, I assumed the effort is still going on, please feel free to let me know if things are in place for electron localization and how can I use it.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @beyackle can you comment?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we're not localizing anything in the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @beyackle sounds good, thanks
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a side note, the l10n script does look in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #4120 Here's the issue. I'll take on it myself. |
||
| 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. | ||
|
|
@@ -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); | ||
| } | ||
| }); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // 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: { | ||
| webSecurity: false, | ||
| }, | ||
| }); | ||
|
|
||
| const args = { | ||
| productName, | ||
| productFamily, | ||
| logo, | ||
| website, | ||
| color, | ||
| status, | ||
| }; | ||
|
|
||
| splashScreenWindow.on('ready-to-show', () => { | ||
| splashScreenWindow.show(); | ||
| }); | ||
|
|
||
| const file = 'data:text/html;charset=UTF-8,' + encodeURIComponent(getSplashScreenContent(args)); | ||
| await splashScreenWindow.loadURL(file); | ||
|
|
||
| const startApp = () => { | ||
| setTimeout(() => splashScreenWindow.destroy(), 500); | ||
hatpick marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| getMainWindow()?.show(); | ||
| }; | ||
|
|
||
| const updateStatus = async (status: string) => { | ||
| await splashScreenWindow.webContents.executeJavaScript( | ||
| `document.querySelector('#${statusElmId}').textContent = '${status}';` | ||
| ); | ||
| }; | ||
|
|
||
| return { startApp, updateStatus }; | ||
| }; | ||
| 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> | ||
| `; |
Uh oh!
There was an error while loading. Please reload this page.