208 lines
5.5 KiB
TypeScript
208 lines
5.5 KiB
TypeScript
import { BrowserWindow, app, shell } from 'electron'
|
|
import { quickAskWindowConfig } from './quickAskWindowConfig'
|
|
import { mainWindowConfig } from './mainWindowConfig'
|
|
import { getAppConfigurations, AppEvent } from '@janhq/core/node'
|
|
import { getBounds, saveBounds } from '../utils/setup'
|
|
|
|
/**
|
|
* Manages the current window instance.
|
|
*/
|
|
// TODO: refactor this
|
|
let isAppQuitting = false
|
|
|
|
class WindowManager {
|
|
public mainWindow?: BrowserWindow
|
|
private _quickAskWindow: BrowserWindow | undefined = undefined
|
|
private _quickAskWindowVisible = false
|
|
private _mainWindowVisible = false
|
|
|
|
private deeplink: string | undefined
|
|
/**
|
|
* Creates a new window instance.
|
|
* @returns The created window instance.
|
|
*/
|
|
async createMainWindow(preloadPath: string, startUrl: string) {
|
|
const bounds = await getBounds()
|
|
|
|
this.mainWindow = new BrowserWindow({
|
|
...mainWindowConfig,
|
|
width: bounds.width,
|
|
height: bounds.height,
|
|
show: false,
|
|
x: bounds.x,
|
|
y: bounds.y,
|
|
webPreferences: {
|
|
nodeIntegration: true,
|
|
preload: preloadPath,
|
|
webSecurity: false,
|
|
},
|
|
})
|
|
|
|
if (process.platform === 'win32' || process.platform === 'linux') {
|
|
/// This is work around for windows deeplink.
|
|
/// second-instance event is not fired when app is not open, so the app
|
|
/// does not received the deeplink.
|
|
const commandLine = process.argv.slice(1)
|
|
if (commandLine.length > 0) {
|
|
const url = commandLine[0]
|
|
this.sendMainAppDeepLink(url)
|
|
}
|
|
}
|
|
|
|
this.mainWindow.on('resized', () => {
|
|
saveBounds(this.mainWindow?.getBounds())
|
|
})
|
|
|
|
this.mainWindow.on('moved', () => {
|
|
saveBounds(this.mainWindow?.getBounds())
|
|
})
|
|
|
|
/* Load frontend app to the window */
|
|
this.mainWindow.loadURL(startUrl)
|
|
|
|
/* Open external links in the default browser */
|
|
this.mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
shell.openExternal(url)
|
|
return { action: 'deny' }
|
|
})
|
|
|
|
app.on('before-quit', function () {
|
|
isAppQuitting = true
|
|
})
|
|
|
|
windowManager.mainWindow?.on('close', function (evt) {
|
|
// Feature Toggle for Quick Ask
|
|
if (!getAppConfigurations().quick_ask) return
|
|
|
|
if (!isAppQuitting) {
|
|
evt.preventDefault()
|
|
windowManager.hideMainWindow()
|
|
}
|
|
})
|
|
|
|
windowManager.mainWindow?.on('ready-to-show', function () {
|
|
// Feature Toggle for Quick Ask
|
|
windowManager.mainWindow?.show()
|
|
})
|
|
}
|
|
|
|
createQuickAskWindow(preloadPath: string, startUrl: string): void {
|
|
this._quickAskWindow = new BrowserWindow({
|
|
...quickAskWindowConfig,
|
|
webPreferences: {
|
|
nodeIntegration: true,
|
|
preload: preloadPath,
|
|
webSecurity: false,
|
|
},
|
|
})
|
|
|
|
this._quickAskWindow.loadURL(startUrl)
|
|
this._quickAskWindow.on('blur', () => {
|
|
this.hideQuickAskWindow()
|
|
})
|
|
}
|
|
|
|
isMainWindowVisible(): boolean {
|
|
return this._mainWindowVisible
|
|
}
|
|
|
|
hideMainWindow(): void {
|
|
this.mainWindow?.hide()
|
|
this._mainWindowVisible = false
|
|
}
|
|
|
|
showMainWindow(): void {
|
|
this.mainWindow?.show()
|
|
this._mainWindowVisible = true
|
|
}
|
|
|
|
hideQuickAskWindow(): void {
|
|
this._quickAskWindow?.hide()
|
|
this._quickAskWindowVisible = false
|
|
}
|
|
|
|
showQuickAskWindow(): void {
|
|
this._quickAskWindow?.show()
|
|
this._quickAskWindowVisible = true
|
|
}
|
|
|
|
closeQuickAskWindow(): void {
|
|
if (this._quickAskWindow?.isDestroyed()) return
|
|
this._quickAskWindow?.close()
|
|
this._quickAskWindow?.destroy()
|
|
this._quickAskWindow = undefined
|
|
this._quickAskWindowVisible = false
|
|
}
|
|
|
|
isQuickAskWindowVisible(): boolean {
|
|
return this._quickAskWindowVisible
|
|
}
|
|
|
|
isQuickAskWindowDestroyed(): boolean {
|
|
return this._quickAskWindow?.isDestroyed() ?? true
|
|
}
|
|
|
|
expandQuickAskWindow(heightOffset: number): void {
|
|
const width = quickAskWindowConfig.width!
|
|
const height = quickAskWindowConfig.height! + heightOffset
|
|
this._quickAskWindow?.setMinimumSize(width, height)
|
|
this._quickAskWindow?.setSize(width, height, true)
|
|
}
|
|
|
|
sendQuickAskSelectedText(selectedText: string): void {
|
|
this._quickAskWindow?.webContents.send(
|
|
AppEvent.onSelectedText,
|
|
selectedText
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Try to send the deep link to the main app.
|
|
*/
|
|
sendMainAppDeepLink(url: string): void {
|
|
this.deeplink = url
|
|
const interval = setInterval(() => {
|
|
if (!this.deeplink) clearInterval(interval)
|
|
const mainWindow = this.mainWindow
|
|
if (mainWindow) {
|
|
mainWindow.webContents.send(AppEvent.onDeepLink, this.deeplink)
|
|
if (mainWindow.isMinimized()) mainWindow.restore()
|
|
mainWindow.focus()
|
|
}
|
|
}, 500)
|
|
}
|
|
|
|
/**
|
|
* Send main view state to the main app.
|
|
*/
|
|
sendMainViewState(route: string) {
|
|
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
|
|
this.mainWindow.webContents.send(AppEvent.onMainViewStateChange, route)
|
|
}
|
|
}
|
|
|
|
cleanUp(): void {
|
|
if (!this.mainWindow?.isDestroyed()) {
|
|
this.mainWindow?.close()
|
|
this.mainWindow?.destroy()
|
|
this.mainWindow = undefined
|
|
this._mainWindowVisible = false
|
|
}
|
|
if (!this._quickAskWindow?.isDestroyed()) {
|
|
this._quickAskWindow?.close()
|
|
this._quickAskWindow?.destroy()
|
|
this._quickAskWindow = undefined
|
|
this._quickAskWindowVisible = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Acknowledges that the window has received a deep link. We can remove it.
|
|
*/
|
|
ackDeepLink() {
|
|
this.deeplink = undefined
|
|
}
|
|
}
|
|
|
|
export const windowManager = new WindowManager()
|