From 9fdb774b5c8f8c2749bdec25d56258b8053e3969 Mon Sep 17 00:00:00 2001 From: Arne van Iterson Date: Thu, 18 Jun 2020 19:23:07 +0200 Subject: [PATCH] Improved 3D view and UI Added random skins WIP: Skin upload and reset --- css/index.css | 29 ++++++- css/index.css.map | 2 +- css/index.scss | 18 ++++- data/data.json | 2 +- html/auth.hbs | 33 +++++--- html/main.hbs | 28 +++++-- html/skin_current.hbs | 21 +++-- html/skin_random.hbs | 22 +++++- html/skin_upload.hbs | 31 ++++++-- main.js | 2 +- src/auth.js | 2 +- src/main.js | 8 +- src/skin.js | 174 +++++++++++++++++++++++++++--------------- 13 files changed, 264 insertions(+), 108 deletions(-) diff --git a/css/index.css b/css/index.css index 1f13163..c8895bf 100644 --- a/css/index.css +++ b/css/index.css @@ -11,6 +11,15 @@ body header h3 { margin: 0; } +body div.content { + display: -ms-grid; + display: grid; + -ms-grid-columns: 50% 50%; + grid-template-columns: 50% 50%; + grid-template-areas: 'message message' 'left right'; + width: 100%; +} + body div.content form label { font-size: small; } @@ -25,10 +34,14 @@ body div.content button { } body div.content .message { - min-width: 80%; + -ms-grid-row: 1; + -ms-grid-column: 1; + -ms-grid-column-span: 2; + grid-area: message; + width: calc(100% - 22px); height: auto; margin: 5px auto; - padding: 5px; + padding: 5px 10px 5px 10px; font-size: small; color: white; } @@ -48,6 +61,18 @@ body div.content .message.success { background: rgba(0, 255, 0, 0.5); } +body div.content div.left { + -ms-grid-row: 2; + -ms-grid-column: 1; + grid-area: left; +} + +body div.content div.right { + -ms-grid-row: 2; + -ms-grid-column: 2; + grid-area: right; +} + body div.content img.skin { width: 60%; padding: 0 1em 1em 1em; diff --git a/css/index.css.map b/css/index.css.map index 777de1a..4e40bf1 100644 --- a/css/index.css.map +++ b/css/index.css.map @@ -1,6 +1,6 @@ { "version": 3, - "mappings": "AAAA,AAAA,IAAI,CAAC;EACD,WAAW,EAAE,4BAA4B;EACzC,UAAU,EAAE,MAAM;CAiErB;;AAnED,AAIQ,IAJJ,CAGA,MAAM,CACF,EAAE,CAAC;EACC,aAAa,EAAE,CAAC;CACnB;;AANT,AAOQ,IAPJ,CAGA,MAAM,CAIF,EAAE,CAAC;EACC,MAAM,EAAE,CAAC;CACZ;;AATT,AAaY,IAbR,CAWA,GAAG,AAAA,QAAQ,CACP,IAAI,CACA,KAAK,CAAC;EACF,SAAS,EAAE,KAAK;CACnB;;AAfb,AAiBQ,IAjBJ,CAWA,GAAG,AAAA,QAAQ,CAMP,KAAK,EAjBb,IAAI,CAWA,GAAG,AAAA,QAAQ,CAMA,MAAM,CAAC;EACV,MAAM,EAAE,KAAK;EACb,OAAO,EAAE,MAAM;CAClB;;AApBT,AAqBQ,IArBJ,CAWA,GAAG,AAAA,QAAQ,CAUP,MAAM,CAAC;EACH,KAAK,EAAE,GAAG;CACb;;AAvBT,AAwBQ,IAxBJ,CAWA,GAAG,AAAA,QAAQ,CAaP,QAAQ,CAAC;EACL,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,QAAQ;EAChB,OAAO,EAAE,GAAG;EACZ,SAAS,EAAE,KAAK;EAChB,KAAK,EAAE,KAAK;CAaf;;AA3CT,AA+BY,IA/BR,CAWA,GAAG,AAAA,QAAQ,CAaP,QAAQ,AAOH,KAAK,CAAC;EACH,MAAM,EAAE,cAAc;EACtB,UAAU,EAAE,oBAAoB;CACnC;;AAlCb,AAmCY,IAnCR,CAWA,GAAG,AAAA,QAAQ,CAaP,QAAQ,AAWH,QAAQ,CAAC;EACN,MAAM,EAAE,aAAa;EACrB,UAAU,EAAE,oBAAoB;CACnC;;AAtCb,AAuCY,IAvCR,CAWA,GAAG,AAAA,QAAQ,CAaP,QAAQ,AAeH,QAAQ,CAAC;EACN,MAAM,EAAE,eAAe;EACvB,UAAU,EAAE,oBAAoB;CACnC;;AA1Cb,AA4CQ,IA5CJ,CAWA,GAAG,AAAA,QAAQ,CAiCP,GAAG,AAAA,KAAK,CAAC;EACL,KAAK,EAAE,GAAG;EACV,OAAO,EAAE,aAAa;EACtB,eAAe,EAAE,SAAS;CAC7B;;AAhDT,AAkDI,IAlDA,AAkDC,KAAK,CAAC;EACH,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,IAAI;CACzB;;AArDL,AAsDI,IAtDA,AAsDC,MAAM,CAAC;EACJ,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,IAAI;CACnB;;AAzDL,AA0DI,IA1DA,CA0DA,MAAM,CAAC;EACH,SAAS,EAAE,KAAK;EAChB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,UAAU,EAAE,MAAM;CACrB", + "mappings": "AAAA,AAAA,IAAI,CAAC;EACD,WAAW,EAAE,4BAA4B;EACzC,UAAU,EAAE,MAAM;CA+ErB;;AAjFD,AAIQ,IAJJ,CAGA,MAAM,CACF,EAAE,CAAC;EACC,aAAa,EAAE,CAAC;CACnB;;AANT,AAOQ,IAPJ,CAGA,MAAM,CAIF,EAAE,CAAC;EACC,MAAM,EAAE,CAAC;CACZ;;AATT,AAWI,IAXA,CAWA,GAAG,AAAA,QAAQ,CAAC;EACR,OAAO,EAAE,IAAI;EACb,qBAAqB,EAAE,OAAO;EAC9B,mBAAmB,EACf,+BAEJ;EACA,KAAK,EAAE,IAAI;CA6Cd;;AA/DL,AAoBY,IApBR,CAWA,GAAG,AAAA,QAAQ,CAQP,IAAI,CACA,KAAK,CAAC;EACF,SAAS,EAAE,KAAK;CACnB;;AAtBb,AAwBQ,IAxBJ,CAWA,GAAG,AAAA,QAAQ,CAaP,KAAK,EAxBb,IAAI,CAWA,GAAG,AAAA,QAAQ,CAaA,MAAM,CAAC;EACV,MAAM,EAAE,KAAK;EACb,OAAO,EAAE,MAAM;CAClB;;AA3BT,AA4BQ,IA5BJ,CAWA,GAAG,AAAA,QAAQ,CAiBP,MAAM,CAAC;EACH,KAAK,EAAE,GAAG;CACb;;AA9BT,AA+BQ,IA/BJ,CAWA,GAAG,AAAA,QAAQ,CAoBP,QAAQ,CAAC;EACL,SAAS,EAAE,OAAO;EAClB,KAAK,EAAE,iBAAiB;EACxB,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,QAAQ;EAChB,OAAO,EAAE,iBAAiB;EAC1B,SAAS,EAAE,KAAK;EAChB,KAAK,EAAE,KAAK;CAaf;;AAnDT,AAuCY,IAvCR,CAWA,GAAG,AAAA,QAAQ,CAoBP,QAAQ,AAQH,KAAK,CAAC;EACH,MAAM,EAAE,cAAc;EACtB,UAAU,EAAE,oBAAoB;CACnC;;AA1Cb,AA2CY,IA3CR,CAWA,GAAG,AAAA,QAAQ,CAoBP,QAAQ,AAYH,QAAQ,CAAC;EACN,MAAM,EAAE,aAAa;EACrB,UAAU,EAAE,oBAAoB;CACnC;;AA9Cb,AA+CY,IA/CR,CAWA,GAAG,AAAA,QAAQ,CAoBP,QAAQ,AAgBH,QAAQ,CAAC;EACN,MAAM,EAAE,eAAe;EACvB,UAAU,EAAE,oBAAoB;CACnC;;AAlDb,AAoDQ,IApDJ,CAWA,GAAG,AAAA,QAAQ,CAyCP,GAAG,AAAA,KAAK,CAAC;EACL,SAAS,EAAE,IAAI;CAClB;;AAtDT,AAuDQ,IAvDJ,CAWA,GAAG,AAAA,QAAQ,CA4CP,GAAG,AAAA,MAAM,CAAC;EACN,SAAS,EAAE,KAAK;CACnB;;AAzDT,AA0DQ,IA1DJ,CAWA,GAAG,AAAA,QAAQ,CA+CP,GAAG,AAAA,KAAK,CAAC;EACL,KAAK,EAAE,GAAG;EACV,OAAO,EAAE,aAAa;EACtB,eAAe,EAAE,SAAS;CAC7B;;AA9DT,AAgEI,IAhEA,AAgEC,KAAK,CAAC;EACH,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,IAAI;CACzB;;AAnEL,AAoEI,IApEA,AAoEC,MAAM,CAAC;EACJ,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,IAAI;CACnB;;AAvEL,AAwEI,IAxEA,CAwEA,MAAM,CAAC;EACH,SAAS,EAAE,KAAK;EAChB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,UAAU,EAAE,MAAM;CACrB", "sources": [ "index.scss" ], diff --git a/css/index.scss b/css/index.scss index 1a9a2fe..f55913c 100644 --- a/css/index.scss +++ b/css/index.scss @@ -10,6 +10,13 @@ body { } } div.content { + display: grid; + grid-template-columns: 50% 50%; + grid-template-areas: + 'message message' + 'left right' + ; + width: 100%; form { label { font-size: small; @@ -23,10 +30,11 @@ body { width: 50%; } .message { - min-width: 80%; + grid-area: message; + width: calc(100% - 22px); height: auto; margin: 5px auto; - padding: 5px; + padding: 5px 10px 5px 10px; font-size: small; color: white; &.info { @@ -42,6 +50,12 @@ body { background: rgba(0, 255, 0, 0.5); } } + div.left { + grid-area: left; + } + div.right { + grid-area: right; + } img.skin { width: 60%; padding: 0 1em 1em 1em; diff --git a/data/data.json b/data/data.json index 829c016..c511306 100644 --- a/data/data.json +++ b/data/data.json @@ -1 +1 @@ -{"theme":"light","user":"arne.v.iterson@hotmail.nl","password":""} \ No newline at end of file +{"theme":"dark","user":"arne.v.iterson@hotmail.nl","password":"","skinDefault":"http://assets.mojang.com/SkinTemplates/steve.png"} \ No newline at end of file diff --git a/html/auth.hbs b/html/auth.hbs index 3330912..b5a7295 100644 --- a/html/auth.hbs +++ b/html/auth.hbs @@ -1,33 +1,41 @@ + {{ title }} +
-

{{ header }}

+

{{ header }}

Login to Minecraft

-
-
-
+
+

+ Your password will stored in plaintext because the Mojang API requires it, do not use this option unless + you are on a private computer. +

+
+
+ +
+
-
-
+
+
- - + +
-

Your password will stored in plaintext because the Mojang API requires it, do not use this option unless you are on a private computer.

- - - + + +
@@ -36,4 +44,5 @@ {{ footer }} + \ No newline at end of file diff --git a/html/main.hbs b/html/main.hbs index 8cc5208..da4d5fc 100644 --- a/html/main.hbs +++ b/html/main.hbs @@ -1,26 +1,37 @@ + {{ title }} +
-

{{ header }}

+

{{ header }}

Main menu

-
-
-
- -

- Logging out will delete your password from storage, if you want it to autofill next time you can just close this window when you are done. -

+
+

+ Logging out will delete your password from storage, if you want it to autofill next time you can just + close this window when you are done. +

+

+ Hecc inc. is not responsible for loss of data or explicit content (using random skin selection) seen + when using this program. +

+
+
+
+
+
+ +
@@ -29,4 +40,5 @@ {{ footer }} + \ No newline at end of file diff --git a/html/skin_current.hbs b/html/skin_current.hbs index e36b17d..eca8fa3 100644 --- a/html/skin_current.hbs +++ b/html/skin_current.hbs @@ -1,26 +1,32 @@ + {{ title }} +
-

{{ header }}

+

{{ header }}

Current Skin

- - -
- - - +
+ +
+ +
+ +
+ + +
@@ -29,4 +35,5 @@ {{ footer }} + \ No newline at end of file diff --git a/html/skin_random.hbs b/html/skin_random.hbs index c8e2130..4f613d6 100644 --- a/html/skin_random.hbs +++ b/html/skin_random.hbs @@ -1,19 +1,34 @@ + {{ title }} +
-

{{ header }}

+

{{ header }}

Random Skin

-
- +
+

+ +
+ +
+ +
+ +
+ + + + +
@@ -22,4 +37,5 @@ {{ footer }} + \ No newline at end of file diff --git a/html/skin_upload.hbs b/html/skin_upload.hbs index ec7aef8..12ea3b4 100644 --- a/html/skin_upload.hbs +++ b/html/skin_upload.hbs @@ -1,22 +1,42 @@ + {{ title }} +
-

{{ header }}

+

{{ header }}

Upload Skin

-
- - -
+

+ +
+ +
+ +
+ +
+ + + + + + +
@@ -25,4 +45,5 @@ {{ footer }} + \ No newline at end of file diff --git a/main.js b/main.js index 75fc75d..0568b4f 100644 --- a/main.js +++ b/main.js @@ -12,7 +12,7 @@ if (process.env.NODE_ENV === "dev") { function createWindow () { // Create the browser window. const win = new BrowserWindow({ - width: 320, + width: 640, height: 520, backgroundColor: "#ffffff", resizable: false, diff --git a/src/auth.js b/src/auth.js index bd47607..99600f7 100644 --- a/src/auth.js +++ b/src/auth.js @@ -54,7 +54,7 @@ async function authenticate(user, password) { } // Get access token from Mojang Authserver -const form = document.querySelectorAll("div.content > form")[0]; +const form = document.querySelectorAll("div.content > div.right > form")[0]; form.querySelectorAll("input#user")[0].value = authData.user; form.querySelectorAll("input#password")[0].value = authData.password; diff --git a/src/main.js b/src/main.js index 5a64bbf..907f05a 100644 --- a/src/main.js +++ b/src/main.js @@ -15,22 +15,22 @@ const msg = document.querySelectorAll("div.content > p.message")[0]; msg.classList.add("success"); msg.innerHTML = `Logged in as ${session.selectedProfile.name}`; -document.querySelectorAll("div.content > button#current")[0].addEventListener("click", (e) => { +document.querySelectorAll("div.content > div.right > button#current")[0].addEventListener("click", (e) => { console.log("Clicked current button"); remote.getCurrentWindow().loadURL(path.join(`file://${__dirname}/skin_current.hbs`)); }); -document.querySelectorAll("div.content > button#upload")[0].addEventListener("click", (e) => { +document.querySelectorAll("div.content > div.right > button#upload")[0].addEventListener("click", (e) => { console.log("Clicked upload button"); remote.getCurrentWindow().loadURL(path.join(`file://${__dirname}/skin_upload.hbs`)); }); -document.querySelectorAll("div.content > button#random")[0].addEventListener("click", (e) => { +document.querySelectorAll("div.content > div.right > button#random")[0].addEventListener("click", (e) => { console.log("Clicked random button"); remote.getCurrentWindow().loadURL(path.join(`file://${__dirname}/skin_random.hbs`)); }); -document.querySelectorAll("div.content > button#logout")[0].addEventListener("click", (e) => { +document.querySelectorAll("div.content > div.right > button#logout")[0].addEventListener("click", (e) => { console.log("Clicked logout button"); if (ipcRenderer.sendSync("setSession", {})) { var authData = ipcRenderer.sendSync("getAuth"); diff --git a/src/skin.js b/src/skin.js index e0d59fb..1c5ad99 100644 --- a/src/skin.js +++ b/src/skin.js @@ -1,5 +1,9 @@ /* eslint-disable no-unused-vars */ -const { BrowserWindow, ipcRenderer, remote } = require("electron"); +const { + BrowserWindow, + ipcRenderer, + remote +} = require("electron"); const axios = require("axios").default; const path = require("path"); @@ -15,6 +19,36 @@ if (!session.accessToken) { const regex = /(?!\w*_)\w*(?=\.\w*)/g; var action = __filename.match(regex)[0]; +var parser = new DOMParser(); + +var randomUrls = []; + +// Switch button and views +var btn = document.querySelectorAll("div.content > div.left > button#switch")[0]; +var view = { + flat: document.querySelectorAll("div.content > div.left > img.skin#flat")[0], + mesh: document.querySelectorAll("div.content > div.left > div#mesh")[0] +}; + +function setView(url, controls = true) { + btn.style.display = "initial"; + view.flat.src = url; + + view.mesh.innerHTML = ""; + + // Set mesh view + let skinViewer = new skinview3d.SkinViewer({ + domElement: view.mesh, + width: 300, + height: 250, + skinUrl: url + }); + + let control = skinview3d.createOrbitControls(skinViewer); + control.enableRotate = controls; + control.enableZoom = false; + control.enablePan = false; +} switch (action) { case "current": @@ -22,72 +56,90 @@ case "current": method: "GET", url: "https://sessionserver.mojang.com/session/minecraft/profile/" + session.selectedProfile.id }).then((data) => { - // Switch button and views - var btn = document.querySelectorAll("div.content > button#switch")[0]; - var view = { - flat: document.querySelectorAll("div.content > img.skin#flat")[0], - mesh: document.querySelectorAll("div.content > div#mesh")[0] - }; - - // Set flat view - const url = JSON.parse(atob(data.data.properties[0].value)).textures.SKIN.url; - view.flat.src = url; - - // Set mesh view - let skinViewer = new skinview3d.SkinViewer({ - domElement: view.mesh, - width: 200, - height: 200, - skinUrl: url - }); - - let control = skinview3d.createOrbitControls(skinViewer); - control.enableRotate = true; - control.enableZoom = false; - control.enablePan = false; - - - // Switch button action - btn.addEventListener("click", (e) => { - console.log("Switch button clicked"); - if (view.flat.style.display == "inline") { - view.flat.style.display = "none"; - view.mesh.style.display = "inline"; - btn.innerHTML = "Switch to 2D"; - } else { - view.flat.style.display = "inline"; - view.mesh.style.display = "none"; - btn.innerHTML = "Switch to 3D"; - } - }); - - // Download button action - document.querySelectorAll("div.content > button#download")[0].addEventListener("click", (e) => { - ipcRenderer.send("download", { - url: url, - properties: { - saveAs: true - } - }); - - ipcRenderer.on("downloadResult", (event, arg) => { - var msg = document.querySelectorAll("div.content > p.message")[0]; - console.log(msg); - msg.classList.add("success"); - msg.innerHTML = "Downloaded successfully"; - }); - }); - + setView(JSON.parse(atob(data.data.properties[0].value)).textures.SKIN.url); }); break; case "upload": - + document.querySelectorAll("div.content > div.right > button").forEach(element => { + element.addEventListener("click", (e) => { + document.querySelectorAll("div.content > div.right > button").forEach(button => { + if (button.id != "main") { + button.style.display = "none"; + } + }); + document.querySelectorAll(`div.content > div.right > form#${element.id}`)[0].style.display = "block"; + }); + }); + break; case "random": - + axios({ + method: "GET", + url: "https://nl.namemc.com/minecraft-skins/random" + }).then((data) => { + var namemc = parser.parseFromString(data.data, "text/html"); + namemc.querySelectorAll("a").forEach((e) => { + var href = e.getAttribute("href"); + if (href.includes("skin")) { + var id = href.split("/")[2]; + if (id && id.length == 16 && !(id.includes("-"))) { + randomUrls.push("https://nl.namemc.com/texture/" + id + ".png"); + } + } + }); + + function random() { + console.log(randomUrls.length); + if (randomUrls.length == 0) { + window.location.reload(); + } else { + var id = Math.floor(Math.random() * (randomUrls.length - 0)) + 0; + setView(randomUrls[id]); + randomUrls.splice(id, 1); + } + } + + random(); + + document.querySelectorAll("div.content > div.right > button#random")[0].addEventListener("click", (e) => { + random(); + }); + }); + break; } -document.querySelectorAll("div.content > button#main")[0].addEventListener("click", (e) => { - remote.getCurrentWindow().loadURL(path.join(`file://${__dirname}/main.hbs`)); +// Download button action +document.querySelectorAll("div.content > div.right > button#download")[0].addEventListener("click", (e) => { + ipcRenderer.send("download", { + url: view.flat.src, + properties: { + saveAs: true + } + }); + + ipcRenderer.on("downloadResult", (event, arg) => { + var msg = document.querySelectorAll("div.content > p.message")[0]; + console.log(msg); + msg.classList.add("success"); + msg.innerHTML = "Downloaded successfully"; + }); }); + +// Switch button action +btn.addEventListener("click", (e) => { + if (view.flat.style.display == "inline") { + view.flat.style.display = "none"; + view.mesh.style.display = "inline"; + btn.innerHTML = "Switch to 2D"; + } else { + view.flat.style.display = "inline"; + view.mesh.style.display = "none"; + btn.innerHTML = "Switch to 3D"; + } +}); + +// Back button action +document.querySelectorAll("div.content > div.right > button#main")[0].addEventListener("click", (e) => { + remote.getCurrentWindow().loadURL(path.join(`file://${__dirname}/main.hbs`)); +}); \ No newline at end of file