add context menu to suggestions
This commit is contained in:
parent
f3e97f03ba
commit
9bbbb6d276
11 changed files with 417 additions and 97 deletions
|
@ -90,6 +90,7 @@ export class BrowserWindow {
|
||||||
"components/equalizer",
|
"components/equalizer",
|
||||||
"components/add-to-playlist",
|
"components/add-to-playlist",
|
||||||
"components/queue",
|
"components/queue",
|
||||||
|
"components/smarthints",
|
||||||
"components/mediaitem-scroller-horizontal",
|
"components/mediaitem-scroller-horizontal",
|
||||||
"components/mediaitem-scroller-horizontal-large",
|
"components/mediaitem-scroller-horizontal-large",
|
||||||
"components/mediaitem-scroller-horizontal-sp",
|
"components/mediaitem-scroller-horizontal-sp",
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
"components/moreinfo-modal",
|
"components/moreinfo-modal",
|
||||||
"components/equalizer",
|
"components/equalizer",
|
||||||
"components/add-to-playlist",
|
"components/add-to-playlist",
|
||||||
|
"components/smarthints",
|
||||||
"components/queue",
|
"components/queue",
|
||||||
"components/mediaitem-scroller-horizontal",
|
"components/mediaitem-scroller-horizontal",
|
||||||
"components/mediaitem-scroller-horizontal-large",
|
"components/mediaitem-scroller-horizontal-large",
|
||||||
|
|
|
@ -397,7 +397,7 @@ const CiderAudio = {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._bufferSize = 1024;
|
this._bufferSize = 2048;
|
||||||
this._buffers = null;
|
this._buffers = null;
|
||||||
this._initBuffer();
|
this._initBuffer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,7 @@ const app = new Vue({
|
||||||
miniTmpY: "",
|
miniTmpY: "",
|
||||||
tmpVar: [],
|
tmpVar: [],
|
||||||
notification: false,
|
notification: false,
|
||||||
|
hintscontext: false,
|
||||||
chrome: {
|
chrome: {
|
||||||
sidebarCollapsed: false,
|
sidebarCollapsed: false,
|
||||||
nativeControls: false,
|
nativeControls: false,
|
||||||
|
|
|
@ -279,7 +279,7 @@
|
||||||
<div class="search-input--icon"></div>
|
<div class="search-input--icon"></div>
|
||||||
<input type="search" spellcheck="false" @click="$root.appRoute('search');search.showHints = true"
|
<input type="search" spellcheck="false" @click="$root.appRoute('search');search.showHints = true"
|
||||||
@focus="search.showHints = true"
|
@focus="search.showHints = true"
|
||||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
@blur="setTimeout(()=>{if(hintscontext != true){search.showHints = false} }, 300)"
|
||||||
v-on:keyup.enter="searchQuery(search.hints[search.cursor].content ?? search.hints[search.cursor].searchTerm);search.showHints = false;search.cursor = -1" @change="$root.appRoute('search');"
|
v-on:keyup.enter="searchQuery(search.hints[search.cursor].content ?? search.hints[search.cursor].searchTerm);search.showHints = false;search.cursor = -1" @change="$root.appRoute('search');"
|
||||||
v-on:keyup="searchCursor"
|
v-on:keyup="searchCursor"
|
||||||
@input="getSearchHints()"
|
@input="getSearchHints()"
|
||||||
|
@ -293,34 +293,7 @@
|
||||||
{{ hint.displayTerm }}
|
{{ hint.displayTerm }}
|
||||||
</button>
|
</button>
|
||||||
<template v-for="(item, position) in search.hints.filter((a) => {return a.content != null})">
|
<template v-for="(item, position) in search.hints.filter((a) => {return a.content != null})">
|
||||||
<div class="cd-queue-item" @click="search.showHints = false;routeView(item.content);search.cursor = -1"
|
<mediaitem-smarthints :item="item.content" :position="position"> </mediaitem-smarthints>
|
||||||
:class="{'hintactive': (search.cursor == position + search.hints.filter((a) => {return a.content == null}).length)}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-auto cider-flex-center">
|
|
||||||
<div class="artwork" :class="{'circle': item.content.type == 'artists'}">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.content.attributes.artwork ? item.content.attributes.artwork.url : ''"
|
|
||||||
:size="32"></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col queue-info">
|
|
||||||
<div class="queue-title text-overflow-elipsis">{{ item.content.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="queue-subtitle text-overflow-elipsis">{{
|
|
||||||
item.content.attributes.artistName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="queue-explicit-icon cider-flex-center"
|
|
||||||
v-if="item.content.attributes.contentRating == 'explicit'">
|
|
||||||
<div class="explicit-icon"></div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="col queue-duration-info">
|
|
||||||
<div class="queue-duration cider-flex-center">
|
|
||||||
{{convertTimeToString(item.content.attributes.durationInMillis)}}
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -576,7 +576,7 @@ Vue.component('mediaitem-square', {
|
||||||
icon: "./assets/feather/play.svg",
|
icon: "./assets/feather/play.svg",
|
||||||
name: app.getLz('action.startRadio'),
|
name: app.getLz('action.startRadio'),
|
||||||
action: () => {
|
action: () => {
|
||||||
app.mk.setStationQueue({ artist: this.item.id }).then(() => {
|
app.mk.setStationQueue({ artist: 'a-'+this.item.id }).then(() => {
|
||||||
app.mk.play()
|
app.mk.play()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -586,7 +586,7 @@ Vue.component('mediaitem-square', {
|
||||||
icon: "./assets/feather/share.svg",
|
icon: "./assets/feather/share.svg",
|
||||||
name: app.getLz('term.share'),
|
name: app.getLz('term.share'),
|
||||||
action: () => {
|
action: () => {
|
||||||
self.app.copyToClipboard(this.item.id.attributes.url)
|
self.app.copyToClipboard(this.item.attributes.url)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script type="text/x-template" id="cider-menu-panel">
|
<script type="text/x-template" id="cider-menu-panel">
|
||||||
<div class="menu-panel" @click.self="menuPanel.visible = false" @contextmenu.self="menuPanel.visible = false">
|
<div class="menu-panel" @click.self="menuPanel.visible = false; if($root.hintscontext){$root.hintscontext = false;focusOther()}" @contextmenu.self="menuPanel.visible = false; if($root.hintscontext){$root.hintscontext = false;focusOther()}">
|
||||||
|
|
||||||
<div class="menu-panel-body" ref="menubody" :style="elStyle" :class="getBodyClasses()">
|
<div class="menu-panel-body" ref="menubody" :style="elStyle" :class="getBodyClasses()">
|
||||||
<div class="menu-header-text" v-if="content.name != ''">
|
<div class="menu-header-text" v-if="content.name != ''">
|
||||||
|
@ -56,12 +56,22 @@
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.event) {
|
if (this.event) {
|
||||||
this.position = [this.event.clientX, this.event.clientY];
|
this.position = [this.event.clientX, this.event.clientY];
|
||||||
}
|
this.$nextTick(() => {
|
||||||
this.$nextTick(() => {
|
|
||||||
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
||||||
// ugly hack
|
// ugly hack
|
||||||
setTimeout(this.getStyle, 1)
|
setTimeout(this.getStyle, 0.8)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.addEventListener('mouseover', event => {
|
||||||
|
this.event = event
|
||||||
|
this.position = [event.clientX, event.clientY]
|
||||||
|
console.log("pos", this.position)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(this.getStyle, 0.8)})
|
||||||
|
},{once: true})
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getBodyClasses() {
|
getBodyClasses() {
|
||||||
|
@ -78,6 +88,9 @@
|
||||||
return "active";
|
return "active";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
focusOther(){
|
||||||
|
document.querySelector('.search-input-container input').focus()
|
||||||
|
},
|
||||||
getStyle() {
|
getStyle() {
|
||||||
let style = {}
|
let style = {}
|
||||||
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
||||||
|
@ -132,7 +145,7 @@
|
||||||
action(item) {
|
action(item) {
|
||||||
item.action()
|
item.action()
|
||||||
if (!item["keepOpen"]) {
|
if (!item["keepOpen"]) {
|
||||||
this.menuPanel.visible = false
|
this.menuPanel.visible = false;if(app.hintscontext){ app.hintscontext = false; document.querySelector('.search-input-container input').focus(); app.search.showHints = false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
@click="$root.appRoute('search');$root.search.showHints = true"
|
@click="$root.appRoute('search');$root.search.showHints = true"
|
||||||
@focus="$root.search.showHints = true"
|
@focus="$root.search.showHints = true"
|
||||||
@blur="$root.setTimeout(()=>{$root.search.showHints = false}, 300)"
|
@blur="$root.setTimeout(()=>{if($root.hintscontext != true){$root.search.showHints = false} }, 300)"
|
||||||
v-on:keyup.enter="$root.searchQuery($root.search.hints[$root.search.cursor].content ?? $root.search.hints[$root.search.cursor].searchTerm);$root.search.showHints = false;$root.search.cursor = -1"
|
v-on:keyup.enter="$root.searchQuery($root.search.hints[$root.search.cursor].content ?? $root.search.hints[$root.search.cursor].searchTerm);$root.search.showHints = false;$root.search.cursor = -1"
|
||||||
v-on:keyup="$root.searchCursor"
|
v-on:keyup="$root.searchCursor"
|
||||||
@change="$root.appRoute('search');"
|
@change="$root.appRoute('search');"
|
||||||
|
@ -33,34 +33,7 @@
|
||||||
{{ hint.displayTerm }}
|
{{ hint.displayTerm }}
|
||||||
</button>
|
</button>
|
||||||
<template v-for="(item, position) in $root.search.hints.filter((a) => {return a.content != null})">
|
<template v-for="(item, position) in $root.search.hints.filter((a) => {return a.content != null})">
|
||||||
<div class="cd-queue-item" @click="$root.search.showHints = false;$root.routeView(item.content);$root.search.cursor = -1"
|
<mediaitem-smarthints :item="item.content" :position="position"> </mediaitem-smarthints>
|
||||||
:class="{'hintactive': ($root.search.cursor == position + $root.search.hints.filter((a) => {return a.content == null}).length)}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-auto cider-flex-center">
|
|
||||||
<div class="artwork" :class="{'circle': item.content.type == 'artists'}">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.content.attributes.artwork ? item.content.attributes.artwork.url : ''"
|
|
||||||
:size="32"></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col queue-info">
|
|
||||||
<div class="queue-title text-overflow-elipsis">{{ item.content.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="queue-subtitle text-overflow-elipsis">{{
|
|
||||||
item.content.attributes.artistName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="queue-explicit-icon cider-flex-center"
|
|
||||||
v-if="item.content.attributes.contentRating == 'explicit'">
|
|
||||||
<div class="explicit-icon"></div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="col queue-duration-info">
|
|
||||||
<div class="queue-duration cider-flex-center">
|
|
||||||
{{convertTimeToString(item.content.attributes.durationInMillis)}}
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
382
src/renderer/views/components/smarthints.ejs
Normal file
382
src/renderer/views/components/smarthints.ejs
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
<script type="text/x-template" id="mediaitem-smarthints">
|
||||||
|
<div class="cd-queue-item" @click="$root.search.showHints = false;$root.routeView(item);$root.search.cursor = -1;$root.search.term == ''" @contextmenu="$root.hintscontext = true;getContextMenu()"
|
||||||
|
:class="{'hintactive': ($root.search.cursor == position + $root.search.hints.filter((a) => {return a.content == null}).length)}">
|
||||||
|
<div class="row" @contextmenu="$root.hintscontext = true;getContextMenu()">
|
||||||
|
<div class="col-auto cider-flex-center" @contextmenu="$root.hintscontext = true;getContextMenu()">
|
||||||
|
<div class="artwork" :class="{'circle': item.type == 'artists'}">
|
||||||
|
<mediaitem-artwork
|
||||||
|
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
||||||
|
:size="32"></mediaitem-artwork>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col queue-info" @contextmenu="$root.hintscontext = true;getContextMenu()">
|
||||||
|
<div class="queue-title text-overflow-elipsis">{{ item.attributes.name }}
|
||||||
|
</div>
|
||||||
|
<div class="queue-subtitle text-overflow-elipsis">{{
|
||||||
|
item.attributes.artistName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="queue-explicit-icon cider-flex-center"
|
||||||
|
v-if="item.attributes.contentRating == 'explicit'">
|
||||||
|
<div class="explicit-icon"></div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="col queue-duration-info">
|
||||||
|
<div class="queue-duration cider-flex-center">
|
||||||
|
{{convertTimeToString(item.content.attributes.durationInMillis)}}
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
Vue.component('mediaitem-smarthints', {
|
||||||
|
template: '#mediaitem-smarthints',
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
app: this.$root,
|
||||||
|
guid: this.uuidv4(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
uuidv4() {
|
||||||
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||||
|
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getContextMenu(event) {
|
||||||
|
if (event){
|
||||||
|
if (this.item.type === "artists") {
|
||||||
|
return this.artistMenu(event)
|
||||||
|
} else {
|
||||||
|
return this.contextMenu(event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.addEventListener('mouseover', event => {
|
||||||
|
if (this.item.type === "artists") {
|
||||||
|
return this.artistMenu(event)
|
||||||
|
} else {
|
||||||
|
return this.contextMenu(event)
|
||||||
|
}
|
||||||
|
},{once: true})}
|
||||||
|
|
||||||
|
},
|
||||||
|
async contextMenu(event) {
|
||||||
|
let self = this
|
||||||
|
let useMenu = "normal"
|
||||||
|
if (app.selectedMediaItems.length <= 1) {
|
||||||
|
app.selectedMediaItems = []
|
||||||
|
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid, this.item.attributes.playParams.isLibrary ?? false)
|
||||||
|
} else {
|
||||||
|
useMenu = "multiple"
|
||||||
|
}
|
||||||
|
let menus = {
|
||||||
|
multiple: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: app.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||||
|
"icon": "./assets/arrow-bend-up.svg",
|
||||||
|
action: () => {
|
||||||
|
let itemsToPlay = {}
|
||||||
|
app.selectedMediaItems.forEach(item => {
|
||||||
|
if (!itemsToPlay[item.kind]) {
|
||||||
|
itemsToPlay[item.kind] = []
|
||||||
|
}
|
||||||
|
itemsToPlay[item.kind].push(item.id)
|
||||||
|
})
|
||||||
|
// loop through itemsToPlay
|
||||||
|
for (let kind in itemsToPlay) {
|
||||||
|
let ids = itemsToPlay[kind]
|
||||||
|
if (ids.length > 0) {
|
||||||
|
app.mk.playNext({ [kind + "s"]: itemsToPlay[kind] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(itemsToPlay)
|
||||||
|
app.selectedMediaItems = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||||
|
"icon": "./assets/arrow-bend-down.svg",
|
||||||
|
action: () => {
|
||||||
|
let itemsToPlay = {}
|
||||||
|
app.selectedMediaItems.forEach(item => {
|
||||||
|
if (!itemsToPlay[item.kind]) {
|
||||||
|
itemsToPlay[item.kind] = []
|
||||||
|
}
|
||||||
|
itemsToPlay[item.kind].push(item.id)
|
||||||
|
})
|
||||||
|
// loop through itemsToPlay
|
||||||
|
for (let kind in itemsToPlay) {
|
||||||
|
let ids = itemsToPlay[kind]
|
||||||
|
if (ids.length > 0) {
|
||||||
|
app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.selectedMediaItems = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
headerItems: [
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/heart.svg",
|
||||||
|
"id": "love",
|
||||||
|
"name": app.getLz('action.love'),
|
||||||
|
"hidden": false,
|
||||||
|
"disabled": true,
|
||||||
|
"action": function () {
|
||||||
|
app.love(self.item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/heart.svg",
|
||||||
|
"id": "unlove",
|
||||||
|
"active": true,
|
||||||
|
"name": app.getLz('action.unlove'),
|
||||||
|
"hidden": true,
|
||||||
|
"action": function () {
|
||||||
|
app.unlove(self.item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/thumbs-down.svg",
|
||||||
|
"id": "dislike",
|
||||||
|
"name": app.getLz('action.dislike'),
|
||||||
|
"hidden": false,
|
||||||
|
"disabled": true,
|
||||||
|
"action": function () {
|
||||||
|
app.dislike(self.item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/thumbs-down.svg",
|
||||||
|
"id": "undo_dislike",
|
||||||
|
"name": app.getLz('action.undoDislike'),
|
||||||
|
"active": true,
|
||||||
|
"hidden": true,
|
||||||
|
"action": function () {
|
||||||
|
app.unlove(self.item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/list.svg",
|
||||||
|
"id": "addToPlaylist",
|
||||||
|
"name": app.getLz('action.addToPlaylist'),
|
||||||
|
"action": function () {
|
||||||
|
app.promptAddToPlaylist()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "addToLibrary",
|
||||||
|
"icon": "./assets/feather/plus.svg",
|
||||||
|
"name": app.getLz('action.addToLibrary'),
|
||||||
|
"hidden": false,
|
||||||
|
"disabled": true,
|
||||||
|
"action": function () {
|
||||||
|
let item_id = self.item.attributes.playParams.id ?? self.item.id;
|
||||||
|
let data_type = self.item.attributes.playParams.kind ?? self.item.type;
|
||||||
|
app.addToLibrary(item_id);
|
||||||
|
self.addedToLibrary = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "removeFromLibrary",
|
||||||
|
"icon": "./assets/feather/x-circle.svg",
|
||||||
|
"name": app.getLz('action.removeFromLibrary'),
|
||||||
|
"hidden": true,
|
||||||
|
"action": async function () {
|
||||||
|
console.log("remove");
|
||||||
|
let item_id = self.item.attributes.playParams.id ?? self.item.id;
|
||||||
|
let data_type = self.item.attributes.playParams.kind ?? self.item.type;
|
||||||
|
await self.removeFromLibrary(item_id);
|
||||||
|
self.addedToLibrary = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": app.getLz('action.playNext'),
|
||||||
|
"icon": "./assets/arrow-bend-up.svg",
|
||||||
|
"action": function () {
|
||||||
|
app.mk.playNext({ [self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id })
|
||||||
|
app.mk.queue._reindex()
|
||||||
|
app.selectedMediaItems = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": app.getLz('action.playLater'),
|
||||||
|
"icon": "./assets/arrow-bend-down.svg",
|
||||||
|
"action": function () {
|
||||||
|
app.mk.playLater({ [self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id })
|
||||||
|
app.mk.queue._reindex()
|
||||||
|
app.selectedMediaItems = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/share.svg",
|
||||||
|
"name": app.getLz('action.share'),
|
||||||
|
"action": function () {
|
||||||
|
if (!self.item.attributes.url && self.item.relationships) {
|
||||||
|
if (self.item.relationships.catalog) {
|
||||||
|
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {
|
||||||
|
self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.app.copyToClipboard(self.item.attributes.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "./assets/feather/share.svg",
|
||||||
|
"name": `${app.getLz('action.share')} (song.link)`,
|
||||||
|
"action": function () {
|
||||||
|
if (!self.item.attributes.url && self.item.relationships) {
|
||||||
|
if (self.item.relationships.catalog) {
|
||||||
|
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {
|
||||||
|
self.app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.app.songLinkShare(self.item.attributes.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((self.item.attributes.playParams.kind ?? self.item.type).includes("playlist")) {
|
||||||
|
// remove the add to playlist option by id "addToPlaylist" using the .filter() method
|
||||||
|
menus.normal.items = menus.normal.items.filter(function (item) {
|
||||||
|
return item.id != "addToPlaylist"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
app.showMenuPanel(menus[useMenu], event)
|
||||||
|
try {
|
||||||
|
await this.isInLibrary().then((_) => {
|
||||||
|
if (self.addedToLibrary) {
|
||||||
|
menus.normal.items.find(x => x.id == 'addToLibrary').hidden = true
|
||||||
|
menus.normal.items.find(x => x.id == 'removeFromLibrary').hidden = false
|
||||||
|
} else {
|
||||||
|
menus.normal.items.find(x => x.id == 'addToLibrary').disabled = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let rating = await app.getRating(self.item)
|
||||||
|
if (rating == 0) {
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'love').disabled = false
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'dislike').disabled = false
|
||||||
|
} else if (rating == 1) {
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'unlove').hidden = false
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'love').hidden = true
|
||||||
|
} else if (rating == -1) {
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'undo_dislike').hidden = false
|
||||||
|
menus.normal.headerItems.find(x => x.id == 'dislike').hidden = true
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.contextExt) {
|
||||||
|
if (this.contextExt.normal) {
|
||||||
|
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||||
|
}
|
||||||
|
if (this.contextExt.multiple) {
|
||||||
|
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async artistMenu(event) {
|
||||||
|
let self = this
|
||||||
|
let followAction = "follow"
|
||||||
|
let followActions = {
|
||||||
|
follow: {
|
||||||
|
icon: "./assets/star.svg",
|
||||||
|
name: app.getLz('action.favorite'),
|
||||||
|
action: () => {
|
||||||
|
self.$root.setArtistFavorite(this.item.id, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unfollow: {
|
||||||
|
icon: "./assets/star.svg",
|
||||||
|
name: app.getLz('action.removeFavorite'),
|
||||||
|
action: () => {
|
||||||
|
self.$root.setArtistFavorite(this.item.id, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.app.cfg.home.followedArtists.includes(this.item.id)) {
|
||||||
|
followAction = "unfollow"
|
||||||
|
}
|
||||||
|
app.showMenuPanel({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
icon: "./assets/feather/play.svg",
|
||||||
|
name: app.getLz('action.startRadio'),
|
||||||
|
action: () => {
|
||||||
|
app.mk.setStationQueue({ artist: 'a-'+this.item.id }).then(() => {
|
||||||
|
app.mk.play()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
followActions[followAction],
|
||||||
|
{
|
||||||
|
icon: "./assets/feather/share.svg",
|
||||||
|
name: app.getLz('term.share'),
|
||||||
|
action: () => {
|
||||||
|
self.app.copyToClipboard(this.item.attributes.url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "./assets/feather/external-link.svg",
|
||||||
|
name: app.getLz('action.openArtworkInBrowser'),
|
||||||
|
action: () => {
|
||||||
|
window.open(app.getMediaItemArtwork(this.getArtworkUrl(), 1024, 1024))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}, event)
|
||||||
|
},
|
||||||
|
getArtworkUrl(size = -1, includeUrl = false) {
|
||||||
|
let artwork = this.item.attributes.artwork ? this.item.attributes.artwork.url : ''
|
||||||
|
if (size != -1) {
|
||||||
|
artwork = artwork.replace('{w}', size).replace('{h}', size).replace('{f}', "webp").replace('{c}', ((size === 900) ? "sr" : "cc"))
|
||||||
|
}
|
||||||
|
switch (this.kind) {
|
||||||
|
case "385":
|
||||||
|
artwork = this.item.attributes?.editorialArtwork?.subscriptionHero?.url
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!includeUrl) {
|
||||||
|
return artwork
|
||||||
|
} else {
|
||||||
|
return `url("${artwork}")`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeDestroy: function () {
|
||||||
|
// this.item = null;
|
||||||
|
// this.kind = null;
|
||||||
|
// this.size = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -23,8 +23,10 @@
|
||||||
<hr>
|
<hr>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h4>{{ convertToHours(loaded.attributes.listenTimeInMinutes) }}
|
<h4 @click="hourshow = !hourshow">{{convertToHours(loaded.attributes.listenTimeInMinutes)}}
|
||||||
{{$root.getLz('term.time.hours')}}</h4>
|
{{$root.getLz('term.time.hours')}}
|
||||||
|
{{hourshow ? "" : (loaded.attributes.listenTimeInMinutes % 60) }}
|
||||||
|
{{hourshow ? "" : $root.getLz('term.time.minutes')}}</h4>
|
||||||
<h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4>
|
<h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4>
|
||||||
<h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
|
<h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
|
||||||
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
|
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
|
||||||
|
@ -101,6 +103,7 @@
|
||||||
loaded: {
|
loaded: {
|
||||||
id: -1
|
id: -1
|
||||||
},
|
},
|
||||||
|
hourshow: true,
|
||||||
musicTypeGenre: ""
|
musicTypeGenre: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="search-input-container fs-search" v-if="$root.appMode == 'fullscreen'">
|
<div class="search-input-container fs-search" v-if="$root.appMode == 'fullscreen'">
|
||||||
<div class="search-input--icon"></div>
|
<div class="search-input--icon"></div>
|
||||||
<input type="search" spellcheck="false" @focus="$root.search.showHints = true"
|
<input type="search" spellcheck="false" @focus="$root.search.showHints = true"
|
||||||
@blur="$root.setTimeout(()=>{$root.search.showHints = false}, 300)"
|
@blur="$root.setTimeout(()=>{if($root.hintscontext != true){$root.search.showHints = false} }, 300)"
|
||||||
v-on:keyup.enter="$root.searchQuery($root.search.hints[$root.search.cursor].content ?? $root.search.hints[$root.search.cursor].searchTerm);$root.search.showHints = false" @input="$root.getSearchHints()"
|
v-on:keyup.enter="$root.searchQuery($root.search.hints[$root.search.cursor].content ?? $root.search.hints[$root.search.cursor].searchTerm);$root.search.showHints = false" @input="$root.getSearchHints()"
|
||||||
:placeholder="$root.getLz('term.search') + '...'" v-model="$root.search.term"
|
:placeholder="$root.getLz('term.search') + '...'" v-model="$root.search.term"
|
||||||
class="search-input" />
|
class="search-input" />
|
||||||
|
@ -15,34 +15,7 @@
|
||||||
{{ hint.displayTerm }}
|
{{ hint.displayTerm }}
|
||||||
</button>
|
</button>
|
||||||
<template v-for="(item, position) in $root.search.hints.filter((a) => {return a.content != null})">
|
<template v-for="(item, position) in $root.search.hints.filter((a) => {return a.content != null})">
|
||||||
<div class="cd-queue-item" @click="$root.search.showHints = false;$root.routeView(item.content);$root.search.cursor = -1"
|
<mediaitem-smarthints :item="item.content" :position="position"> </mediaitem-smarthints>
|
||||||
:class="{'hintactive': ($root.search.cursor == position + $root.search.hints.filter((a) => {return a.content == null}).length)}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-auto cider-flex-center">
|
|
||||||
<div class="artwork" :class="{'circle': item.content.type == 'artists'}">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.content.attributes.artwork ? item.content.attributes.artwork.url : ''"
|
|
||||||
:size="32"></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col queue-info">
|
|
||||||
<div class="queue-title text-overflow-elipsis">{{ item.content.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="queue-subtitle text-overflow-elipsis">{{
|
|
||||||
item.content.attributes.artistName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="queue-explicit-icon cider-flex-center"
|
|
||||||
v-if="item.content.attributes.contentRating == 'explicit'">
|
|
||||||
<div class="explicit-icon"></div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="col queue-duration-info">
|
|
||||||
<div class="queue-duration cider-flex-center">
|
|
||||||
{{convertTimeToString(item.content.attributes.durationInMillis)}}
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue