Compare commits

...

5 commits

Author SHA1 Message Date
dependabot[bot]
b514df1f01
Bump @types/node from 17.0.45 to 18.7.13
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.45 to 18.7.13.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-25 14:12:00 +00:00
smartfridge
75276dee90 Update Electron 2022-08-25 16:10:26 +02:00
smartfridge
99417c3d29 Add tray icon ping icon 2022-08-25 14:57:41 +02:00
Hugel
934e56bdb0
Translated using Weblate (Chinese (Simplified))
Currently translated at 12.9% (7 of 54 strings)

Translation: ArmCord/ArmCord
Translate-URL: https://hosted.weblate.org/projects/armcord/armcord/zh_Hans/
2022-08-25 06:21:10 +02:00
smartfridge
77b5455139 Add zoom controls back and open settings 2022-08-24 17:27:44 +02:00
18 changed files with 226 additions and 79 deletions

View file

@ -4,18 +4,18 @@
"settings-patches": "Automatic Patches",
"settings-mod-desc4": "heavily work in progress, doesn't have a working UI.",
"loading_screen_update": "A new version of ArmCord is available. Please update to the latest version.",
"loading_screen_start": "Starting ArmCord…",
"loading_screen_start": "启动ArmCord…",
"setup_question1": "Select what kind of setup you want to perform:",
"loading_screen_offline": "You appear to be offline. Please connect to the Internet and try again.",
"setup_question1_answer1": "Express Setup",
"setup_question1_answer2": "Full Setup",
"setup_offline": "You appear to be offline. Please connect to the internet and restart ArmCord.",
"setup_question2": "Choose your Discord channel/instance:",
"settings-updater": "Check for updates",
"settings-updater": "检查更新",
"setup_question3": "Should ArmCord handle client mods installation?",
"yes": "Yes",
"no": "No",
"next": "Next",
"yes": "是的",
"no": "不是",
"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",
@ -52,5 +52,5 @@
"settings-themesFolder": "Open themes folder",
"settings-storageFolder": "Open storage folder",
"settings-none": "None",
"settings-save": "Save Settings"
"settings-save": "保存设置"
}

BIN
assets/ping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

View file

@ -26,15 +26,15 @@
},
"homepage": "https://github.com/armcord/armcord#readme",
"devDependencies": {
"@types/node": "^17.0.42",
"@types/node": "^18.7.13",
"@types/ws": "^8.5.3",
"chalk-cli": "^5.0.0",
"copyfiles": "^2.4.1",
"electron": "^19.0.8",
"electron": "^20.1.0",
"electron-builder": "^23.0.3",
"husky": "^8.0.1",
"prettier": "^2.7.0",
"typescript": "^4.7.3",
"chalk-cli": "^5.0.0"
"typescript": "^4.7.3"
},
"dependencies": {
"electron-context-menu": "github:ArmCord/electron-context-menu",

View file

@ -254,36 +254,3 @@ select {
white-space: nowrap;
outline: none !important;
}
.acTheme {
height: 15em !important;
}
.acCSP {
height: 10em !important;
}
.acPatches {
height: 10em !important;
}
.acWebsocket {
height: 10em !important;
}
.acMobileMode {
height: 11em !important;
}
.acAltPaste {
height: 11em !important;
}
.acChannel {
height: 21em !important;
}
.acClientMod {
height: 18em !important;
}
.acCordwood {
height: 8em !important;
}
.acPrfmMode {
height: 10em !important;
}
.acTray {
height: 8em !important;
}

View file

@ -0,0 +1,33 @@
.acTheme {
height: 15em !important;
}
.acCSP {
height: 10em !important;
}
.acPatches {
height: 10em !important;
}
.acWebsocket {
height: 10em !important;
}
.acMobileMode {
height: 11em !important;
}
.acAltPaste {
height: 11em !important;
}
.acChannel {
height: 21em !important;
}
.acClientMod {
height: 18em !important;
}
.acCordwood {
height: 8em !important;
}
.acPrfmMode {
height: 10em !important;
}
.acTray {
height: 8em !important;
}

View file

@ -122,7 +122,7 @@
mods: "cumcord",
inviteWebsocket: true,
mobileMode: false,
trayIcon: "ac_plug_colored",
trayIcon: "default",
performanceMode: "none"
});
setTimeout(() => window.armcordinternal.restart(), 5000);
@ -154,7 +154,7 @@
automaticPatches: false,
performanceMode: "none",
alternativePaste: false,
trayIcon: "ac_plug_colored",
trayIcon: "default",
mods: options.mod,
inviteWebsocket: true
});
@ -171,7 +171,7 @@
mods: "none",
alternativePaste: false,
performanceMode: "none",
trayIcon: "ac_plug_colored",
trayIcon: "default",
inviteWebsocket: true
});
setTimeout(() => window.armcordinternal.restart(), 500);

