Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add reversed mode & improvements to lyrics animation #1226

Merged
merged 5 commits into from Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/assets/icons/sort-up.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/components/Player.vue
Expand Up @@ -134,6 +134,13 @@
@click.native="player.switchShuffle"
><svg-icon icon-class="shuffle"
/></button-icon>
<button-icon
v-if="settings.enableReversedMode"
:class="{ active: player.reversed, disabled: player.isPersonalFM }"
:title="$t('player.reversed')"
@click.native="player.switchReversed"
><svg-icon icon-class="sort-up"
/></button-icon>
<div class="volume-control">
<button-icon :title="$t('player.mute')" @click.native="player.mute">
<svg-icon v-show="volume > 0.5" icon-class="volume" />
Expand Down
6 changes: 4 additions & 2 deletions src/locale/lang/en.js
Expand Up @@ -100,6 +100,7 @@ export default {
repeat: 'Repeat',
repeatTrack: 'Repeat Track',
shuffle: 'Shuffle',
reversed: 'Reversed',
play: 'Play',
pause: 'Pause',
mute: 'Mute',
Expand Down Expand Up @@ -154,8 +155,9 @@ export default {
showPlaylistsByAppleMusic: 'Show playlists by Apple Music',
enableDiscordRichPresence: 'Enable Discord Rich Presence',
enableGlobalShortcut: 'Enable Global Shortcut',
showLibraryDefault: 'Show library default',
subTitleDefault: 'Sub title alia default',
showLibraryDefault: 'Show Library after App Launched',
subTitleDefault: 'Show Alias for Subtitle by default',
enableReversedMode: 'Enable Reversed Mode (Experimental)',
lyricsBackground: {
text: 'Show Lyrics Background',
off: 'Off',
Expand Down
2 changes: 2 additions & 0 deletions src/locale/lang/zh-CN.js
Expand Up @@ -101,6 +101,7 @@ export default {
repeat: '循环播放',
repeatTrack: '单曲循环',
shuffle: '随机播放',
reversed: '倒序播放',
play: '播放',
pause: '暂停',
mute: '静音',
Expand Down Expand Up @@ -157,6 +158,7 @@ export default {
enableGlobalShortcut: '启用全局快捷键',
showLibraryDefault: '启动后显示音乐库',
subTitleDefault: '副标题使用别名',
enableReversedMode: '启用倒序播放功能 (实验性功能)',
lyricsBackground: {
text: '显示歌词背景',
off: '关闭',
Expand Down
2 changes: 2 additions & 0 deletions src/locale/lang/zh-TW.js
Expand Up @@ -97,6 +97,7 @@ export default {
repeat: '循環播放',
repeatTrack: '單曲循環',
shuffle: '隨機播放',
reversed: '倒序播放',
play: '播放',
pause: '暫停',
mute: '靜音',
Expand Down Expand Up @@ -154,6 +155,7 @@ export default {
enableGlobalShortcut: '啟用全域快捷鍵',
showLibraryDefault: '啟動後顯示音樂庫',
subTitleDefault: '副標題使用別名',
enableReversedMode: '啟用倒序播放功能 (實驗性功能)',
lyricsBackground: {
text: '顯示歌詞背景',
off: '關閉',
Expand Down
1 change: 1 addition & 0 deletions src/store/initLocalStorage.js
Expand Up @@ -19,6 +19,7 @@ let localStorage = {
enableUnblockNeteaseMusic: true,
automaticallyCacheSongs: true,
cacheLimit: 8192,
enableReversedMode: false,
nyancatStyle: false,
showLyricsTranslation: true,
lyricsBackground: true,
Expand Down
48 changes: 40 additions & 8 deletions src/utils/Player.js
Expand Up @@ -23,6 +23,7 @@ export default class {
this._enabled = false; // 是否启用Player
this._repeatMode = 'off'; // off | on | one
this._shuffle = false; // true | false
this._reversed = false;
this._volume = 1; // 0 to 1
this._volumeBeforeMuted = 1; // 用于保存静音前的音量

Expand Down Expand Up @@ -84,6 +85,18 @@ export default class {
this._shuffleTheList();
}
}
get reversed() {
return this._reversed;
}
set reversed(reversed) {
if (this._isPersonalFM) return;
if (reversed !== true && reversed !== false) {
Copy link
Collaborator

@pan93412 pan93412 Jan 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

檢查類型建議用 typeof: typeof reversed !== 'boolean'

console.warn('reversed: invalid args, must be Boolean');
return;
}
console.log('changing reversed to:', reversed);
this._reversed = reversed;
}
get volume() {
return this._volume;
}
Expand Down Expand Up @@ -180,27 +193,43 @@ export default class {
}, 1000);
}
_getNextTrack() {
const next = this._reversed ? this.current - 1 : this.current + 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const next = this.current + (this._reversed ? -1 : 1);

個人拙見。


if (this._playNextList.length > 0) {
let trackID = this._playNextList.shift();
return [trackID, this.current];
}

// 当歌曲是列表最后一首 && 循环模式开启
if (this.list.length === this.current + 1 && this.repeatMode === 'on') {
return [this.list[0], 0];
// 循环模式开启,则重新播放当前模式下的相对的下一首
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

能有 Unit Test 更好。

if (this.repeatMode === 'on') {
if (this._reversed && this.current === 0) {
// 倒序模式,当前歌曲是第一首,则重新播放列表最后一首
return [this.list[this.list.length - 1], this.list.length - 1];
} else if (this.list.length === this.current + 1) {
// 正序模式,当前歌曲是最后一首,则重新播放第一首
return [this.list[0], 0];
}
}

// 返回 [trackID, index]
return [this.list[this.current + 1], this.current + 1];
return [this.list[next], next];
}
_getPrevTrack() {
// 当歌曲是列表第一首 && 循环模式开启
if (this.current === 0 && this.repeatMode === 'on') {
return [this.list[this.list.length - 1], this.list.length - 1];
const next = this._reversed ? this.current + 1 : this.current - 1;

// 循环模式开启,则重新播放当前模式下的相对的下一首
if (this.repeatMode === 'on') {
if (this._reversed && this.current === 0) {
// 倒序模式,当前歌曲是最后一首,则重新播放列表第一首
return [this.list[0], 0];
} else if (this.list.length === this.current + 1) {
// 正序模式,当前歌曲是第一首,则重新播放列表最后一首
return [this.list[this.list.length - 1], this.list.length - 1];
}
}

// 返回 [trackID, index]
return [this.list[this.current - 1], this.current - 1];
return [this.list[next], next];
}
async _shuffleTheList(firstTrackID = this._currentTrack.id) {
let list = this._list.filter(tid => tid !== firstTrackID);
Expand Down Expand Up @@ -659,6 +688,9 @@ export default class {
switchShuffle() {
this.shuffle = !this.shuffle;
}
switchReversed() {
this.reversed = !this.reversed;
}

clearPlayNextList() {
this._playNextList = [];
Expand Down
51 changes: 43 additions & 8 deletions src/views/lyrics.vue
Expand Up @@ -187,8 +187,18 @@
}"
@click="clickLyricLine(line.time)"
@dblclick="clickLyricLine(line.time, true)"
><span v-html="formatLine(line)"></span
></div>
>
<span v-if="line.contents[0]">{{ line.contents[0] }}</span>
<br />
<span
v-if="
line.contents[1] &&
$store.state.settings.showLyricsTranslation
"
class="translation"
>{{ line.contents[1] }}</span
>
</div>
</div>
</transition>
</div>
Expand Down Expand Up @@ -394,10 +404,8 @@ export default {
}, 50);
},
formatLine(line) {
GalvinGao marked this conversation as resolved.
Show resolved Hide resolved
const showLyricsTranslation = this.$store.state.settings
.showLyricsTranslation;
if (showLyricsTranslation && line.contents[1]) {
return `<span>${line.contents[0]}<br/>${line.contents[1]}</span>`;
if (line.contents[1]) {
return `<span>${line.contents[0]}</span><br/><span class="">${line.contents[1]}</span>`;
} else if (line.contents[0] !== undefined) {
return `<span>${line.contents[0]}</span>`;
}
Expand Down Expand Up @@ -666,27 +674,48 @@ export default {
scrollbar-width: none; // firefox

.line {
padding: 18px;
margin: 2px 0;
padding: 12px 18px;
transition: 0.2s;
border-radius: 12px;

&:hover {
background: var(--color-secondary-bg-for-transparent);
}
&:active {
transform: scale(0.95);
}

span {
opacity: 0.28;
cursor: default;
font-size: 1em;
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

span.translation {
opacity: 0.2;
font-size: 0.95em;
}
}

.line#line-1:hover {
background: unset;
}

.translation {
margin-top: 0.1em;
}

.highlight span {
opacity: 0.98;
transition: 0.5s;
display: inline-block;
font-size: 1.25em;
}

.highlight span.translation {
opacity: 0.65;
font-size: 1.1em;
}
}

Expand Down Expand Up @@ -748,6 +777,12 @@ export default {
}
}

@media screen and (min-width: 1200px) {
.right-side .lyrics-container {
max-width: 600px;
}
}

.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.4s;
Expand Down
32 changes: 32 additions & 0 deletions src/views/settings.vue
Expand Up @@ -384,6 +384,23 @@
</div>
</div>

<div class="item">
<div class="left">
<div class="title">{{ $t('settings.enableReversedMode') }}</div>
</div>
<div class="right">
<div class="toggle">
<input
id="enable-reversed-mode"
v-model="enableReversedMode"
type="checkbox"
name="enable-reversed-mode"
/>
<label for="enable-reversed-mode"></label>
</div>
</div>
</div>

<div class="item">
<div class="left">
<div class="title" style="transform: scaleX(-1)">🐈️ 🏳️‍🌈</div>
Expand Down Expand Up @@ -805,6 +822,21 @@ export default {
});
},
},
enableReversedMode: {
get() {
if (this.settings.enableReversedMode === undefined) return false;
return this.settings.enableReversedMode;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'enableReversedMode',
value,
});
if (value === false) {
this.$store.state.player.reversed = false;
}
},
},
enableGlobalShortcut: {
get() {
return this.settings.enableGlobalShortcut;
Expand Down