mirror of
				https://github.com/smartfrigde/armcord.git
				synced 2024-08-14 23:56:58 +00:00 
			
		
		
		
	implement keybind maker ui
This commit is contained in:
		
							parent
							
								
									c15eee11c4
								
							
						
					
					
						commit
						d066c9ebc1
					
				
					 8 changed files with 493 additions and 8 deletions
				
			
		|  | @ -1,5 +1,6 @@ | |||
| import {BrowserWindow, app, shell} from "electron"; | ||||
| import {BrowserWindow, app, globalShortcut, ipcMain, shell} from "electron"; | ||||
| import path from "path"; | ||||
| import {getConfig, registerGlobalKeybinds, setConfig} from "../utils"; | ||||
| let keybindWindow: BrowserWindow; | ||||
| let instance = 0; | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ export function createKeybindWindow(): void { | |||
|         } | ||||
|     } else { | ||||
|         keybindWindow = new BrowserWindow({ | ||||
|             width: 660, | ||||
|             width: 720, | ||||
|             height: 670, | ||||
|             title: `ArmCord Global Keybinds Maker`, | ||||
|             darkTheme: true, | ||||
|  | @ -26,12 +27,40 @@ export function createKeybindWindow(): void { | |||
|             } | ||||
|         }); | ||||
|         async function makerLoadPage(): Promise<void> { | ||||
|             globalShortcut.unregisterAll(); | ||||
|             keybindWindow.loadURL(`file://${__dirname}/maker.html`); | ||||
|         } | ||||
|         keybindWindow.webContents.setWindowOpenHandler(({url}) => { | ||||
|             shell.openExternal(url); | ||||
|             return {action: "deny"}; | ||||
|         }); | ||||
|         ipcMain.on("addKeybind", async (_event, keybind) => { | ||||
|             var keybinds = await getConfig("keybinds"); | ||||
|             keybind.replace(" ", "Space"); | ||||
|             if (keybinds.includes(keybind)) return; | ||||
|             keybinds.push(keybind); | ||||
|             await setConfig("keybinds", keybinds); | ||||
|             keybindWindow.webContents.reload(); | ||||
|         }); | ||||
|         ipcMain.on("removeKeybind", async (_event, keybind) => { | ||||
|             var keybinds = await getConfig("keybinds"); | ||||
|             const index = keybinds.indexOf(keybind); | ||||
|             keybinds.splice(index, 1); | ||||
|             await setConfig("keybinds", keybinds); | ||||
|             keybindWindow.webContents.reload(); | ||||
|         }); | ||||
|         keybindWindow.webContents.on("did-finish-load", async () => { | ||||
|             for (const keybind of await getConfig("keybinds")) { | ||||
|                 console.log(keybind); | ||||
|                 keybindWindow.webContents.send("keybindCombo", keybind); | ||||
|             } | ||||
|         }); | ||||
|         keybindWindow.on("close", () => { | ||||
|             registerGlobalKeybinds(); | ||||
|         }); | ||||
|         makerLoadPage(); | ||||
|         keybindWindow.on("close", () => { | ||||
|             instance = 0; | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,392 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <style> | ||||
|             :root { | ||||
|                 --background-secondary: #2f3136; | ||||
|                 --background-secondary-alt: #292b2f; | ||||
|                 --background-floating: #18191c; | ||||
|                 --background-modifier-hover: rgba(106, 116, 128, 0.16); | ||||
|                 --brand-experiment: #7289da; | ||||
|                 --brand-experiment-560: #5c6fb1; | ||||
|                 --brand-experiment-600: #4e5d94; | ||||
|                 --interactive-normal: #b9bbbe; | ||||
|                 --interactive-hover: #dcddde; | ||||
|                 --text-muted: #72767d; | ||||
|                 --font-primary: "Whitney"; | ||||
|                 --header-primary: #fff; | ||||
|             } | ||||
| 
 | ||||
|             html { | ||||
|                 font-size: 22px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 padding: 1rem; | ||||
|                 background: var(--background-secondary); | ||||
|             } | ||||
| 
 | ||||
|             @font-face { | ||||
|                 font-family: Whitney; | ||||
|                 font-weight: 200; | ||||
|                 font-style: normal; | ||||
|                 src: url(https://armcord.xyz/whitney_400.woff) format("woff"); | ||||
|             } | ||||
| 
 | ||||
|             * { | ||||
|                 font-family: "Whitney", sans-serif; | ||||
|                 box-sizing: border-box; | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 cursor: default; | ||||
|             } | ||||
| 
 | ||||
|             .card { | ||||
|                 background-color: var(--background-floating); | ||||
|                 color: white; | ||||
|                 padding: 1rem; | ||||
|                 border-color: var(--background-floating); | ||||
|                 border-style: solid; | ||||
|                 width: 100%; | ||||
|                 border-radius: 10px; | ||||
|             } | ||||
| 
 | ||||
|             .cards { | ||||
|                 max-width: 1200px; | ||||
|                 margin: 0 auto; | ||||
|                 display: grid; | ||||
|                 grid-gap: 1rem; | ||||
|                 justify-content: space-evenly; | ||||
|             } | ||||
| 
 | ||||
|             /* Screen larger than 600px? 2 column */ | ||||
|             @media (min-width: 600px) { | ||||
|                 .cards { | ||||
|                     grid-template-columns: repeat(2, 1fr); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             /* Screen larger than 900px? 3 columns */ | ||||
|             @media (min-width: 900px) { | ||||
|                 .cards { | ||||
|                     grid-template-columns: repeat(3, 1fr); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             .flex-box { | ||||
|                 display: flex; | ||||
|                 justify-content: space-between; | ||||
|             } | ||||
| 
 | ||||
|             /* switches */ | ||||
|             .tgl { | ||||
|                 display: none; | ||||
|             } | ||||
| 
 | ||||
|             .tgl::-moz-selection, | ||||
|             .tgl:after::-moz-selection, | ||||
|             .tgl:before::-moz-selection, | ||||
|             .tgl *::-moz-selection, | ||||
|             .tgl *:after::-moz-selection, | ||||
|             .tgl *:before::-moz-selection, | ||||
|             .tgl + .tgl-btn::-moz-selection { | ||||
|                 background: none; | ||||
|             } | ||||
| 
 | ||||
|             .tgl::selection, | ||||
|             .tgl:after::selection, | ||||
|             .tgl:before::selection, | ||||
|             .tgl *::selection, | ||||
|             .tgl *:after::selection, | ||||
|             .tgl *:before::selection, | ||||
|             .tgl + .tgl-btn::selection { | ||||
|                 background: none; | ||||
|             } | ||||
| 
 | ||||
|             .tgl + .tgl-btn { | ||||
|                 outline: 0; | ||||
|                 display: block; | ||||
|                 width: 3em; | ||||
|                 position: relative; | ||||
|                 cursor: pointer; | ||||
|                 -webkit-user-select: none; | ||||
|                 -moz-user-select: none; | ||||
|                 -ms-user-select: none; | ||||
|                 user-select: none; | ||||
|             } | ||||
| 
 | ||||
|             .tgl + .tgl-btn:after, | ||||
|             .tgl + .tgl-btn:before { | ||||
|                 position: relative; | ||||
|                 display: block; | ||||
|                 content: ""; | ||||
|                 width: 50%; | ||||
|                 height: 100%; | ||||
|             } | ||||
| 
 | ||||
|             .tgl + .tgl-btn:after { | ||||
|                 left: 1px; | ||||
|             } | ||||
| 
 | ||||
|             .tgl + .tgl-btn:before { | ||||
|                 display: none; | ||||
|             } | ||||
| 
 | ||||
|             .tgl:checked + .tgl-btn:after { | ||||
|                 left: 56%; | ||||
|             } | ||||
| 
 | ||||
|             .tgl-light + .tgl-btn { | ||||
|                 background: var(--text-muted); | ||||
|                 border-radius: 25px; | ||||
|                 padding: 4px; | ||||
|                 transition: all 0.4s ease; | ||||
|             } | ||||
| 
 | ||||
|             .tgl-light + .tgl-btn:after { | ||||
|                 border-radius: 50px; | ||||
|                 position: relative; | ||||
|                 top: 50%; | ||||
|                 transform: translateY(-50%); | ||||
|                 width: 24px; | ||||
|                 height: 24px; | ||||
|                 background: rgb(255, 255, 255); | ||||
|                 transition: all 0.2s ease; | ||||
|             } | ||||
| 
 | ||||
|             .tgl-light:checked + .tgl-btn { | ||||
|                 background: var(--brand-experiment); | ||||
|             } | ||||
| 
 | ||||
|             input[type="text"], | ||||
|             select { | ||||
|                 width: 100%; | ||||
|                 padding: 12px 20px; | ||||
|                 margin: 8px 0; | ||||
|                 display: inline-block; | ||||
|                 border: 1px solid #72767d; | ||||
|                 background-color: #46484d; | ||||
|                 color: white; | ||||
|                 border-radius: 4px; | ||||
|                 box-sizing: border-box; | ||||
|             } | ||||
| 
 | ||||
|             #download { | ||||
|                 margin-top: 3px; | ||||
|                 height: 50px; | ||||
|                 vertical-align: middle; | ||||
|                 text-align: right; | ||||
|                 z-index: 99; | ||||
|             } | ||||
| 
 | ||||
|             /* The Modal (background) */ | ||||
|             .modal { | ||||
|                 display: none; | ||||
|                 /* Hidden by default */ | ||||
|                 position: fixed; | ||||
|                 /* Stay in place */ | ||||
|                 z-index: 1; | ||||
|                 /* Sit on top */ | ||||
|                 padding-top: 100px; | ||||
|                 /* Location of the box */ | ||||
|                 background-color: var(--background-secondary); | ||||
|                 left: 0; | ||||
|                 top: 0; | ||||
|                 width: 100%; | ||||
|                 /* Full width */ | ||||
|                 height: 100%; | ||||
|                 /* Full height */ | ||||
|                 overflow: auto; | ||||
|                 /* Enable scroll if needed */ | ||||
|                 background-color: rgb(0, 0, 0); | ||||
|                 /* Fallback color */ | ||||
|                 background-color: rgba(0, 0, 0, 0.4); | ||||
|                 /* Black w/ opacity */ | ||||
|             } | ||||
| 
 | ||||
|             /* Modal Content */ | ||||
|             .modal-content { | ||||
|                 position: relative; | ||||
|                 margin: auto; | ||||
|                 padding: 1rem; | ||||
|                 background-color: var(--background-secondary); | ||||
|                 border-color: var(--background-floating); | ||||
|                 border-style: solid; | ||||
|                 border-radius: 10px; | ||||
|                 width: 80%; | ||||
|                 box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); | ||||
|                 -webkit-animation-name: animatetop; | ||||
|                 -webkit-animation-duration: 0.4s; | ||||
|                 animation-name: animatetop; | ||||
|                 animation-duration: 0.4s; | ||||
|             } | ||||
| 
 | ||||
|             /* Add Animation */ | ||||
|             @-webkit-keyframes animatetop { | ||||
|                 from { | ||||
|                     top: -300px; | ||||
|                     opacity: 0; | ||||
|                 } | ||||
| 
 | ||||
|                 to { | ||||
|                     top: 0; | ||||
|                     opacity: 1; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             @keyframes animatetop { | ||||
|                 from { | ||||
|                     top: -300px; | ||||
|                     opacity: 0; | ||||
|                 } | ||||
| 
 | ||||
|                 to { | ||||
|                     top: 0; | ||||
|                     opacity: 1; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             /* The Close Button */ | ||||
|             .close { | ||||
|                 color: white; | ||||
|                 float: right; | ||||
|                 font-size: 28px; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
| 
 | ||||
|             .close:hover, | ||||
|             .close:focus { | ||||
|                 color: red; | ||||
|                 text-decoration: none; | ||||
|                 cursor: pointer; | ||||
|             } | ||||
| 
 | ||||
|             .modal-header { | ||||
|                 padding: 2px 16px; | ||||
|                 color: white; | ||||
|             } | ||||
| 
 | ||||
|             .modal-body { | ||||
|                 padding: 2px 16px; | ||||
|                 color: white; | ||||
|             } | ||||
| 
 | ||||
|             .modal-footer { | ||||
|                 padding: 2px 16px; | ||||
|                 color: white; | ||||
|             } | ||||
|             a.button { | ||||
|                 color: var(--brand-experiment-560); | ||||
|             } | ||||
|             .button { | ||||
|                 margin-right: 10px; | ||||
|             } | ||||
|             img.themeInfoIcon { | ||||
|                 height: 30px; | ||||
|                 position: relative; | ||||
|                 top: 5px; | ||||
|             } | ||||
|             .addKbd { | ||||
|                 width: 100%; | ||||
|                 height: 30px; | ||||
|                 color: var(--header-primary); | ||||
|                 border-radius: 8px; | ||||
|                 border: none; | ||||
|                 font-weight: bold; | ||||
|                 background-color: var(--brand-experiment); | ||||
|             } | ||||
|             .addKbd:hover { | ||||
|                 background-color: var(--brand-experiment-560); | ||||
|                 color: var(--interactive-hover); | ||||
|             } | ||||
|             kbd { | ||||
|                 display: inline-block; | ||||
|                 border: 1px solid #ccc; | ||||
|                 border-radius: 4px; | ||||
|                 padding: 0.1em 0.5em; | ||||
|                 position: relative; | ||||
| 
 | ||||
|                 margin: 0 0.2em; | ||||
|                 box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px var(--background-floating) inset; | ||||
|                 background-color: #41434a; | ||||
|                 color: var(--header-primary); | ||||
|             } | ||||
|             #output { | ||||
|                 margin-top: 10px; | ||||
|                 width: 100%; | ||||
|                 margin-bottom: 10px; | ||||
|                 min-height: 50px; | ||||
|                 background-color: var(--background-secondary-alt); | ||||
|                 border-radius: 8px; | ||||
|                 border: 3px dashed var(--interactive-normal); | ||||
|             } | ||||
|             .preview { | ||||
|                 top: 5px; | ||||
|             } | ||||
|             #warning { | ||||
|                 color: yellow; | ||||
|                 text-align: center; | ||||
|                 font-size: 20px; | ||||
|                 margin-bottom: 20px; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <body> | ||||
|         <p id="warning">Global keybinds are disabled while this window is open.</p> | ||||
|         <button class="addKbd" id="startButton">Add a global keybind</button> | ||||
|         <div id="output"></div> | ||||
|         <div class="cards" id="cardBox"></div> | ||||
|         <script> | ||||
|             let captureStarted = false; | ||||
| 
 | ||||
|             const outputElement = document.getElementById("output"); | ||||
| 
 | ||||
|             function startCapture() { | ||||
|                 if (captureStarted) return; | ||||
|                 let keys = ""; | ||||
|                 captureStarted = true; | ||||
|                 outputElement.innerHTML = ""; | ||||
| 
 | ||||
|                 const kbdElement = document.createElement("div"); | ||||
|                 outputElement.appendChild(kbdElement); | ||||
| 
 | ||||
|                 let capturedKeystrokes = ""; | ||||
|                 const startTime = Date.now(); | ||||
| 
 | ||||
|                 function displayKeystrokes() { | ||||
|                     const currentTime = Date.now(); | ||||
|                     const elapsedSeconds = Math.floor((currentTime - startTime) / 1000); | ||||
| 
 | ||||
|                     if (elapsedSeconds >= 5) { | ||||
|                         captureStarted = false; | ||||
|                         //remove last character from keys | ||||
|                         manager.add(keys.slice(0, -1)); | ||||
|                         outputElement.innerHTML = ""; | ||||
|                         keys = ""; | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     kbdElement.innerHTML = capturedKeystrokes; | ||||
|                     requestAnimationFrame(displayKeystrokes); | ||||
|                 } | ||||
| 
 | ||||
|                 function handleKeystroke(event) { | ||||
|                     const key = event.key; | ||||
|                     if (keys.includes(key)) { | ||||
|                         console.log("already in array"); | ||||
|                     } else { | ||||
|                         keys += key + "+"; //electron friendly format | ||||
|                         capturedKeystrokes += `<kbd class="preview">${key}</kbd>`; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 document.addEventListener("keydown", handleKeystroke); | ||||
|                 displayKeystrokes(); | ||||
|             } | ||||
| 
 | ||||
|             const startButton = document.getElementById("startButton"); | ||||
|             startButton.addEventListener("click", startCapture); | ||||
|         </script> | ||||
|     </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,36 @@ | |||
| import {contextBridge, ipcRenderer} from "electron"; | ||||
| import {sleep} from "../utils"; | ||||
| contextBridge.exposeInMainWorld("manager", { | ||||
|     add: (keybindName: string) => ipcRenderer.send("addKeybind", keybindName), | ||||
|     remove: (keybindName: string) => ipcRenderer.send("removeKeybind", keybindName) | ||||
| }); | ||||
| ipcRenderer.on("keybindCombo", (_event, keybindName) => { | ||||
|     sleep(1000); | ||||
|     console.log(keybindName); | ||||
|     let e = document.getElementById("cardBox"); | ||||
|     var keys = keybindName.split("+"); | ||||
|     var id = keybindName.replace("+", ""); | ||||
|     var html = ""; | ||||
|     for (var key in keys) { | ||||
|         html += `<kbd>${keys[key]}</kbd>`; | ||||
|     } | ||||
|     e?.insertAdjacentHTML( | ||||
|         "beforeend", | ||||
|         ` | ||||
|         <div class="card"> | ||||
|                 <div class="flex-box"> | ||||
|                     ${html} | ||||
|                     <input id="${id}" class="tgl tgl-light left" type="checkbox" /> | ||||
|                     <label class="tgl-btn left" for="${id}"></label> | ||||
|                 </div> | ||||
|             </div> | ||||
|         ` | ||||
|     ); | ||||
|     (document.getElementById(id) as HTMLInputElement)!.checked = true; | ||||
|     (document.getElementById(id) as HTMLInputElement)!.addEventListener("input", function (evt) { | ||||
|         ipcRenderer.send("removeKeybind", keybindName); | ||||
|     }); | ||||
| }); | ||||
| sleep(3000).then(() => { | ||||
|     document.getElementById("warning")!.style.display = "none"; | ||||
| }); | ||||
|  | @ -22,6 +22,7 @@ import path from "path"; | |||
| import {createTManagerWindow} from "./themeManager/main"; | ||||
| import {createSplashWindow} from "./splash/main"; | ||||
| import {createSetupWindow} from "./setup/main"; | ||||
| import {createKeybindWindow} from "./keybindMaker/main"; | ||||
| export let iconPath: string; | ||||
| export let settings: any; | ||||
| export let customTitlebar: boolean; | ||||
|  | @ -46,6 +47,10 @@ async function args(): Promise<void> { | |||
|         app.whenReady().then(async () => { | ||||
|             createTManagerWindow(); | ||||
|         }); | ||||
|     } else if (args == "keybinds") { | ||||
|         app.whenReady().then(async () => { | ||||
|             createKeybindWindow(); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| args(); // i want my top level awaits
 | ||||
|  |  | |||
							
								
								
									
										26
									
								
								src/utils.ts
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								src/utils.ts
									
										
									
									
									
								
							|  | @ -1,5 +1,5 @@ | |||
| import * as fs from "fs"; | ||||
| import {app, dialog} from "electron"; | ||||
| import {app, dialog, globalShortcut} from "electron"; | ||||
| import path from "path"; | ||||
| import fetch from "cross-fetch"; | ||||
| import extract from "extract-zip"; | ||||
|  | @ -44,6 +44,7 @@ export function setup(): void { | |||
|         armcordCSP: true, | ||||
|         minimizeToTray: true, | ||||
|         automaticPatches: false, | ||||
|         keybinds: [], | ||||
|         alternativePaste: false, | ||||
|         mods: "none", | ||||
|         spellcheck: true, | ||||
|  | @ -244,7 +245,6 @@ export interface Settings { | |||
|     // Only used for external url warning dialog.
 | ||||
|     ignoreProtocolWarning?: boolean; | ||||
|     customIcon: string; | ||||
| 
 | ||||
|     windowStyle: string; | ||||
|     channel: string; | ||||
|     armcordCSP: boolean; | ||||
|  | @ -260,6 +260,7 @@ export interface Settings { | |||
|     startMinimized: boolean; | ||||
|     useLegacyCapturer: boolean; | ||||
|     tray: boolean; | ||||
|     keybinds: Array<string>; | ||||
|     inviteWebsocket: boolean; | ||||
|     disableAutogain: boolean; | ||||
|     trayIcon: string; | ||||
|  | @ -285,7 +286,17 @@ export async function setConfig<K extends keyof Settings>(object: K, toSet: Sett | |||
|     fs.writeFileSync(getConfigLocation(), toSave, "utf-8"); | ||||
| } | ||||
| export async function setConfigBulk(object: Settings): Promise<void> { | ||||
|     let toSave = JSON.stringify(object, null, 4); | ||||
|     let existingData = {}; | ||||
|     try { | ||||
|         const existingDataBuffer = fs.readFileSync(getConfigLocation(), "utf-8"); | ||||
|         existingData = JSON.parse(existingDataBuffer.toString()); | ||||
|     } catch (error) { | ||||
|         // Ignore errors when the file doesn't exist or parsing fails
 | ||||
|     } | ||||
|     // Merge the existing data with the new data
 | ||||
|     const mergedData = {...existingData, ...object}; | ||||
|     // Write the merged data back to the file
 | ||||
|     const toSave = JSON.stringify(mergedData, null, 4); | ||||
|     fs.writeFileSync(getConfigLocation(), toSave, "utf-8"); | ||||
| } | ||||
| export async function checkIfConfigExists(): Promise<void> { | ||||
|  | @ -389,3 +400,12 @@ export async function installModLoader(): Promise<void> { | |||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export async function registerGlobalKeybinds() { | ||||
|     const keybinds = await getConfig("keybinds"); | ||||
|     keybinds.forEach((keybind) => { | ||||
|         globalShortcut.register(keybind, () => { | ||||
|             console.log(keybind); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import { | |||
|     getConfig, | ||||
|     getWindowState, | ||||
|     modInstallState, | ||||
|     registerGlobalKeybinds, | ||||
|     setConfig, | ||||
|     setLang, | ||||
|     setWindowState, | ||||
|  | @ -198,6 +199,7 @@ async function doAfterDefiningTheWindow(): Promise<void> { | |||
|     if (!fs.existsSync(`${userDataPath}/disabled.txt`)) { | ||||
|         fs.writeFileSync(path.join(userDataPath, "/disabled.txt"), ""); | ||||
|     } | ||||
|     registerGlobalKeybinds(); | ||||
|     mainWindow.webContents.on("did-finish-load", () => { | ||||
|         fs.readdirSync(themesFolder).forEach((file) => { | ||||
|             try { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue