Skip to content

Commit

Permalink
singer modify record drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
mebtte committed Jul 3, 2023
1 parent 460a351 commit 3ff6a67
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,35 @@ import {
MusicProperty,
MusicSingerRelation,
MusicSingerRelationProperty,
SINGER_MODIFY_RECORD_TABLE_NAME,
Singer,
SingerModifyRecordProperty,
SingerProperty,
} from '@/constants/db_definition';
import { updateSinger } from '@/db/singer';
import { saveSingerModifyRecord } from '@/db/singer_modify_record';
import { getAssetFilePath } from '@/platform/asset';
import { getDB } from '@/db';
import getSingerById from '@/db/get_singer_by_id';
import { Context } from '../constants';

function saveSingerModifyRecord({
singerId,
key,
modifyUserId,
}: {
singerId: string;
key: AllowUpdateKey;
modifyUserId: string;
}) {
return getDB().run(
`
INSERT INTO ${SINGER_MODIFY_RECORD_TABLE_NAME} ( ${SingerModifyRecordProperty.SINGER_ID}, ${SingerModifyRecordProperty.KEY}, ${SingerModifyRecordProperty.MODIFY_USER_ID}, ${SingerModifyRecordProperty.MODIFY_TIMESTAMP})
VALUES ( ?, ?, ?, ? )
`,
[singerId, key, modifyUserId, Date.now()],
);
}

type LocalSinger = Pick<
Singer,
| SingerProperty.ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SINGER_MODIFY_RECORD_TABLE_NAME,
SingerModifyRecordProperty,
} from '@/constants/db_definition';
import { SINGER_MODIFY_RECORD_TTL } from '#/constants';

