Compare commits

..

No commits in common. "72c35cb2f3cfe521dd5177a2f9dcf2df59abb5cc" and "7f53710d6af56e2c1b7b2c90511f66667b8d6d87" have entirely different histories.

24 changed files with 261 additions and 104 deletions

BIN
assets/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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",

View file

@ -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"
}

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Before After
Before After

View file

@ -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",

46
src/content/css/tabs.css Normal file
View file

@ -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;
}

View file

@ -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);
}

View file

@ -17,27 +17,29 @@
</div>
</body>
<script>
async function loadLang() {
const text = document.getElementById("text-splashscreen");
if (window.navigator.onLine === false) {
text.innerHTML = await armcord.getLang("loading_screen_offline");
text.innerHTML = "You appear to be offline. Please connect to the internet and try again.";
} else {
text.innerHTML = await armcord.getLang("loading_screen_start");
text.innerHTML = "Starting ArmCord...";
if (window.armcord.version === "DEV") {
console.log("Running a development build of ArmCord. Skipping updater.");
} else {
const response = await fetch("https://armcord.xyz/latest.json");
const data = await response.json();
fetch("https://armcord.xyz/latest.json")
.then((response) => response.json())
.then((data) => {
if (data.version !== window.armcord.version) {
var elem = document.createElement("img");
elem.classList.add("logo");
elem.src = "https://armcord.smartfridge.space/update.webp";
document.body.prepend(elem);
document.getElementById("splashscreen-armcord").remove();
text.innerHTML = await armcord.getLang("loading_screen_update");
text.innerHTML =
"A new version of ArmCord is available. Please update to the latest version.";
} else {
console.log("ArmCord is up to date.");
}
});
}
setTimeout(() => {
window.armcordinternal.splashEnd();
@ -62,8 +64,5 @@
}
}, 5000);
}
}
loadLang();
</script>
</html>

View file

@ -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");
});

View file

@ -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();

View file

@ -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"));

26
src/preload/tabs.ts Normal file
View file

@ -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 = `<nav class="tabs">
<div id="tabs-controls-container">
<button class="tabs-buttons" onclick="armcord.openTab(1)">1</button>
<button class="tabs-buttons" onclick="armcord.openTab(2)">2</button>
<button class="tabs-buttons" onclick="armcord.openTab(3)">3</button>
<button class="tabs-buttons" onclick="armcord.openTab(4)">4</button>
<button class="tabs-buttons" onclick="armcord.openTab(5)">5</button>
<p class="experimental">Experimental</p>
</div>
</nav>`;
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"));
});
}

View file

@ -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", "");
}
});

View file

@ -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;
});

View file

@ -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

View file

@ -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([
{

View file

@ -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;
}

View file

@ -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,