diff --git a/assets/16.png b/assets/16.png new file mode 100644 index 0000000..f43ff68 Binary files /dev/null and b/assets/16.png differ diff --git a/assets/lang/en-US.json b/assets/lang/en-US.json index 86d1b3c..979bc73 100644 --- a/assets/lang/en-US.json +++ b/assets/lang/en-US.json @@ -14,6 +14,8 @@ "setup_question4": "Select a client mod you want to install:", "setup_question4_clientmodnotice": "Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our Discord.", "settings-theme": "ArmCord theme:", + "settings-theme-glasstron": "Glasstron (experimental)", + "settings-theme-tabs": "Tabs (experimental)", "settings-theme-default": "Default", "settings-theme-native": "Native", "settings-tray": "Minimize to tray", diff --git a/assets/lang/es-419.json b/assets/lang/es-419.json deleted file mode 100644 index 3230182..0000000 --- a/assets/lang/es-419.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "loading_screen_start": "Starting ArmCord…", - "loading_screen_offline": "You appear to be offline. Please connect to the Internet and try again.", - "loading_screen_update": "A new version of ArmCord is available. Please update to the latest version.", - "setup_question1": "Select what kind of setup you want to perform:", - "yes": "Yes", - "setup_question2": "Choose your Discord channel/instance:", - "setup_question3": "Should ArmCord handle client mods installation?", - "setup_question1_answer1": "Express setup", - "setup_question1_answer2": "Full setup", - "setup_offline": "You appear to be offline. Please connect to the Internet and restart the ArmCord setup.", - "no": "No", - "next": "Next", - "setup_question4": "Select a client mod you want to install:", - "setup_question4_clientmodnotice": "Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our Discord.", - "settings-theme": "ArmCord theme:", - "settings-theme-default": "Default", - "settings-theme-native": "Native", - "settings-tray": "Minimize to tray", - "settings-patches": "Automatic Patches", - "settings-channel": "Discord channel:", - "settings-invitewebsocket": "Invite Websocket", - "settings-mod": "Client mod:", - "settings-prfmMode": "Performance mode:", - "settings-prfmMode-performance": "Performance", - "settings-prfmMode-battery": "Battery", - "settings-none": "None", - "settings-save": "Save settings", - "settings-updater": "Check for updates" -} diff --git a/assets/lang/fr-FR.json b/assets/lang/fr-FR.json index 774fd98..7745641 100644 --- a/assets/lang/fr-FR.json +++ b/assets/lang/fr-FR.json @@ -19,7 +19,9 @@ "settings-save": "Save settings", "settings-updater": "Check for updates", "settings-theme": "Thème ArmCord :", + "settings-theme-tabs": "Tabs (experimental)", "settings-theme-default": "Default", + "settings-theme-glasstron": "Glasstron (experimental)", "settings-theme-native": "Native", "settings-patches": "Automatic Patches", "settings-invitewebsocket": "Lien discord.gg", diff --git a/assets/lang/id-ID.json b/assets/lang/id-ID.json index 51bef0a..03f2b4f 100644 --- a/assets/lang/id-ID.json +++ b/assets/lang/id-ID.json @@ -14,6 +14,7 @@ "setup_question4": "Select a client mod you want to install:", "setup_question4_clientmodnotice": "Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our documentation.", "settings-theme": "ArmCord Theme:", + "settings-theme-glasstron": "Glasstron (experimental)", "settings-theme-tabs": "Tabs (experimental)", "settings-theme-default": "Default", "settings-theme-native": "Native", diff --git a/assets/lang/it-IT.json b/assets/lang/it-IT.json index 25d10d4..a301d5c 100644 --- a/assets/lang/it-IT.json +++ b/assets/lang/it-IT.json @@ -19,6 +19,7 @@ "settings-updater": "Controlla gli aggiornamenti", "settings-mod": "Client mod:", "settings-theme": "ArmCord Theme:", + "settings-theme-glasstron": "Glasstron (experimental)", "settings-theme-tabs": "Tabs (experimental)", "settings-theme-default": "Default", "settings-theme-native": "Native", diff --git a/assets/lang/nb-NO.json b/assets/lang/nb-NO.json index 29ed697..050af76 100644 --- a/assets/lang/nb-NO.json +++ b/assets/lang/nb-NO.json @@ -19,6 +19,7 @@ "settings-save": "Save settings", "settings-updater": "Check for updates", "settings-theme": "ArmCord Theme:", + "settings-theme-glasstron": "Glasstron (experimental)", "settings-theme-tabs": "Tabs (experimental)", "settings-theme-default": "Default", "settings-theme-native": "Native", diff --git a/assets/lang/nl-NL.json b/assets/lang/nl-NL.json index c981b8d..bb37188 100644 --- a/assets/lang/nl-NL.json +++ b/assets/lang/nl-NL.json @@ -20,6 +20,7 @@ "settings-updater": "Check voor updates", "settings-patches": "Automatische Patches", "settings-theme": "ArmCord Thema:", + "settings-theme-glasstron": "Glasstron (experimenteel)", "settings-theme-tabs": "Tabs (experimenteel)", "settings-theme-default": "Standaard", "settings-theme-native": "Native", diff --git a/assets/lang/pl-PL.json b/assets/lang/pl-PL.json index 4870b4f..e4892b6 100644 --- a/assets/lang/pl-PL.json +++ b/assets/lang/pl-PL.json @@ -19,6 +19,7 @@ "settings-save": "Zapisz ustawienia", "settings-mod": "Modyfikacja klienta:", "settings-theme": "Motyw ArmCord:", + "settings-theme-glasstron": "Glasstron (eksperymentalne)", "settings-theme-tabs": "Karty (eksperymentalne)", "settings-theme-default": "Domyślny", "settings-theme-native": "Natywny", diff --git a/assets/macos.png b/assets/macos.png index f43ff68..953ecfa 100644 Binary files a/assets/macos.png and b/assets/macos.png differ diff --git a/package.json b/package.json index b636089..9541221 100644 --- a/package.json +++ b/package.json @@ -23,20 +23,20 @@ }, "homepage": "https://github.com/armcord/armcord#readme", "devDependencies": { - "@types/node": "^17.0.42", + "@types/node": "^17.0.33", "@types/ws": "^8.5.3", "copyfiles": "^2.4.1", "electron": "^19.0.4", "electron-builder": "^23.0.3", "husky": "^8.0.1", - "prettier": "^2.7.0", - "typescript": "^4.7.3" + "prettier": "^2.5.1", + "typescript": "^4.6.3" }, "dependencies": { "electron-context-menu": "github:ArmCord/electron-context-menu", "os-locale": "^6.0.2", "v8-compile-cache": "^2.3.0", - "ws": "^8.8.0" + "ws": "^8.6.0" }, "build": { "appId": "com.smartfridge.armcord", diff --git a/src/content/css/tabs.css b/src/content/css/tabs.css new file mode 100644 index 0000000..d8f10cb --- /dev/null +++ b/src/content/css/tabs.css @@ -0,0 +1,46 @@ +.tabs { + display: block; + top: 0; + left: 0; + right: 0; + flex-shrink: 0; + overflow: hidden; + zoom: 1; + box-sizing: border-box; + width: 100%; + clear: both; + height: 30px; + line-height: 30px; + background-color: #202225; + -webkit-app-region: drag; + width: 100%; + user-select: none; + -webkit-user-select: none; + position: fixed; + z-index: 99999; +} + +.tabs #tabs-controls-container { + float: left; + width: 150px; + height: 100%; + line-height: 30px; + background-color: #202225; + -webkit-app-region: no-drag; +} +.tabs-buttons { + color: white; + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + transition: 0.3s; + font-size: 20px; +} +.tabs-buttons:hover { + background-color: #4e515a; +} +.withFrame-haYltI { + height: 30px !important; +} diff --git a/src/content/setup.html b/src/content/setup.html index cdf790a..04b743c 100644 --- a/src/content/setup.html +++ b/src/content/setup.html @@ -123,7 +123,8 @@ automaticPatches: false, mods: "cumcord", inviteWebsocket: true, - performanceMode: "none" + performanceMode: "none", + blurType: "acrylic" }); setTimeout(() => window.armcordinternal.restart(), 5000); }); @@ -154,7 +155,8 @@ automaticPatches: false, performanceMode: "none", mods: options.mod, - inviteWebsocket: true + inviteWebsocket: true, + blurType: "acrylic" }); setTimeout(() => window.armcordinternal.restart(), 500); }); @@ -168,7 +170,8 @@ autoLaunch: true, mods: "none", performanceMode: "none", - inviteWebsocket: true + inviteWebsocket: true, + blurType: "acrylic" }); setTimeout(() => window.armcordinternal.restart(), 500); } diff --git a/src/content/splash.html b/src/content/splash.html index c75ca52..83cd134 100644 --- a/src/content/splash.html +++ b/src/content/splash.html @@ -17,53 +17,52 @@ diff --git a/src/ipc.ts b/src/ipc.ts index 5ad4e44..1248891 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -1,18 +1,21 @@ //ipc stuff import {app, ipcMain, shell, desktopCapturer} from "electron"; -import {mainWindow} from "./window"; +import {createTabsGuest, mainWindow} from "./window"; import {setConfigBulk, getVersion, getConfig, setLang, getLang} from "./utils"; -import {customTitlebar} from "./main"; +import {customTitlebar, tabs} from "./main"; import {createSettingsWindow} from "./settings/main"; export function registerIpc() { ipcMain.on("get-app-path", (event, arg) => { event.reply("app-path", app.getAppPath()); }); + ipcMain.on("openTab", (event, number: number) => { + createTabsGuest(number); + }); ipcMain.on("setLang", (event, lang: string) => { setLang(lang); }); - ipcMain.handle("getLang", (event, toGet: string) => { - return getLang(toGet); + ipcMain.on("getLang", (event, object: string) => { + getLang(object); }); ipcMain.on("open-external-link", (event, href: string) => { shell.openExternal(href); @@ -57,12 +60,18 @@ export function registerIpc() { ipcMain.on("channel", async (event) => { event.returnValue = await getConfig("channel"); }); + ipcMain.handle("getLang", (event, toGet: string) => { + return getLang(toGet); + }); ipcMain.on("clientmod", async (event, arg) => { event.returnValue = await getConfig("mods"); }); ipcMain.on("titlebar", (event, arg) => { event.returnValue = customTitlebar; }); + ipcMain.on("tabs", (event, arg) => { + event.returnValue = tabs; + }); ipcMain.on("shouldPatch", async (event, arg) => { event.returnValue = await getConfig("automaticPatches"); }); diff --git a/src/main.ts b/src/main.ts index 096e8b7..8d1abb9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,16 @@ // Modules to control application life and create native browser window -import {app, BrowserWindow, session} from "electron"; +import {app, BrowserWindow, session, dialog} from "electron"; import "v8-compile-cache"; -import {getConfig, checkIfConfigExists, injectElectronFlags} from "./utils"; +import {getConfig, setup, checkIfConfigExists, injectElectronFlags} from "./utils"; import "./extensions/mods"; import "./extensions/plugin"; import "./tray"; -import {createCustomWindow, createNativeWindow} from "./window"; +import {createCustomWindow, createNativeWindow, createTabsHost} from "./window"; import "./shortcuts"; export var settings: any; export var customTitlebar: boolean; +export var tabs: boolean; if (process.platform == "linux") { @@ -37,6 +38,17 @@ app.whenReady().then(async () => { case "discord": createNativeWindow(); break; + case "glasstron": + dialog.showErrorBox( + "Glasstron is unsupported.", + "This build doesn't include Glasstron functionality, please edit windowStyle value in your settings.json to something different (default for example)" + ); + app.quit(); + break; + case "tabs": + createTabsHost(); + tabs = true; + break; default: createCustomWindow(); customTitlebar = true; @@ -61,8 +73,16 @@ app.whenReady().then(async () => { case "native": createNativeWindow(); break; - case "discord": - createNativeWindow(); + case "glasstron": + dialog.showErrorBox( + "Glasstron is unsupported.", + "This build doesn't include Glasstron functionality, please edit windowStyle value in your settings.json to something different (default for example)" + ); + app.quit(); + break; + case "tabs": + createTabsHost(); + tabs = true; break; default: createCustomWindow(); diff --git a/src/preload/preload.ts b/src/preload/preload.ts index 1b58435..8b6ac48 100644 --- a/src/preload/preload.ts +++ b/src/preload/preload.ts @@ -6,6 +6,7 @@ import * as path from "path"; import {injectTitlebar} from "./titlebar"; import {sleep, addStyle, injectJS, addScript} from "../utils"; import {ipcRenderer} from "electron"; +import {injectTabs} from "./tabs"; var version = ipcRenderer.sendSync("get-app-version", "app-version"); async function updateLang() { if (window.location.href.indexOf("setup.html") > -1) { @@ -34,6 +35,9 @@ if (window.location.href.indexOf("splash.html") > -1) { if (ipcRenderer.sendSync("titlebar")) { injectTitlebar(); } + if (ipcRenderer.sendSync("tabs")) { + injectTabs(); + } sleep(5000).then(async () => { const cssPath = path.join(__dirname, "../", "/content/css/discord.css"); addStyle(fs.readFileSync(cssPath, "utf8")); diff --git a/src/preload/tabs.ts b/src/preload/tabs.ts new file mode 100644 index 0000000..960dc16 --- /dev/null +++ b/src/preload/tabs.ts @@ -0,0 +1,26 @@ +import {addStyle} from "../utils"; +import * as fs from "fs"; +import * as path from "path"; +export function injectTabs() { + document.addEventListener("DOMContentLoaded", function (event) { + var elem = document.createElement("div"); + elem.innerHTML = ``; + elem.classList.add("withFrame-haYltI"); + if (document.getElementById("app-mount") == null) { + document.body.appendChild(elem); + } else { + document.getElementById("app-mount")!.prepend(elem); + } + const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); + addStyle(fs.readFileSync(cssPath, "utf8")); + }); +} diff --git a/src/preload/titlebar.ts b/src/preload/titlebar.ts index 28a94f9..3c58fc1 100644 --- a/src/preload/titlebar.ts +++ b/src/preload/titlebar.ts @@ -38,8 +38,10 @@ export function injectTitlebar() { maximize!.addEventListener("click", () => { if (ipcRenderer.sendSync("win-isMaximized") == true) { ipcRenderer.send("win-unmaximize"); + document.body.removeAttribute("isMaximized"); } else { ipcRenderer.send("win-maximize"); + document.body.setAttribute("isMaximized", ""); } }); diff --git a/src/settings/main.ts b/src/settings/main.ts index e25b865..4167f62 100644 --- a/src/settings/main.ts +++ b/src/settings/main.ts @@ -31,6 +31,9 @@ export function createSettingsWindow() { ipcMain.handle("getSetting", (event, toGet: string) => { return getConfig(toGet); }); + ipcMain.handle("getLang", (event, toGet: string) => { + return getLang(toGet); + }); settingsWindow.webContents.setWindowOpenHandler(({url}) => { shell.openExternal(url); return {action: "deny"}; @@ -38,6 +41,7 @@ export function createSettingsWindow() { settingsWindow.loadURL(`file://${__dirname}/settings.html`); settingsWindow.on("close", (event: Event) => { ipcMain.removeHandler("getSetting"); + ipcMain.removeHandler("getLang"); ipcMain.removeAllListeners("saveSettings"); instance = 0; }); diff --git a/src/settings/settings.html b/src/settings/settings.html index 4b0b806..e352741 100644 --- a/src/settings/settings.html +++ b/src/settings/settings.html @@ -104,6 +104,7 @@ } loadSettings(); document.getElementById("settings-save").addEventListener("click", function () { + //function saveSettings(windowStyle: string, channelSetting: string, armcordCSPSetting: boolean, minimizeToTray: boolean, automaticPatches: boolean,modsSetting: string, blurType: string) settings.save({ windowStyle: document.getElementById("theme").value, channel: document.getElementById("channel").value, @@ -111,6 +112,7 @@ minimizeToTray: document.getElementById("tray").checked, automaticPatches: document.getElementById("patches").checked, mods: document.getElementById("mod").value, + blurType: "acrylic", inviteWebsocket: document.getElementById("websocket").checked, performanceMode: document.getElementById("prfmMode").value, doneSetup: true diff --git a/src/tray.ts b/src/tray.ts index d690914..6129949 100644 --- a/src/tray.ts +++ b/src/tray.ts @@ -3,13 +3,8 @@ import {mainWindow} from "./window"; import {getConfig} from "./utils"; import * as path from "path"; import {createSettingsWindow} from "./settings/main"; -import {platform} from "process"; let tray: any = null; -let defaultIcon = "ac_plug_colored"; app.whenReady().then(async () => { - if (platform == "darwin") { - defaultIcon = "macos" - } if ((await getConfig("windowStyle")) == "discord") { tray = new Tray(path.join(__dirname, "../", "/assets/dsc-tray.png")); const contextMenu = Menu.buildFromTemplate([ @@ -30,7 +25,7 @@ app.whenReady().then(async () => { tray.setToolTip("Discord"); tray.setContextMenu(contextMenu); } else { - var trayIcon = (await getConfig("trayIcon")) ?? defaultIcon; + var trayIcon = (await getConfig("trayIcon")) ?? "ac_plug_colored"; tray = new Tray(path.join(__dirname, "../", `/assets/${trayIcon}.png`)); const contextMenu = Menu.buildFromTemplate([ { diff --git a/src/utils.ts b/src/utils.ts index c3b5bf2..04fe9e2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -42,6 +42,7 @@ export function setup() { minimizeToTray: true, automaticPatches: false, mods: "cumcord", + blurType: "acrylic", performanceMode: "none", inviteWebsocket: true, doneSetup: false @@ -147,6 +148,7 @@ export interface Settings { automaticPatches: boolean; mods: string; performanceMode: string; + blurType: string; inviteWebsocket: boolean; doneSetup: boolean; } diff --git a/src/window.ts b/src/window.ts index d523314..a8b622e 100644 --- a/src/window.ts +++ b/src/window.ts @@ -2,7 +2,7 @@ // 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. -import {BrowserWindow, shell, app, dialog} from "electron"; +import {BrowserWindow, shell, app, ipcMain, dialog, clipboard} from "electron"; import path from "path"; import {checkIfConfigIsBroken, firstRun, getConfig, contentPath, isSetup, setConfig, setLang} from "./utils"; import {registerIpc} from "./ipc"; @@ -12,6 +12,7 @@ import os from "os"; export var icon: string; export let mainWindow: BrowserWindow; export let inviteWindow: BrowserWindow; +let guestWindows: BrowserWindow[] = []; var osType = os.type() contextMenu({ @@ -80,12 +81,6 @@ async function doAfterDefiningTheWindow() { app.quit(); } }); - mainWindow.on('maximize',() =>{ - mainWindow.webContents.executeJavaScript(`document.body.setAttribute("isMaximized", "");`) - }) - mainWindow.on('unmaximize',() =>{ - mainWindow.webContents.executeJavaScript(`document.body.removeAttribute("isMaximized");`) - }) console.log(contentPath); if ((await getConfig("inviteWebsocket")) == true) { startServer(); @@ -153,6 +148,77 @@ export function createNativeWindow() { doAfterDefiningTheWindow(); } +export function createTabsHost() { + dialog.showErrorBox( + "READ THIS BEFORE USING THE APP", + "ArmCord Tabs are highly experimental and should be only used for strict testing purposes. Please don't ask for support, however you can still report bugs!" + ); + guestWindows[1] = mainWindow; + mainWindow = new BrowserWindow({ + width: 300, + height: 350, + title: "ArmCord", + darkTheme: true, + icon: path.join(__dirname, "../", "/assets/ac_icon_transparent.png"), + frame: true, + autoHideMenuBar: true, + webPreferences: { + preload: path.join(__dirname, "preload/preload.js") + } + }); + doAfterDefiningTheWindow(); +} +export function createTabsGuest(number: number) { + console.log(guestWindows); + if (guestWindows[number] !== undefined || null) { + try { + console.log("Showing Guest Window " + number); + mainWindow.hide(); + guestWindows[number].show(); + mainWindow = guestWindows[number]; + } catch (e) { + console.error(e); + } + } else { + console.log("Creating Guest Window " + number); + mainWindow.hide(); + + guestWindows[number] = new BrowserWindow({ + width: 800, + height: 600, + title: "ArmCord Guest Window " + number, + darkTheme: true, + icon: path.join(__dirname, "../", "/assets/ac_icon_transparent.png"), + frame: true, + autoHideMenuBar: true, + webPreferences: { + preload: path.join(__dirname, "preload/preload.js") + } + }); + + mainWindow = guestWindows[number]; + ipcMain.on("tab" + number, (event) => { + event.returnValue = true; //return true so we know the tab exists + }); + + guestWindows[number].webContents.userAgent = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work + + guestWindows[number].webContents.setWindowOpenHandler(({url}) => { + shell.openExternal(url); + return {action: "deny"}; + }); + + guestWindows[number].webContents.session.webRequest.onBeforeRequest( + (details: {url: string}, callback: (arg0: {cancel?: boolean}) => any) => { + if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true}); + return callback({}); + } + ); + + guestWindows[number].loadURL("https://discord.com/app"); + } +} export function createInviteWindow() { inviteWindow = new BrowserWindow({ width: 800,