View file

@ -47,7 +47,7 @@
}
}
setTimeout(() => {
window.armcordinternal.splashEnd();
window.armcord.splashEnd();
switch (window.armcord.channel) {
case "stable":
window.location.replace("https://discord.com/app");

View file

@ -1,9 +1,19 @@
//ipc stuff
import {app, ipcMain, shell, desktopCapturer} from "electron";
import {app, ipcMain, shell, desktopCapturer,nativeImage} from "electron";
import {mainWindow} from "./window";
import {setConfigBulk, getVersion, getConfig, setLang, getLang, getWindowState, packageVersion} from "./utils";
import {
setConfigBulk,
getVersion,
getConfig,
setLang,
getLang,
getWindowState,
packageVersion, getDisplayVersion
} from "./utils";
import {customTitlebar} from "./main";
import {createSettingsWindow} from "./settings/main";
import os from "os";
import path from "path";
export function registerIpc() {
ipcMain.on("get-app-path", (event, arg) => {
event.reply("app-path", app.getAppPath());
@ -17,6 +27,21 @@ export function registerIpc() {
ipcMain.on("open-external-link", (event, href: string) => {
shell.openExternal(href);
});
ipcMain.on("setPing", (event, pingCount: number) => {
switch (os.platform()) {
case "linux" ?? "macos":
app.setBadgeCount(pingCount)
break;
case "win32":
if (pingCount > 0) {
var image = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/ping.png`))
mainWindow.setOverlayIcon(image, "badgeCount")
} else {
mainWindow.setOverlayIcon(null, "badgeCount")
}
break;
}
});
ipcMain.on("win-maximize", (event, arg) => {
mainWindow.maximize();
});
@ -44,10 +69,13 @@ export function registerIpc() {
ipcMain.on("get-app-version", (event) => {
event.returnValue = getVersion();
});
ipcMain.on("displayVersion", (event) => {
event.returnValue = getDisplayVersion();
});
ipcMain.on("get-package-version", (event) => {
event.returnValue = packageVersion;
});
ipcMain.on("splashEnd", async (event, arg) => {
ipcMain.on("splashEnd", async () => {
try {
var width = (await getWindowState("width")) ?? 800;
var height = (await getWindowState("height")) ?? 600;

View file

@ -1,6 +1,7 @@
import {Menu, app, clipboard, globalShortcut} from "electron";
import {mainWindow} from "./window";
import {getConfig} from "./utils";
import {createSettingsWindow} from "./settings/main";
function paste(contents: any) {
const contentTypes = clipboard.availableFormats().toString();
@ -51,6 +52,20 @@ export async function setMenu() {
mainWindow.webContents.openDevTools();
}
},
{
label: "Open settings",
accelerator: "CmdOrCtrl+Shift+'",
click: function () {
createSettingsWindow();
}
},
{
label: "Reload",
accelerator: "CmdOrCtrl+R",
click: function () {
mainWindow.reload()
}
},
{
label: "Quit",
accelerator: "CmdOrCtrl+Q",
@ -77,6 +92,13 @@ export async function setMenu() {
},
{label: "Select All", accelerator: "CmdOrCtrl+A", role: "selectAll"}
]
},
{
label: "Zoom",
submenu: [
{label: "Zoom in", accelerator: "CmdOrCtrl+Plus", role: "zoomIn"},
{label: "Zoom out", accelerator: "CmdOrCtrl+-", role: "zoomOut"},
]
}
];

View file

@ -16,6 +16,8 @@ contextBridge.exposeInMainWorld("armcord", {
electron: process.versions.electron,
channel: ipcRenderer.sendSync("channel"),
setLang: (lang: string) => ipcRenderer.send("setLang", lang),
setPingCount: (pingCount: number) => ipcRenderer.send("setPing", pingCount),
setTrayIcon: (favicon: string) => ipcRenderer.send("sendTrayIcon", favicon),
getLang: (toGet: string) =>
ipcRenderer.invoke("getLang", toGet).then((result) => {
return result;
@ -23,13 +25,13 @@ contextBridge.exposeInMainWorld("armcord", {
version: ipcRenderer.sendSync("get-app-version", "app-version"),
packageVersion: ipcRenderer.sendSync("get-package-version", "app-version"),
getDisplayMediaSelector: getDisplayMediaSelector,
splashEnd: () => ipcRenderer.send("splashEnd"),
openSettingsWindow: () => ipcRenderer.send("openSettingsWindow")
});
//to be only used inside armcord internal setup/splash etc
if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) {
contextBridge.exposeInMainWorld("armcordinternal", {
restart: () => ipcRenderer.send("restart"),
saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args),
splashEnd: () => ipcRenderer.send("splashEnd")
saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args)
});
}

View file

@ -7,7 +7,7 @@ import {injectHummusTitlebar, injectTitlebar} from "./titlebar";
import {sleep, addStyle, injectJS, addScript} from "../utils";
import {ipcRenderer} from "electron";
import {injectMobileStuff} from "./mobile";
var version = ipcRenderer.sendSync("get-app-version", "app-version");
var version = ipcRenderer.sendSync("displayVersion");
var channel = ipcRenderer.sendSync("channel");
async function updateLang() {
if (window.location.href.indexOf("setup.html") > -1) {

View file

@ -15,6 +15,23 @@
<div class="saveBar">
<button id="settings-save" class="center">Save Settings</button>
</div>
<div class="switch acTheme">
<select name="theme" id="theme" class="left dropdown">
<option value="default">Default</option>
<option value="native">Native</option>
</select>
<p class="header" id="settings-theme">ArmCord theme</p>
<p class="description">
ArmCord "themes" manage apps behaviour and looks.
<br />
<b>Default</b> - this is how ArmCord looks when you first launch it. It includes recreation of Discord's
custom titlebar and ArmCord specific styles injected into Discord.
<br />
<b>Native</b> - uses native titlebar of OS you're currently running (e.g Windows 7/10). Functions more
similar to actual Discord app on Linux.
</p>
</div>
<br />
<div class="switch acCSP">
<label class="header2">ArmCord CSP</label>
<input class="tgl tgl-light left" id="csp" type="checkbox" />
@ -107,7 +124,8 @@
<br />
<div class="switch acTray">
<select name="trayIcon" id="trayIcon" class="left dropdown">
<option value="ac_plug_colored">Default</option>
<option value="default">Default (Dynamic)</option>
<option value="ac_plug_colored">Plug colored</option>
<option value="dsc-tray">Discord Icon</option>
<option value="ac_white_plug">White Icon</option>
<option value="ac_black_plug">Black Icon</option>
@ -133,17 +151,10 @@
<script>
async function loadLang() {
document.getElementById("settings-save").innerHTML = await settings.getLang("settings-save");
document.getElementById("settings-mod").innerHTML = await settings.getLang("settings-mod");
document.getElementById("settings-channel").innerHTML = await settings.getLang("settings-channel");
document.getElementById("settings-invitewebsocket").innerHTML = await settings.getLang(
"settings-invitewebsocket"
);
document.getElementById("settings-patches").innerHTML = await settings.getLang("settings-patches");
document.getElementById("settings-tray").innerHTML = await settings.getLang("settings-tray");
document.getElementById("settings-mobileMode").innerHTML = await settings.getLang("settings-mobileMode");
document.getElementById("settings-theme").innerHTML = await settings.getLang("settings-theme");
//select stuff
document.getElementById("mod").options[3].text = await settings.getLang("settings-none");
document.getElementById("prfmMode").options[2].text = await settings.getLang("settings-none");
document.getElementById("prfmMode").options[1].text = await settings.getLang("settings-prfmMode-battery");
document.getElementById("prfmMode").options[0].text = await settings.getLang(
@ -158,18 +169,26 @@
async function loadSettings() {
document.getElementById("csp").checked = await settings.get("armcordCSP");
document.getElementById("tray").checked = await settings.get("minimizeToTray");
document.getElementById("websocket").checked = await settings.get("inviteWebsocket");
document.getElementById("alternativePaste").checked = await settings.get("alternativePaste");
document.getElementById("mobile").checked = await settings.get("mobileMode");
document.getElementById("patches").value = await settings.get("automaticPatches");
document.getElementById("mod").value = await settings.get("mods");
if ((await settings.get("mods")) == "cordwood") {
document.getElementById("cordwood").checked = true;
} else {
document.getElementById("cordwood").checked = false;
}
document.getElementById("channel").value = await settings.get("channel");
document.getElementById("theme").value = await settings.get("windowStyle");
document.getElementById("prfmMode").value = await settings.get("performanceMode");
document.getElementById("trayIcon").value = await settings.get("trayIcon");
}
loadSettings();
document.getElementById("settings-save").addEventListener("click", function () {
document.getElementById("settings-save").addEventListener("click", async function () {
var cordwood;
if (document.getElementById("cordwood").checked) {
cordwood = true;
} else {
cordwood = false;
}
settings.save({
windowStyle: document.getElementById("theme").value,
channel: document.getElementById("channel").value,
@ -177,22 +196,25 @@
minimizeToTray: document.getElementById("tray").checked,
alternativePaste: document.getElementById("alternativePaste").checked,
automaticPatches: document.getElementById("patches").checked,
mods: document.getElementById("mod").value,
mobileMode: document.getElementById("mobile").checked,
inviteWebsocket: document.getElementById("websocket").checked,
mods: cordwood,
mobileMode: await settings.get("mobileMode"),
inviteWebsocket: await settings.get("inviteWebsocket"),
performanceMode: document.getElementById("prfmMode").value,
trayIcon: document.getElementById("trayIcon").value,
doneSetup: true
});
});
document.getElementById("settings-pluginsFolder").addEventListener("click", function () {
document.getElementById("settings-pluginsFolder").addEventListener("click", async function () {
settings.openPluginsFolder();
await new Promise((r) => setTimeout(r, 2000));
});
document.getElementById("settings-themesFolder").addEventListener("click", function () {
document.getElementById("settings-themesFolder").addEventListener("click", async function () {
settings.openThemesFolder();
await new Promise((r) => setTimeout(r, 2000));
});
document.getElementById("settings-storageFolder").addEventListener("click", function () {
document.getElementById("settings-storageFolder").addEventListener("click", async function () {
settings.openStorageFolder();
await new Promise((r) => setTimeout(r, 2000));
});
document.getElementById("settings-copyDebugInfo").addEventListener("click", function () {
settings.copyDebugInfo();

View file

@ -1,5 +1,5 @@
import {BrowserWindow, shell, ipcMain, app, clipboard} from "electron";
import {getConfig, setConfigBulk, Settings, getLang, getVersion, getConfigLocation} from "../utils";
import {getConfig, setConfigBulk, Settings, getLang, getVersion, getConfigLocation, getLangName} from "../utils";
import path from "path";
import os from "os";
import fs from "fs";
@ -26,6 +26,7 @@ export function createSettingsWindow() {
frame: true,
autoHideMenuBar: true,
webPreferences: {
sandbox: false,
preload: path.join(__dirname, "preload.js")
}
});
@ -50,6 +51,9 @@ export function createSettingsWindow() {
ipcMain.on("openPluginsFolder", (event) => {
shell.openPath(pluginsPath);
});
ipcMain.on("getLangName", async (event) => {
event.returnValue = await getLangName();
});
ipcMain.handle("getSetting", (event, toGet: string) => {
return getConfig(toGet);
});

View file

@ -1,4 +1,7 @@
import {contextBridge, ipcRenderer} from "electron";
import * as path from "path";
import {addStyle} from "../utils";
import fs from "fs";
console.log("ArmCord Settings");
contextBridge.exposeInMainWorld("settings", {
@ -16,3 +19,7 @@ contextBridge.exposeInMainWorld("settings", {
openStorageFolder: () => ipcRenderer.send("openStorageFolder"),
copyDebugInfo: () => ipcRenderer.send("copyDebugInfo")
});
if (ipcRenderer.sendSync("getLangName") == "en-US") {
const cssPath = path.join(__dirname, "../", "/content/css/settingsEng.css");
addStyle(fs.readFileSync(cssPath, "utf8"));
}

View file

@ -159,7 +159,8 @@
<br />
<div class="switch acTray">
<select name="trayIcon" id="trayIcon" class="left dropdown">
<option value="ac_plug_colored">Default</option>
<option value="default">Default (dynamic)</option>
<option value="ac_plug_colored">Plug colored</option>
<option value="dsc-tray">Discord Icon</option>
<option value="ac_white_plug">White Icon</option>
<option value="ac_black_plug">Black Icon</option>

View file

@ -4,12 +4,15 @@ import {mainWindow} from "./window";
import {getConfig, getConfigLocation, setWindowState} from "./utils";
import * as path from "path";
import {createSettingsWindow} from "./settings/main";
let tray: any = null;
export let tray: any = null;
app.whenReady().then(async () => {
let finishedSetup = await getConfig("doneSetup");
var trayIcon = (await getConfig("trayIcon")) ?? "ac_plug_colored";
if (trayIcon = "default") {
trayIcon = "dsc-tray"
}
let trayPath = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/${trayIcon}.png`));
if (process.platform === "darwin" && trayPath.getSize().height > 22) trayPath = trayIcon.resize({height: 22});
if (process.platform === "darwin" && trayPath.getSize().height > 22) trayPath = trayPath.resize({height: 22});
if ((await getConfig("windowStyle")) == "basic") {
var clientName = (await getConfig("clientName")) ?? "ArmCord";
tray = new Tray(trayPath);

View file

@ -45,7 +45,7 @@ export function setup() {
skipSplash: false,
inviteWebsocket: true,
mobileMode: false,
trayIcon: "ac_plug_colored",
trayIcon: "default",
doneSetup: false
};
setConfigBulk({
@ -57,6 +57,9 @@ export function setup() {
export var packageVersion = require("../package.json").version;
export function getVersion() {
return packageVersion;
}
export function getDisplayVersion() {
//Checks if the app version # has 4 sections (3.1.0.0) instead of 3 (3.1.0) / Shitty way to check if Kernel Mod is installed
if ((app.getVersion() == packageVersion) == false) {
return `${packageVersion} [Kernel Mod]`;
@ -157,7 +160,25 @@ export async function getLang(object: string) {
return parsed[object];
}
}
export async function getLangName() {
if (language == undefined) {
try {
const userDataPath = app.getPath("userData");
const storagePath = path.join(userDataPath, "/storage/");
const langConfigFile = storagePath + "lang.json";
let rawdata = fs.readFileSync(langConfigFile, "utf-8");
let parsed = JSON.parse(rawdata);
language = parsed["lang"];
} catch (e) {
console.log("Language config file doesn't exist. Fallback to English.");
language = "en-US";
}
}
if (language.length == 2) {
language = language + "-" + language.toUpperCase();
}
return language;
}
//ArmCord Window State manager
export interface WindowState {
width: number;

View file

@ -2,15 +2,24 @@
// 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, dialog, nativeImage} from "electron";
import path from "path";
import {checkIfConfigIsBroken, firstRun, getConfig, contentPath, setConfig, setLang, setWindowState} from "./utils";
import {
checkIfConfigIsBroken,
firstRun,
getConfig,
contentPath,
setConfig,
setLang,
setWindowState
} from "./utils";
import {registerIpc} from "./ipc";
import {setMenu} from "./menu";
import * as fs from "fs";
import startServer from "./socket";
import contextMenu from "electron-context-menu";
import os from "os";
import {tray} from "./tray";
export var icon: string;
export let mainWindow: BrowserWindow;
export let inviteWindow: BrowserWindow;
@ -78,6 +87,31 @@ async function doAfterDefiningTheWindow() {
if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true});
return callback({});
});
if (await getConfig("trayIcon") == "default") {
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()
`)
console.log(app.getPath("temp"))
var buf = new Buffer(faviconBase64.replace(/^data:image\/\w+;base64,/, ""), 'base64');
fs.writeFileSync(path.join(app.getPath("temp"), "/", "tray.png"), buf, "utf-8");
let trayPath = nativeImage.createFromPath(path.join(app.getPath("temp"), "/", "tray.png"));
if (process.platform === "darwin" && trayPath.getSize().height > 22) trayPath = trayPath.resize({height: 22});
tray.setImage(trayPath)
})
}
const userDataPath = app.getPath("userData");
const themesFolder = userDataPath + "/themes/";
if (!fs.existsSync(themesFolder)) {
@ -173,6 +207,7 @@ export function createCustomWindow() {
frame: false,
autoHideMenuBar: true,
webPreferences: {
sandbox: false,
preload: path.join(__dirname, "preload/preload.js"),
spellcheck: true
}
@ -189,6 +224,7 @@ export function createNativeWindow() {
frame: true,
autoHideMenuBar: true,
webPreferences: {
sandbox: false,
preload: path.join(__dirname, "preload/preload.js"),
spellcheck: true
}
@ -206,6 +242,7 @@ export function createInviteWindow() {
frame: true,
autoHideMenuBar: true,
webPreferences: {
sandbox: false,
spellcheck: true
}
});