finisch sharing functionality
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing

This commit is contained in:
Artem Anufrij 2023-02-16 23:59:01 +01:00
parent efef863e66
commit 4d4fb4b4e9
13 changed files with 567 additions and 110 deletions

File diff suppressed because it is too large Load Diff

View File

@ -245,7 +245,7 @@ export default {
}, },
login() { login() {
let hash = window.location.hash.replace("#/", ""); let hash = window.location.hash.replace("#/", "");
if (!hash.startsWith("login") && !hash.startsWith("setup")) { if (!hash.startsWith("login") && !hash.startsWith("setup") && !hash.startsWith("share")) {
let redirect = encodeURIComponent(hash); let redirect = encodeURIComponent(hash);
if (redirect) { if (redirect) {
this.$router.replace({ this.$router.replace({

View File

@ -0,0 +1,72 @@
<template>
<div id="content" class="flex-column">
<div class="flex-column ma-horizontal">
<h1>{{ album.title }}</h1>
<h2>{{ album.artist_name }}</h2>
</div>
<div id="tracks" class="flex-row border-top">
<div class="flex-column">
<img id="cover" class="shadow ma24" :src="cover" />
<p class="center ma-off hideOnMobile">
<b>{{ album.tracks.length }}</b> Tracks
</p>
</div>
<ul id="trackList" class="tracks">
<li v-for="track in album.tracks" :key="track._id">
<TrackItem :track="track" :showCover="false" />
</li>
</ul>
</div>
</div>
</template>
<script>
import TrackItem from "../components/Track";
export default {
data() {
return {
album: {
covers: {},
tracks: [],
},
};
},
methods: {
show(album) {
this.album = album;
},
},
computed: {
cover() {
if (!this.album.covers) {
return "/static/icons/dummy/album.svg";
}
return this.album.covers.cover256;
},
},
components: {
TrackItem,
},
};
</script>
<style scoped>
#cover {
align-self: center;
width: 256px;
}
#content,
#tracks {
overflow: auto;
}
@media (max-width: 480px) {
#tracks {
flex-direction: column;
}
#trackList {
border-top: 1px solid var(--light-border);
}
}
</style>

View File

@ -0,0 +1,78 @@
<template>
<div id="content" class="flex-column">
<div class="flex-column ma-horizontal">
<h1>{{ box.title }}</h1>
</div>
<div id="videos" class="flex-row border-top">
<div class="flex-column">
<img id="cover" class="shadow ma24" :src="cover" />
<p class="center ma-off hideOnMobile">
<b>{{ box.videos.length }}</b> Videos
</p>
</div>
<ul id="videoList" class="videos">
<li v-for="video in box.videos" :key="video._id">
<VideoItem :video="video" />
</li>
</ul>
</div>
</div>
</template>
<script>
import VideoItem from "../components/Video.vue";
export default {
data() {
return {
box: {
covers: {},
videos: [],
},
};
},
methods: {
show(box) {
this.box = box;
},
},
computed: {
cover() {
if (!this.box.covers) {
return "/static/icons/dummy/box.svg";
}
return this.box.covers.cover256;
},
},
components: {
VideoItem,
},
};
</script>
<style scoped>
#cover {
align-self: center;
width: 256px;
}
#content,
#videos {
overflow: auto;
}
.video {
max-width: 256px;
}
@media (max-width: 480px) {
#videos {
flex-direction: column;
}
#videoList {
border-top: 1px solid var(--light-border);
}
.video {
max-width: inherit;
}
}
</style>

View File

@ -181,6 +181,13 @@ export default {
this.audio.pause(); this.audio.pause();
this.audio.src = url; this.audio.src = url;
this.pushHistoryItem();
},
pushHistoryItem() {
if (!this.currentUser._id) {
return;
}
let item = { let item = {
id: this.currentTrackParent._id, id: this.currentTrackParent._id,
type: this.currentTrackParentType, type: this.currentTrackParentType,
@ -258,15 +265,17 @@ export default {
} }
}, },
gotoContainer() { gotoContainer() {
switch (this.selectedTrack.parentType) { if (this.currentUser._id) {
case "album": switch (this.selectedTrack.parentType) {
this.$router.push("/albums?id=" + this.selectedTrack.parent._id); case "album":
break; this.$router.push("/albums?id=" + this.selectedTrack.parent._id);
case "artist": break;
this.$router.push( case "artist":
"/artists?id=" + this.selectedTrack.parent.parent._id this.$router.push(
); "/artists?id=" + this.selectedTrack.parent.parent._id
break; );
break;
}
} }
}, },
switchShuffle() { switchShuffle() {
@ -275,9 +284,15 @@ export default {
}, },
switchRepeatType() { switchRepeatType() {
this.$store.dispatch("player/switchPlayerRepeatMode"); this.$store.dispatch("player/switchPlayerRepeatMode");
if (!this.currentUser._id) {
return;
}
this.saveUserSettings(); this.saveUserSettings();
}, },
saveUserSettings() { saveUserSettings() {
if (!this.currentUser._id) {
return;
}
this.$store.dispatch("user/savePlayerSettings"); this.$store.dispatch("user/savePlayerSettings");
}, },
timeUpdate(event) { timeUpdate(event) {
@ -314,6 +329,9 @@ export default {
} }
return type; return type;
}, },
currentUser() {
return this.$store.getters["user/user"];
},
formatedD() { formatedD() {
let m = Math.floor(this.duration / 60); let m = Math.floor(this.duration / 60);
let s = Math.floor(this.duration - m * 60); let s = Math.floor(this.duration - m * 60);

View File

@ -40,7 +40,13 @@
<button v-if="!selectedAlbum.share._id" @click="shareEnable"> <button v-if="!selectedAlbum.share._id" @click="shareEnable">
<awesome-icon icon="share" />Share this album <awesome-icon icon="share" />Share this album
</button> </button>
<button v-else @click="shareDisable"> <button
v-if="selectedAlbum.share._id"
@click="addShareUrlToClipboard"
>
<awesome-icon icon="clipboard" />Copy url into clipboard
</button>
<button v-if="selectedAlbum.share._id" @click="shareDisable">
<awesome-icon icon="share" />Remove share <awesome-icon icon="share" />Remove share
</button> </button>
</div> </div>
@ -110,6 +116,11 @@ export default {
}; };
}, },
methods: { methods: {
addShareUrlToClipboard() {
let url =
window.location.origin + "/#/share?id=" + this.selectedAlbum.share._id;
navigator.clipboard.writeText(url);
},
dblclick() { dblclick() {
this.$store.commit("tracks/resetSelectedTrack"); this.$store.commit("tracks/resetSelectedTrack");
this.$store.commit("radios/resetSelectedRadio"); this.$store.commit("radios/resetSelectedRadio");
@ -208,7 +219,11 @@ export default {
this.$store.dispatch("albums/selectAlbum", album); this.$store.dispatch("albums/selectAlbum", album);
}, },
shareEnable() { shareEnable() {
this.$store.dispatch("albums/shareEnable", this.selectedAlbum); this.$store
.dispatch("albums/shareEnable", this.selectedAlbum)
.then(() => {
this.addShareUrlToClipboard();
});
}, },
shareDisable() { shareDisable() {
this.$store.dispatch("albums/shareDisable", this.selectedAlbum); this.$store.dispatch("albums/shareDisable", this.selectedAlbum);
@ -342,7 +357,7 @@ export default {
border-top: 1px solid #ffffff20; border-top: 1px solid #ffffff20;
border-bottom: 1px solid #00000020; border-bottom: 1px solid #00000020;
} }
#stats button { .dropdown-activator button {
width: 32px; width: 32px;
height: 32px; height: 32px;
} }

View File

@ -41,7 +41,13 @@
<button v-if="!selectedBox.share._id" @click="shareEnable"> <button v-if="!selectedBox.share._id" @click="shareEnable">
<awesome-icon icon="share" />Share this box <awesome-icon icon="share" />Share this box
</button> </button>
<button v-else @click="shareDisable"> <button
v-if="selectedBox.share._id"
@click="addShareUrlToClipboard"
>
<awesome-icon icon="clipboard" />Copy url into clipboard
</button>
<button v-if="selectedBox.share._id" @click="shareDisable">
<awesome-icon icon="share" />Remove share <awesome-icon icon="share" />Remove share
</button> </button>
</div> </div>
@ -95,6 +101,11 @@ import { mapGetters } from "vuex";
export default { export default {
methods: { methods: {
addShareUrlToClipboard() {
let url =
window.location.origin + "/#/share?id=" + this.selectedBox.share._id;
navigator.clipboard.writeText(url);
},
dblclick() { dblclick() {
this.$store.commit("tracks/resetSelectedTrack"); this.$store.commit("tracks/resetSelectedTrack");
this.$store.commit("radios/resetSelectedRadio"); this.$store.commit("radios/resetSelectedRadio");
@ -174,7 +185,9 @@ export default {
this.$store.dispatch("boxes/resetCover", this.selectedBox); this.$store.dispatch("boxes/resetCover", this.selectedBox);
}, },
shareEnable() { shareEnable() {
this.$store.dispatch("boxes/shareEnable", this.selectedBox); this.$store.dispatch("boxes/shareEnable", this.selectedBox).then(() => {
this.addShareUrlToClipboard();
});
}, },
shareDisable() { shareDisable() {
this.$store.dispatch("boxes/shareDisable", this.selectedBox); this.$store.dispatch("boxes/shareDisable", this.selectedBox);
@ -274,7 +287,7 @@ export default {
border-top: 1px solid #ffffff20; border-top: 1px solid #ffffff20;
border-bottom: 1px solid #00000020; border-bottom: 1px solid #00000020;
} }
#stats button { .dropdown-activator button {
width: 32px; width: 32px;
height: 32px; height: 32px;
} }

View File

@ -89,6 +89,9 @@ export default {
this.$store.dispatch("videos/playNextTo", this.selectedVideo); this.$store.dispatch("videos/playNextTo", this.selectedVideo);
}, },
pushHistoryItem() { pushHistoryItem() {
if (!this.currentUser._id) {
return;
}
let item = { let item = {
id: this.selectedVideo.parent._id, id: this.selectedVideo.parent._id,
type: "box", type: "box",
@ -154,6 +157,9 @@ export default {
}, },
}, },
computed: { computed: {
currentUser() {
return this.$store.getters["user/user"];
},
selectedVideo() { selectedVideo() {
return this.$store.getters["videos/selectedVideo"]; return this.$store.getters["videos/selectedVideo"];
}, },

View File

@ -155,8 +155,11 @@ export default {
axios.put(context.rootGetters.server + "/api/albums/" + album._id, body, context.rootGetters.headers); axios.put(context.rootGetters.server + "/api/albums/" + album._id, body, context.rootGetters.headers);
}, },
shareEnable(context, album) { shareEnable(context, album) {
axios.post(context.rootGetters.server + "/api/albums/" + album._id + "/share", {}, context.rootGetters.headers).then(res => { return new Promise(resolve => {
album.share = res.data; axios.post(context.rootGetters.server + "/api/albums/" + album._id + "/share", {}, context.rootGetters.headers).then(res => {
album.share = res.data;
resolve();
});
}); });
}, },
shareDisable(context, album) { shareDisable(context, album) {

View File

@ -131,8 +131,11 @@ export default {
}); });
}, },
shareEnable(context, box) { shareEnable(context, box) {
axios.post(context.rootGetters.server + "/api/boxes/" + box._id + "/share", {}, context.rootGetters.headers).then(res => { return new Promise(resolve => {
box.share = res.data; axios.post(context.rootGetters.server + "/api/boxes/" + box._id + "/share", {}, context.rootGetters.headers).then(res => {
box.share = res.data;
resolve();
});
}); });
}, },
shareDisable(context, box) { shareDisable(context, box) {

View File

@ -4,12 +4,23 @@ export default {
get(context, id) { get(context, id) {
return new Promise((resolve) => { return new Promise((resolve) => {
axios.get(context.rootGetters.server + "/api/shares/" + id, context.rootGetters.headers).then((res) => { axios.get(context.rootGetters.server + "/api/shares/" + id, context.rootGetters.headers).then((res) => {
if (res.data.object.type == "album") { if (!res.data._id) {
console.log(res.data) resolve(res.data);
res.data.object.tracks.forEach(track => { return;
track.parent = res.data.object; }
track.parentType = "album" switch (res.data.object.type) {
}); case "album":
res.data.object.tracks.forEach(track => {
track.parent = res.data.object;
track.parentType = "album"
});
break;
case "box":
res.data.object.videos.forEach(video => {
video.parent = res.data.object;
video.parentType = "box"
});
break;
} }
resolve(res.data); resolve(res.data);
}); });

View File

@ -4,7 +4,7 @@ import router from '../../../router'
export default { export default {
play(context, video) { play(context, video) {
context.commit("selectVideo", video); context.commit("selectVideo", video);
if (context.rootGetters.routerQuery.play != video._id) { if (context.rootGetters.routerQuery.play != video._id && context.rootGetters.routerPath != "/share") {
router.push("/boxes?id=" + video.parent._id + "&play=" + video._id); router.push("/boxes?id=" + video.parent._id + "&play=" + video._id);
} }
}, },

View File

@ -1,52 +1,62 @@
<template> <template>
<div ref="share" id="share" class="flex-column"> <div ref="share" id="share" class="flex-column">
<div class="flex-column ma-horizontal"> <AlbumContent ref="album" v-if="type == 'album'" />
<h1>{{ object.title }}</h1> <BoxContent ref="box" v-if="type == 'box'" />
<h2>{{ object.artist_name }}</h2>
</div>
<div id="content" class="flex-row border-top">
<div>
<img id="cover" class="shadow ma24" :src="cover" />
</div>
<ul id="trackList" class="tracks">
<li v-for="track in object.tracks" :key="track._id">
<TrackItem :track="track" :showCover="false" />
</li>
</ul>
</div>
</div> </div>
</template> </template>
<script> <script>
import TrackItem from "../components/Track"; import AlbumContent from "../components/AlbumContent.vue";
import BoxContent from "../components/BoxContent.vue";
export default { export default {
name: "ShareView", name: "ShareView",
data() { data() {
return { return {
object: { type: "",
covers: { cover256: "" },
},
}; };
}, },
mounted() { methods: {
if (this.$route.query.id) { loadShare() {
this.$store.dispatch("share/get", this.$route.query.id).then((res) => { if (this.$route.query.id) {
this.$nextTick(() => { this.$store.dispatch("share/get", this.$route.query.id).then((res) => {
this.object = res.object; if (!res._id) {
this.$router.replace("/login");
return;
}
this.type = res.object.type;
this.$nextTick(() => {
switch (this.type) {
case "album":
this.$refs.album.show(res.object);
break;
case "box":
this.$refs.box.show(res.object);
break;
}
});
}); });
}); } else {
} else { this.$router.replace("/login");
this.$router.replace("/"); }
} },
}, },
computed: { computed: {
cover() { server() {
return this.object.covers.cover256; return this.$store.getters.server;
}, },
}, },
components: { components: {
TrackItem, AlbumContent,
BoxContent,
},
watch: {
server() {
this.loadShare();
},
"$route.query.id": function () {
this.loadShare();
},
}, },
}; };
</script> </script>
@ -55,12 +65,4 @@ export default {
#share { #share {
overflow: auto; overflow: auto;
} }
#cover {
align-self: flex-start;
width: 256px;
align-self: center;
}
#content {
overflow: auto;
}
</style> </style>