-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
2,805 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/renderer/.next/ | ||
/renderer/out/ | ||
|
||
# production | ||
/main | ||
/dist | ||
|
||
.idea/ | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
db.sqlite* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"private": true, | ||
"main": "main/index.js", | ||
"productName": "huntly", | ||
"scripts": { | ||
"clean": "rimraf dist main", | ||
"dev": "npm run build-electron && electron .", | ||
"build-electron": "tsc -p src", | ||
"build": "npm run build-electron", | ||
"pack-app": "npm run build && electron-builder --dir", | ||
"dist": "npm run build && electron-builder", | ||
"type-check": "tsc -p src/tsconfig.json", | ||
"lint": "eslint ." | ||
}, | ||
"dependencies": { | ||
"app-root-path": "^3.1.0", | ||
"electron-is-dev": "^1.2.0", | ||
"electron-window-state": "^5.0.3" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^17.0.40", | ||
"@typescript-eslint/eslint-plugin": "^5.27.1", | ||
"@typescript-eslint/parser": "^5.27.1", | ||
"electron": "^19.0.3", | ||
"electron-builder": "^23.0.3", | ||
"eslint": "^8.17.0", | ||
"rimraf": "^3.0.0", | ||
"typescript": "^4.7.3" | ||
}, | ||
"build": { | ||
"asar": true, | ||
"files": [ | ||
"main" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { ipcMain, shell, dialog, app, session, clipboard } from "electron" | ||
import { WindowManager } from "./window" | ||
|
||
export function setIpcMainEventHandler(manager: WindowManager) { | ||
async function openExternal(url: string, background = false) { | ||
if (url.startsWith("https://") || url.startsWith("http://")) { | ||
if (background && process.platform === "darwin") { | ||
shell.openExternal(url, { activate: false }) | ||
} else if (background && manager.hasWindow()) { | ||
manager.mainWindow.setAlwaysOnTop(true) | ||
await shell.openExternal(url) | ||
setTimeout(() => manager.mainWindow.setAlwaysOnTop(false), 1000) | ||
} else { | ||
shell.openExternal(url) | ||
} | ||
} | ||
} | ||
|
||
app.on("web-contents-created", (_, contents) => { | ||
contents.setWindowOpenHandler(details => { | ||
if (contents.getType() === "webview") | ||
openExternal( | ||
details.url, | ||
details.disposition === "background-tab" | ||
) | ||
return { | ||
action: manager.hasWindow() ? "deny" : "allow", | ||
} | ||
}) | ||
contents.on("will-navigate", (event, url) => { | ||
event.preventDefault() | ||
if (contents.getType() === "webview") openExternal(url) | ||
}) | ||
}) | ||
|
||
ipcMain.on("get-version", event => { | ||
event.returnValue = app.getVersion() | ||
}) | ||
|
||
ipcMain.handle("open-external", (_, url: string, background: boolean) => { | ||
openExternal(url, background) | ||
}) | ||
|
||
ipcMain.handle("show-error-box", (_, title, content) => { | ||
dialog.showErrorBox(title, content) | ||
}) | ||
|
||
ipcMain.handle( | ||
"show-message-box", | ||
async (_, title, message, confirm, cancel, defaultCancel, type) => { | ||
if (manager.hasWindow()) { | ||
let response = await dialog.showMessageBox(manager.mainWindow, { | ||
type: type, | ||
title: title, | ||
message: message, | ||
buttons: | ||
process.platform === "win32" | ||
? ["Yes", "No"] | ||
: [confirm, cancel], | ||
cancelId: 1, | ||
defaultId: defaultCancel ? 1 : 0, | ||
}) | ||
return response.response === 0 | ||
} else { | ||
return false | ||
} | ||
} | ||
) | ||
|
||
|
||
ipcMain.handle("get-cache", async () => { | ||
return await session.defaultSession.getCacheSize() | ||
}) | ||
|
||
ipcMain.handle("clear-cache", async () => { | ||
await session.defaultSession.clearCache() | ||
}) | ||
|
||
ipcMain.handle("write-clipboard", (_, text) => { | ||
clipboard.writeText(text) | ||
}) | ||
|
||
ipcMain.handle("close-window", () => { | ||
if (manager.hasWindow()) manager.mainWindow.close() | ||
}) | ||
|
||
ipcMain.handle("minimize-window", () => { | ||
if (manager.hasWindow()) manager.mainWindow.minimize() | ||
}) | ||
|
||
ipcMain.handle("maximize-window", () => { | ||
manager.zoom() | ||
}) | ||
|
||
ipcMain.on("is-maximized", event => { | ||
event.returnValue = | ||
Boolean(manager.mainWindow) && manager.mainWindow.isMaximized() | ||
}) | ||
|
||
ipcMain.on("is-focused", event => { | ||
event.returnValue = | ||
manager.hasWindow() && manager.mainWindow.isFocused() | ||
}) | ||
|
||
ipcMain.on("is-fullscreen", event => { | ||
event.returnValue = | ||
manager.hasWindow() && manager.mainWindow.isFullScreen() | ||
}) | ||
|
||
ipcMain.handle("request-focus", () => { | ||
if (manager.hasWindow()) { | ||
const win = manager.mainWindow | ||
if (win.isMinimized()) win.restore() | ||
if (process.platform === "win32") { | ||
win.setAlwaysOnTop(true) | ||
win.setAlwaysOnTop(false) | ||
} | ||
win.focus() | ||
} | ||
}) | ||
|
||
ipcMain.handle("request-attention", () => { | ||
if (manager.hasWindow() && !manager.mainWindow.isFocused()) { | ||
if (process.platform === "win32") { | ||
manager.mainWindow.flashFrame(true) | ||
manager.mainWindow.once("focus", () => { | ||
manager.mainWindow.flashFrame(false) | ||
}) | ||
} else if (process.platform === "darwin") { | ||
app.dock.bounce() | ||
} | ||
} | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Native | ||
|
||
// Packages | ||
import {app, BrowserWindow, ipcMain, IpcMainEvent} from 'electron' | ||
import path, {join} from 'path'; | ||
import isDev from "electron-is-dev"; | ||
|
||
import {WindowManager} from "./window"; | ||
import {format} from 'url'; | ||
|
||
|
||
app.on("ready", async () => { | ||
const mainWindow = new BrowserWindow({ | ||
width: 1600, | ||
height: 900, | ||
minWidth: 1600, | ||
minHeight: 900, | ||
titleBarStyle: 'hidden', | ||
// titleBarOverlay: {height: 44}, | ||
trafficLightPosition:{x: 15, y: 15}, | ||
webPreferences: { | ||
nodeIntegration: false, | ||
// contextIsolation: false, | ||
preload: join(__dirname, 'preload.js'), | ||
}, | ||
}) | ||
|
||
const windowManager = new WindowManager(mainWindow); | ||
windowManager.init(); | ||
|
||
const url = isDev | ||
? 'http://localhost:3000/' | ||
: format({ | ||
pathname: join(__dirname, '../renderer/out/index.html'), | ||
protocol: 'file:', | ||
slashes: true, | ||
}) | ||
|
||
|
||
mainWindow.loadURL(url) | ||
}) | ||
|
||
// Quit the app once all windows are closed | ||
app.on('window-all-closed', app.quit) | ||
|
||
// listen the channel `message` and resend the received message to the renderer process | ||
ipcMain.on('message', (event: IpcMainEvent, message: any) => { | ||
console.log(message) | ||
setTimeout(() => event.sender.send('message', 'hi from electron'), 500) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* eslint-disable @typescript-eslint/no-namespace */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
import { ipcRenderer, IpcRenderer, contextBridge } from 'electron' | ||
import { utilsBridge } from "./utilsBridge"; | ||
|
||
declare global { | ||
var ipcRenderer: IpcRenderer | ||
} | ||
|
||
// Since we disabled nodeIntegration we can reintroduce | ||
// needed node functionality here | ||
process.once('loaded', () => { | ||
global.ipcRenderer = ipcRenderer | ||
}) | ||
|
||
contextBridge.exposeInMainWorld("electron", { utilsBridge: utilsBridge }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"compilerOptions": { | ||
"experimentalDecorators": true, | ||
"emitDecoratorMetadata": true, | ||
"allowJs": true, | ||
"alwaysStrict": true, | ||
"esModuleInterop": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"strictPropertyInitialization": false, | ||
"isolatedModules": true, | ||
"jsx": "preserve", | ||
"lib": ["dom", "es2017"], | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"noEmit": false, | ||
"noFallthroughCasesInSwitch": true, | ||
// "noUnusedLocals": true, | ||
// "noUnusedParameters": true, | ||
"noImplicitAny": false, | ||
"resolveJsonModule": true, | ||
"skipLibCheck": true, | ||
"strict": true, | ||
"target": "esnext", | ||
"outDir": "../main" | ||
}, | ||
"exclude": ["node_modules"], | ||
"include": ["**/*.ts", "**/*.tsx", "**/*.js"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const enum WindowStateListenerType { | ||
Maximized, | ||
Focused, | ||
Fullscreen | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { ipcRenderer } from "electron"; | ||
import { WindowStateListenerType } from "./types"; | ||
import * as process from "node:process"; | ||
|
||
export const utilsBridge = { | ||
isBrowser: process.type === 'browser', | ||
isMac: process.platform === 'darwin', | ||
isWin: process.platform === 'win32', | ||
isLinux: process.platform === 'linux', | ||
isLinux64: process.platform === 'linux' && process.arch === 'x64', | ||
isLinux32: process.platform === 'linux' && process.arch === 'ia32', | ||
isLinuxARM: process.platform === 'linux' && process.arch === 'arm', | ||
isLinuxARM64: process.platform === 'linux' && process.arch === 'arm64', | ||
addWindowStateListener: (callback: (type: WindowStateListenerType, state: boolean) => void) => { | ||
ipcRenderer.removeAllListeners("maximized") | ||
ipcRenderer.on("maximized", () => { | ||
callback(WindowStateListenerType.Maximized, true) | ||
}) | ||
ipcRenderer.removeAllListeners("unmaximized") | ||
ipcRenderer.on("unmaximized", () => { | ||
callback(WindowStateListenerType.Maximized, false) | ||
}) | ||
ipcRenderer.removeAllListeners("enter-fullscreen") | ||
ipcRenderer.on("enter-fullscreen", () => { | ||
callback(WindowStateListenerType.Fullscreen, true) | ||
}) | ||
ipcRenderer.removeAllListeners("leave-fullscreen") | ||
ipcRenderer.on("leave-fullscreen", () => { | ||
callback(WindowStateListenerType.Fullscreen, false) | ||
}) | ||
ipcRenderer.removeAllListeners("window-focus") | ||
ipcRenderer.on("window-focus", () => { | ||
callback(WindowStateListenerType.Focused, true) | ||
}) | ||
ipcRenderer.removeAllListeners("window-blur") | ||
ipcRenderer.on("window-blur", () => { | ||
callback(WindowStateListenerType.Focused, false) | ||
}) | ||
}, | ||
closeWindow: () => { | ||
ipcRenderer.invoke("close-window") | ||
}, | ||
minimizeWindow: () => { | ||
ipcRenderer.invoke("minimize-window") | ||
}, | ||
maximizeWindow: () => { | ||
ipcRenderer.invoke("maximize-window") | ||
}, | ||
isMaximized: () => { | ||
return ipcRenderer.sendSync("is-maximized") as boolean | ||
}, | ||
isFullscreen: () => { | ||
return ipcRenderer.sendSync("is-fullscreen") as boolean | ||
}, | ||
isFocused: () => { | ||
return ipcRenderer.sendSync("is-focused") as boolean | ||
}, | ||
} | ||
|
||
declare global { | ||
interface Window { | ||
electron: { | ||
utilsBridge: typeof utilsBridge | ||
} | ||
} | ||
} |
Oops, something went wrong.