Skip to content

Commit

Permalink
renderer: Favorite: search favorite resources (except DjRadio)
Browse files Browse the repository at this point in the history
  • Loading branch information
rocka committed Jul 9, 2023
1 parent b28f837 commit 000fe62
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/renderer/components/AlbumList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { bkgImg, sizeImg, HiDpiPx } from '@/util/image';
export default {
props: {
/** @type {Vue.PropOptions<Models.Album[]>} */
list: {
type: Array
},
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/components/ArtistDetail/RelatedMVs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="related-mvs resource">
<CenteredLoading v-if="loading"></CenteredLoading>
<VideoList v-else
:videos="mvs"></VideoList>
:list="mvs"></VideoList>
<div class="pagination"
v-if="showPagination">
<mu-pagination :total="total"
Expand All @@ -22,6 +22,7 @@ import CenteredLoading from '@/components/CenteredLoading.vue';
export default {
props: {
/** @type {Vue.PropOptions<Models.Artist>} */
artist: {
required: true
}
Expand All @@ -36,6 +37,7 @@ export default {
};
},
computed: {
/** @returns {boolean} */
showPagination() {
return this.total > this.pageSize;
}
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/ArtistList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { bkgImg, sizeImg, HiDpiPx } from '@/util/image';
export default {
props: {
/** @type {Vue.PropOptions<Models.Artist[]>} */
list: {
type: Array
}
Expand Down
10 changes: 7 additions & 3 deletions src/renderer/components/PlayerBar/VirtualCurrentPlaylist.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
</template>

<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { mapActions } from 'vuex';
import { workerExecute } from '@/worker/message';
import CenteredTip from '@/components/CenteredTip.vue';
Expand Down Expand Up @@ -117,8 +117,12 @@ export default {
};
},
computed: {
...mapState(['ui']),
...mapGetters(['playing', 'queue']),
/** @returns {import('@/store/modules/ui').State} */
ui() { return this.$store.state.ui; },
/** @returns {import('@/store/getters').PlayingGetter}*/
playing() { return this.$store.getters.playing; },
/** @returns {import('@/store/getters').QueueGetter}*/
queue() { return this.$store.getters.queue; },
queueEmpty() {
return this.queue.list.length === 0;
},
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/PlaylistList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { bkgImg, sizeImg, HiDpiPx } from '@/util/image';
export default {
props: {
/** @type {Vue.PropOptions<Models.PlayList>} */
list: {
type: Array
}
Expand Down
5 changes: 3 additions & 2 deletions src/renderer/components/VideoList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="v-list">
<router-link v-for="v in videos"
<router-link v-for="v in list"
:key="v.id"
:to="{ name:'video', params:{ id: v.id } }"
tag="div"
Expand Down Expand Up @@ -34,7 +34,8 @@ import { bkgImg, sizeImg, HiDpiPx } from '@/util/image';
export default {
props: {
videos: {
/** @type {Vue.PropOptions<Models.Video[]>} */
list: {
type: Array,
required: true
},
Expand Down
54 changes: 41 additions & 13 deletions src/renderer/page/Favorite/Favorite.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,47 @@
:value="tab"
@change="handelTabChange">
<mu-tab v-for="tab of FavTabs"
:key="tab[0]"
:value="tab[0]">{{tab[1]}}</mu-tab>
:key="tab.key"
:value="tab.key">
<mu-icon v-if="tab.icon"
:value="tab.icon"></mu-icon>
<span v-else
v-text="tab.title"></span>
</mu-tab>
</mu-tabs>
<div class="fav-content">
<transition mode="out-in"
:name="transitionName">
<component :is="favCompo"></component>
:name="transitionName"
@after-enter="handleTabPageEnter">
<component ref="tabPage"
:is="favCompo"></component>
</transition>
</div>
</div>
</template>

<script>
import SearchFavorites from './SearchFavrites.vue';
import FavAlbums from './FavAlbums.vue';
import FavVideos from './FavVideos.vue';
import FavArtists from './FavArtists.vue';
import FavPlaylists from './FavPlaylists.vue';
import FavDjRadios from './FavDjRadios.vue';
/** @typedef {{ key: string, title?: string, icon?: string }} FavTab */
/** @type {FavTab[]} */
const FavTabs = [
['playlist', '歌单'],
['album', '专辑'],
['artist', '歌手'],
['video', '视频'],
['djradio', '电台']
{ key: 'search', icon: 'search' },
{ key: 'playlist', title: '歌单' },
{ key: 'album', title: '专辑' },
{ key: 'artist', title: '歌手' },
{ key: 'video', title: '视频' },
{ key: 'djradio', title: '电台' }
];
const FavCompos = {
search: 'SearchFavorites',
album: 'FavAlbums',
video: 'FavVideos',
artist: 'FavArtists',
Expand All @@ -49,28 +62,37 @@ export default {
};
},
computed: {
/** @returns {FavTab[]} */
FavTabs() { return FavTabs; },
/** @returns {string} */
favCompo() {
return FavCompos[this.tab];
}
},
methods: {
handelTabChange(val) {
/** @param {string} newTab */
handelTabChange(newTab) {
let oldIndex, newIndex;
FavTabs.forEach((tab, index) => {
if (tab[0] === this.tab) oldIndex = index;
if (tab[0] === val) newIndex = index;
if (tab.key === this.tab) oldIndex = index;
if (tab.key === newTab) newIndex = index;
});
if (newIndex < oldIndex) {
this.transitionName = 'slide-right';
} else {
this.transitionName = 'slide-left';
}
this.tab = val;
this.tab = newTab;
},
handleTabPageEnter() {
this.$refs.tabPage.tabActivated?.call();
}
},
activated() {
this.$refs.tabPage.tabActivated?.call();
},
components: {
SearchFavorites,
FavAlbums,
FavVideos,
FavArtists,
Expand All @@ -88,6 +110,12 @@ export default {
.fav-tab {
z-index: 10;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.4);
.mu-tab:first-child {
min-width: 72px !important;
.mu-icon {
margin: 0;
}
}
}
.fav-content {
height: calc(~'100% - 48px');
Expand Down
178 changes: 178 additions & 0 deletions src/renderer/page/Favorite/SearchFavrites.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<template>
<div class="fav-search">
<div class="text-field-container">
<mu-text-field ref="search"
full-width
v-model="search"
placeholder="搜索我的收藏"
:disabled="!user.loginValid"
:action-icon="textFieldAction"
:action-click="clearSearch"
@input="performSearch"></mu-text-field>
</div>
<CenteredTip v-if="!user.loginValid"
icon="nature_people"
tip="登录后搜索收藏的资源"></CenteredTip>
<CenteredTip v-else-if="search.length === 0"
icon="bookmarks"
tip="搜索收藏的歌单、专辑、歌手、视频 ..."></CenteredTip>
<CenteredLoading v-else-if="loading"></CenteredLoading>
<CenteredTip v-else-if="allEmpty"
icon="inbox"
tip="哎呀~什么都没找到 ..."></CenteredTip>
<mu-list v-else>
<template v-if="playlists.length > 0">
<mu-sub-header>歌单</mu-sub-header>
<PlaylistList :list="playlists"></PlaylistList>
</template>
<template v-if="albums.length > 0">
<mu-sub-header>专辑</mu-sub-header>
<AlbumList :list="albums"></AlbumList>
</template>
<template v-if="artists.length > 0">
<mu-sub-header>歌手</mu-sub-header>
<ArtistList :list="artists"></ArtistList>
</template>
<template v-if="videos.length > 0">
<mu-sub-header>视频</mu-sub-header>
<VideoList :list="videos"></VideoList>
</template>
</mu-list>
</div>
</template>

<script>
import { mapActions } from 'vuex';
import { FetchOnLoginMixin } from './fetch-on-login';
import CenteredTip from '@/components/CenteredTip.vue';
import CenteredLoading from '@/components/CenteredLoading.vue';
import PlaylistList from '@/components/PlaylistList.vue';
import AlbumList from '@/components/AlbumList.vue';
import ArtistList from '@/components/ArtistList.vue';
import VideoList from '@/components/VideoList.vue';
export default {
name: 'search-favorites',
mixins: [FetchOnLoginMixin],
data: () => ({
search: '',
loading: false,
allEmpty: false,
/** @type {Models.PlayList[]} */
playlists: [],
/** @type {Models.Album[]} */
albums: [],
/** @type {Models.Artist[]} */
artists: [],
/** @type {Models.Video[]} */
videos: []
}),
computed: {
/** @returns {import('@/store/modules/user').State} */
user() { return this.$store.state.user; },
/** @returns {string?} */
textFieldAction() {
return this.search.length > 0 ? 'close' : null;
}
},
methods: {
...mapActions([
'updateUserPlaylists',
'updateUserAlbums',
'updateUserArtists',
'updateUserVideos'
]),
focusSearchInput() {
this.$refs.search.focus();
},
clearSearch() {
this.allEmpty = false;
this.search = '';
this.$refs.search.focus();
},
fetchData() {
this.loading = true;
Promise.all([
this.updateUserPlaylists(),
this.updateUserAlbums(),
this.updateUserArtists(),
this.updateUserVideos()
]).then(() => this.loading = false);
},
tabActivated() {
this.fetchData();
this.focusSearchInput();
},
/**
* @param {string} input
*/
performSearch(input) {
const search = input.toLowerCase();
if (search.length == 0) {
this.allEmpty = true;
this.playlists = [];
this.albums = [];
this.artists = [];
this.videos = [];
return;
}
this.playlists = this.user.playlist.filter(p =>
p.name.toLowerCase().includes(search) ||
p.creator.nickname.toLowerCase().includes(search)
);
this.albums = this.user.albums.filter(a =>
a.name.toLowerCase().includes(search) ||
a.alias.some(n => n.toLowerCase().includes(search)) ||
a.artists.some(ar =>
ar.name.toLowerCase().includes(search) ||
ar.alias.some(tn => tn.toLowerCase().includes(search))
)
);
this.artists = this.user.artists.filter(a =>
a.name.toLowerCase().includes(search) ||
a.alias.some(tn => tn.toLowerCase().includes(search))
);
this.videos = this.user.videos.filter(v =>
v.name.toLowerCase().includes(search) ||
v.creator.some(c => c.name.toLowerCase().includes(search))
);
this.allEmpty = this.playlists.length === 0 &&
this.albums.length === 0 &&
this.artists.length === 0 &&
this.videos.length === 0;
}
},
mounted() {
this.tabActivated();
},
components: {
CenteredTip,
CenteredLoading,
PlaylistList,
AlbumList,
ArtistList,
VideoList
}
};
</script>

<style lang="less">
.fav-search {
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: stretch;
align-items: center;
.text-field-container {
width: 100%;
max-width: 600px;
margin: 16px 16px 0;
}
.centered-tip {
flex-grow: 1;
}
}
</style>
2 changes: 1 addition & 1 deletion src/renderer/page/Search/Search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
:list="ui.search.result.items"></PlaylistList>
<VideoList v-else-if="tab === 'video'"
showBadge
:videos="ui.search.result.items"></VideoList>
:list="ui.search.result.items"></VideoList>
<CenteredTip v-else
icon="bug_report"
tip="为什么会这样呢 ..."></CenteredTip>
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/util/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ namespace Models {
export class Video {
constructor(o: any);
id: string;
name: number;
name: string;
alias: string[];
/** type `0` MV, `1` UGC */
type: number;
Expand Down

0 comments on commit 000fe62

Please sign in to comment.