Skip to content

Commit

Permalink
feat(dynamic-feed): add min-duration filter
Browse files Browse the repository at this point in the history
  • Loading branch information
magicdawn committed Nov 1, 2024
1 parent 0c334e4 commit 93ccff0
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 8 deletions.
20 changes: 19 additions & 1 deletion src/modules/rec-services/dynamic-feed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { CHARGE_ONLY_TEXT } from '$components/VideoCard/top-marks'
import { type DynamicFeedItemExtend, type DynamicFeedJson } from '$define'
import { EApiType } from '$define/index.shared'
import { isWebApiSuccess, request } from '$request'
import { toast } from '$utility'
import { parseDuration, toast } from '$utility'
import type { IService } from '../_base'
import { getFollowGroupContent } from './group'
import {
DynamicFeedVideoMinDuration,
DynamicFeedVideoType,
QUERY_DYNAMIC_UP_MID,
dfStore,
Expand Down Expand Up @@ -40,6 +41,12 @@ export class DynamicFeedRecService implements IService {
get hideChargeOnlyVideos() {
return this.filterConfig.hideChargeOnlyVideos
}
get filterMinDuration() {
return this.filterConfig.filterMinDuration
}
get filterMinDurationValue() {
return this.filterConfig.filterMinDurationValue
}
get hasSelectedUp() {
return this.filterConfig.hasSelectedUp
}
Expand Down Expand Up @@ -135,6 +142,17 @@ export class DynamicFeedRecService implements IService {
return !chargeOnly
})

// by 最短时长
.filter((x) => {
// only when the filter UI visible
if (!this.showFilter) return true
if (this.filterMinDuration === DynamicFeedVideoMinDuration.All) return true

const v = x.modules.module_dynamic.major.archive
const duration = parseDuration(v.duration_text)
return duration >= this.filterMinDurationValue
})

// by 关键字搜索
.filter((x) => {
// only when the filter UI visible
Expand Down
34 changes: 33 additions & 1 deletion src/modules/rec-services/dynamic-feed/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ export const DynamicFeedVideoTypeLabel: Record<DynamicFeedVideoType, string> = {
[DynamicFeedVideoType.DynamicOnly]: '仅动态视频',
}

export enum DynamicFeedVideoMinDuration {
All = 'all',
_2m = '2min',
_1m = '1min',
_30s = '30s',
_10s = '10s',
}

export const DynamicFeedVideoMinDurationConfig: Record<
DynamicFeedVideoMinDuration,
{ label: string; duration: number }
> = {
// 及以上
[DynamicFeedVideoMinDuration.All]: { label: '全部时长', duration: 0 },
[DynamicFeedVideoMinDuration._2m]: { label: '2分钟', duration: 2 * 60 },
[DynamicFeedVideoMinDuration._1m]: { label: '1分钟', duration: 60 },
[DynamicFeedVideoMinDuration._30s]: { label: '30秒', duration: 30 },
[DynamicFeedVideoMinDuration._10s]: { label: '10秒', duration: 10 },
}

/**
* df expand to `dynamic-feed`
*/
Expand Down Expand Up @@ -78,6 +98,11 @@ export const dfStore = proxy({
get hideChargeOnlyVideos() {
return this.hideChargeOnlyVideosForKeysSet.has(this.selectedKey)
},

filterMinDuration: DynamicFeedVideoMinDuration.All,
get filterMinDurationValue() {
return DynamicFeedVideoMinDurationConfig[this.filterMinDuration].duration
},
})

export type DynamicFeedStore = typeof dfStore
Expand All @@ -87,14 +112,21 @@ export type DynamicFeedStoreFilterConfig = ReturnType<typeof getDfStoreFilterCon
export function getDfStoreFilterConfig() {
const snap = snapshot(dfStore)
return {
// state
// UP | 分组
upMid: snap.upMid,
followGroupTagid: snap.selectedFollowGroup?.tagid,

// 搜索
searchText: snap.searchText,

// 类型
dynamicFeedVideoType: snap.dynamicFeedVideoType,
hideChargeOnlyVideos: snap.hideChargeOnlyVideos,

// 时长
filterMinDuration: snap.filterMinDuration,
filterMinDurationValue: snap.filterMinDurationValue,

// flags
hasSelectedUp: snap.hasSelectedUp,
showFilter: snap.showFilter,
Expand Down
49 changes: 45 additions & 4 deletions src/modules/rec-services/dynamic-feed/usage-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import TablerFilter from '~icons/tabler/filter'
import TablerFilterCheck from '~icons/tabler/filter-check'
import { usePopupContainer } from '../_base'
import {
DynamicFeedVideoMinDuration,
DynamicFeedVideoMinDurationConfig,
DynamicFeedVideoType,
DynamicFeedVideoTypeLabel,
dfStore,
Expand All @@ -37,6 +39,8 @@ const clearPayload: Partial<DynamicFeedStore> = {
upName: undefined,
searchText: undefined,
selectedFollowGroup: undefined,
dynamicFeedVideoType: DynamicFeedVideoType.All,
filterMinDuration: DynamicFeedVideoMinDuration.All,
}

const S = {
Expand All @@ -45,7 +49,7 @@ const S = {
`,

filterSection: css`
width: 300px;
min-width: 300px;
margin-top: 10px;
&:first-child {
margin-top: 0;
Expand Down Expand Up @@ -75,6 +79,7 @@ export function DynamicFeedUsageInfo() {
followGroups,
selectedFollowGroup,
dynamicFeedVideoType,
filterMinDuration,
showFilter,
searchText,
selectedKey,
Expand All @@ -84,9 +89,14 @@ export function DynamicFeedUsageInfo() {
const showFilterBadge = useMemo(() => {
return (
showFilter &&
!!(dynamicFeedVideoType !== DynamicFeedVideoType.All || hideChargeOnlyVideos || searchText)
!!(
dynamicFeedVideoType !== DynamicFeedVideoType.All ||
hideChargeOnlyVideos ||
searchText ||
filterMinDuration !== DynamicFeedVideoMinDuration.All
)
)
}, [showFilter, dynamicFeedVideoType, hideChargeOnlyVideos, searchText])
}, [showFilter, dynamicFeedVideoType, hideChargeOnlyVideos, searchText, filterMinDuration])

// try update on mount
useMount(() => {
Expand Down Expand Up @@ -195,6 +205,7 @@ export function DynamicFeedUsageInfo() {
<HelpInfo>
{CHARGE_ONLY_TEXT}」在此程序中归类为「投稿视频」
<br />
「动态视频」时长通常较短
</HelpInfo>
</div>
<div className='content'>
Expand Down Expand Up @@ -255,11 +266,41 @@ export function DynamicFeedUsageInfo() {
</div>
)}

<div className='section' css={S.filterSection}>
<div className='title'>最短时长</div>
<div className='content'>
<Radio.Group
css={css`
overflow: hidden;
.ant-radio-button-wrapper {
padding-inline: 10px; // 原始 15px
}
`}
buttonStyle='solid'
value={filterMinDuration}
onChange={async (v) => {
dfStore.filterMinDuration = v.target.value
await delay(100)
onRefresh?.()
}}
>
{Object.values(DynamicFeedVideoMinDuration).map((k) => {
const { label } = DynamicFeedVideoMinDurationConfig[k]
return (
<Radio.Button key={k} value={k}>
{label}
</Radio.Button>
)
})}
</Radio.Group>
</div>
</div>

<div className='section' css={S.filterSection}>
<div className='title'>搜索</div>
<div className='content'>
<Input.Search
style={{ width: 280 }}
style={{ width: '97%' }}
placeholder='按标题关键字过滤'
type='search'
autoCorrect='off'
Expand Down
7 changes: 5 additions & 2 deletions src/modules/rec-services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { RecItemTypeOrSeparator } from '$define'
import { EApiType } from '$define/index.shared'
import { uniqBy } from 'es-toolkit'
import { AppRecService } from './app'
import { DynamicFeedVideoType } from './dynamic-feed/store'
import { DynamicFeedVideoMinDuration, DynamicFeedVideoType } from './dynamic-feed/store'
import { PcRecService } from './pc'
import { REC_TABS, getIService, type FetcherOptions } from './service-map'

Expand Down Expand Up @@ -144,7 +144,10 @@ export async function refreshForGrid(fetcherOptions: FetcherOptions) {
if (
s.followGroupTagid || // 选择了分组 & 分组很少更新
(s.showFilter &&
(s.searchText || s.dynamicFeedVideoType === DynamicFeedVideoType.DynamicOnly)) // 过滤结果可能比较少
// 过滤结果可能比较少
(s.searchText ||
s.dynamicFeedVideoType === DynamicFeedVideoType.DynamicOnly ||
s.filterMinDuration !== DynamicFeedVideoMinDuration.All))
) {
minCount = 1
}
Expand Down

0 comments on commit 93ccff0

Please sign in to comment.