diff --git a/electron.vite.config.ts b/electron.vite.config.ts index c7b7e58..dfab181 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -39,6 +39,7 @@ export default defineConfig({ ], publicDir: resolve('resources'), server: { + host: '0.0.0.0', proxy: { // with options [process.env.VITE_API_LOCAL as string]: { diff --git a/src/i18n/lang/en-US/settings.ts b/src/i18n/lang/en-US/settings.ts index aa21568..3e7c60f 100644 --- a/src/i18n/lang/en-US/settings.ts +++ b/src/i18n/lang/en-US/settings.ts @@ -168,42 +168,57 @@ export default { }, lyricSettings: { title: 'Lyric Settings', + tabs: { + display: 'Display', + interface: 'Interface', + typography: 'Typography', + mobile: 'Mobile' + }, pureMode: 'Pure Mode', hideCover: 'Hide Cover', centerDisplay: 'Center Display', showTranslation: 'Show Translation', + hideLyrics: 'Hide Lyrics', hidePlayBar: 'Hide Play Bar', - fontSize: 'Font Size', - letterSpacing: 'Letter Spacing', - lineHeight: 'Line Height', + hideMiniPlayBar: 'Hide Mini Play Bar', backgroundTheme: 'Background Theme', - fontSizeMarks: { - small: 'Small', - medium: 'Medium', - large: 'Large' - }, - letterSpacingMarks: { - compact: 'Compact', - default: 'Default', - loose: 'Loose' - }, - lineHeightMarks: { - compact: 'Compact', - default: 'Default', - loose: 'Loose' - }, themeOptions: { default: 'Default', light: 'Light', dark: 'Dark' }, - hideMiniPlayBar: 'Hide Mini Play Bar', - hideLyrics: 'Hide Lyrics', - tabs: { - interface: 'Interface', - display: 'Display', - typography: 'Typography' - } + fontSize: 'Font Size', + fontSizeMarks: { + small: 'Small', + medium: 'Medium', + large: 'Large' + }, + letterSpacing: 'Letter Spacing', + letterSpacingMarks: { + compact: 'Compact', + default: 'Default', + loose: 'Loose' + }, + lineHeight: 'Line Height', + lineHeightMarks: { + compact: 'Compact', + default: 'Default', + loose: 'Loose' + }, + mobileLayout: 'Mobile Layout', + layoutOptions: { + default: 'Default', + ios: 'iOS Style', + android: 'Android Style' + }, + mobileCoverStyle: 'Cover Style', + coverOptions: { + record: 'Record', + square: 'Square', + full: 'Full Screen' + }, + lyricLines: 'Lyric Lines', + mobileUnavailable: 'This setting is only available on mobile devices' }, shortcutSettings: { title: 'Shortcut Settings', diff --git a/src/i18n/lang/zh-CN/player.ts b/src/i18n/lang/zh-CN/player.ts index 073b5c4..867ff49 100644 --- a/src/i18n/lang/zh-CN/player.ts +++ b/src/i18n/lang/zh-CN/player.ts @@ -16,7 +16,7 @@ export default { playFailed: '当前歌曲播放失败,播放下一首', playMode: { sequence: '顺序播放', - loop: '循环播放', + loop: '单曲循环', random: '随机播放' }, fullscreen: { diff --git a/src/i18n/lang/zh-CN/settings.ts b/src/i18n/lang/zh-CN/settings.ts index 6731ab9..bbed282 100644 --- a/src/i18n/lang/zh-CN/settings.ts +++ b/src/i18n/lang/zh-CN/settings.ts @@ -167,19 +167,33 @@ export default { portNumber: '请输入有效的端口号(1-65535)' }, lyricSettings: { - title: '页面设置', + title: '歌词设置', + tabs: { + display: '显示', + interface: '界面', + typography: '文字', + mobile: '移动端' + }, pureMode: '纯净模式', hideCover: '隐藏封面', centerDisplay: '居中显示', showTranslation: '显示翻译', + hideLyrics: '隐藏歌词', hidePlayBar: '隐藏播放栏', + hideMiniPlayBar: '隐藏迷你播放栏', + backgroundTheme: '背景主题', + themeOptions: { + default: '默认', + light: '亮色', + dark: '暗色' + }, fontSize: '字体大小', fontSizeMarks: { small: '小', medium: '中', large: '大' }, - letterSpacing: '文字间距', + letterSpacing: '字间距', letterSpacingMarks: { compact: '紧凑', default: '默认', @@ -191,19 +205,20 @@ export default { default: '默认', loose: '宽松' }, - backgroundTheme: '背景主题', - themeOptions: { + mobileLayout: '移动端布局', + layoutOptions: { default: '默认', - light: '亮色', - dark: '暗色' + ios: 'iOS风格', + android: '安卓风格' }, - hideMiniPlayBar: '隐藏迷你播放栏', - hideLyrics: '隐藏歌词', - tabs: { - interface: '界面', - typography: '文字', - display: '显示' - } + mobileCoverStyle: '封面样式', + coverOptions: { + record: '唱片', + square: '方形', + full: '全屏' + }, + lyricLines: '歌词行数', + mobileUnavailable: '此设置仅在移动端可用' }, shortcutSettings: { title: '快捷键设置', diff --git a/src/locale/zh-CN.json b/src/locale/zh-CN.json new file mode 100644 index 0000000..a5563da --- /dev/null +++ b/src/locale/zh-CN.json @@ -0,0 +1,58 @@ +{ + "settings": { + "lyricSettings": { + "title": "歌词设置", + "tabs": { + "display": "显示", + "interface": "界面", + "typography": "文字", + "mobile": "移动端" + }, + "pureMode": "纯净模式", + "hideCover": "隐藏封面", + "centerDisplay": "居中显示", + "showTranslation": "显示翻译", + "hideLyrics": "隐藏歌词", + "hidePlayBar": "隐藏播放栏", + "hideMiniPlayBar": "隐藏迷你播放栏", + "backgroundTheme": "背景主题", + "themeOptions": { + "default": "默认", + "light": "亮色", + "dark": "暗色" + }, + "fontSize": "字体大小", + "fontSizeMarks": { + "small": "小", + "medium": "中", + "large": "大" + }, + "letterSpacing": "字间距", + "letterSpacingMarks": { + "compact": "紧凑", + "default": "默认", + "loose": "宽松" + }, + "lineHeight": "行高", + "lineHeightMarks": { + "compact": "紧凑", + "default": "默认", + "loose": "宽松" + }, + "mobileLayout": "移动端布局", + "layoutOptions": { + "default": "默认", + "ios": "iOS风格", + "android": "安卓风格" + }, + "mobileCoverStyle": "封面样式", + "coverOptions": { + "record": "唱片", + "square": "方形", + "full": "全屏" + }, + "lyricLines": "歌词行数", + "mobileUnavailable": "此设置仅在移动端可用" + } + } +} \ No newline at end of file diff --git a/src/renderer/components/lyric/LyricSettings.vue b/src/renderer/components/lyric/LyricSettings.vue index 2e1ff77..243d374 100644 --- a/src/renderer/components/lyric/LyricSettings.vue +++ b/src/renderer/components/lyric/LyricSettings.vue @@ -114,6 +114,47 @@ + + + +
+
{{ t('settings.lyricSettings.mobileLayout') }}
+ + + {{ t('settings.lyricSettings.layoutOptions.default') }} + {{ t('settings.lyricSettings.layoutOptions.ios') }} + {{ t('settings.lyricSettings.layoutOptions.android') }} + + + +
{{ t('settings.lyricSettings.mobileCoverStyle') }}
+ + + {{ t('settings.lyricSettings.coverOptions.record') }} + {{ t('settings.lyricSettings.coverOptions.square') }} + {{ t('settings.lyricSettings.coverOptions.full') }} + + + +
+ {{ t('settings.lyricSettings.lyricLines') }} + +
+
+
+ {{ t('settings.lyricSettings.mobileUnavailable') }} +
+
@@ -124,6 +165,7 @@ import { onMounted, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric'; +import { isMobile } from '@/utils'; const { t } = useI18n(); const config = ref({ ...DEFAULT_LYRIC_CONFIG }); @@ -253,4 +295,8 @@ defineExpose({ color: var(--text-color-active) !important; @apply text-xs; } + +.mobile-unavailable { + @apply text-center py-4 text-gray-500 text-sm; +} diff --git a/src/renderer/components/lyric/MusicFullMobile.vue b/src/renderer/components/lyric/MusicFullMobile.vue new file mode 100644 index 0000000..ecb30ad --- /dev/null +++ b/src/renderer/components/lyric/MusicFullMobile.vue @@ -0,0 +1,1166 @@ + + + + + \ No newline at end of file diff --git a/src/renderer/components/player/MobilePlayBar.vue b/src/renderer/components/player/MobilePlayBar.vue index 51cdc89..d73cd24 100644 --- a/src/renderer/components/player/MobilePlayBar.vue +++ b/src/renderer/components/player/MobilePlayBar.vue @@ -3,7 +3,8 @@ class="mobile-play-bar" :class="[ setAnimationClass('animate__fadeInUp'), - musicFullVisible ? 'play-bar-expanded' : 'play-bar-mini' + musicFullVisible ? 'play-bar-expanded' : 'play-bar-mini', + !shouldShowMobileMenu ? 'mobile-play-bar-no-menu' : '' ]" :style="{ color: musicFullVisible @@ -16,7 +17,7 @@ }" > - @@ -154,21 +112,19 @@ import { useThrottleFn } from '@vueuse/core'; import { computed, ref, watch } from 'vue'; -import SongItem from '@/components/common/SongItem.vue'; import { allTime, artistList, nowTime, playMusic, sound, textColors } from '@/hooks/MusicHook'; -import MusicFull from '@/layout/components/MusicFull.vue'; +import MusicFullWrapper from '@/layout/components/MusicFullWrapper.vue'; import { usePlayerStore } from '@/store/modules/player'; import { useSettingsStore } from '@/store/modules/settings'; -import type { SongResult } from '@/type/music'; import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils'; +const shouldShowMobileMenu = inject('shouldShowMobileMenu'); + const playerStore = usePlayerStore(); const settingsStore = useSettingsStore(); // 是否播放 const play = computed(() => playerStore.isPlay); -// 播放列表 -const playList = computed(() => playerStore.playList as SongResult[]); // 背景颜色 const background = ref('#000'); @@ -206,14 +162,9 @@ const setMusicFull = () => { } }; -// 播放列表引用 -const playListRef = ref(null); - -const scrollToPlayList = (val: boolean) => { - if (!val) return; - setTimeout(() => { - playListRef.value?.scrollTo({ top: playerStore.playListIndex * 56 }); - }, 50); +// 打开播放列表抽屉 +const openPlayListDrawer = () => { + playerStore.setPlayListDrawerVisible(true); }; // 收藏功能 @@ -251,11 +202,15 @@ watch( diff --git a/src/renderer/layout/components/AppMenu.vue b/src/renderer/layout/components/AppMenu.vue index ec5e287..3c6122f 100644 --- a/src/renderer/layout/components/AppMenu.vue +++ b/src/renderer/layout/components/AppMenu.vue @@ -27,6 +27,7 @@ \ No newline at end of file diff --git a/src/renderer/router/index.ts b/src/renderer/router/index.ts index 34fbc20..13a1be2 100644 --- a/src/renderer/router/index.ts +++ b/src/renderer/router/index.ts @@ -20,10 +20,11 @@ const getSettingsStore = () => { const loginRouter = { path: '/login', name: 'login', - mate: { + meta: { keepAlive: true, title: '登录', - icon: 'icon-Home' + icon: 'icon-Home', + back: true }, component: () => import('@/views/login/index.vue') }; @@ -31,7 +32,7 @@ const loginRouter = { const setRouter = { path: '/set', name: 'set', - mate: { + meta: { keepAlive: true, title: '设置', icon: 'icon-Home' diff --git a/src/renderer/types/lyric.ts b/src/renderer/types/lyric.ts index 4cbf670..03aa1c9 100644 --- a/src/renderer/types/lyric.ts +++ b/src/renderer/types/lyric.ts @@ -10,6 +10,10 @@ export interface LyricConfig { pureModeEnabled: boolean; hideMiniPlayBar: boolean; hideLyrics: boolean; + // 移动端配置 + mobileLayout: 'default' | 'ios' | 'android'; + mobileCoverStyle: 'record' | 'square' | 'full'; + mobileShowLyricLines: number; } export const DEFAULT_LYRIC_CONFIG: LyricConfig = { @@ -23,5 +27,9 @@ export const DEFAULT_LYRIC_CONFIG: LyricConfig = { hidePlayBar: false, hideMiniPlayBar: true, pureModeEnabled: false, - hideLyrics: false + hideLyrics: false, + // 移动端默认配置 + mobileLayout: 'ios', + mobileCoverStyle: 'full', + mobileShowLyricLines: 3 }; diff --git a/src/renderer/views/artist/detail.vue b/src/renderer/views/artist/detail.vue index 194246b..1a151a2 100644 --- a/src/renderer/views/artist/detail.vue +++ b/src/renderer/views/artist/detail.vue @@ -115,6 +115,7 @@ :compact="isCompactLayout" :item="formatSong(item)" @play="handlePlay" + :style="{paddingBottom: index === filteredSongs.length - 1 ? '100px' : '0'}" /> @@ -697,7 +698,7 @@ const handleVirtualScroll = (e: any) => { } .albums-grid { - @apply grid gap-6 grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-6; + @apply grid gap-6 grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-6 pb-40; } .loading-more { diff --git a/src/renderer/views/favorite/index.vue b/src/renderer/views/favorite/index.vue index bec557a..212a2a0 100644 --- a/src/renderer/views/favorite/index.vue +++ b/src/renderer/views/favorite/index.vue @@ -539,7 +539,7 @@ const handleBatchDownload = async () => { .mobile { .favorite-page { - @apply p-4; + @apply p-4 m-0; .favorite-header { @apply mb-4; diff --git a/src/renderer/views/login/index.vue b/src/renderer/views/login/index.vue index c78cbc2..b24dec3 100644 --- a/src/renderer/views/login/index.vue +++ b/src/renderer/views/login/index.vue @@ -146,7 +146,7 @@ const loginPhone = async () => { diff --git a/src/renderer/views/music/MusicListPage.vue b/src/renderer/views/music/MusicListPage.vue index fc502e0..89d98ab 100644 --- a/src/renderer/views/music/MusicListPage.vue +++ b/src/renderer/views/music/MusicListPage.vue @@ -160,7 +160,7 @@ diff --git a/src/renderer/views/user/index.vue b/src/renderer/views/user/index.vue index 36db8d5..9475d44 100644 --- a/src/renderer/views/user/index.vue +++ b/src/renderer/views/user/index.vue @@ -90,6 +90,10 @@ + + @@ -109,6 +113,7 @@ import { useUserStore } from '@/store/modules/user'; import type { Playlist } from '@/type/listDetail'; import type { IUserDetail } from '@/type/user'; import { getImgUrl, isElectron, isMobile, setAnimationClass, setAnimationDelay } from '@/utils'; +import LoginComponent from '@/views/login/index.vue'; defineOptions({ name: 'User' @@ -143,7 +148,7 @@ const checkLoginStatus = () => { const userData = localStorage.getItem('user'); if (!token || !userData) { - router.push('/login'); + !isMobile.value && router.push('/login'); return false; } @@ -270,6 +275,14 @@ const showFollowList = () => { // if (!user.value) return; // router.push('/user/followers'); // }; + +const handleLoginSuccess = () => { + // 处理登录成功后的逻辑 + checkLoginStatus(); + loadData(); +}; + +const isLoggedIn = computed(() => userStore.user);