Commit 0fbd4383 authored by SpinShare's avatar SpinShare

library removal, frontpage pagination

parent 1bca3c81
......@@ -7,33 +7,91 @@
<ContextMenu>
</ContextMenu>
<DeleteOverlay v-if="showDeleteOverlay" v-bind:deleteFiles="deleteFiles" />
</div>
</template>
<script>
import fs from 'fs';
import glob from 'glob';
import path from 'path';
import UserSettings from '@/modules/module.usersettings.js';
import Navigation from '@/components/Navigation/Navigation.vue';
import ContextMenu from '@/components/ContextMenu/ContextMenu.vue';
import DeleteOverlay from '@/components/Overlays/DeleteOverlay.vue';
export default {
name: 'App',
components: {
Navigation,
ContextMenu
ContextMenu,
DeleteOverlay
},
data: function() {
return {
downloadQueue: []
downloadQueue: [],
showDeleteOverlay: false,
deleteFiles: []
}
},
mounted: function() {
this.$root.$on('download', (url) => {
this.addToQueue(url);
});
this.$root.$on('delete', (file) => {
this.$data.showDeleteOverlay = true;
this.$data.deleteFiles = this.getConnectedFiles(file);
console.log(this.$data.deleteFiles);
});
this.$root.$on('deleteDeny', () => {
this.$data.showDeleteOverlay = false;
this.$data.deleteFiles = "";
});
this.$root.$on('deleteConfirmed', () => {
this.$data.deleteFiles.forEach((file) => {
fs.unlinkSync(file);
});
this.$data.showDeleteOverlay = false;
this.$data.deleteFiles = "";
});
},
methods: {
addToQueue: function(url) {
this.$data.downloadQueue.push(url);
console.log("Added " + url + " to queue");
},
getConnectedFiles: function(srtbFilePath) {
let userSettings = new UserSettings();
let srtbContent = JSON.parse( fs.readFileSync(srtbFilePath) );
let connectedFiles = [];
connectedFiles.push(srtbFilePath);
let stringValueContainers = srtbContent['largeStringValuesContainer'].values;
stringValueContainers.forEach((stringValueContainer) => {
if(stringValueContainer.key == "SO_TrackInfo_TrackInfo") {
let rawTrackInfo = JSON.parse( stringValueContainer.val );
let coverPath = glob.sync(path.join(userSettings.get('gameDirectory'), "AlbumArt", rawTrackInfo.albumArtReference.assetName + ".*"))[0];
if(coverPath) {
connectedFiles.push(coverPath);
}
}
if(stringValueContainer.key.includes("SO_ClipInfo")) {
let rawClipInfo = JSON.parse( stringValueContainer.val );
let clipPath = glob.sync(path.join(userSettings.get('gameDirectory'), "AudioClips", rawClipInfo.clipAssetReference.assetName + ".*"))[0];
if(clipPath) {
connectedFiles.push(clipPath);
}
}
});
return connectedFiles;
}
},
watch: {
......
<template>
<div class="delete-overlay">
<div class="delete-content">
<div class="delete-main">
<div class="delete-title">library.deletemodal.title</div>
<div class="delete-text">library.deletemodal.text</div>
<div class="delete-files">
<span v-for="deleteFile in deleteFiles">{{ deleteFile }}</span>
</div>
</div>
<div class="delete-actions">
<button class="button">Delete</button>
<button class="button" v-on:click="close()">Close</button>
</div>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'DeleteOverlay',
props: [
'deleteFiles'
],
methods: {
confirm() {
this.$root.$emit('deleteConfirm');
},
close() {
this.$root.$emit('deleteDeny');
}
}
}
</script>
<style scoped lang="less">
.delete-overlay {
position: fixed;
z-index: 100;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: rgba(0,0,0,0.75);
display: flex;
justify-content: center;
align-items: center;
& .delete-content {
width: 500px;
background: #212629;
border-radius: 6px;
position: relative;
overflow: hidden;
& .delete-main {
padding: 25px;
& .delete-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
& .delete-text {
padding: 15px 0px;
opacity: 0.6;
}
& .delete-files {
font-size: 12px;
& span {
display: block;
padding: 5px 0px;
}
}
}
& .delete-actions {
display: flex;
justify-content: flex-end;
padding: 25px;
background: rgba(0,0,0,0.4);
& button {
margin-left: 10px;
}
}
}
}
</style>
......@@ -52,9 +52,9 @@
x: e.pageX,
y: e.pageY,
items: [
{ icon: "eye", title: "Open", method: function() { alert('TODO') }.bind(this) },
{ icon: "link", title: "Copy Link", method: function() { clipboard.writeText('https://spinsha.re/song/' + this.$props.id) }.bind(this) },
{ icon: "download", title: "Download", method: function() { this.$root.$emit('download', this.$props.zip); }.bind(this) }
{ icon: "eye", title: "Open", method: () => { alert('TODO') } },
{ icon: "link", title: "Copy Link", method: () => { clipboard.writeText('https://spinsha.re/song/' + this.$props.id) } },
{ icon: "download", title: "Download", method: () => { this.$root.$emit('download', this.$props.zip); } }
]});
}
}
......
......@@ -5,6 +5,7 @@
<div class="song-title">&nbsp;</div>
<div class="song-artist">&nbsp;</div>
<div class="song-difficulties">
<img src="@/assets/img/difficultyEasy.svg" />
</div>
</div>
</div>
......@@ -41,14 +42,32 @@
& .song-metadata {
padding: 15px;
& .song-title {
height: 19px;
}
& .song-artist {
margin-top: 5px;
height: 19px;
}
& .song-difficulties {
margin-top: 10px;
height: 20px;
display: flex;
& img {
height: 18px;
margin-right: 10px;
opacity: 0;
}
}
}
}
@keyframes songLoadingShimmer {
from {
background-position: 0px 0px;
}
to {
background-position: 173px 0px;
}
}
</style>
......@@ -20,6 +20,7 @@
name: 'SongLocalItem',
props: [
'id',
'file',
'detail',
'cover',
'isSpinShare'
......@@ -37,7 +38,7 @@
x: e.pageX,
y: e.pageY,
items: [
{ icon: "delete", title: "Delete", method: function() { alert('TODO') }.bind(this) }
{ icon: "delete", title: "Delete", method: () => { this.$root.$emit('delete', this.$props.file); } }
]});
}
}
......
......@@ -3,12 +3,11 @@
<div class="song-header">
<div :class="'row-title ' + (noactions ? 'row-title-noactions' : '')">{{ title }}</div>
<div class="row-controls" v-if="!noactions">
<div class="item disabled row-controls-previous"><i class="mdi mdi-chevron-left"></i></div>
<div class="item row-controls-next"><i class="mdi mdi-chevron-right"></i></div>
<slot name="controls"></slot>
</div>
</div>
<div class="song-list">
<slot></slot>
<slot name="song-list"></slot>
</div>
</div>
</template>
......
<template>
<div class="user-row">
<div class="user-header">
<div :class="'row-title ' + (noactions ? 'row-title-noactions' : '')">{{ title }}</div>
<div class="row-controls" v-if="!noactions">
<div class="item disabled row-controls-previous"><i class="mdi mdi-chevron-left"></i></div>
<div class="item row-controls-next"><i class="mdi mdi-chevron-right"></i></div>
</div>
<div class="row-title">{{ title }}</div>
</div>
<div class="user-list">
<slot></slot>
......@@ -20,8 +16,7 @@
export default {
name: 'UserRow',
props: [
'title',
'noactions'
'title'
]
}
</script>
......@@ -41,10 +36,7 @@
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
&.row-title-noactions {
margin: 10px 0px;
}
margin: 10px 0px;
}
}
& .user-list {
......
<template>
<section class="section-library">
<SongRow title="Installed Songs" noactions="true">
<SongInstallItem />
<SongRow title="Installed Songs">
<template v-slot:controls>
<div class="item"></div>
<div class="item" v-on:click="refreshLibrary()"><i class="mdi mdi-refresh"></i></div>
</template>
<template v-slot:song-list>
<SongInstallItem />
<SongLocalItem
v-for="song in librarySongs"
v-bind:key="song.detail.id"
v-bind="song" />
<SongLocalItem
v-for="song in librarySongs"
v-bind:key="song.detail.id"
v-bind="song" />
</template>
</SongRow>
</section>
</template>
......@@ -61,6 +67,7 @@
}
let librarySong = {
file: file,
detail: songDetail,
cover: songCover,
isSpinShare: songSpinShareReference
......
......@@ -7,7 +7,7 @@
<input type="search" placeholder="Search for songs, tags &amp; profiles..." v-on:input="search()" v-model="searchQuery">
</div>
<div class="search-results">
<UserRow title="Users" noactions="true" v-if="searchResultsUsers.length > 0">
<UserRow title="Users" v-if="searchResultsUsers.length > 0">
<UserItem
v-for="user in searchResultsUsers"
v-bind:key="user.id"
......
......@@ -14,28 +14,40 @@
<SongRow
title="New Songs">
<SongItemPlaceholder
v-if="isNewSongsLoading"
v-for="n in 6"
v-bind:key="n" />
<SongItem
v-if="!isNewSongsLoading"
v-for="song in newSongs"
v-bind:key="song.id"
v-bind="song" />
<template v-slot:controls>
<div :class="'item ' + (newSongsOffset == 0 ? 'disabled' : '')" v-on:click="newPrevious()"><i class="mdi mdi-chevron-left"></i></div>
<div :class="'item ' + (newSongs.length < 5 ? 'disabled' : '')" v-on:click="newNext()"><i class="mdi mdi-chevron-right"></i></div>
</template>
<template v-slot:song-list>
<SongItemPlaceholder
v-if="isNewSongsLoading"
v-for="n in 6"
v-bind:key="n" />
<SongItem
v-if="!isNewSongsLoading"
v-for="song in newSongs"
v-bind:key="song.id"
v-bind="song" />
</template>
</SongRow>
<SongRow
title="Popular Songs">
<SongItemPlaceholder
v-if="isPopularSongsLoading"
v-for="n in 6"
v-bind:key="n" />
<SongItem
v-if="!isPopularSongsLoading"
v-for="song in popularSongs"
v-bind:key="song.id"
v-bind="song" />
<template v-slot:controls>
<div :class="'item ' + (popularSongsOffset == 0 ? 'disabled' : '')" v-on:click="popularPrevious()"><i class="mdi mdi-chevron-left"></i></div>
<div :class="'item ' + (popularSongs.length < 5 ? 'disabled' : '')" v-on:click="popularNext()"><i class="mdi mdi-chevron-right"></i></div>
</template>
<template v-slot:song-list>
<SongItemPlaceholder
v-if="isPopularSongsLoading"
v-for="n in 6"
v-bind:key="n" />
<SongItem
v-if="!isPopularSongsLoading"
v-for="song in popularSongs"
v-bind:key="song.id"
v-bind="song" />
</template>
</SongRow>
</section>
</template>
......@@ -86,6 +98,50 @@
SongRow,
SongItem,
SongItemPlaceholder
},
methods: {
newNext: function() {
if(this.$data.newSongs.length > 5) {
this.$data.newSongsOffset++;
this.updateNew();
}
},
newPrevious: function() {
if(this.$data.newSongsOffset > 0) {
this.$data.newSongsOffset--;
this.updateNew();
}
},
popularNext: function() {
if(this.$data.popularSongs.length > 5) {
this.$data.popularSongsOffset++;
this.updatePopular();
}
},
popularPrevious: function() {
if(this.$data.popularSongsOffset > 0) {
this.$data.popularSongsOffset--;
this.updatePopular();
}
},
updateNew: function() {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
this.$data.isNewSongsLoading = true;
ssapi.getNewSongs(this.$data.newSongsOffset).then((data) => {
this.$data.isNewSongsLoading = false;
this.$data.newSongs = data;
});
},
updatePopular: function() {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
this.$data.isPopularSongsLoading = true;
ssapi.getPopularSongs(this.$data.popularSongsOffset).then((data) => {
this.$data.isPopularSongsLoading = false;
this.$data.popularSongs = data;
});
}
}
}
</script>
......
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