mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
add experimental remove from queue action
+ show albumartist on TrackItem if artists == "" + add action to reset playlist page artists to prevent content flashes + remove use of defaultTrackItem
This commit is contained in:
+2
-2
@@ -47,7 +47,7 @@ const queue = useQStore();
|
||||
const router = useRouter();
|
||||
const modal = useModalStore();
|
||||
const context_store = useContextStore();
|
||||
const app_dom = document.getElementById("app");
|
||||
const app_dom = document.getElementById("app") as HTMLElement;
|
||||
|
||||
queue.readQueue();
|
||||
handleShortcuts(useQStore);
|
||||
@@ -59,7 +59,7 @@ app_dom.addEventListener("click", (e) => {
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
document.getElementById("acontent")?.scrollTo(0, 0);
|
||||
(document.getElementById("acontent") as HTMLElement).scrollTo(0, 0);
|
||||
});
|
||||
|
||||
onStartTyping(() => {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@updateQueue="updateQueue"
|
||||
:isPlaying="queue.playing"
|
||||
:isCurrent="queue.currentid == track.trackid"
|
||||
:isHighlighted="($route.query.highlight as string) == track.uniq_hash"
|
||||
:isHighlighted="($route.query.highlight as string) == track.hash"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,12 +39,12 @@ import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||
|
||||
import SongItem from "../shared/SongItem.vue";
|
||||
|
||||
import { Routes } from "@/composables/enums";
|
||||
import { Track } from "@/interfaces";
|
||||
import useAlbumStore from "@/stores/pages/album";
|
||||
import useQStore from "@/stores/queue";
|
||||
import { focusElem } from "@/utils";
|
||||
import { onMounted, onUpdated, ref } from "vue";
|
||||
import { Track } from "@/interfaces";
|
||||
import useQStore from "@/stores/queue";
|
||||
import useAlbumStore from "@/stores/pages/album";
|
||||
import { Routes } from "@/composables/enums";
|
||||
|
||||
const queue = useQStore();
|
||||
const album = useAlbumStore();
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
:to="{
|
||||
name: 'AlbumView',
|
||||
params: {
|
||||
hash: track.albumhash,
|
||||
hash: track?.albumhash ? track.albumhash : ' ',
|
||||
},
|
||||
}"
|
||||
>
|
||||
<div class="art">
|
||||
<img
|
||||
:src="imguri + track.image"
|
||||
:src="imguri + track?.image"
|
||||
alt=""
|
||||
class="l-image rounded force-lm"
|
||||
loading="lazy"
|
||||
@@ -20,23 +20,27 @@
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<div id="bitrate" v-if="track.bitrate">
|
||||
<div id="bitrate" v-if="track?.bitrate">
|
||||
<span v-if="track.bitrate > 1500">MASTER</span>
|
||||
<span v-else-if="track.bitrate > 330">FLAC</span>
|
||||
<span v-else>MP3</span>
|
||||
• {{ track.bitrate }}
|
||||
</div>
|
||||
<div class="title ellip">{{ props.track.title }}</div>
|
||||
<div class="title ellip">{{ props.track?.title }}</div>
|
||||
<div class="separator no-border"></div>
|
||||
<div class="artists ellip" v-if="props.track.artists[0] !== ''">
|
||||
<span
|
||||
v-for="artist in putCommas(props.track.artists)"
|
||||
:key="artist"
|
||||
>{{ artist }}</span
|
||||
>
|
||||
<div
|
||||
class="artists ellip"
|
||||
v-if="track?.artists && track?.artists[0] !== ''"
|
||||
>
|
||||
<span v-for="artist in putCommas(track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="artists" v-else-if="track?.artists">
|
||||
<span>{{ track.albumartist }}</span>
|
||||
</div>
|
||||
<div class="artists" v-else>
|
||||
<span>{{ props.track.albumartist }}</span>
|
||||
<span>Meh</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,6 +54,6 @@ import { Track } from "../../../interfaces";
|
||||
const imguri = paths.images.thumb;
|
||||
|
||||
const props = defineProps<{
|
||||
track: Track;
|
||||
track: Track | null;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
@playThis="queue.play(index)"
|
||||
:isCurrent="index === queue.current"
|
||||
:isPlaying="queue.playing"
|
||||
:isQueueTrack="true"
|
||||
:index="index"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
@@ -88,7 +90,6 @@ onUpdated(() => {
|
||||
grid-template-rows: max-content 1fr max-content;
|
||||
gap: $small;
|
||||
|
||||
|
||||
.scrollable-r {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
@contextmenu.prevent="showMenu"
|
||||
>
|
||||
<div class="nextup abs">next up</div>
|
||||
<img :src="paths.images.thumb + track.image" class="rounded" />
|
||||
<img :src="paths.images.thumb + track?.image" class="rounded" />
|
||||
<div class="tags">
|
||||
<div class="title ellip">{{ track.title }}</div>
|
||||
<div class="artist ellip">
|
||||
<div class="title ellip">{{ track?.title || "Don't click here" }}</div>
|
||||
<div class="artist ellip" v-if="track">
|
||||
<span v-for="artist in putCommas(track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
</div>
|
||||
<span v-else class="artist">nothing will happen</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -27,14 +28,16 @@ import { showTrackContextMenu as showContext } from "@/composables/context";
|
||||
import { ref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
track: Track;
|
||||
track: Track | null;
|
||||
playNext: () => void;
|
||||
}>();
|
||||
|
||||
const context_on = ref(false);
|
||||
|
||||
function showMenu(e: Event) {
|
||||
showContext(e, props.track, context_on);
|
||||
if (props.track) {
|
||||
showContext(e, props.track, context_on);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
highlighted: isHighlighted,
|
||||
},
|
||||
]"
|
||||
v-bind:class="`track-${track.uniq_hash}`"
|
||||
v-bind:class="`track-${track.hash}`"
|
||||
@dblclick="emitUpdate(track)"
|
||||
@contextmenu.prevent="showMenu"
|
||||
>
|
||||
@@ -75,10 +75,10 @@ import { ref } from "vue";
|
||||
|
||||
import OptionSvg from "@/assets/icons/more.svg";
|
||||
|
||||
import { showTrackContextMenu as showContext } from "@/composables/context";
|
||||
import { paths } from "@/config";
|
||||
import { Track } from "@/interfaces";
|
||||
import { formatSeconds, putCommas } from "@/utils";
|
||||
import { showTrackContextMenu as showContext } from "@/composables/context";
|
||||
|
||||
const context_on = ref(false);
|
||||
const imguri = paths.images.thumb;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div
|
||||
class="track-item"
|
||||
@click="playThis(props.track)"
|
||||
@click="playThis(track)"
|
||||
:class="[
|
||||
{
|
||||
currentInQueue: props.isCurrent,
|
||||
currentInQueue: isCurrent,
|
||||
},
|
||||
{ contexton: context_on },
|
||||
]"
|
||||
@@ -14,21 +14,33 @@
|
||||
<img :src="paths.images.thumb + track.image" alt="" class="rounded" />
|
||||
<div
|
||||
class="now-playing-track-indicator image"
|
||||
v-if="props.isCurrent"
|
||||
:class="{ last_played: !props.isPlaying }"
|
||||
v-if="isCurrent"
|
||||
:class="{ last_played: !isPlaying }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<div class="title ellip">
|
||||
{{ props.track.title }}
|
||||
{{ track.title }}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="artist ellip">
|
||||
<span v-for="artist in putCommas(props.track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
<div class="artist">
|
||||
<div class="ellip" v-if="track.artists[0] !== ''">
|
||||
<span v-for="artist in putCommas(track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="ellip" v-else>
|
||||
<span>{{ track.albumartist }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="remove-track flex"
|
||||
@click.stop="queue.removeFromQueue(index)"
|
||||
v-if="isQueueTrack"
|
||||
>
|
||||
<DelSvg />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -39,13 +51,18 @@ import { paths } from "@/config";
|
||||
import { putCommas } from "@/utils";
|
||||
import { Track } from "@/interfaces";
|
||||
import { showTrackContextMenu as showContext } from "@/composables/context";
|
||||
import DelSvg from "@/assets/icons/plus.svg";
|
||||
import useQueueStore from "@/stores/queue";
|
||||
|
||||
const props = defineProps<{
|
||||
track: Track;
|
||||
isCurrent: boolean;
|
||||
isPlaying: boolean;
|
||||
isQueueTrack?: boolean;
|
||||
index?: number;
|
||||
}>();
|
||||
|
||||
const queue = useQueueStore();
|
||||
const context_on = ref(false);
|
||||
|
||||
function showMenu(e: Event) {
|
||||
@@ -73,11 +90,26 @@ const playThis = (track: Track) => {
|
||||
|
||||
.track-item {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-columns: min-content 1fr max-content;
|
||||
align-items: center;
|
||||
padding: $small 1rem;
|
||||
|
||||
.remove-track {
|
||||
opacity: 0;
|
||||
transition: all 0.25s ease;
|
||||
transform: translateX(1rem) rotate(45deg);
|
||||
|
||||
&:hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.remove-track {
|
||||
opacity: 0.5;
|
||||
transform: translateX(0) rotate(45deg);
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
background: linear-gradient(37deg, $gray4, $gray3, $gray3);
|
||||
}
|
||||
@@ -87,10 +119,6 @@ const playThis = (track: Track) => {
|
||||
margin: 0.1rem;
|
||||
}
|
||||
|
||||
// .tags {
|
||||
// border: solid 1px;
|
||||
// }
|
||||
|
||||
.album-art {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Playlist, Track } from "../interfaces";
|
||||
import Router from "../router";
|
||||
|
||||
// @ts-ignore
|
||||
import { Option } from "../interfaces";
|
||||
import Router from "../router";
|
||||
|
||||
import {
|
||||
getAllPlaylists,
|
||||
addTrackToPlaylist,
|
||||
addTrackToPlaylist, getAllPlaylists
|
||||
} from "../composables/fetch/playlists";
|
||||
|
||||
import useQueueStore from "../stores/queue";
|
||||
import useModalStore from "../stores/modal";
|
||||
import useQueueStore from "../stores/queue";
|
||||
/**
|
||||
* Returns a list of context menu items for a track.
|
||||
* @param {any} track a track object.
|
||||
@@ -90,7 +92,7 @@ export default async (
|
||||
Router.push({
|
||||
name: "FolderView",
|
||||
params: { path: track.folder },
|
||||
query: { highlight: track.uniq_hash },
|
||||
query: { highlight: track.hash },
|
||||
});
|
||||
},
|
||||
icon: "folder",
|
||||
|
||||
+7
-7
@@ -16,7 +16,7 @@ export interface Track {
|
||||
tracknumber?: number;
|
||||
discnumber?: number;
|
||||
index?: number;
|
||||
uniq_hash: string;
|
||||
hash: string;
|
||||
copyright?: string;
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ export interface Playlist {
|
||||
playlistid: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
image?: string | FormData;
|
||||
tracks?: Track[];
|
||||
count?: number;
|
||||
lastUpdated?: string;
|
||||
thumb?: string;
|
||||
duration?: number;
|
||||
image: string | FormData;
|
||||
tracks: Track[];
|
||||
count: number;
|
||||
lastUpdated: string;
|
||||
thumb: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export interface Notif {
|
||||
|
||||
@@ -40,7 +40,7 @@ const props = defineProps<{
|
||||
/**
|
||||
* Called when the bottom container is raised.
|
||||
*/
|
||||
bottomRaisedCallback?: (routeparams?: RouteParams) => void;
|
||||
bottomRaisedCallback?: (routeparams: RouteParams) => void;
|
||||
}>();
|
||||
|
||||
let elem: HTMLElement;
|
||||
|
||||
@@ -53,6 +53,7 @@ export default defineStore("context-menu", {
|
||||
hideContextMenu() {
|
||||
this.visible = false;
|
||||
this.src = null;
|
||||
this.options = [];
|
||||
},
|
||||
hasManyChildren() {
|
||||
let result = false;
|
||||
|
||||
@@ -20,8 +20,8 @@ export default defineStore("playlist-tracks", {
|
||||
async fetchAll(playlistid: string) {
|
||||
const playlist = await getPlaylist(playlistid);
|
||||
|
||||
this.info = playlist.info;
|
||||
this.tracks = playlist.tracks;
|
||||
this.info = playlist?.info || ({} as Playlist);
|
||||
this.tracks = playlist?.tracks || [];
|
||||
},
|
||||
|
||||
async fetchArtists(playlistid: string) {
|
||||
@@ -35,5 +35,8 @@ export default defineStore("playlist-tracks", {
|
||||
updatePInfo(info: Playlist) {
|
||||
this.info = info;
|
||||
},
|
||||
resetArtists() {
|
||||
this.artists = [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+12
-18
@@ -35,14 +35,6 @@ function readCurrent(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const defaultTrack = <Track>{
|
||||
title: "Nothing played yet",
|
||||
albumhash: " ",
|
||||
artists: ["Alice"],
|
||||
trackid: "",
|
||||
image: "meh",
|
||||
};
|
||||
|
||||
function shuffle(tracks: Track[]) {
|
||||
const shuffled = tracks.slice();
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
@@ -70,18 +62,19 @@ export default defineStore("Queue", {
|
||||
current: 0,
|
||||
next: 0,
|
||||
prev: 0,
|
||||
currentid: "",
|
||||
currentid: <string | null>"",
|
||||
playing: false,
|
||||
from: {} as From,
|
||||
currenttrack: {} as Track,
|
||||
tracklist: [defaultTrack] as Track[],
|
||||
tracklist: [] as Track[],
|
||||
}),
|
||||
actions: {
|
||||
play(index: number = 0) {
|
||||
if (this.tracklist.length === 0) return;
|
||||
this.current = index;
|
||||
const track = this.tracklist[index];
|
||||
this.currentid = track.trackid;
|
||||
const uri = state.settings.uri + "/file/" + track.trackid;
|
||||
const uri = state.settings.uri + "/file/" + track.hash;
|
||||
const elem = document.getElementById("progress") as HTMLElement;
|
||||
this.updateCurrent(index);
|
||||
|
||||
@@ -178,8 +171,8 @@ export default defineStore("Queue", {
|
||||
|
||||
this.currenttrack = track;
|
||||
this.current = index;
|
||||
this.currentid = track.trackid;
|
||||
this.duration.full = track.length || 0;
|
||||
this.currentid = track?.trackid || null;
|
||||
this.duration.full = track?.length || 0;
|
||||
},
|
||||
setNewQueue(tracklist: Track[]) {
|
||||
if (this.tracklist !== tracklist) {
|
||||
@@ -256,15 +249,13 @@ export default defineStore("Queue", {
|
||||
writeQueue(this.from, this.tracklist);
|
||||
},
|
||||
clearQueue() {
|
||||
this.tracklist = [defaultTrack] as Track[];
|
||||
this.current = 0;
|
||||
this.tracklist = [] as Track[];
|
||||
this.currentid = "";
|
||||
this.next = 0;
|
||||
this.prev = 0;
|
||||
this.current, this.next, (this.prev = 0);
|
||||
this.from = <From>{};
|
||||
|
||||
writeQueue(this.from, [defaultTrack] as Track[]);
|
||||
writeCurrent(0);
|
||||
writeQueue(this.from, [] as Track[]);
|
||||
},
|
||||
shuffleQueue() {
|
||||
const Toast = useNotifStore();
|
||||
@@ -286,5 +277,8 @@ export default defineStore("Queue", {
|
||||
writeQueue(this.from, shuffled);
|
||||
writeCurrent(0);
|
||||
},
|
||||
removeFromQueue(index: number = 0) {
|
||||
this.tracklist.splice(index, 1);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
<div class="bottom-content">
|
||||
<FeaturedArtists :artists="artists" />
|
||||
|
||||
<AlbumBio :bio="bio" :images="{ album: image, artist: artists[0].image }" />
|
||||
<AlbumBio
|
||||
:bio="bio"
|
||||
:images="{ album: image, artist: artists[0]?.image }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Bottom
|
||||
:artists="album.artists"
|
||||
:bio="album.bio"
|
||||
:image="album.info.image"
|
||||
:image="album.info?.image"
|
||||
/>
|
||||
</template>
|
||||
</Page>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<template #content>
|
||||
<Content
|
||||
:tracks="playlist.tracks"
|
||||
:count="playlist.info.count"
|
||||
:count="playlist.info?.count"
|
||||
:name="playlist.info.name"
|
||||
:playlistid="playlist.info.playlistid"
|
||||
/>
|
||||
@@ -25,7 +25,7 @@ import Content from "./Content.vue";
|
||||
import FeaturedArtists from "@/components/PlaylistView/FeaturedArtists.vue";
|
||||
|
||||
import usePTrackStore from "@/stores/pages/playlist";
|
||||
import { onBeforeUnmount, onMounted } from "vue";
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const route = useRoute();
|
||||
@@ -34,6 +34,8 @@ const playlist = usePTrackStore();
|
||||
onMounted(() => {
|
||||
playlist.fetchArtists(route.params.pid as string);
|
||||
});
|
||||
|
||||
onUnmounted(() => playlist.reset());
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
||||
Reference in New Issue
Block a user