Commit ef025358 authored by Andreas Heimann's avatar Andreas Heimann

removed popular tab, implemented userprofile, implemented new search api syntax

parent 61ec76cf
{
"name": "spinshare-client",
"version": "2.4.0",
"version": "2.5.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -9002,9 +9002,9 @@
}
},
"node-forge": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
"dev": true
},
"node-ipc": {
......@@ -11281,12 +11281,12 @@
"dev": true
},
"selfsigned": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
"version": "1.10.8",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
"dev": true,
"requires": {
"node-forge": "0.9.0"
"node-forge": "^0.10.0"
}
},
"semver": {
......
......@@ -21,8 +21,6 @@
import { remote, ipcRenderer } from 'electron';
const { app, dialog } = remote;
import fs from 'fs';
import glob from 'glob';
import path from 'path';
import UserSettings from '@/modules/module.usersettings.js';
......
......@@ -17,7 +17,41 @@
<i class="mdi mdi-download-outline"></i>
<span class="indicator" v-show="downloadQueueCount > 0">{{ downloadQueueCount }}</span>
</div>
<router-link to="/settings" class="item" v-tooltip.down="'Settings'"><i class="mdi mdi-cog-outline"></i></router-link>
<div class="item item-user" tabindex="0" v-if="userData != null">
<div class="user-avatar" :style="'background-image: url(' + userData.avatar + ');'"></div>
<div class="user-actions">
<router-link :to="{ name: 'UserDetailCharts', params: { id: userData.id } }" class="user-action-item">
<i class="mdi mdi-music"></i>
<span>My Charts</span>
</router-link>
<router-link :to="{ name: 'UserDetailReviews', params: { id: userData.id } }" class="user-action-item">
<i class="mdi mdi-playlist-music"></i>
<span>My Playlists</span>
</router-link>
<router-link :to="{ name: 'UserDetailSpinPlays', params: { id: userData.id } }" class="user-action-item">
<i class="mdi mdi-thumbs-up-down"></i>
<span>My Reviews</span>
</router-link>
<router-link :to="{ name: 'UserDetailSpinPlays', params: { id: userData.id } }" class="user-action-item">
<i class="mdi mdi-youtube"></i>
<span>My SpinPlays</span>
</router-link>
<div class="user-action-spacer"></div>
<router-link to="/settings" class="user-action-item">
<i class="mdi mdi-cog"></i>
<span>App-Settings</span>
</router-link>
<div v-on:click="openExternal('https://spinsha.re/settings')" class="user-action-item">
<i class="mdi mdi-cog"></i>
<span>Account-Settings</span>
</div>
<div class="user-action-spacer"></div>
<div v-on:click="userLogout()" class="user-action-item">
<i class="mdi mdi-close-circle-outline"></i>
<span>Logout</span>
</div>
</div>
</div>
</nav>
</aside>
</template>
......@@ -26,12 +60,33 @@
import { remote } from 'electron';
const { shell } = remote;
import SSAPI from '@/modules/module.api.js';
import UserSettings from '@/modules/module.usersettings.js';
export default {
name: 'Navigation',
props: [
'downloadQueueCount',
'downloadOverlayShown'
],
data: function() {
return {
userData: {}
}
},
mounted: function () {
let userSettings = new UserSettings();
if(!userSettings.get("connectProfile")) {
this.$router.replace({ name: 'Login' });
}
this.$data.userData = userSettings.get("connectProfile");
this.$root.$on("LoadIntoProfile", (data) => {
this.$data.userData = data;
});
},
methods: {
navigateBack: function() {
this.$router.back();
......@@ -41,6 +96,13 @@
},
openExternal: function(url) {
shell.openExternal(url);
},
userLogout: function() {
let userSettings = new UserSettings();
userSettings.set("connectProfile", null);
userSettings.set("connectToken", null);
window.location.reload();
}
}
}
......@@ -237,6 +299,7 @@
position: absolute;
top: 70px;
right: 10px;
overflow: hidden;
border-radius: 4px;
background: #000;
box-shadow: 0px 4px 12px rgba(0,0,0,0.6);
......@@ -264,6 +327,12 @@
background: rgba(255,255,255,0.1);
}
}
& .user-action-spacer {
margin: 5px 15px;
height: 1px;
width: auto;
background: rgba(255,255,255,0.2);
}
&:after {
bottom: 100%;
......
......@@ -132,22 +132,6 @@ class SSAPI {
});
}
async getPopularSongs(_offset) {
let apiPath = this.apiBase + "songs/popular/" + _offset;
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 getSongDetail(_songId) {
let apiPath = this.apiBase + "song/" + _songId;
let supportedVersion = this.supportedVersion;
......@@ -277,10 +261,12 @@ class SSAPI {
}
async search(_searchQuery) {
let apiPath = this.apiBase + "search/" + _searchQuery;
let apiPath = this.apiBase + "search";
let supportedVersion = this.supportedVersion;
return axios.get(apiPath)
return axios.get(apiPath, {
searchQuery: _searchQuery
})
.then(function(response) {
if(response.data.version !== supportedVersion) {
throw new Error("Client is outdated!");
......@@ -346,6 +332,22 @@ class SSAPI {
throw new Error(error);
});
}
async getConnectProfile(connectToken) {
let apiPath = this.apiBase + "connect/profile/?connectToken=" + connectToken;
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);
});
}
}
module.exports = SSAPI;
......@@ -7,7 +7,6 @@ import ViewStartup from '../views/Startup.vue';
import ViewStartupFrontpage from '../views/StartupFrontpage.vue';
import ViewStartupNewSongs from '../views/StartupNewSongs.vue';
import ViewStartupHotSongs from '../views/StartupHotSongs.vue';
import ViewStartupPopularSongs from '../views/StartupPopularSongs.vue';
import ViewSearch from '../views/Search.vue';
import ViewLibrary from '../views/Library.vue';
import ViewSongDetail from '../views/SongDetail.vue';
......@@ -30,11 +29,14 @@ const routes = [{
component: ViewLogin
}, {
path: '/startup',
name: 'Startup',
component: ViewStartup,
name: 'ViewStartup',
redirect: {
name: 'StartupFrontpage'
},
children: [
{
path: '',
path: '/frontpage',
name: 'StartupFrontpage',
component: ViewStartupFrontpage
},
......@@ -47,11 +49,6 @@ const routes = [{
path: '/hot',
name: 'StartupHot',
component: ViewStartupHotSongs
},
{
path: '/popular',
name: 'StartupPopular',
component: ViewStartupPopularSongs
}
]
}, {
......
......@@ -51,7 +51,7 @@
} else {
ssapi.validateConnectToken(userSettings.get("connectToken")).then((data) => {
if(data) {
this.$router.replace({ name: 'StartupFrontpage' });
this.loadIntoProfile();
} else {
this.showLoginBox();
}
......@@ -80,7 +80,7 @@
case 200:
// Successfull
userSettings.set("connectToken", data.data);
this.$router.replace({ name: 'StartupFrontpage' });
this.loadIntoProfile();
break;
case 403:
case 404:
......@@ -98,6 +98,16 @@
this.$data.apiLoginLoading = false;
this.$data.apiLoginCodeError = false;
this.$data.apiLoginServerError = false;
},
loadIntoProfile: function() {
let ssapi = new SSAPI();
let userSettings = new UserSettings();
ssapi.getConnectProfile(userSettings.get("connectToken")).then((data) => {
userSettings.set("connectProfile", data);
this.$root.$emit("LoadIntoProfile", data);
this.$router.replace({ name: 'StartupFrontpage' });
});
}
},
watch: {
......
......@@ -97,9 +97,9 @@
let ssapi = new SSAPI();
this.$data.apiFinished = false;
if(this.$data.searchQuery != "") {
if(this.$data.searchQuery !== "") {
ssapi.search(this.$data.searchQuery).then((data) => {
if(data.status == 200) {
if(data.status === 200) {
this.$data.searchResultsUsers = data.data.users;
this.$data.searchResultsSongs = data.data.songs;
......
......@@ -2,10 +2,9 @@
<section class="section-startup">
<header>
<div class="tabs">
<router-link to="/" class="tab"><span>{{ $t('startup.tabs.frontpage') }}</span></router-link>
<router-link to="/frontpage" class="tab"><span>{{ $t('startup.tabs.frontpage') }}</span></router-link>
<router-link to="/new" class="tab"><span>{{ $t('startup.tabs.new') }}</span></router-link>
<router-link to="/hot" class="tab"><span>{{ $t('startup.tabs.hot') }}</span></router-link>
<router-link to="/popular" class="tab"><span>{{ $t('startup.tabs.popular') }}</span></router-link>
</div>
</header>
......@@ -49,7 +48,7 @@
background: #272c2e;
color: rgba(255,255,255,0.75);
}
&.router-link-exact-active {
&.router-link-exact-active, &.router-link-active {
opacity: 1;
color: rgba(255,255,255,1);
background: #212629;
......
<template>
<SongRow>
<template v-slot:controls>
<div :class="'button ' + (popularSongsOffset == 0 ? 'button-disabled' : '')" v-on:click="popularPrevious()"><i class="mdi mdi-chevron-left"></i> {{ $t('songrow.navigation.previous' )}}</div>
<div :class="'button ' + (popularSongs.length < 11 ? 'button-disabled' : '')" v-on:click="popularNext()">{{ $t('songrow.navigation.next' )}} <i class="mdi mdi-chevron-right"></i></div>
</template>
<template v-slot:song-list>
<SongItemPlaceholder
v-if="isPopularSongsLoading"
v-for="n in 12"
v-bind:key="n" />
<SongItem
v-if="!isPopularSongsLoading"
v-for="song in popularSongs"
v-bind:key="song.id"
v-bind="song" />
</template>
</SongRow>
</template>
<script>
import SSAPI from '@/modules/module.api.js';
import SongRow from '@/components/Song/SongRow.vue';
import SongItem from '@/components/Song/SongItem.vue';
import SongItemPlaceholder from '@/components/Song/SongItemPlaceholder.vue';
export default {
name: 'Startup',
data: function() {
return {
isPopularSongsLoading: true,
popularSongsOffset: 0,
popularSongs: []
}
},
mounted: function() {
let ssapi = new SSAPI();
ssapi.getPopularSongs(this.$data.popularSongsOffset).then((data) => {
this.$data.isPopularSongsLoading = false;
this.$data.popularSongs = data;
});
},
components: {
SongRow,
SongItem,
SongItemPlaceholder
},
methods: {
popularNext: function() {
if(this.$data.popularSongs.length > 11) {
this.$data.popularSongsOffset++;
this.updatePopular();
}
},
popularPrevious: function() {
if(this.$data.popularSongsOffset > 0) {
this.$data.popularSongsOffset--;
this.updatePopular();
}
},
updatePopular: function() {
let ssapi = new SSAPI();
this.$data.isPopularSongsLoading = true;
ssapi.getPopularSongs(this.$data.popularSongsOffset).then((data) => {
this.$data.isPopularSongsLoading = false;
this.$data.popularSongs = data;
});
}
}
}
</script>
<style scoped lang="less">
.song-row {
padding: 50px;
}
</style>
\ 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