Commit 319c3485 authored by Andreas Heimann's avatar Andreas Heimann

client v1.0.0 finish-up

parent ffea5d5c
...@@ -35,7 +35,7 @@ bower_components ...@@ -35,7 +35,7 @@ bower_components
.lock-wscript .lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html) # Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release build/
# Dependency directories # Dependency directories
node_modules/ node_modules/
......
const { app, BrowserWindow, ipcMain } = require('electron'); const { app, BrowserWindow, ipcMain, protocol } = require('electron');
const { download } = require('electron-dl'); const { download } = require('electron-dl');
const isDev = require('electron-is-dev');
let win; let win;
let deeplinkingUrl;
const PROTOCOL_PREFIX = "csinstall"; const gotTheLock = app.requestSingleInstanceLock();
app.setAsDefaultProtocolClient(PROTOCOL_PREFIX); if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (process.platform == 'win32') {
let commandLineString = commandLine.slice(1) + '';
let commandLineArgs = commandLineString.split(",");
deeplinkingUrl = commandLineArgs[commandLineArgs.length - 1].replace("spinshare-song://", "").replace("/", "");
}
if (win) {
if (win.isMinimized()) win.restore();
win.focus();
win.webContents.executeJavaScript(`NavigateToSongDetail("${deeplinkingUrl}")`);
}
});
}
function createWindow () { function createWindow () {
win = new BrowserWindow({ win = new BrowserWindow({
title: "SpinSha.re",
width: 1300, width: 1300,
height: 700, height: 700,
minHeight: 700, minHeight: 700,
...@@ -19,13 +38,14 @@ function createWindow () { ...@@ -19,13 +38,14 @@ function createWindow () {
win.loadFile('./src/app.htm'); win.loadFile('./src/app.htm');
win.webContents.openDevTools(); if(isDev) {
win.webContents.openDevTools();
}
win.setMenuBarVisibility(false); win.setMenuBarVisibility(false);
protocol.registerHttpProtocol(PROTOCOL_PREFIX, (req, cb) => { if (process.platform == 'win32') {
const fullUrl = formFullTodoUrl(req.url); deeplinkingUrl = process.argv.slice(1);
console.log(fullUrl); }
});
} }
app.whenReady().then(createWindow); app.whenReady().then(createWindow);
...@@ -41,6 +61,13 @@ app.on('activate', () => { ...@@ -41,6 +61,13 @@ app.on('activate', () => {
createWindow(); createWindow();
} }
}); });
app.on('open-url', function (event, url) {
event.preventDefault();
deeplinkingUrl = url;
});
const PROTOCOL_PREFIX_SONG = "spinshare-song";
app.setAsDefaultProtocolClient(PROTOCOL_PREFIX_SONG);
ipcMain.on("download", (event, info) => { ipcMain.on("download", (event, info) => {
console.log("Download Request Received"); console.log("Download Request Received");
......
This diff is collapsed.
{ {
"name": "customspeens-client", "name": "customspeens-client",
"version": "0.1.0", "version": "1.0.0",
"main": "main.js", "main": "./main.js",
"description": "Spin Rhythm XD Custom Songs", "description": "Spin Rhythm XD Custom Songs",
"scripts": { "scripts": {
"start": "electron ." "start": "electron .",
"build": "electron-builder"
}, },
"protocols": [
{
"name": "customspeens",
"role": "CustomSpeens",
"schemes": [
"csinstall"
]
}
],
"author": "Andreas Heimann", "author": "Andreas Heimann",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"electron": "^8.0.1" "electron": "^8.0.1",
"electron-builder": "^22.4.1"
}, },
"dependencies": { "dependencies": {
"axios": "^0.19.2", "axios": "^0.19.2",
...@@ -28,5 +21,40 @@ ...@@ -28,5 +21,40 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"uniqid": "^5.2.0", "uniqid": "^5.2.0",
"unzipper": "^0.10.10" "unzipper": "^0.10.10"
},
"build": {
"productName": "SpinShare",
"appId": "re.spinsha.client",
"directories": {
"output": "build"
},
"protocols": {
"name": "spinshare-song-deeplink",
"schemes": ["spinshare-song"]
},
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "build/icons/icon.icns"
},
"win": {
"icon": "build/icons/icon.ico"
},
"linux": {
"icon": "build/icons"
}
} }
} }
This diff is collapsed.
.download-overlay { .download-overlay {
position: absolute; position: fixed;
z-index: 100; z-index: 100;
top: 0px; top: 0px;
left: 0px; left: 0px;
...@@ -14,10 +14,48 @@ ...@@ -14,10 +14,48 @@
width: 500px; width: 500px;
background: #212629; background: #212629;
border-radius: 6px; border-radius: 6px;
position: relative;
overflow: hidden;
} }
.download-overlay .download-content .download-output { .download-overlay .download-content .download-statusbar {
text-align: center; position: absolute;
height: 5px;
background: rgba(0, 0, 0, 0.2);
left: 0px;
right: 0px;
}
.download-overlay .download-content .download-statusbar .download-statusbar-handle {
height: 5px;
width: 0px;
background: #74b959;
transition: 1s ease-in-out width;
}
.download-overlay .download-content .download-status {
padding: 25px; padding: 25px;
display: none;
grid-template-rows: 1fr auto;
grid-gap: 25px;
}
.download-overlay .download-content .download-status .icon {
margin: 10px auto;
width: 150px;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
}
.download-overlay .download-content .download-status .icon .mdi {
font-size: 72px;
}
.download-overlay .download-content .download-status .text {
text-align: center;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.25em;
}
.download-overlay .download-content .download-status.active {
display: grid;
} }
.download-overlay .download-content .download-actions { .download-overlay .download-content .download-actions {
display: none; display: none;
......
.download-overlay { .download-overlay {
position: absolute; position: fixed;
z-index: 100; z-index: 100;
top: 0px; top: 0px;
left: 0px; left: 0px;
...@@ -14,10 +14,54 @@ ...@@ -14,10 +14,54 @@
width: 500px; width: 500px;
background: #212629; background: #212629;
border-radius: 6px; border-radius: 6px;
position: relative;
overflow: hidden;
& .download-output { & .download-statusbar {
text-align: center; position: absolute;
height: 5px;
background: rgba(0,0,0,0.2);
left: 0px;
right: 0px;
& .download-statusbar-handle {
height: 5px;
width: 0px;
background: #74b959;
transition: 1s ease-in-out width;
}
}
& .download-status {
padding: 25px; padding: 25px;
display: none;
grid-template-rows: 1fr auto;
grid-gap: 25px;
& .icon {
margin: 10px auto;
width: 150px;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
& .mdi {
font-size: 72px;
}
}
& .text {
text-align: center;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.25em;
}
&.active {
display: grid;
}
} }
& .download-actions { & .download-actions {
......
...@@ -63,28 +63,22 @@ main aside .item.active { ...@@ -63,28 +63,22 @@ main aside .item.active {
main aside .item .mdi { main aside .item .mdi {
font-size: 22px; font-size: 22px;
} }
input { section {
font-family: 'Open Sans', sans-serif; display: none;
font-size: 12px;
color: #222;
background: #fff;
text-transform: uppercase;
font-weight: 700;
border-radius: 4px;
padding: 7px 14px;
border: 0px;
transition: 0.2s ease-in-out all;
} }
input:hover { section.active {
background: #fff; display: block;
color: #222;
cursor: pointer;
} }
input:focus { section.section-startup {
outline: 0; padding: 50px;
} }
input::placeholder { section.section-startup.active {
color: rgba(0, 0, 0, 0.6); display: grid;
grid-template-rows: auto;
grid-gap: 25px;
}
section.section-library {
padding: 50px;
} }
button, button,
.button { .button {
...@@ -109,20 +103,201 @@ button:focus, ...@@ -109,20 +103,201 @@ button:focus,
.button:focus { .button:focus {
outline: 0; outline: 0;
} }
section { .song-row {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
}
.song-row .song-header {
display: grid;
grid-template-columns: 1fr auto;
}
.song-row .song-header .row-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
.song-row .song-header .row-title.row-title-noactions {
margin: 10px 0px;
}
.song-row .song-header .row-controls {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 15px;
}
.song-row .song-header .row-controls .item {
width: 28px;
height: 28px;
font-size: 22px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.song-row .song-header .row-controls .item.disabled {
opacity: 0.4;
}
.song-row .song-header .row-controls .item:not(.disabled):hover {
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.song-row .song-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 15px;
}
.song-row .song-list .song-item {
background: rgba(255, 255, 255, 0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
}
.song-row .song-list .song-item .song-cover {
background: rgba(255, 255, 255, 0.1);
background-size: cover;
width: 100%;
padding-top: 100%;
position: relative;
}
.song-row .song-list .song-item .song-cover .song-charter {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.8));
opacity: 0;
padding: 15px;
overflow: hidden;
display: grid;
transition: 0.2s ease-in-out opacity;
grid-template-columns: auto 1fr;
grid-gap: 10px;
align-items: flex-end;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info {
display: grid;
align-items: center;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info .mdi {
font-size: 18px;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info span {
font-size: 12px;
color: transparent;
transition: 0.2s ease-in-out color;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item .song-metadata {
padding: 15px;
}
.song-row .song-list .song-item .song-metadata .song-title {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item .song-metadata .song-artist {
margin-top: 5px;
opacity: 0.6;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item:not(.song-item-loading):not(.song-item-local):hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
}
.song-row .song-list .song-item:not(.song-item-loading):not(.song-item-local):hover .song-cover .song-charter {
opacity: 1;
}
.song-row .song-list .song-item.song-item-loading {
background: linear-gradient(to right, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
animation-name: songLoadingShimmer;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 2s;
}
.song-row .song-list .song-item.song-item-loading .song-cover {
opacity: 0;
}
.song-row .song-list .song-item.song-item-local {
opacity: 0.6;
}
.song-row .song-list .song-item.song-item-local:hover .song-cover .song-charter {
opacity: 1;
}
.song-row .song-list-noresults {
display: none; display: none;
background: rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 25px;
opacity: 0.6;
text-align: center;
} }
section.active { .song-row .song-list-noresults.active {
display: block; display: block;
} }
section.section-startup { .user-row {
padding: 50px; display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
} }
section.section-startup.active { .user-row .user-header {
display: grid; display: grid;
grid-template-rows: auto; grid-template-columns: 1fr auto;
grid-gap: 25px;
} }
section.section-library { .user-row .user-header .row-title {
padding: 50px; letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
.user-row .user-header .row-title.row-title-noactions {
margin: 10px 0px;
}
.user-row .user-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 15px;
}
.user-item {
background: rgba(255, 255, 255, 0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
display: grid;
padding: 10px;
grid-gap: 15px;
grid-template-columns: 32px 1fr;
}
.user-item .user-avatar {
background: rgba(255, 255, 255, 0.1);
background-size: cover;
width: 32px;
height: 32px;
border-radius: 32px;
}
.user-item .user-metadata {
align-self: center;
}
.user-item .user-metadata .user-name {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
.user-item:hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
}
@keyframes songLoadingShimmer {
from {
background-position: 0px 0px;
}
to {
background-position: 173px 0px;
}
} }
...@@ -65,28 +65,25 @@ main { ...@@ -65,28 +65,25 @@ main {
} }
} }
} }
input { section {
font-family: 'Open Sans', sans-serif; display: none;
font-size: 12px;
color: #222;
background: #fff;
text-transform: uppercase;
font-weight: 700;
border-radius: 4px;
padding: 7px 14px;
border: 0px;
transition: 0.2s ease-in-out all;
&:hover { &.active {
background: #fff; display: block;
color: #222;
cursor: pointer;
} }
&:focus {
outline: 0; &.section-startup {
padding: 50px;
&.active {
display: grid;
grid-template-rows: auto;
grid-gap: 25px;
}
} }
&::placeholder {
color: rgba(0,0,0,0.6); &.section-library {
padding: 50px;
} }
} }
button, .button { button, .button {
...@@ -110,24 +107,233 @@ button, .button { ...@@ -110,24 +107,233 @@ button, .button {
outline: 0; outline: 0;
} }
} }
section { .song-row {
display: none; display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
&.active { & .song-header {
display: block; display: grid;
grid-template-columns: 1fr auto;
& .row-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
&.row-title-noactions {
margin: 10px 0px;
}
}
& .row-controls {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 15px;
& .item {
width: 28px;
height: 28px;
font-size: 22px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
&.disabled {
opacity: 0.4;
}
&:not(.disabled):hover {
background: rgba(255,255,255,0.2);
cursor: pointer;
}
}
}
} }
& .song-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 15px;
&.section-startup { & .song-item {
padding: 50px; background: rgba(255,255,255,0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
& .song-cover {
background: rgba(255,255,255,0.1);
background-size: cover;
width: 100%;
padding-top: 100%;
position: relative;
& .song-charter {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: linear-gradient(180deg, rgba(0,0,0,0.2), rgba(0,0,0,0.8));
opacity: 0;
padding: 15px;
overflow: hidden;
display: grid;
transition: 0.2s ease-in-out opacity;
grid-template-columns: auto 1fr;
grid-gap: 10px;
align-items: flex-end;
& .song-charter-info {
display: grid;
align-items: center;
& .mdi {
font-size: 18px;
}
& span {
font-size: 12px;
color: transparent;
transition: 0.2s ease-in-out color;
overflow: hidden;
white-space: nowrap;
}
}
}
}
& .song-metadata {
padding: 15px;
& .song-title {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
& .song-artist {
margin-top: 5px;
opacity: 0.6;
overflow: hidden;
white-space: nowrap;
}
}
&:not(.song-item-loading):not(.song-item-local):hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
& .song-cover {
& .song-charter {
opacity: 1;
}
}
}
&.song-item-loading {
background: linear-gradient(to right, rgba(255,255,255,0.1), rgba(255,255,255,0.2), rgba(255,255,255,0.1));
animation-name: songLoadingShimmer;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 2s;
& .song-cover {
opacity: 0;
}
}
&.song-item-local {
opacity: 0.6;
&:hover {
& .song-cover {
& .song-charter {
opacity: 1;
}
}
}
}
}
}
& .song-list-noresults {
display: none;
background: rgba(255,255,255,0.1);
border-radius: 6px;
padding: 25px;
opacity: 0.6;
text-align: center;
&.active { &.active {
display: grid; display: block;
grid-template-rows: auto;
grid-gap: 25px;
} }
} }
}
.user-row {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
&.section-library { & .user-header {
padding: 50px; display: grid;
grid-template-columns: 1fr auto;
& .row-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
&.row-title-noactions {
margin: 10px 0px;
}
}
}
& .user-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 15px;
}
}
.user-item {
background: rgba(255,255,255,0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
display: grid;
padding: 10px;
grid-gap: 15px;
grid-template-columns: 32px 1fr;
& .user-avatar {
background: rgba(255,255,255,0.1);
background-size: cover;
width: 32px;
height: 32px;
border-radius: 32px;
}
& .user-metadata {
align-self: center;
& .user-name {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
}
&:hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
}
}
@keyframes songLoadingShimmer {
from {
background-position: 0px 0px;
}
to {
background-position: 173px 0px;
} }
} }
\ No newline at end of file
.section-search {
grid-template-rows: auto 1fr;
grid-gap: 25px;
padding: 50px;
}
.section-search .search-bar input {
width: 100%;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
color: #fff;
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
padding: 14px 28px;
border: 0px;
transition: 0.2s ease-in-out all;
}
.section-search .search-bar input:hover {
background: rgba(255, 255, 255, 0.4);
color: #fff;
}
.section-search .search-bar input:focus {
outline: 0;
}
.section-search .search-bar input::placeholder {
color: rgba(255, 255, 255, 0.6);
}
.section-search .search-results {
display: grid;
grid-template-rows: auto auto auto 1fr;
grid-gap: 25px;
}
.section-search .search-results .search-results-users {
display: none;
}
.section-search .search-results .search-results-users.active {
display: grid;
}
.section-search .search-results .search-results-songs {
display: none;
}
.section-search .search-results .search-results-songs.active {
display: grid;
}
.section-search .search-results .search-results-noresults {
background: rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 25px;
display: none;
}
.section-search .search-results .search-results-noresults .noresults-title {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
}
.section-search .search-results .search-results-noresults .noresults-text {
opacity: 0.6;
}
.section-search .search-results .search-results-noresults.active {
display: block;
}
.section-search.active {
display: grid;
}
.section-search {
grid-template-rows: auto 1fr;
grid-gap: 25px;
padding: 50px;
& .search-bar {
input {
width: 100%;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
color: #fff;
background: rgba(255,255,255,0.2);
border-radius: 4px;
padding: 14px 28px;
border: 0px;
transition: 0.2s ease-in-out all;
&:hover {
background: rgba(255,255,255,0.4);
color: #fff;
}
&:focus {
outline: 0;
}
&::placeholder {
color: rgba(255,255,255,0.6);
}
}
}
& .search-results {
display: grid;
grid-template-rows: auto auto auto 1fr;
grid-gap: 25px;
& .search-results-users {
display: none;
&.active {
display: grid;
}
}
& .search-results-songs {
display: none;
&.active {
display: grid;
}
}
& .search-results-noresults {
background: rgba(255,255,255,0.1);
border-radius: 6px;
padding: 25px;
display: none;
& .noresults-title {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
}
& .noresults-text {
opacity: 0.6;
}
&.active {
display: block;
}
}
}
&.active {
display: grid;
}
}
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
} }
.section-settings .settings-box .settings-item { .section-settings .settings-box .settings-item {
display: grid; display: grid;
grid-template-columns: 200px 1fr; grid-template-columns: 170px 1fr;
grid-gap: 15px; grid-gap: 15px;
margin-top: 15px; margin-top: 15px;
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
& .settings-item { & .settings-item {
display: grid; display: grid;
grid-template-columns: 200px 1fr; grid-template-columns: 170px 1fr;
grid-gap: 15px; grid-gap: 15px;
margin-top: 15px; margin-top: 15px;
......
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-artist { .section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-artist {
margin-top: 5px; margin-top: 5px;
font-size: 18px; font-size: 18px;
}
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter {
margin-top: 10px;
font-size: 14px;
opacity: 0.6; opacity: 0.6;
} }
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-tags { .section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-tags {
...@@ -50,28 +54,13 @@ ...@@ -50,28 +54,13 @@
opacity: 0.6; opacity: 0.6;
cursor: pointer; cursor: pointer;
} }
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter { .section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-uploader {
margin-top: 15px; margin-top: 15px;
display: flex; display: flex;
} }
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter .song-charter-user { .section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-uploader .user-item {
justify-self: left; width: auto;
background: #222; padding-right: 15px;
padding: 10px 15px;
border-radius: 6px;
display: flex;
align-items: center;
transition: 0.2s ease-in-out all;
}
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter .song-charter-user .mdi {
font-size: 22px;
}
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter .song-charter-user span {
margin-left: 15px;
}
.section-song-detail .song-detail-background .song-detail-dim .song-detail .song-meta-data .song-charter .song-charter-user:hover {
opacity: 0.6;
cursor: pointer;
} }
.section-song-detail .song-detail-background .song-detail-dim .song-detail.active { .section-song-detail .song-detail-background .song-detail-dim .song-detail.active {
display: grid; display: grid;
......
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
& .song-artist { & .song-artist {
margin-top: 5px; margin-top: 5px;
font-size: 18px; font-size: 18px;
}
& .song-charter {
margin-top: 10px;
font-size: 14px;
opacity: 0.6; opacity: 0.6;
} }
& .song-tags { & .song-tags {
...@@ -55,30 +59,13 @@ ...@@ -55,30 +59,13 @@
} }
} }
& .song-charter { & .song-uploader {
margin-top: 15px; margin-top: 15px;
display: flex; display: flex;
& .song-charter-user { & .user-item {
justify-self: left; width: auto;
background: #222; padding-right: 15px;
padding: 10px 15px;
border-radius: 6px;
display: flex;
align-items: center;
transition: 0.2s ease-in-out all;
& .mdi {
font-size: 22px;
}
& span {
margin-left: 15px;
}
&:hover {
opacity: 0.6;
cursor: pointer;
}
} }
} }
} }
......
...@@ -55,129 +55,6 @@ ...@@ -55,129 +55,6 @@
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-duration: 1s; animation-duration: 1s;
} }
.song-row {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
}
.song-row .song-header {
display: grid;
grid-template-columns: 1fr auto;
}
.song-row .song-header .row-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
.song-row .song-header .row-controls {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 15px;
}
.song-row .song-header .row-controls .item {
width: 28px;
height: 28px;
font-size: 22px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.song-row .song-header .row-controls .item.disabled {
opacity: 0.4;
}
.song-row .song-header .row-controls .item:not(.disabled):hover {
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.song-row .song-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 15px;
}
.song-row .song-list .song-item {
background: rgba(255, 255, 255, 0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
}
.song-row .song-list .song-item .song-cover {
background: rgba(255, 255, 255, 0.1);
background-size: cover;
width: 100%;
padding-top: 100%;
position: relative;
}
.song-row .song-list .song-item .song-cover .song-charter {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.8));
opacity: 0;
padding: 15px;
overflow: hidden;
display: grid;
transition: 0.2s ease-in-out opacity;
grid-template-columns: auto 1fr;
grid-gap: 10px;
align-items: flex-end;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info {
display: grid;
align-items: center;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info .mdi {
font-size: 18px;
}
.song-row .song-list .song-item .song-cover .song-charter .song-charter-info span {
font-size: 12px;
color: transparent;
transition: 0.2s ease-in-out color;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item .song-metadata {
padding: 15px;
}
.song-row .song-list .song-item .song-metadata .song-title {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item .song-metadata .song-artist {
margin-top: 5px;
opacity: 0.6;
overflow: hidden;
white-space: nowrap;
}
.song-row .song-list .song-item:not(.song-item-loading):not(.song-item-local):hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
}
.song-row .song-list .song-item:not(.song-item-loading):not(.song-item-local):hover .song-cover .song-charter {
opacity: 1;
}
.song-row .song-list .song-item.song-item-loading {
background: linear-gradient(to right, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
animation-name: songLoadingShimmer;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 2s;
}
.song-row .song-list .song-item.song-item-loading .song-cover {
opacity: 0;
}
.song-row .song-list .song-item.song-item-local {
opacity: 0.6;
}
.song-row .song-list .song-item.song-item-local:hover .song-cover .song-charter {
opacity: 1;
}
@keyframes adLoadingShimmer { @keyframes adLoadingShimmer {
from { from {
background-position: 0px 0px; background-position: 0px 0px;
...@@ -186,11 +63,3 @@ ...@@ -186,11 +63,3 @@
background-position: 544px 0px; background-position: 544px 0px;
} }
} }
@keyframes songLoadingShimmer {
from {
background-position: 0px 0px;
}
to {
background-position: 173px 0px;
}
}
...@@ -60,151 +60,6 @@ ...@@ -60,151 +60,6 @@
} }
} }
} }
.song-row {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 5px;
& .song-header {
display: grid;
grid-template-columns: 1fr auto;
& .row-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
& .row-controls {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 15px;
& .item {
width: 28px;
height: 28px;
font-size: 22px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
&.disabled {
opacity: 0.4;
}
&:not(.disabled):hover {
background: rgba(255,255,255,0.2);
cursor: pointer;
}
}
}
}
& .song-list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 15px;
& .song-item {
background: rgba(255,255,255,0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
& .song-cover {
background: rgba(255,255,255,0.1);
background-size: cover;
width: 100%;
padding-top: 100%;
position: relative;
& .song-charter {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: linear-gradient(180deg, rgba(0,0,0,0.2), rgba(0,0,0,0.8));
opacity: 0;
padding: 15px;
overflow: hidden;
display: grid;
transition: 0.2s ease-in-out opacity;
grid-template-columns: auto 1fr;
grid-gap: 10px;
align-items: flex-end;
& .song-charter-info {
display: grid;
align-items: center;
& .mdi {
font-size: 18px;
}
& span {
font-size: 12px;
color: transparent;
transition: 0.2s ease-in-out color;
overflow: hidden;
white-space: nowrap;
}
}
}
}
& .song-metadata {
padding: 15px;
& .song-title {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
& .song-artist {
margin-top: 5px;
opacity: 0.6;
overflow: hidden;
white-space: nowrap;
}
}
&:not(.song-item-loading):not(.song-item-local):hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
& .song-cover {
& .song-charter {
opacity: 1;
}
}
}
&.song-item-loading {
background: linear-gradient(to right, rgba(255,255,255,0.1), rgba(255,255,255,0.2), rgba(255,255,255,0.1));
animation-name: songLoadingShimmer;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 2s;
& .song-cover {
opacity: 0;
}
}
&.song-item-local {
opacity: 0.6;
&:hover {
& .song-cover {
& .song-charter {
opacity: 1;
}
}
}
}
}
}
}
@keyframes adLoadingShimmer { @keyframes adLoadingShimmer {
from { from {
...@@ -213,13 +68,4 @@ ...@@ -213,13 +68,4 @@
to { to {
background-position: 544px 0px; background-position: 544px 0px;
} }
}
@keyframes songLoadingShimmer {
from {
background-position: 0px 0px;
}
to {
background-position: 173px 0px;
}
} }
\ No newline at end of file
.update-overlay {
position: fixed;
z-index: 100;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: rgba(0, 0, 0, 0.75);
display: none;
justify-content: center;
align-items: center;
}
.update-overlay .update-content {
width: 500px;
background: #212629;
border-radius: 6px;
position: relative;
overflow: hidden;
}
.update-overlay .update-content .update-status {
padding: 25px;
display: none;
grid-template-rows: 1fr auto;
grid-gap: 25px;
}
.update-overlay .update-content .update-status .icon {
margin: 10px auto;
width: 150px;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
}
.update-overlay .update-content .update-status .icon .mdi {
font-size: 72px;
}
.update-overlay .update-content .update-status .text {
text-align: center;
}
.update-overlay .update-content .update-status.active {
display: grid;
}
.update-overlay .update-content .update-actions {
display: none;
justify-content: flex-end;
padding: 25px;
background: rgba(0, 0, 0, 0.4);
}
.update-overlay .update-content .update-actions button {
margin-left: 10px;
}
.update-overlay .update-content .update-actions.active {
display: flex;
}
.update-overlay.active {
display: flex;
}
.update-overlay {
position: fixed;
z-index: 100;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: rgba(0,0,0,0.75);
display: none;
justify-content: center;
align-items: center;
& .update-content {
width: 500px;
background: #212629;
border-radius: 6px;
position: relative;
overflow: hidden;
& .update-status {
padding: 25px;
display: none;
grid-template-rows: 1fr auto;
grid-gap: 25px;
& .icon {
margin: 10px auto;
width: 150px;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
& .mdi {
font-size: 72px;
}
}
& .text {
text-align: center;
}
&.active {
display: grid;
}
}
& .update-actions {
display: none;
justify-content: flex-end;
padding: 25px;
background: rgba(0,0,0,0.4);
& button {
margin-left: 10px;
}
&.active {
display: flex;
}
}
}
&.active {
display: flex;
}
}
\ No newline at end of file
.section-user-detail .user-detail-background {
background-size: cover;
background-position: center;
}
.section-user-detail .user-detail-background .user-detail-dim {
backdrop-filter: blur(10px);
background: linear-gradient(180deg, rgba(0, 0, 0, 0.4), #212629);
}
.section-user-detail .user-detail-background .user-detail-dim .user-detail {
padding: 50px;
display: none;
grid-template-columns: 200px 1fr;
grid-gap: 25px;
}
.section-user-detail .user-detail-background .user-detail-dim .user-detail .user-avatar {
width: 200px;
height: 200px;
align-self: center;
background: #eee;
border-radius: 6px;
background-size: cover;
}
.section-user-detail .user-detail-background .user-detail-dim .user-detail .user-meta-data .user-name {
font-weight: bold;
font-size: 48px;
}
.section-user-detail .user-detail-background .user-detail-dim .user-detail.active {
display: grid;
}
.section-user-detail .song-row-user {
padding: 0px 50px;
margin-bottom: 50px;
display: none;
}
.section-user-detail .song-row-user.active {
display: grid;
}
.section-user-detail {
& .user-detail-background {
background-size: cover;
background-position: center;
& .user-detail-dim {
backdrop-filter: blur(10px);
background: linear-gradient(180deg, rgba(0,0,0,0.4), #212629);
& .user-detail {
padding: 50px;
display: none;
grid-template-columns: 200px 1fr;
grid-gap: 25px;
& .user-avatar {
width: 200px;
height: 200px;
align-self: center;
background: #eee;
border-radius: 6px;
background-size: cover;
}
& .user-meta-data {
& .user-name {
font-weight: bold;
font-size: 48px;
}
}
&.active {
display: grid;
}
}
}
}
& .song-row-user {
padding: 0px 50px;
margin-bottom: 50px;
display: none;
&.active {
display: grid;
}
}
}
\ No newline at end of file
// Backup Data
let currentBackupLocation = "";
let currentSRTBLocation = "";
let currentSongLocation = "";
let currentSongTrackInfo = {};
function UIOpenBackup() {
dialog.showOpenDialog({ title: "Open Backup", properties: ['openFile'], filters: [{"name": "Backup Archive", "extensions": ["zip"]}] }).then(result => {
if(!result.canceled) {
let filePath = result.filePaths[0];
let fileName = path.basename(filePath);
loadBackup(filePath, fileName).then(function(result) {
if(result) {
UIUpdateMetadata();
} else {
console.error("Backup could not be loaded!");
}
});
}
});
}
function UICopyBackup() {
copyBackup();
}
function UIUpdateMetadata() {
console.log(currentSongTrackInfo);
DOMSectionTrackinfo.classList.add("active");
DOMUISongCover.style.backgroundImage = "url(" + getSongCover(currentSongTrackInfo.albumArtReference.assetName) + ")";
DOMUISongTitle.innerHTML = currentSongTrackInfo.title;
DOMUISongSubtitle.innerHTML = currentSongTrackInfo.subtitle;
DOMUISongArtist.innerHTML = "Song by " + currentSongTrackInfo.artistName;
DOMUISongAuthor.innerHTML = "Chart by " + currentSongTrackInfo.charter;
}
let apiVersion = 1;
function UIDownloadBackup() {
DOMExternalBackupProgress.innerHTML = "";
http.get('http://localhost/www/customspeens-server/public/index.php/api/song/' + DOMExternalBackupID.value, function(response) {
let data = "";
response.on('data', function(chunk) { data += chunk; });
response.on('end', function() {
let apiResponse = JSON.parse( data );
if(apiResponse.version === apiVersion) {
console.log(apiResponse.data);
DOMExternalBackupProgress.innerHTML = "Downloading...";
// Let the main renderer download the backup
ipcRenderer.send("download", {
url: apiResponse.data.paths.zip,
properties: { directory: tempDirLocation }
});
} else {
console.error("Client is outdated!");
DOMExternalBackupProgress.innerHTML = "Client is outdated!";
}
});
});
}
\ No newline at end of file
let DOMDownloadOverlay = document.querySelector(".download-overlay"); let DOMDownloadOverlay = document.querySelector(".download-overlay");
let DOMDownloadOutput = DOMDownloadOverlay.querySelector(".download-content .download-output"); let DOMDownloadStatusBarHandle = DOMDownloadOverlay.querySelector(".download-content .download-statusbar-handle");
let DOMDownloadStatusDownloading = DOMDownloadOverlay.querySelector(".download-content .download-status-downloading");
let DOMDownloadStatusExtracting = DOMDownloadOverlay.querySelector(".download-content .download-status-extracting");
let DOMDownloadStatusInstalling = DOMDownloadOverlay.querySelector(".download-content .download-status-installing");
let DOMDownloadStatusDone = DOMDownloadOverlay.querySelector(".download-content .download-status-done");
let DOMDownloadActions = DOMDownloadOverlay.querySelector(".download-content .download-actions"); let DOMDownloadActions = DOMDownloadOverlay.querySelector(".download-content .download-actions");
function DownloadSong(songData) { function DownloadSong(songData) {
DOMDownloadOverlay.classList.add("active"); DOMDownloadOverlay.classList.add("active");
DOMDownloadActions.classList.remove("active"); DOMDownloadActions.classList.remove("active");
DOMDownloadOutput.innerText = "Downloading...";
// Send download command to main.js DOMDownloadStatusBarHandle.style.width = "0%";
ipcRenderer.send("download", {
url: songData.paths.zip, setTimeout(function() {
properties: { directory: tempDirLocation } UpdateDownloadStatus(0);
});
console.log(songData); // Send download command to main.js
ipcRenderer.send("download", {
url: songData.paths.zip,
properties: { directory: tempDirLocation }
});
}, 100);
} }
function CloseDownloadOverlay() { function CloseDownloadOverlay() {
DOMDownloadOverlay.classList.remove("active"); DOMDownloadOverlay.classList.remove("active");
DOMDownloadActions.classList.remove("active"); DOMDownloadActions.classList.remove("active");
DOMDownloadOutput.innerText = "Downloading...";
UpdateDownloadStatus(0);
DOMDownloadStatusBarHandle.style.width = "0%";
} }
ipcRenderer.on("download-complete", (event, downloadPath) => { ipcRenderer.on("download-complete", (event, downloadPath) => {
DOMDownloadOutput.innerText = "Extracing..."; UpdateDownloadStatus(1);
srxdControl.extractBackup(downloadPath, path.basename(downloadPath)).then(function(extractResult) { setTimeout(function() {
DOMDownloadOutput.innerText = "Installing..."; srxdControl.extractBackup(downloadPath, path.basename(downloadPath)).then(function(extractResult) {
UpdateDownloadStatus(2);
if(extractResult) { if(extractResult) {
installBackup(extractResult); installBackup(extractResult);
} else { } else {
console.error("Backup could not be loaded!"); // DOMDownloadOutput.innerText = locale.get('download.status.extractingFailed');
} console.error("Backup could not be loaded!");
}); }
});
}, 750);
}); });
// Install local backup folder // Install local backup folder
...@@ -45,12 +57,39 @@ async function installBackup(backupLocation) { ...@@ -45,12 +57,39 @@ async function installBackup(backupLocation) {
console.error("Couldn't copy backup!"); console.error("Couldn't copy backup!");
DOMDownloadActions.classList.add("active"); DOMDownloadActions.classList.add("active");
DOMDownloadOutput.innerText = "Error!"; // DOMDownloadOutput.innerText = locale.get('download.status.installingFailed');
} }
console.log("Successfully copied backup!"); setTimeout(function() {
DOMDownloadActions.classList.add("active");
DOMDownloadActions.classList.add("active"); UpdateDownloadStatus(3);
DOMDownloadOutput.innerText = "Done!"; }, 750);
}); });
}
function UpdateDownloadStatus(_status) {
DOMDownloadStatusDownloading.classList.remove("active");
DOMDownloadStatusExtracting.classList.remove("active");
DOMDownloadStatusInstalling.classList.remove("active");
DOMDownloadStatusDone.classList.remove("active");
switch(_status) {
default:
case 0:
DOMDownloadStatusDownloading.classList.add("active");
DOMDownloadStatusBarHandle.style.width = "25%";
break;
case 1:
DOMDownloadStatusExtracting.classList.add("active");
DOMDownloadStatusBarHandle.style.width = "50%";
break;
case 2:
DOMDownloadStatusInstalling.classList.add("active");
DOMDownloadStatusBarHandle.style.width = "75%";
break;
case 3:
DOMDownloadStatusDone.classList.add("active");
DOMDownloadStatusBarHandle.style.width = "100%";
break;
}
} }
\ No newline at end of file
const { ipcRenderer } = require('electron'); const { ipcRenderer } = require('electron');
const { dialog, shell, app } = require('electron').remote; const { dialog, shell, app, clipboard } = require('electron').remote;
const isDev = require('electron-is-dev'); const isDev = require('electron-is-dev');
const path = require('path'); const path = require('path');
const SSAPI = require( path.resolve(__dirname, './assets/js/module.api.js') ); const SSAPI = require( path.resolve(__dirname, './assets/js/module.api.js') );
...@@ -25,6 +25,7 @@ function detectGameDirectory() { ...@@ -25,6 +25,7 @@ function detectGameDirectory() {
} }
} }
// Initialize User Settings
let userSettings = new UserSettings({ let userSettings = new UserSettings({
defaults: { defaults: {
showExplicit: false, showExplicit: false,
...@@ -33,8 +34,13 @@ let userSettings = new UserSettings({ ...@@ -33,8 +34,13 @@ let userSettings = new UserSettings({
} }
}); });
// Initialize Locale
let locale = new Locale(userSettings.get('language')); let locale = new Locale(userSettings.get('language'));
const DOMLocaleElements = document.querySelectorAll("*[locale]"); const DOMLocaleElements = document.querySelectorAll("*[locale]");
DOMLocaleElements.forEach(function(localeElement) { DOMLocaleElements.forEach(function(localeElement) {
localeElement.innerHTML = locale.get(localeElement.innerHTML); localeElement.innerHTML = locale.get(localeElement.innerHTML);
});
const DOMLocalePlaceholderElements = document.querySelectorAll("*[localePlaceholder]");
DOMLocalePlaceholderElements.forEach(function(localePlaceholderElement) {
localePlaceholderElement.placeholder = locale.get(localePlaceholderElement.placeholder);
}); });
\ No newline at end of file
...@@ -2,7 +2,11 @@ const axios = require('axios'); ...@@ -2,7 +2,11 @@ const axios = require('axios');
class SHAPI { class SHAPI {
constructor() { constructor() {
this.apiBase = "http://localhost/www/customspeens-server/public/index.php/api/"; if(isDev) {
this.apiBase = "https://spinsha.re/api/";
} else {
this.apiBase = "http://localhost/www/spinshare-server/public/index.php/api/";
}
this.supportedVersion = 1; this.supportedVersion = 1;
} }
...@@ -38,6 +42,21 @@ class SHAPI { ...@@ -38,6 +42,21 @@ class SHAPI {
}); });
} }
async getCurrentVersion() {
let apiPath = this.apiBase + "currentVersion";
let supportedVersion = this.supportedVersion;
return axios.get(apiPath)
.then(function(response) {
if(response.data.version !== supportedVersion) {
throw new Error("Client is outdated!");
}
return response.data.data;
}).catch(function(error) {
throw new Error(error);
});
}
async getNewSongs(_offset) { async getNewSongs(_offset) {
let apiPath = this.apiBase + "songs/new/" + _offset; let apiPath = this.apiBase + "songs/new/" + _offset;
let supportedVersion = this.supportedVersion; let supportedVersion = this.supportedVersion;
...@@ -74,7 +93,37 @@ class SHAPI { ...@@ -74,7 +93,37 @@ class SHAPI {
let apiPath = this.apiBase + "song/" + _songId; let apiPath = this.apiBase + "song/" + _songId;
let supportedVersion = this.supportedVersion; let supportedVersion = this.supportedVersion;
console.log(apiPath); return axios.get(apiPath)
.then(function(response) {
if(response.data.version !== supportedVersion) {
throw new Error("Client is outdated!");
}
return response.data;
}).catch(function(error) {
throw new Error(error);
});
}
async getUserDetail(_userId) {
let apiPath = this.apiBase + "user/" + _userId;
let supportedVersion = this.supportedVersion;
return axios.get(apiPath)
.then(function(response) {
if(response.data.version !== supportedVersion) {
throw new Error("Client is outdated!");
}
return response.data;
}).catch(function(error) {
throw new Error(error);
});
}
async search(_searchQuery) {
let apiPath = this.apiBase + "search/" + _searchQuery;
let supportedVersion = this.supportedVersion;
return axios.get(apiPath) return axios.get(apiPath)
.then(function(response) { .then(function(response) {
......
...@@ -2,6 +2,7 @@ let DOMNavigationItems = document.querySelectorAll("aside .item"); ...@@ -2,6 +2,7 @@ let DOMNavigationItems = document.querySelectorAll("aside .item");
let DOMSections = document.querySelectorAll("section"); let DOMSections = document.querySelectorAll("section");
let DOMSectionSongDetail = document.querySelector(".section-song-detail"); let DOMSectionSongDetail = document.querySelector(".section-song-detail");
let DOMSectionUserDetail = document.querySelector(".section-user-detail");
let currentSection = 0; let currentSection = 0;
...@@ -36,6 +37,7 @@ function NavigateToSection(sectionIndex) { ...@@ -36,6 +37,7 @@ function NavigateToSection(sectionIndex) {
break; break;
case 1: case 1:
// Search // Search
InitSearch();
break; break;
case 2: case 2:
// Library // Library
...@@ -48,12 +50,23 @@ function NavigateToSection(sectionIndex) { ...@@ -48,12 +50,23 @@ function NavigateToSection(sectionIndex) {
case 4: case 4:
// SongDetail // SongDetail
break; break;
case 5:
// Connection Error
break;
case 6:
// 404 Error
break;
case 7:
// User Detail
break;
} }
} }
NavigateToSection(0); NavigateToSection(0);
function NavigateToSongDetail(songId) { function NavigateToSongDetail(songId) {
console.log("Loading Song " + songId);
// Stop audio if playing // Stop audio if playing
SongDetailStopPreview(); SongDetailStopPreview();
...@@ -71,4 +84,24 @@ function NavigateToSongDetail(songId) { ...@@ -71,4 +84,24 @@ function NavigateToSongDetail(songId) {
DOMSectionSongDetail.classList.add("active"); DOMSectionSongDetail.classList.add("active");
SongDetailLoad(songId); SongDetailLoad(songId);
}
function NavigateToUser(userId) {
// Stop audio if playing
SongDetailStopPreview();
// Navigation
DOMNavigationItems.forEach(function(DOMNavigation) {
DOMNavigation.classList.remove("active");
});
// Section
DOMSections.forEach(function(DOMSection) {
DOMSection.classList.remove("active");
});
// Load Detail
DOMSectionUserDetail.classList.add("active");
UserDetailLoad(userId);
} }
\ No newline at end of file
// Protocol
ipcRenderer.on("protocol-to-songdetail", (event, info) => {
console.log(info);
});
\ No newline at end of file
const DOMSearchBar = document.querySelector(".search-bar input");
const DOMSearchResultsUsers = document.querySelector(".search-results-users");
const DOMSearchResultsSongs = document.querySelector(".search-results-songs");
const DOMSearchResultsNoresults = document.querySelector(".search-results-noresults");
const DOMUsersList = DOMSearchResultsUsers.querySelector(".user-list");
const DOMSongsList = DOMSearchResultsSongs.querySelector(".song-list");
function InitSearch() {
SearchQuery("");
}
function SearchQuery(query) {
DOMSearchBar.value = query;
DOMSearchResultsUsers.classList.remove("active");
DOMSearchResultsSongs.classList.remove("active");
DOMSearchResultsNoresults.querySelector(".noresults-title").innerText = query;
DOMSearchResultsNoresults.classList.remove("active");
DOMUsersList.innerHTML = "";
DOMSongsList.innerHTML = "";
if(query != "") {
api.search(query).then(function(searchResults) {
if(searchResults.data.users.length == 0 && searchResults.data.songs.length == 0) {
DOMSearchResultsNoresults.classList.add("active");
} else {
if(searchResults.data.users.length > 0) {
DOMSearchResultsUsers.classList.add("active");
searchResults.data.users.forEach(function(user) {
DOMUsersList.appendChild(BuildUserDOM(user));
});
}
if(searchResults.data.songs.length > 0) {
DOMSearchResultsSongs.classList.add("active");
searchResults.data.songs.forEach(function(song) {
DOMSongsList.appendChild(BuildSongDOM(song));
});
}
}
}).catch(function(error) {
NavigateToSection(6);
console.error(error);
});
}
}
function BuildUserDOM(userItem) {
let userContainer = document.createElement("div");
userContainer.classList.add("user-item");
let userAvatar = document.createElement("div");
userAvatar.classList.add("user-avatar");
userAvatar.style.backgroundImage = "url('" + userItem.avatar + "')";
userContainer.appendChild(userAvatar);
let userMetaData = document.createElement("div");
userMetaData.classList.add("user-metadata");
let userName = document.createElement("div");
userName.classList.add("user-username");
userName.innerText = userItem.username;
userMetaData.appendChild(userName);
userContainer.appendChild(userMetaData);
userContainer.addEventListener('click', function() {
NavigateToUser(userItem.id);
});
return userContainer;
}
\ No newline at end of file
...@@ -14,10 +14,6 @@ function InitSettings() { ...@@ -14,10 +14,6 @@ function InitSettings() {
DOMSettingsInputGameDirectory.value = userSettings.get('gameDirectory'); DOMSettingsInputGameDirectory.value = userSettings.get('gameDirectory');
} }
function CheckForUpdate() {
}
function SettingsChangeLanguage() { function SettingsChangeLanguage() {
let selectedLanguage = DOMSettingsInputLanguage.value; let selectedLanguage = DOMSettingsInputLanguage.value;
userSettings.set('language', selectedLanguage); userSettings.set('language', selectedLanguage);
......
...@@ -10,8 +10,9 @@ const DOMButtonPreview = DOMSongDetailActions.querySelector(".button-preview"); ...@@ -10,8 +10,9 @@ const DOMButtonPreview = DOMSongDetailActions.querySelector(".button-preview");
const DOMSongTitle = DOMSongDetail.querySelector(".song-title"); const DOMSongTitle = DOMSongDetail.querySelector(".song-title");
const DOMSongSubtitle = DOMSongDetail.querySelector(".song-subtitle"); const DOMSongSubtitle = DOMSongDetail.querySelector(".song-subtitle");
const DOMSongArtist = DOMSongDetail.querySelector(".song-artist"); const DOMSongArtist = DOMSongDetail.querySelector(".song-artist");
const DOMSongCharter = DOMSongDetail.querySelector(".song-charter span"); const DOMSongCharter = DOMSongDetail.querySelector(".song-charter");
const DOMSongTags = DOMSongDetail.querySelector(".song-tags"); const DOMSongTags = DOMSongDetail.querySelector(".song-tags");
const DOMSongUploader = DOMSongDetail.querySelector(".song-uploader");
function SongDetailLoad(songId) { function SongDetailLoad(songId) {
currentSongId = 0; currentSongId = 0;
...@@ -23,31 +24,43 @@ function SongDetailLoad(songId) { ...@@ -23,31 +24,43 @@ function SongDetailLoad(songId) {
api.getSongDetail(songId).then(function(apiResponse) { api.getSongDetail(songId).then(function(apiResponse) {
let songData = apiResponse.data; let songData = apiResponse.data;
if(apiResponse.status == 404) { if(apiResponse.status == 404 || songData.length == 0) {
NavigateToSection(6); NavigateToSection(7);
} else { } else {
DOMSongDetail.classList.add("active"); api.getUserDetail(songData.uploader).then(function(uploaderResponse) {
DOMSongDetailActions.classList.add("active"); let uploaderData = uploaderResponse.data;
DOMSongDetailBackground.style.backgroundImage = "url('" + songData.paths.cover + "')"; DOMSongDetail.classList.add("active");
DOMSongDetailCover.style.backgroundImage = "url('" + songData.paths.cover + "')"; DOMSongDetailActions.classList.add("active");
DOMSongTitle.innerText = songData.title; DOMSongDetailBackground.style.backgroundImage = "url('" + songData.paths.cover + "')";
DOMSongSubtitle.innerText = songData.subtitle; DOMSongDetailCover.style.backgroundImage = "url('" + songData.paths.cover + "')";
DOMSongArtist.innerText = songData.artist;
DOMSongCharter.innerText = songData.charter;
DOMButtonPreview.innerText = "PLAY PREVIEW"; DOMSongTitle.innerText = songData.title;
DOMSongSubtitle.innerText = songData.subtitle;
DOMSongArtist.innerText = songData.artist;
DOMSongCharter.innerText = locale.get('songdetail.createdBy') + " " + songData.charter;
DOMSongTags.innerHTML = ""; DOMSongUploader.innerHTML = "";
songData.tags.forEach(function(tag) { DOMSongUploader.appendChild(BuildUserDOM(uploaderData));
if(tag != "") {
let newTag = document.createElement("div");
newTag.classList.add("tag");
newTag.innerText = tag;
DOMSongTags.appendChild(newTag); DOMButtonPreview.innerText = locale.get('songdetail.actions.playPreviewButton');
}
DOMSongTags.innerHTML = "";
songData.tags.forEach(function(tag) {
if(tag != "") {
let newTag = document.createElement("div");
newTag.classList.add("tag");
newTag.innerText = tag;
newTag.addEventListener('click', function() {
NavigateToSection(1);
SearchQuery(tag);
});
DOMSongTags.appendChild(newTag);
}
});
}); });
} }
...@@ -55,7 +68,7 @@ function SongDetailLoad(songId) { ...@@ -55,7 +68,7 @@ function SongDetailLoad(songId) {
currentSongData = songData; currentSongData = songData;
}).catch(function(error) { }).catch(function(error) {
console.error(error); console.error(error);
NavigateToSection(5); NavigateToSection(6);
}); });
} }
...@@ -74,7 +87,7 @@ function SongDetailStartPreview() { ...@@ -74,7 +87,7 @@ function SongDetailStartPreview() {
SongDetailStopPreview(); SongDetailStopPreview();
} }
isPlayingPreview = true; isPlayingPreview = true;
DOMButtonPreview.innerText = "PAUSE PREVIEW"; DOMButtonPreview.innerText = locale.get('songdetail.actions.stopPreviewButton');
DOMButtonPreview.classList.add("button-primary"); DOMButtonPreview.classList.add("button-primary");
} }
function SongDetailStopPreview() { function SongDetailStopPreview() {
...@@ -85,7 +98,7 @@ function SongDetailStopPreview() { ...@@ -85,7 +98,7 @@ function SongDetailStopPreview() {
currentPreviewAudio = null; currentPreviewAudio = null;
isPlayingPreview = false; isPlayingPreview = false;
DOMButtonPreview.innerText = "PLAY PREVIEW"; DOMButtonPreview.innerText = locale.get('songdetail.actions.playPreviewButton');
DOMButtonPreview.classList.remove("button-primary"); DOMButtonPreview.classList.remove("button-primary");
} }
...@@ -94,9 +107,9 @@ function SongDetailDownload() { ...@@ -94,9 +107,9 @@ function SongDetailDownload() {
} }
function SongDetailCopyLink() { function SongDetailCopyLink() {
clipboard.writeText("https://spinsha.re/song/" + currentSongId);
} }
function SongDetailReport() { function SongDetailReport() {
alert("Coming soon..."); shell.openExternal("https://spinsha.re/report/" + currentSongId);
} }
\ No newline at end of file
...@@ -23,7 +23,7 @@ function InitStartup() { ...@@ -23,7 +23,7 @@ function InitStartup() {
DOMStaffAds.appendChild(BuildAdDOM(ad)); DOMStaffAds.appendChild(BuildAdDOM(ad));
}); });
}).catch(function(error) { }).catch(function(error) {
NavigateToSection(5); NavigateToSection(6);
console.error(error); console.error(error);
}); });
...@@ -84,7 +84,7 @@ function LoadNewSongs() { ...@@ -84,7 +84,7 @@ function LoadNewSongs() {
DOMNewSongsList.appendChild(BuildSongDOM(song)); DOMNewSongsList.appendChild(BuildSongDOM(song));
}); });
}).catch(function(error) { }).catch(function(error) {
NavigateToSection(5); NavigateToSection(6);
console.error(error); console.error(error);
}); });
} }
...@@ -97,7 +97,7 @@ function LoadPopularSongs() { ...@@ -97,7 +97,7 @@ function LoadPopularSongs() {
DOMPopularSongsList.appendChild(BuildSongDOM(song)); DOMPopularSongsList.appendChild(BuildSongDOM(song));
}); });
}).catch(function(error) { }).catch(function(error) {
NavigateToSection(5); NavigateToSection(6);
console.error(error); console.error(error);
}); });
} }
...@@ -141,14 +141,14 @@ function BuildAdDOM(adItem) { ...@@ -141,14 +141,14 @@ function BuildAdDOM(adItem) {
break; break;
case 2: case 2:
// Search Query // Search Query
// TODO NavigateToSection(1);
SearchQuery(adItem.button.data);
break; break;
case 3: case 3:
// External // External
adButton.addEventListener('click', function() { adButton.addEventListener('click', function() {
shell.openExternal(adItem.button.data); shell.openExternal(adItem.button.data);
}); });
// TODO
} }
adContainer.appendChild(adButton); adContainer.appendChild(adButton);
......
const DOMUserDetailBackground = document.querySelector(".user-detail-background");
const DOMUserDetail = document.querySelector(".section-user-detail .user-detail");
const DOMUserDetailAvatar = document.querySelector(".section-user-detail .user-avatar");
const DOMUserSongRow = document.querySelector(".song-row-user");
const DOMUserName = DOMUserDetail.querySelector(".user-name");
const DOMUserSongsList = document.querySelector(".song-row-user .song-list");
const DOMUserSongsNoResults = document.querySelector(".song-row-user .song-list-noresults");
function UserDetailLoad(userId) {
DOMUserDetail.classList.remove("active");
DOMUserSongRow.classList.remove("active");
DOMUserSongsNoResults.classList.remove("active");
DOMUserSongsList.innerHTML = "";
api.getUserDetail(userId).then(function(apiResponse) {
let userData = apiResponse.data;
if(apiResponse.status == 404) {
NavigateToSection(7);
} else {
DOMUserDetail.classList.add("active");
DOMUserSongRow.classList.add("active");
DOMUserDetailBackground.style.backgroundImage = "url('" + userData.avatar + "')";
DOMUserDetailAvatar.style.backgroundImage = "url('" + userData.avatar + "')";
DOMUserName.innerText = userData.username;
if(userData.songs.length > 0) {
userData.songs.forEach(function(song) {
DOMUserSongsList.appendChild(BuildSongDOM(song));
});
} else {
DOMUserSongsNoResults.classList.add("active");
}
}
}).catch(function(error) {
console.error(error);
NavigateToSection(6);
});
}
\ No newline at end of file
const DOMUpdateOverlay = document.querySelector(".update-overlay");
const DOMUpdateStatusAvailable = DOMUpdateOverlay.querySelector(".update-status-available");
const DOMUpdateStatusLatest = DOMUpdateOverlay.querySelector(".update-status-latest");
const DOMUpdateActionsAvailable = DOMUpdateOverlay.querySelector(".update-actions-available");
const DOMUpdateActionsLatest = DOMUpdateOverlay.querySelector(".update-actions-latest");
// Check Updates
function CheckForUpdates(showIfLatest) {
api.getCurrentVersion().then(function(versionData) {
DOMUpdateStatusAvailable.classList.remove("active");
DOMUpdateStatusLatest.classList.remove("active");
DOMUpdateActionsAvailable.classList.remove("active");
DOMUpdateActionsLatest.classList.remove("active");
if(versionData.join(".") != app.getVersion() && !isDev) {
DOMUpdateOverlay.classList.add("active");
DOMUpdateStatusAvailable.classList.add("active");
DOMUpdateActionsAvailable.classList.add("active");
} else {
if(showIfLatest) {
DOMUpdateOverlay.classList.add("active");
DOMUpdateStatusLatest.classList.add("active");
DOMUpdateActionsLatest.classList.add("active");
}
}
}).catch(function(error) {
NavigateToSection(6);
console.error(error);
});
}
function DownloadUpdate() {
shell.openExternal("https://spinsha.re/download-client");
}
function IgnoreUpdate() {
DOMUpdateOverlay.classList.remove("active");
}
CheckForUpdates(false);
\ No newline at end of file
...@@ -2,10 +2,25 @@ ...@@ -2,10 +2,25 @@
"startup.newsongs.header": "Neue Songs", "startup.newsongs.header": "Neue Songs",
"startup.popularsongs.header": "Populäre Songs", "startup.popularsongs.header": "Populäre Songs",
"search.input.placeholder": "Suche nach Songs, Tags & Profilen...",
"search.results.users.header": "Nutzer",
"search.results.songs.header": "Songs",
"search.noresults.text": "Deine Suche ergab kein Ergebnis. Vergewissere dich, dass alle Wörter korrekt geschrieben wurden oder versuche es mit einem anderen Suchbegriff.",
"library.installed.header": "Installierte Songs", "library.installed.header": "Installierte Songs",
"library.installed.install.title": "Installieren", "library.installed.install.title": "Installieren",
"library.installed.install.text": "Lokale .zip installieren", "library.installed.install.text": "Lokale .zip installieren",
"songdetail.createdBy": "Erstellt von ",
"songdetail.actions.downloadButton": "Downloaden",
"songdetail.actions.playPreviewButton": "Vorschau abspielen",
"songdetail.actions.stopPreviewButton": "Vorschau abbrechen",
"songdetail.actions.copyLinkButton": "Link Kopieren",
"songdetail.actions.reportButton": "Melden",
"userdetail.uploaded.header": "Hochgeladene Songs",
"userdetail.uploaded.noresults": "Dieser Nutzer hat noch keine Songs hochgeladen.",
"settings.general.header": "SpinShare", "settings.general.header": "SpinShare",
"settings.general.version.label": "Version", "settings.general.version.label": "Version",
"settings.general.update.label": "Update", "settings.general.update.label": "Update",
...@@ -15,5 +30,24 @@ ...@@ -15,5 +30,24 @@
"settings.directories.header": "Ordner", "settings.directories.header": "Ordner",
"settings.directories.gameDirectory.label": "Spiel-Ordner", "settings.directories.gameDirectory.label": "Spiel-Ordner",
"settings.directories.gameDirectory.changeButton": "Ändern", "settings.directories.gameDirectory.changeButton": "Ändern",
"settings.directories.gameDirectory.resetButton": "Zurücksetzen" "settings.directories.gameDirectory.resetButton": "Zurücksetzen",
"connectionerror.server.title": "Verbindungsfehler",
"connectionerror.server.text": "Bitte überprüfe deine Internetverbindung oder versuche es später erneut. Du kannst weiterhin deine Audiothek nutzen und lokale .zip Backups installieren.",
"connectionerror.notfound.title": "404 - Nicht gefunden",
"connectionerror.notfound.text": "Entschuldigung, das konnten wir nicht finden. Es wurde entweder gelöscht oder war ohnehin nie verfügbar.",
"download.status.downloading": "Herunterladen",
"download.status.extracting": "Auspacken",
"download.status.extractingFailed": "Konnte den Song nicht auspacken!",
"download.status.installing": "Installieren",
"download.status.installingFailed": "Konnte den Song nicht installieren!",
"download.status.done": "Fertig",
"download.closeButton": "Schließen",
"update.availableText": "Ein Update ist verfügbar.",
"update.latestText": "Du hast bereits die neueste Version.",
"update.download": "Herunterladen",
"update.later": "Später",
"update.close": "Schließen"
} }
\ No newline at end of file
...@@ -2,10 +2,25 @@ ...@@ -2,10 +2,25 @@
"startup.newsongs.header": "New Songs", "startup.newsongs.header": "New Songs",
"startup.popularsongs.header": "Popular Songs", "startup.popularsongs.header": "Popular Songs",
"search.input.placeholder": "Search for songs, tags & profiles...",
"search.results.users.header": "Users",
"search.results.songs.header": "Songs",
"search.noresults.text": "Your search did not match any songs or users. Make sure, that all words are spelled correctly or try a different query.",
"library.installed.header": "Installed Songs", "library.installed.header": "Installed Songs",
"library.installed.install.title": "Install", "library.installed.install.title": "Install",
"library.installed.install.text": "Install a local .zip", "library.installed.install.text": "Install a local .zip",
"songdetail.createdBy": "Created by ",
"songdetail.actions.downloadButton": "Download",
"songdetail.actions.playPreviewButton": "Play Preview",
"songdetail.actions.stopPreviewButton": "Stop Preview",
"songdetail.actions.copyLinkButton": "Copy Link",
"songdetail.actions.reportButton": "Report",
"userdetail.uploaded.header": "Uploaded Songs",
"userdetail.uploaded.noresults": "This user did not upload any songs yet.",
"settings.general.header": "SpinShare", "settings.general.header": "SpinShare",
"settings.general.version.label": "Version", "settings.general.version.label": "Version",
"settings.general.update.label": "Update", "settings.general.update.label": "Update",
...@@ -15,5 +30,24 @@ ...@@ -15,5 +30,24 @@
"settings.directories.header": "Directories", "settings.directories.header": "Directories",
"settings.directories.gameDirectory.label": "Game Directory", "settings.directories.gameDirectory.label": "Game Directory",
"settings.directories.gameDirectory.changeButton": "Change", "settings.directories.gameDirectory.changeButton": "Change",
"settings.directories.gameDirectory.resetButton": "Reset" "settings.directories.gameDirectory.resetButton": "Reset",
"connectionerror.server.title": "Connection error",
"connectionerror.server.text": "Please check your internet connection or try again later. You can still access your library and install local .zip backups.",
"connectionerror.notfound.title": "404 - Not Found",
"connectionerror.notfound.text": "Sorry, we couldn't find that. It was either removed or never available in the first place.",
"download.status.downloading": "Downloading",
"download.status.extracting": "Extracting",
"download.status.extractingFailed": "Could not extract song!",
"download.status.installing": "Installing",
"download.status.installingFailed": "Could not install song!",
"download.status.done": "Done",
"download.closeButton": "Close",
"update.availableText": "An update is available.",
"update.latestText": "You already have the latest version.",
"update.download": "Download",
"update.later": "Later",
"update.close": "Close"
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment