2022-01-30 19:48:32 +00:00
// To allow seamless switching between custom titlebar and native os titlebar,
// I had to add most of the window creation code here to split both into seperete functions
// WHY? Because I can't use the same code for both due to annoying bug with value `frame` not responding to variables
// I'm sorry for this mess but I'm not sure how to fix it.
2022-08-25 12:57:28 +00:00
import { BrowserWindow , shell , app , dialog , nativeImage } from "electron" ;
2022-01-30 19:48:32 +00:00
import path from "path" ;
2022-09-25 18:30:09 +00:00
import { checkIfConfigIsBroken , firstRun , getConfig , contentPath , setConfig , setLang , setWindowState } from "./utils" ;
2022-08-22 09:24:55 +00:00
import { registerIpc } from "./ipc" ;
import { setMenu } from "./menu" ;
2022-06-16 21:09:41 +00:00
import * as fs from "fs" ;
2022-05-22 11:52:26 +00:00
import startServer from "./socket" ;
2022-02-26 21:26:16 +00:00
import contextMenu from "electron-context-menu" ;
2022-05-14 17:55:06 +00:00
import os from "os" ;
2022-08-25 12:57:28 +00:00
import { tray } from "./tray" ;
2022-08-25 14:42:54 +00:00
import { iconPath } from "./main" ;
2022-01-30 19:48:32 +00:00
export let mainWindow : BrowserWindow ;
2022-04-19 13:56:04 +00:00
export let inviteWindow : BrowserWindow ;
2022-05-14 17:55:06 +00:00
2022-08-25 16:40:43 +00:00
var osType = os . type ( ) ;
2022-02-26 21:26:16 +00:00
contextMenu ( {
2022-03-04 17:53:18 +00:00
showSaveImageAs : true ,
showCopyImageAddress : true ,
2022-09-25 18:30:09 +00:00
showSearchWithGoogle : false ,
prepend : ( defaultActions , parameters , browserWindow ) = > [
{
label : "Search with Google" ,
// Only show it when right-clicking text
visible : parameters.selectionText.trim ( ) . length > 0 ,
click : ( ) = > {
shell . openExternal ( ` https://google.com/search?q= ${ encodeURIComponent ( parameters . selectionText ) } ` ) ;
}
} ,
{
label : "Search with DuckDuckGo" ,
// Only show it when right-clicking text
visible : parameters.selectionText.trim ( ) . length > 0 ,
click : ( ) = > {
shell . openExternal ( ` https://duckduckgo.com/?q= ${ encodeURIComponent ( parameters . selectionText ) } ` ) ;
}
}
]
2022-02-26 21:26:16 +00:00
} ) ;
2022-04-19 17:59:52 +00:00
async function doAfterDefiningTheWindow() {
2022-06-03 13:18:36 +00:00
var ignoreProtocolWarning = await getConfig ( "ignoreProtocolWarning" ) ;
2022-08-25 16:40:43 +00:00
await checkIfConfigIsBroken ( ) ;
2022-03-04 17:53:18 +00:00
registerIpc ( ) ;
2022-07-11 17:13:52 +00:00
if ( await getConfig ( "mobileMode" ) ) {
2022-08-22 09:24:55 +00:00
mainWindow . webContents . userAgent =
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.149 Mobile Safari/537.36" ;
2022-07-11 17:13:52 +00:00
} else {
// A little sloppy but it works :p
2022-08-22 09:24:55 +00:00
if ( osType == "Windows_NT" ) {
osType = "Windows " + os . release ( ) . split ( "." ) [ 0 ] + " (" + os . release ( ) + ")" ;
2022-07-11 17:13:52 +00:00
}
mainWindow . webContents . userAgent = ` Mozilla/5.0 (X11; ${ osType } ${ os . arch ( ) } ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 ` ; //fake useragent for screenshare to work
2022-06-03 16:05:28 +00:00
}
2022-07-11 17:13:52 +00:00
2022-08-22 09:24:55 +00:00
mainWindow . webContents . setWindowOpenHandler ( ( { url } ) = > {
2022-06-03 13:18:36 +00:00
if ( url . startsWith ( "https:" || url . startsWith ( "http:" ) || url . startsWith ( "mailto:" ) ) ) {
shell . openExternal ( url ) ;
} else {
if ( ignoreProtocolWarning ) {
shell . openExternal ( url ) ;
} else {
const options = {
type : "question" ,
buttons : [ "Yes, please" , "No, I don't" ] ,
defaultId : 1 ,
title : url ,
message : ` Do you want to open ${ url } ? ` ,
detail : "This url was detected to not use normal browser protocols. It could mean that this url leads to a local program on your computer. Please check if you recognise it, before proceeding!" ,
checkboxLabel : "Remember my answer and ignore this warning for future sessions" ,
checkboxChecked : false
} ;
2022-08-22 09:24:55 +00:00
dialog . showMessageBox ( mainWindow , options ) . then ( ( { response , checkboxChecked } ) = > {
2022-06-03 13:18:36 +00:00
console . log ( response , checkboxChecked ) ;
if ( checkboxChecked ) {
if ( response == 0 ) {
setConfig ( "ignoreProtocolWarning" , true ) ;
} else {
setConfig ( "ignoreProtocolWarning" , false ) ;
}
}
if ( response == 0 ) {
shell . openExternal ( url ) ;
} else {
return ;
}
} ) ;
}
}
2022-08-22 09:24:55 +00:00
return { action : "deny" } ;
2022-03-04 17:53:18 +00:00
} ) ;
mainWindow . webContents . session . webRequest . onBeforeRequest ( ( details , callback ) = > {
2022-08-22 09:24:55 +00:00
if ( /api\/v\d\/science$/g . test ( details . url ) ) return callback ( { cancel : true } ) ;
2022-03-04 17:53:18 +00:00
return callback ( { } ) ;
} ) ;
2022-09-25 18:30:09 +00:00
if ( ( await getConfig ( "trayIcon" ) ) == "default" ) {
2022-08-25 12:57:28 +00:00
mainWindow . webContents . on ( "page-favicon-updated" , async ( event ) = > {
var faviconBase64 = await mainWindow . webContents . executeJavaScript ( `
var getFavicon = function ( ) {
var favicon = undefined ;
var nodeList = document . getElementsByTagName ( "link" ) ;
for ( var i = 0 ; i < nodeList . length ; i ++ )
{
if ( ( nodeList [ i ] . getAttribute ( "rel" ) == "icon" ) || ( nodeList [ i ] . getAttribute ( "rel" ) == "shortcut icon" ) )
{
favicon = nodeList [ i ] . getAttribute ( "href" ) ;
}
}
return favicon ;
}
getFavicon ( )
2022-09-25 18:30:09 +00:00
` );
var buf = new Buffer ( faviconBase64 . replace ( /^data:image\/\w+;base64,/ , "" ) , "base64" ) ;
2022-08-25 14:10:26 +00:00
fs . writeFileSync ( path . join ( app . getPath ( "temp" ) , "/" , "tray.png" ) , buf , "utf-8" ) ;
let trayPath = nativeImage . createFromPath ( path . join ( app . getPath ( "temp" ) , "/" , "tray.png" ) ) ;
2022-09-25 18:30:09 +00:00
if ( process . platform === "darwin" && trayPath . getSize ( ) . height > 22 )
trayPath = trayPath . resize ( { height : 22 } ) ;
tray . setImage ( trayPath ) ;
} ) ;
2022-08-25 12:57:28 +00:00
}
2022-06-16 21:09:41 +00:00
const userDataPath = app . getPath ( "userData" ) ;
const themesFolder = userDataPath + "/themes/" ;
if ( ! fs . existsSync ( themesFolder ) ) {
fs . mkdirSync ( themesFolder ) ;
console . log ( "Created missing theme folder" ) ;
}
2022-08-22 09:24:55 +00:00
mainWindow . webContents . on ( "did-finish-load" , ( ) = > {
2022-06-16 21:09:41 +00:00
fs . readdirSync ( themesFolder ) . forEach ( ( file ) = > {
try {
const manifest = fs . readFileSync ( ` ${ themesFolder } / ${ file } /manifest.json ` , "utf8" ) ;
var themeFile = JSON . parse ( manifest ) ;
2022-08-22 09:24:55 +00:00
mainWindow . webContents . send (
"themeLoader" ,
fs . readFileSync ( ` ${ themesFolder } / ${ file } / ${ themeFile . theme } ` , "utf-8" )
) ;
2022-06-16 21:09:41 +00:00
console . log ( ` %cLoaded ${ themeFile . name } made by ${ themeFile . author } ` , "color:red" ) ;
} catch ( err ) {
console . error ( err ) ;
}
} ) ;
} ) ;
2022-08-25 16:40:43 +00:00
await setMenu ( ) ;
2022-03-04 17:53:18 +00:00
mainWindow . on ( "close" , async ( e ) = > {
2022-08-22 09:24:55 +00:00
let [ width , height ] = mainWindow . getSize ( ) ;
2022-08-25 16:40:43 +00:00
await setWindowState ( {
2022-06-16 15:24:37 +00:00
width : width ,
height : height ,
isMaximized : mainWindow.isMaximized ( )
2022-08-22 09:24:55 +00:00
} ) ;
2022-04-18 10:25:10 +00:00
if ( await getConfig ( "minimizeToTray" ) ) {
2022-03-04 17:53:18 +00:00
e . preventDefault ( ) ;
mainWindow . hide ( ) ;
2022-04-18 10:25:10 +00:00
} else if ( ! ( await getConfig ( "minimizeToTray" ) ) ) {
2022-03-04 17:53:18 +00:00
e . preventDefault ( ) ;
app . quit ( ) ;
}
} ) ;
2022-08-22 09:24:55 +00:00
mainWindow . on ( "focus" , ( ) = > {
mainWindow . webContents . executeJavaScript ( ` document.body.removeAttribute("unFocused"); ` ) ;
} ) ;
mainWindow . on ( "blur" , ( ) = > {
mainWindow . webContents . executeJavaScript ( ` document.body.setAttribute("unFocused", ""); ` ) ;
} ) ;
mainWindow . on ( "maximize" , ( ) = > {
mainWindow . webContents . executeJavaScript ( ` document.body.setAttribute("isMaximized", ""); ` ) ;
} ) ;
mainWindow . on ( "unmaximize" , ( ) = > {
mainWindow . webContents . executeJavaScript ( ` document.body.removeAttribute("isMaximized"); ` ) ;
} ) ;
2022-03-04 17:53:18 +00:00
console . log ( contentPath ) ;
2022-05-22 11:52:26 +00:00
if ( ( await getConfig ( "inviteWebsocket" ) ) == true ) {
2022-07-11 18:19:50 +00:00
await startServer ( ) ;
2022-04-19 17:59:52 +00:00
}
2022-07-11 18:19:50 +00:00
if ( firstRun ) {
2022-08-22 09:24:55 +00:00
await setLang ( Intl . DateTimeFormat ( ) . resolvedOptions ( ) . locale ) ;
2022-07-11 18:19:50 +00:00
mainWindow . setSize ( 390 , 470 ) ;
await mainWindow . loadFile ( path . join ( __dirname , "/content/setup.html" ) ) ;
} else {
2022-08-22 09:24:55 +00:00
if ( ( await getConfig ( "skipSplash" ) ) == true ) {
2022-07-18 15:13:52 +00:00
switch ( await getConfig ( "channel" ) ) {
case "stable" :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://discord.com/app" ) ;
2022-07-18 15:13:52 +00:00
break ;
case "canary" :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://canary.discord.com/app" ) ;
2022-07-18 15:13:52 +00:00
break ;
case "ptb" :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://ptb.discord.com/app" ) ;
2022-07-18 15:13:52 +00:00
break ;
case "hummus" :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://hummus.sys42.net/" ) ;
2022-07-18 15:13:52 +00:00
break ;
case undefined :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://discord.com/app" ) ;
2022-07-18 15:13:52 +00:00
break ;
default :
2022-08-25 16:40:43 +00:00
await mainWindow . loadURL ( "https://discord.com/app" ) ;
2022-07-18 15:13:52 +00:00
}
} else {
await mainWindow . loadFile ( path . join ( __dirname , "/content/splash.html" ) ) ;
}
2022-01-30 19:48:32 +00:00
}
}
export function createCustomWindow() {
2022-03-04 17:53:18 +00:00
mainWindow = new BrowserWindow ( {
2022-05-14 19:02:09 +00:00
width : 300 ,
height : 350 ,
2022-03-04 17:53:18 +00:00
title : "ArmCord" ,
darkTheme : true ,
2022-08-25 14:42:54 +00:00
icon : iconPath ,
2022-03-04 17:53:18 +00:00
frame : false ,
autoHideMenuBar : true ,
webPreferences : {
2022-08-25 14:10:26 +00:00
sandbox : false ,
2022-03-04 17:53:18 +00:00
preload : path.join ( __dirname , "preload/preload.js" ) ,
spellcheck : true
}
} ) ;
doAfterDefiningTheWindow ( ) ;
2022-01-30 19:48:32 +00:00
}
export function createNativeWindow() {
2022-03-04 17:53:18 +00:00
mainWindow = new BrowserWindow ( {
width : 300 ,
height : 350 ,
title : "ArmCord" ,
darkTheme : true ,
2022-08-25 14:42:54 +00:00
icon : iconPath ,
2022-03-04 17:53:18 +00:00
frame : true ,
autoHideMenuBar : true ,
webPreferences : {
2022-08-25 14:10:26 +00:00
sandbox : false ,
2022-03-04 17:53:18 +00:00
preload : path.join ( __dirname , "preload/preload.js" ) ,
spellcheck : true
}
} ) ;
doAfterDefiningTheWindow ( ) ;
2022-02-26 21:26:16 +00:00
}
2022-04-19 13:56:04 +00:00
export function createInviteWindow() {
inviteWindow = new BrowserWindow ( {
width : 800 ,
height : 600 ,
title : "ArmCord Invite Manager" ,
darkTheme : true ,
2022-08-25 14:42:54 +00:00
icon : iconPath ,
2022-04-19 13:56:04 +00:00
frame : true ,
autoHideMenuBar : true ,
webPreferences : {
2022-08-25 14:10:26 +00:00
sandbox : false ,
2022-04-19 13:56:04 +00:00
spellcheck : true
}
} ) ;
2022-05-22 11:52:26 +00:00
inviteWindow . hide ( ) ;
}