const TABLES: {
table: string;
Expand All @@ -34,7 +35,7 @@ const TABLES: {
{
table: SINGER_MODIFY_RECORD_TABLE_NAME,
timestampColumn: SingerModifyRecordProperty.MODIFY_TIMESTAMP,
ttl: 1000 * 60 * 60 * 24 * 180,
ttl: SINGER_MODIFY_RECORD_TTL,
},
];

Expand Down
20 changes: 0 additions & 20 deletions apps/cli/src/db/singer_modify_record.ts

This file was deleted.

2 changes: 1 addition & 1 deletion apps/pwa/src/pages/player/music_drawer/use_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default (id: string) => {
const getMusic = useCallback(async () => {
setData(dataLoading);
try {
const music = await getMusicRequest(id);
const music = await getMusicRequest({ id, requestMinimalDuration: 0 });
let lyrics: Lyric[] = [];
if (music.type === MusicType.SONG) {
lyrics = await getLyricList({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import getSingerModifyRecordList from '@/server/api/get_singer_modify_record_list';

export interface Singer {
id: string;
avatar: string;
name: string;
}

export type ModifyRecord = AsyncReturnType<typeof getSingerModifyRecordList>[0];
46 changes: 46 additions & 0 deletions apps/pwa/src/pages/player/singer_modify_record_drawer/content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import styled from 'styled-components';
import Cover from '@/components/cover';
import getResizedImage from '@/server/asset/get_resized_image';
import useTitlebarArea from '@/utils/use_titlebar_area_rect';
import { Singer } from './constants';
import RecordList from './record_list';

const COVER_SIZE = 24;
const Style = styled.div`
min-height: 100vh;
display: flex;
flex-direction: column;
> .singer {
display: flex;
align-items: center;
padding: 5px 10px;
}
`;

function Content({ singer }: { singer: Singer }) {
const { height } = useTitlebarArea();
return (
<Style style={{ paddingTop: height }}>
<div className="singer">
<Cover
src={
singer.avatar
? getResizedImage({
url: singer.avatar,
size: COVER_SIZE * 2,
})
: ''
}
size={COVER_SIZE}
/>
<div className="name">{singer.name}</div>
</div>
<RecordList singerId={singer.id} />
</Style>
);
}

export default Content;
23 changes: 23 additions & 0 deletions apps/pwa/src/pages/player/singer_modify_record_drawer/hint.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import styled from 'styled-components';
import { SINGER_MODIFY_RECORD_TTL } from '#/constants';
import { CSSVariable } from '@/global_style';

const Style = styled.div`
padding: 10px;
font-size: 12px;
color: ${CSSVariable.TEXT_COLOR_SECONDARY};
text-align: center;
`;

function Hint() {
return (
<Style>
歌手修改记录保留时间为&nbsp;
{SINGER_MODIFY_RECORD_TTL / (1000 * 60 * 60 * 24)}
&nbsp;天
</Style>
);
}

export default Hint;
122 changes: 122 additions & 0 deletions apps/pwa/src/pages/player/singer_modify_record_drawer/record_list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import styled from 'styled-components';
import { flexCenter } from '@/style/flexbox';
import ErrorCard from '@/components/error_card';
import Spinner from '@/components/spinner';
import day from '#/utils/day';
import { AllowUpdateKey } from '#/constants/singer';
import { CSSVariable } from '@/global_style';
import Empty from '@/components/empty';
import useModifyRecordList from './use_modify_record_list';
import playerEventemitter, {
EventType as PlayerEventType,
} from '../eventemitter';

const KEY_MAP_LABEL: Record<AllowUpdateKey, string> = {
[AllowUpdateKey.AVATAR]: '头像',
[AllowUpdateKey.NAME]: '名字',
[AllowUpdateKey.ALIASES]: '别名',
};
const Root = styled.div`
flex: 1;
min-height: 0;
`;
const CardContainer = styled(Root)`
${flexCenter}
`;
const Style = styled(Root)`
> .record {
margin: 0 20px;
padding: 5px 10px;
position: relative;
border-left: 1px solid ${CSSVariable.BACKGROUND_COLOR_LEVEL_THREE};
> .time {
font-size: 12px;
color: ${CSSVariable.TEXT_COLOR_SECONDARY};
}
> .description {
font-size: 14px;
color: ${CSSVariable.TEXT_COLOR_PRIMARY};
> .user {
color: ${CSSVariable.COLOR_PRIMARY};
cursor: pointer;
}
> .key {
text-decoration: underline;
}
}
&::after {
content: '';
--size: 8px;
position: absolute;
top: calc(50% - var(--size) / 2);
left: calc(var(--size) / 2 * -1);
width: var(--size);
height: var(--size);
border-radius: 50%;
border: 1px solid ${CSSVariable.COLOR_PRIMARY};
}
}
`;

function RecordList({ singerId }: { singerId: string }) {
const { data, reload } = useModifyRecordList({ singerId });

if (data.error) {
return (
<CardContainer>
<ErrorCard errorMessage={data.error.message} retry={reload} />
</CardContainer>
);
}
if (data.loading) {
return (
<CardContainer>
<Spinner />
</CardContainer>
);
}
if (!data.value.length) {
return (
<CardContainer>
<Empty description="暂无修改记录" />
</CardContainer>
);
}
return (
<Style>
{data.value.map((record) => (
<div key={record.id} className="record">
<div className="time">
{day(record.modifyTimestamp).format('YYYY-MM-DD HH:mm')}
</div>
<div className="description">
<span
className="user"
onClick={() =>
playerEventemitter.emit(PlayerEventType.OPEN_USER_DRAWER, {
id: record.modifyUserId,
})
}
>
{record.modifyUserNickname}
</span>
修改了
<span className="key">
{KEY_MAP_LABEL[record.key] || record.key}
</span>
</div>
</div>
))}
</Style>
);
}

export default RecordList;
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { CSSProperties } from 'react';
import { Singer } from './constants';
import useDynamicZIndex from '../use_dynamic_z_index';
import { EventType } from '../eventemitter';
import Content from './content';
import Hint from './hint';

const bodyProps: { style: CSSProperties } = {
style: {
width: 300,
overflow: 'auto',
},
};

Expand All @@ -29,7 +32,8 @@ function SingerModifyRecordDrawer({
}}
bodyProps={bodyProps}
>
styled_function_component
<Content singer={singer} />
<Hint />
</Drawer>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback, useEffect, useState } from 'react';
import getSingerModifyRecordList from '@/server/api/get_singer_modify_record_list';
import { ModifyRecord } from './constants';

type Data =
| { error: null; loading: true; value: null }
| {
error: Error;
loading: false;
value: null;
}
| {
error: null;
loading: false;
value: ModifyRecord[];
};
const dataLoading: Data = {
error: null,
loading: true,
value: null,
};

export default ({ singerId }: { singerId: string }) => {
const [data, setData] = useState<Data>(dataLoading);
const getModifyRecordList = useCallback(async () => {
setData(dataLoading);
try {
const modifyRecordList = await getSingerModifyRecordList({
id: singerId,
});
setData({ error: null, loading: false, value: modifyRecordList });
} catch (error) {
setData({ error, loading: false, value: null });
}
}, [singerId]);

useEffect(() => {
getModifyRecordList();
}, [getModifyRecordList]);

return { data, reload: getModifyRecordList };
};
4 changes: 2 additions & 2 deletions apps/pwa/src/pages/player/use_playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default () => {
const unlistenMusicUpdated = eventemitter.listen(
EventType.MUSIC_UPDATED,
({ id }) =>
getMusic(id)
getMusic({ id, requestMinimalDuration: 0 })
.then((music) =>
setPlaylist((pl) =>
pl.map((m) =>
Expand Down Expand Up @@ -123,7 +123,7 @@ export default () => {
for (const music of playlist) {
const exist = music.singers.find((s) => s.id === payload.id);
if (exist) {
getMusic(music.id)
getMusic({ id: music.id, requestMinimalDuration: 0 })
.then((newMusic) =>
setPlaylist((pl) =>
pl.map((m) =>
Expand Down
9 changes: 8 additions & 1 deletion apps/pwa/src/server/api/get_music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import { request } from '..';
* 获取音乐详情
* @author mebtte<hi@mebtte.com>
*/
async function getMusic(id: string) {
async function getMusic({
id,
requestMinimalDuration,
}: {
id: string;
requestMinimalDuration?: number;
}) {
const music = await request<Response>({
path: '/api/music',
params: { id },
withToken: true,
requestMinimalDuration,
});
return {
...music,
Expand Down
Loading

0 comments on commit 3ff6a67

Please sign in to comment.