-
+
([]);
+
+const immer = new Immer({
+ autoFreeze: false,
+});
+
+const HARD_LIMIT = 500;
+
+async function fetchRecentlyPlaylist() {
+ return (await getUserPreferenceIDB("recentlyPlayList")) || [];
+}
+
+async function setRecentlyPlaylist(musicItems: IMusic.IMusicItem[]) {
+ recentlyPlayListStore.setValue(musicItems);
+ return await setUserPreferenceIDB("recentlyPlayList", musicItems);
+}
+
+export async function setupRecentlyPlaylist() {
+ const playList = await fetchRecentlyPlaylist();
+ recentlyPlayListStore.setValue(playList);
+}
+
+export async function addToRecentlyPlaylist(musicItem: IMusic.IMusicItem) {
+ const playList = recentlyPlayListStore.getValue();
+ const existId = playList.findIndex((it) => isSameMedia(musicItem, it));
+ let newPlayList = playList;
+
+ if (existId !== -1) {
+ newPlayList = immer.produce(playList, (draft) => {
+ draft.splice(existId, 1);
+ });
+ }
+ newPlayList = [musicItem].concat(newPlayList).slice(0, HARD_LIMIT);
+ setRecentlyPlaylist(newPlayList);
+}
+
+export async function removeRecentlyPlayList(musicItem: IMusic.IMusicItem) {
+ const playList = recentlyPlayListStore.getValue();
+ const existId = playList.findIndex((it) => isSameMedia(musicItem, it));
+ let newPlayList = playList;
+
+ if (existId !== -1) {
+ newPlayList = immer.produce(playList, (draft) => {
+ draft.splice(existId, 1);
+ });
+ setRecentlyPlaylist(newPlayList);
+ }
+}
+
+export async function clearRecentlyPlaylist() {
+ setRecentlyPlaylist([]);
+}
+
+export function useRecentlyPlaylistSheet() {
+ const recentlyPlayList = recentlyPlayListStore.useValue();
+ const { t } = useTranslation();
+
+ const musicSheet: IMusic.IMusicSheetItem = useMemo(() => {
+ return {
+ id: "recently-play",
+ title: t("side_bar.recently_play"),
+ platform: "recently-play",
+ playCount: recentlyPlayList?.length || 0,
+ artwork: recentlyPlayList?.[0]?.artwork,
+ musicList: recentlyPlayList || [],
+ };
+ }, [recentlyPlayList, t]);
+
+ return musicSheet;
+}
diff --git a/src/renderer/document/bootstrap.ts b/src/renderer/document/bootstrap.ts
index 9904b29..a7f6ae4 100644
--- a/src/renderer/document/bootstrap.ts
+++ b/src/renderer/document/bootstrap.ts
@@ -23,6 +23,11 @@ import {
setupPlayerSyncHandler,
} from "../core/command-handler";
import ThemePack from "@/shared/themepack/renderer";
+import {
+ addToRecentlyPlaylist,
+ setupRecentlyPlaylist,
+} from "../core/recently-playlist";
+import { TrackPlayerEvent } from "../core/track-player/enum";
setAutoFreeze(false);
@@ -43,6 +48,7 @@ export default async function () {
setupDeviceChange();
localMusic.setupLocalMusic();
await Downloader.setupDownloader();
+ setupRecentlyPlaylist();
// 自动更新插件
if (getAppConfigPath("plugin.autoUpdatePlugin")) {
@@ -152,6 +158,11 @@ function setupEvents() {
MusicSheet.frontend.addMusicToFavorite(realItem);
}
});
+
+ // 最近播放
+ trackPlayer.on(TrackPlayerEvent.MusicChanged, (musicItem) => {
+ addToRecentlyPlaylist(musicItem);
+ });
}
async function setupDeviceChange() {
diff --git a/src/renderer/document/index.scss b/src/renderer/document/index.scss
index f0ea6b6..377843e 100644
--- a/src/renderer/document/index.scss
+++ b/src/renderer/document/index.scss
@@ -87,6 +87,7 @@ input {
}
}
+// 按钮样式
div[role="button"] {
cursor: pointer;
user-select: none;
@@ -114,6 +115,7 @@ div[role="button"] {
border: 1px solid currentColor;
width: fit-content;
line-height: 1em;
+ background-color: color-mix(in srgb, currentColor 15%, transparent);
}
&[data-type="dangerButton"] {
diff --git a/src/renderer/document/index.tsx b/src/renderer/document/index.tsx
index 602a2e9..2982e35 100644
--- a/src/renderer/document/index.tsx
+++ b/src/renderer/document/index.tsx
@@ -8,7 +8,6 @@ import MainPage from "../pages/main-page";
import { ContextMenuComponent } from "../components/ContextMenu";
import { ToastContainer } from "react-toastify";
-
import "rc-slider/assets/index.css";
import "react-toastify/dist/ReactToastify.css";
import "./index.css"; // 全局样式
@@ -48,7 +47,6 @@ function Root() {
}
function BootstrapComponent(): null {
-
useBootstrap();
return null;
diff --git a/src/renderer/pages/main-page/components/SideBar/index.tsx b/src/renderer/pages/main-page/components/SideBar/index.tsx
index 12edae5..23c1cd4 100644
--- a/src/renderer/pages/main-page/components/SideBar/index.tsx
+++ b/src/renderer/pages/main-page/components/SideBar/index.tsx
@@ -36,6 +36,11 @@ export default function () {
title: t("side_bar.plugin_management"),
route: "plugin-manager-view",
},
+ {
+ iconName: "clock",
+ title: t("side_bar.recently_play"),
+ route: "recently_play",
+ },
] as const;
return (
diff --git a/src/renderer/pages/main-page/index.scss b/src/renderer/pages/main-page/index.scss
index 66d45ac..bd446ae 100644
--- a/src/renderer/pages/main-page/index.scss
+++ b/src/renderer/pages/main-page/index.scss
@@ -1,14 +1,20 @@
.page-container {
- flex: auto;
- overflow-y: auto;
- overflow-x: hidden;
- width: 100%;
- padding-left: 1.5rem;
- padding-right: 1.5rem;
- position: relative;
+ flex: auto;
+ overflow-y: auto;
+ overflow-x: hidden;
+ width: 100%;
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ position: relative;
}
.page-container-full-width {
- padding-left: 0;
- padding-right: 0;
-}
\ No newline at end of file
+ padding-left: 0;
+ padding-right: 0;
+}
+
+.page-container-fw {
+ @extend .page-container;
+ padding-left: 0;
+ padding-right: 0;
+}
diff --git a/src/renderer/pages/main-page/index.tsx b/src/renderer/pages/main-page/index.tsx
index 4589b93..80c4e4f 100644
--- a/src/renderer/pages/main-page/index.tsx
+++ b/src/renderer/pages/main-page/index.tsx
@@ -13,58 +13,55 @@ import SettingView from "./views/setting-view";
import LocalMusicView from "./views/local-music-view";
import Empty from "@/renderer/components/Empty";
import DownloadView from "./views/download-view";
+import ThemeView from "./views/theme-view";
+import RecentlyPlayView from "./views/recently-play-view";
import "./index.scss";
-import ThemeView from "./views/theme-view";
export default function MainPage() {
return (
<>
-
-
- }
- >
- }
- >
- }
- >
- }
- >
- }
- >
- }>
- }
- >
- }
- >
- }
- >
- }
- >
- }>
- }>
- }>
-
-
+
+ }>
+ }
+ >
+ }
+ >
+ }
+ >
+ }
+ >
+ }>
+ }
+ >
+ }
+ >
+ }
+ >
+ }>
+ }>
+ }>
+ }
+ >
+ }>
+
>
);
diff --git a/src/renderer/pages/main-page/views/album-view/index.tsx b/src/renderer/pages/main-page/views/album-view/index.tsx
index 22b2fe7..6319c28 100644
--- a/src/renderer/pages/main-page/views/album-view/index.tsx
+++ b/src/renderer/pages/main-page/views/album-view/index.tsx
@@ -20,11 +20,13 @@ export default function AlbumView() {
useAlbumDetail(originalAlbumItem);
return (
-
+
+
+
);
}
diff --git a/src/renderer/pages/main-page/views/artist-view/components/Body/index.tsx b/src/renderer/pages/main-page/views/artist-view/components/Body/index.tsx
index 336103b..2a44d79 100644
--- a/src/renderer/pages/main-page/views/artist-view/components/Body/index.tsx
+++ b/src/renderer/pages/main-page/views/artist-view/components/Body/index.tsx
@@ -12,11 +12,9 @@ interface IBodyProps {
const supportedMediaType = ["music", "album"];
export default function Body(props: IBodyProps) {
- const {artistItem} = props;
+ const { artistItem } = props;
const [currentMediaType, setCurrentMediaType] = useState("music");
const { t } = useTranslation();
-
-
return (
@@ -28,21 +26,21 @@ export default function Body(props: IBodyProps) {
{supportedMediaType.map((type) => (
- {t(type)}
+ {t(`media.media_type_${type}`)}
))}
{supportedMediaType.map((type) => (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
))}
diff --git a/src/renderer/pages/main-page/views/artist-view/components/Header/index.tsx b/src/renderer/pages/main-page/views/artist-view/components/Header/index.tsx
index 0ed0cbf..cea64d2 100644
--- a/src/renderer/pages/main-page/views/artist-view/components/Header/index.tsx
+++ b/src/renderer/pages/main-page/views/artist-view/components/Header/index.tsx
@@ -11,7 +11,7 @@ interface IProps {
export default function Header(props: IProps) {
const { artistItem } = props;
- const {t} = useTranslation();
+ const { t } = useTranslation();
return (
@@ -23,7 +23,9 @@ export default function Header(props: IProps) {
{artistItem?.platform}
-
{artistItem?.name ?? t("media.unknown_artist")}
+
+ {artistItem?.name ?? t("media.unknown_artist")}
+
@@ -35,7 +37,7 @@ export default function Header(props: IProps) {
dataset.fold = dataset.fold === "true" ? "false" : "true";
}}
>
- 简介:{artistItem?.description}
+ {artistItem?.description}
diff --git a/src/renderer/pages/main-page/views/artist-view/index.tsx b/src/renderer/pages/main-page/views/artist-view/index.tsx
index 8f129f0..7ba8265 100644
--- a/src/renderer/pages/main-page/views/artist-view/index.tsx
+++ b/src/renderer/pages/main-page/views/artist-view/index.tsx
@@ -22,12 +22,12 @@ export default function ArtistView() {
return () => {
queryResultStore.setValue(initQueryResult);
};
- })
+ });
return (
-
+
-
+
);
}
diff --git a/src/renderer/pages/main-page/views/download-view/index.tsx b/src/renderer/pages/main-page/views/download-view/index.tsx
index bb57a3b..57944f2 100644
--- a/src/renderer/pages/main-page/views/download-view/index.tsx
+++ b/src/renderer/pages/main-page/views/download-view/index.tsx
@@ -8,7 +8,10 @@ export default function DownloadView() {
const { t } = useTranslation();
return (
-
+
diff --git a/src/renderer/pages/main-page/views/local-music-view/index.tsx b/src/renderer/pages/main-page/views/local-music-view/index.tsx
index 9acc3a4..55de1b7 100644
--- a/src/renderer/pages/main-page/views/local-music-view/index.tsx
+++ b/src/renderer/pages/main-page/views/local-music-view/index.tsx
@@ -74,7 +74,8 @@ export default function LocalMusicView() {
return (
{t("local_music_page.local_music")}
diff --git a/src/renderer/pages/main-page/views/music-sheet-view/index.tsx b/src/renderer/pages/main-page/views/music-sheet-view/index.tsx
index 076e6ec..7172f9f 100644
--- a/src/renderer/pages/main-page/views/music-sheet-view/index.tsx
+++ b/src/renderer/pages/main-page/views/music-sheet-view/index.tsx
@@ -1,10 +1,10 @@
import { useParams } from "react-router-dom";
-import "./index.scss";
-import Condition from "@/renderer/components/Condition";
import { localPluginName } from "@/common/constant";
import LocalSheet from "./local-sheet";
import RemoteSheet from "./remote-sheet";
+import "./index.scss";
+
/**
* path: /main/musicsheet/platform/id
*
@@ -17,11 +17,12 @@ export default function MusicSheetView() {
const { platform } = useParams() ?? {};
return (
-
}
- >
-
-
+
+ {platform === localPluginName ? (
+
+ ) : (
+
+ )}
+
);
}
diff --git a/src/renderer/pages/main-page/views/music-sheet-view/local-sheet/index.tsx b/src/renderer/pages/main-page/views/music-sheet-view/local-sheet/index.tsx
index c4cf5f4..1bf767e 100644
--- a/src/renderer/pages/main-page/views/music-sheet-view/local-sheet/index.tsx
+++ b/src/renderer/pages/main-page/views/music-sheet-view/local-sheet/index.tsx
@@ -19,6 +19,7 @@ export default function LocalSheet() {
return (
+
{t("plugin_management_page.plugin_management")}
diff --git a/src/renderer/pages/main-page/views/recently-play-view/index.tsx b/src/renderer/pages/main-page/views/recently-play-view/index.tsx
new file mode 100644
index 0000000..346eac5
--- /dev/null
+++ b/src/renderer/pages/main-page/views/recently-play-view/index.tsx
@@ -0,0 +1,40 @@
+import MusicSheetlikeView from "@/renderer/components/MusicSheetlikeView";
+import SvgAsset from "@/renderer/components/SvgAsset";
+import {
+ clearRecentlyPlaylist,
+ useRecentlyPlaylistSheet,
+} from "@/renderer/core/recently-playlist";
+import { useTranslation } from "react-i18next";
+
+export default function RecentlyPlayView() {
+ const recentlyPlaylistSheet = useRecentlyPlaylistSheet();
+ const { t } = useTranslation();
+
+ const options = (
+ <>
+
{
+ clearRecentlyPlaylist();
+ }}
+ >
+
+ {t("common.clear")}
+
+ >
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/src/renderer/pages/main-page/views/recommend-sheets-view/index.tsx b/src/renderer/pages/main-page/views/recommend-sheets-view/index.tsx
index 41c3dd4..3b37137 100644
--- a/src/renderer/pages/main-page/views/recommend-sheets-view/index.tsx
+++ b/src/renderer/pages/main-page/views/recommend-sheets-view/index.tsx
@@ -10,41 +10,43 @@ export default function RecommendSheetsView() {
const navigate = useNavigate();
return (
-
}
- >
- {
- const usr = history.state.usr ?? {};
-
- navigate("", {
- replace: true,
- state: {
- ...usr,
- pluginHash: availablePlugins[index].hash,
- pluginIndex: index,
- tag: null
- },
- });
- }}
+
+ }
>
-
- {availablePlugins.map((plugin) => (
-
- {plugin.platform}
-
- ))}
-
-
- {availablePlugins.map((plugin) => (
-
-
-
- ))}
-
-
-
+ {
+ const usr = history.state.usr ?? {};
+
+ navigate("", {
+ replace: true,
+ state: {
+ ...usr,
+ pluginHash: availablePlugins[index].hash,
+ pluginIndex: index,
+ tag: null,
+ },
+ });
+ }}
+ >
+
+ {availablePlugins.map((plugin) => (
+
+ {plugin.platform}
+
+ ))}
+
+
+ {availablePlugins.map((plugin) => (
+
+
+
+ ))}
+
+
+
+
);
}
diff --git a/src/renderer/pages/main-page/views/search-view/index.tsx b/src/renderer/pages/main-page/views/search-view/index.tsx
index 2be3b02..f79f7d9 100644
--- a/src/renderer/pages/main-page/views/search-view/index.tsx
+++ b/src/renderer/pages/main-page/views/search-view/index.tsx
@@ -39,7 +39,7 @@ export default function SearchView() {
}, []);
return (
-
+
「{decodeURIComponent(query)}」
{t("search_result_page.search_result_title")}
diff --git a/src/renderer/pages/main-page/views/setting-view/index.tsx b/src/renderer/pages/main-page/views/setting-view/index.tsx
index 17d8a0c..4a649ad 100644
--- a/src/renderer/pages/main-page/views/setting-view/index.tsx
+++ b/src/renderer/pages/main-page/views/setting-view/index.tsx
@@ -18,9 +18,6 @@ export default function SettingView() {
const intersectionRatioRef = useRef