191 lines
6.2 KiB
Vue
191 lines
6.2 KiB
Vue
<template>
|
|
<modal
|
|
id="reorder_modal"
|
|
ref="$modal"
|
|
size="lg"
|
|
:title="$gettext('Reorder Playlist')"
|
|
:busy="loading"
|
|
hide-footer
|
|
@hidden="onHidden"
|
|
>
|
|
<inline-player class="text-start bg-primary rounded mb-2 p-1" />
|
|
|
|
<table class="table table-striped sortable mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 5%">
|
|
|
|
</th>
|
|
<th style="width: 25%;">
|
|
{{ $gettext('Title') }}
|
|
</th>
|
|
<th style="width: 25%;">
|
|
{{ $gettext('Artist') }}
|
|
</th>
|
|
<th style="width: 25%;">
|
|
{{ $gettext('Album') }}
|
|
</th>
|
|
<th style="width: 20%;">
|
|
{{ $gettext('Actions') }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<draggable
|
|
v-model="media"
|
|
tag="tbody"
|
|
item-key="id"
|
|
@change="save"
|
|
>
|
|
<template #item="{element, index}">
|
|
<tr class="align-middle">
|
|
<td class="pe-2">
|
|
<play-button
|
|
:url="element.media.links.play"
|
|
/>
|
|
</td>
|
|
<td class="ps-2">
|
|
<span class="typography-subheading">{{ element.media.title }}</span>
|
|
</td>
|
|
<td>{{ element.media.artist }}</td>
|
|
<td>{{ element.media.album }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button
|
|
v-if="index+1 < media.length"
|
|
type="button"
|
|
class="btn btn-secondary"
|
|
:title="$gettext('Move to Bottom')"
|
|
@click.prevent="moveToBottom(index)"
|
|
>
|
|
<icon :icon="IconChevronBarDown" />
|
|
</button>
|
|
<button
|
|
v-if="index+1 < media.length"
|
|
type="button"
|
|
class="btn btn-primary"
|
|
:title="$gettext('Move Down')"
|
|
@click.prevent="moveDown(index)"
|
|
>
|
|
<icon :icon="IconChevronDown" />
|
|
</button>
|
|
<button
|
|
v-if="index > 0"
|
|
type="button"
|
|
class="btn btn-primary"
|
|
:title="$gettext('Move Up')"
|
|
@click.prevent="moveUp(index)"
|
|
>
|
|
<icon :icon="IconChevronUp" />
|
|
</button>
|
|
<button
|
|
v-if="index > 0"
|
|
type="button"
|
|
class="btn btn-secondary"
|
|
:title="$gettext('Move to Top')"
|
|
@click.prevent="moveToTop(index)"
|
|
>
|
|
<icon :icon="IconChevronBarUp" />
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</draggable>
|
|
</table>
|
|
</modal>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Draggable from 'vuedraggable';
|
|
import Icon from '~/components/Common/Icon.vue';
|
|
import PlayButton from "~/components/Common/PlayButton.vue";
|
|
import InlinePlayer from '~/components/InlinePlayer.vue';
|
|
import {ref} from "vue";
|
|
import {useAxios} from "~/vendor/axios";
|
|
import {useNotify} from "~/functions/useNotify";
|
|
import {useTranslate} from "~/vendor/gettext";
|
|
import Modal from "~/components/Common/Modal.vue";
|
|
import {IconChevronBarDown, IconChevronBarUp, IconChevronDown, IconChevronUp} from "~/components/Common/icons";
|
|
import {ModalTemplateRef, useHasModal} from "~/functions/useHasModal.ts";
|
|
import {usePlayerStore, useProvidePlayerStore} from "~/functions/usePlayerStore.ts";
|
|
|
|
const loading = ref(true);
|
|
const reorderUrl = ref(null);
|
|
const media = ref([]);
|
|
|
|
const $modal = ref<ModalTemplateRef>(null);
|
|
const {show} = useHasModal($modal);
|
|
|
|
const {axios} = useAxios();
|
|
|
|
const open = (newReorderUrl) => {
|
|
reorderUrl.value = newReorderUrl;
|
|
loading.value = true;
|
|
show();
|
|
|
|
axios.get(newReorderUrl).then((resp) => {
|
|
media.value = resp.data;
|
|
loading.value = false;
|
|
});
|
|
};
|
|
|
|
const {notifySuccess} = useNotify();
|
|
const {$gettext} = useTranslate();
|
|
|
|
const save = () => {
|
|
const newOrder = {};
|
|
let i = 0;
|
|
|
|
media.value.forEach((row) => {
|
|
i++;
|
|
newOrder[row.id] = i;
|
|
});
|
|
|
|
axios.put(reorderUrl.value, {'order': newOrder}).then(() => {
|
|
notifySuccess($gettext('Playlist order set.'));
|
|
});
|
|
};
|
|
|
|
const moveDown = (index) => {
|
|
const currentItem = media.value.splice(index, 1)[0];
|
|
media.value.splice(index + 1, 0, currentItem);
|
|
save();
|
|
};
|
|
|
|
const moveToBottom = (index) => {
|
|
const currentItem = media.value.splice(index, 1)[0];
|
|
media.value.splice(media.value.length, 0, currentItem);
|
|
save();
|
|
};
|
|
|
|
const moveUp = (index) => {
|
|
const currentItem = media.value.splice(index, 1)[0];
|
|
media.value.splice(index - 1, 0, currentItem);
|
|
save();
|
|
};
|
|
|
|
const moveToTop = (index) => {
|
|
const currentItem = media.value.splice(index, 1)[0];
|
|
media.value.splice(0, 0, currentItem);
|
|
save();
|
|
};
|
|
|
|
useProvidePlayerStore('reorder');
|
|
|
|
const {stop} = usePlayerStore();
|
|
|
|
const onHidden = () => {
|
|
stop();
|
|
};
|
|
|
|
defineExpose({
|
|
open
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
table.sortable {
|
|
cursor: pointer;
|
|
}
|
|
</style>
|