forked from platypush/platypush
[Youtube UI] More playlist actions.
- `create_playlist` - `rename_playlist` - `delete_playlist`
This commit is contained in:
parent
d4354e81f8
commit
98a6adb7ef
5 changed files with 229 additions and 4 deletions
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<Modal ref="modal" :title="title">
|
||||
<Modal ref="modal" :title="title" @close="close">
|
||||
<div class="dialog-content">
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@
|
|||
import Modal from "@/components/Modal";
|
||||
|
||||
export default {
|
||||
emits: ['input', 'click', 'touch'],
|
||||
emits: ['input', 'click', 'close', 'touch'],
|
||||
components: {Modal},
|
||||
props: {
|
||||
title: {
|
||||
|
@ -49,6 +49,7 @@ export default {
|
|||
|
||||
close() {
|
||||
this.$refs.modal.hide()
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
show() {
|
||||
|
|
|
@ -39,7 +39,7 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.floating-btn {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: auto 1em 1em auto;
|
||||
|
|
|
@ -59,7 +59,10 @@ export default {
|
|||
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.$emit('input', this.value_)
|
||||
if (this.value_?.trim()?.length) {
|
||||
this.$emit('input', this.value_)
|
||||
}
|
||||
|
||||
this.close()
|
||||
},
|
||||
|
||||
|
@ -120,6 +123,8 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
:deep(.modal) {
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,15 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
async createPlaylist(name) {
|
||||
this.loading = true
|
||||
try {
|
||||
await this.request('youtube.create_playlist', {name: name})
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
selectView(view) {
|
||||
this.selectedView = view
|
||||
if (view === 'playlists')
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
@click="$emit('select', playlist)">
|
||||
<MediaImage :item="playlist" :has-play="false" />
|
||||
<div class="title">{{ playlist.name }}</div>
|
||||
<div class="actions">
|
||||
<button title="Remove" @click.stop="deletedPlaylist = playlist.id">
|
||||
<i class="fa fa-trash" />
|
||||
</button>
|
||||
<button title="Edit" @click.stop="editedPlaylist = playlist.id">
|
||||
<i class="fa fa-pencil" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,14 +35,74 @@
|
|||
@play="$emit('play', $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextPrompt
|
||||
:visible="showCreatePlaylist"
|
||||
@input="createPlaylist($event)"
|
||||
@close="showCreatePlaylist = false"
|
||||
>
|
||||
Playlist name
|
||||
</TextPrompt>
|
||||
|
||||
<ConfirmDialog
|
||||
ref="removePlaylist"
|
||||
title="Remove Playlist"
|
||||
:visible="deletedPlaylist != null"
|
||||
@close="deletedPlaylist = null"
|
||||
@input="removePlaylist"
|
||||
>
|
||||
Are you sure you want to remove this playlist?
|
||||
</ConfirmDialog>
|
||||
|
||||
<Modal
|
||||
ref="editPlaylist"
|
||||
title="Edit Playlist"
|
||||
:visible="editedPlaylist != null"
|
||||
@close="clearEditPlaylist"
|
||||
@open="onEditPlaylistOpen"
|
||||
>
|
||||
<form class="edit-playlist-form" @submit.prevent="editPlaylist">
|
||||
<div class="row">
|
||||
<input ref="editPlaylistName" placeholder="Playlist name" v-model="editedPlaylistName" />
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<input placeholder="Playlist description" v-model="editedPlaylistDescription" />
|
||||
</div>
|
||||
|
||||
<div class="row buttons">
|
||||
<div class="btn-container col-6">
|
||||
<button type="submit">
|
||||
<i class="fa fa-check" /> Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-container col-6">
|
||||
<button @click="clearEditPlaylist">
|
||||
<i class="fa fa-times" /> Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<FloatingButton
|
||||
icon-class="fa fa-plus"
|
||||
title="Create Playlist"
|
||||
@click="showCreatePlaylist = true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConfirmDialog from "@/components/elements/ConfirmDialog";
|
||||
import FloatingButton from "@/components/elements/FloatingButton";
|
||||
import MediaImage from "@/components/panels/Media/MediaImage";
|
||||
import Modal from "@/components/Modal";
|
||||
import NoItems from "@/components/elements/NoItems";
|
||||
import Loading from "@/components/Loading";
|
||||
import Playlist from "./Playlist";
|
||||
import TextPrompt from "@/components/elements/TextPrompt"
|
||||
import Utils from "@/Utils";
|
||||
|
||||
export default {
|
||||
|
@ -50,10 +118,14 @@ export default {
|
|||
],
|
||||
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
FloatingButton,
|
||||
Loading,
|
||||
MediaImage,
|
||||
Modal,
|
||||
NoItems,
|
||||
Playlist,
|
||||
TextPrompt,
|
||||
},
|
||||
|
||||
props: {
|
||||
|
@ -70,8 +142,13 @@ export default {
|
|||
|
||||
data() {
|
||||
return {
|
||||
deletedPlaylist: null,
|
||||
editedPlaylist: null,
|
||||
editedPlaylistName: '',
|
||||
editedPlaylistDescription: '',
|
||||
playlists: [],
|
||||
loading: false,
|
||||
showCreatePlaylist: false,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -95,6 +172,64 @@ export default {
|
|||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
async createPlaylist(name) {
|
||||
this.loading = true
|
||||
try {
|
||||
await this.request('youtube.create_playlist', {name: name})
|
||||
this.showCreatePlaylist = false
|
||||
this.loadPlaylists()
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
async removePlaylist() {
|
||||
if (!this.deletedPlaylist)
|
||||
return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
await this.request('youtube.delete_playlist', {id: this.deletedPlaylist})
|
||||
this.deletedPlaylist = null
|
||||
this.loadPlaylists()
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
async editPlaylist() {
|
||||
if (!this.editedPlaylist)
|
||||
return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
await this.request('youtube.rename_playlist', {
|
||||
id: this.editedPlaylist,
|
||||
name: this.editedPlaylistName,
|
||||
description: this.editedPlaylistDescription,
|
||||
})
|
||||
|
||||
this.clearEditPlaylist()
|
||||
this.loadPlaylists()
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
clearEditPlaylist() {
|
||||
this.editedPlaylist = null
|
||||
this.editedPlaylistName = ''
|
||||
this.editedPlaylistDescription = ''
|
||||
this.$refs.editPlaylist.hide()
|
||||
},
|
||||
|
||||
onEditPlaylistOpen() {
|
||||
const playlist = this.playlistsById[this.editedPlaylist]
|
||||
this.editedPlaylistName = playlist.name
|
||||
this.editedPlaylistDescription = playlist.description
|
||||
this.$nextTick(() => this.$refs.editPlaylistName.focus())
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
@ -106,12 +241,14 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
.media-youtube-playlists {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.playlist-body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.playlist.item) {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.title {
|
||||
|
@ -119,6 +256,33 @@ export default {
|
|||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
padding: 0.5em;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
opacity: 0.9;
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 1;
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
color: $default-hover-fg;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
|
@ -127,5 +291,51 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.modal) {
|
||||
.edit-playlist-form {
|
||||
min-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.row {
|
||||
margin: 0.5em 0;
|
||||
|
||||
input {
|
||||
border: $default-border;
|
||||
border-radius: 1em;
|
||||
padding: 0.5em;
|
||||
width: 100%;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $selected-fg;
|
||||
}
|
||||
}
|
||||
|
||||
&.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 0.5em;
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0 0.5em;
|
||||
padding: 0.5em;
|
||||
border-radius: 1em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue