make watched filter nullable dropdown

This commit is contained in:
Simon 2025-08-11 19:55:27 +07:00
parent 59331b2b40
commit d8e5ee7e04
No known key found for this signature in database
GPG Key ID: 2C15AA5E89985DD4
10 changed files with 42 additions and 12 deletions

View File

@ -38,7 +38,7 @@ class UserMeConfigSerializer(serializers.Serializer):
view_style_downloads = serializers.ChoiceField(choices=["grid", "list"]) view_style_downloads = serializers.ChoiceField(choices=["grid", "list"])
view_style_playlist = serializers.ChoiceField(choices=["grid", "list"]) view_style_playlist = serializers.ChoiceField(choices=["grid", "list"])
grid_items = serializers.IntegerField(max_value=7, min_value=3) grid_items = serializers.IntegerField(max_value=7, min_value=3)
hide_watched = serializers.BooleanField() hide_watched = serializers.BooleanField(allow_null=True)
file_size_unit = serializers.ChoiceField(choices=["binary", "metric"]) file_size_unit = serializers.ChoiceField(choices=["binary", "metric"])
show_ignored_only = serializers.BooleanField() show_ignored_only = serializers.BooleanField()
show_subed_only = serializers.BooleanField() show_subed_only = serializers.BooleanField()

View File

@ -21,7 +21,7 @@ class UserConfigType(TypedDict, total=False):
view_style_downloads: str view_style_downloads: str
view_style_playlist: str view_style_playlist: str
grid_items: int grid_items: int
hide_watched: bool hide_watched: bool | None
file_size_unit: str file_size_unit: str
show_ignored_only: bool show_ignored_only: bool
show_subed_only: bool show_subed_only: bool

View File

@ -112,7 +112,7 @@ class VideoListQuerySerializer(serializers.Serializer):
playlist = serializers.CharField(required=False) playlist = serializers.CharField(required=False)
channel = serializers.CharField(required=False) channel = serializers.CharField(required=False)
watch = serializers.ChoiceField( watch = serializers.ChoiceField(
choices=WatchedEnum.values(), required=False choices=WatchedEnum.values(), required=False, allow_null=True
) )
sort = serializers.ChoiceField(choices=SortEnum.names(), required=False) sort = serializers.ChoiceField(choices=SortEnum.names(), required=False)
order = serializers.ChoiceField(choices=OrderEnum.values(), required=False) order = serializers.ChoiceField(choices=OrderEnum.values(), required=False)

View File

@ -35,7 +35,7 @@ class QueryBuilder:
must_list.append({"match": {"playlist.keyword": playlist}}) must_list.append({"match": {"playlist.keyword": playlist}})
watch = self.request_params.get("watch") watch = self.request_params.get("watch")
if watch: if watch is not None:
watch_must_list = self.parse_watch(watch) watch_must_list = self.parse_watch(watch)
must_list.append(watch_must_list) must_list.append(watch_must_list)

View File

@ -32,7 +32,7 @@ export type UserConfigType = {
view_style_downloads: ViewStylesType; view_style_downloads: ViewStylesType;
view_style_playlist: ViewStylesType; view_style_playlist: ViewStylesType;
grid_items: number; grid_items: number;
hide_watched: boolean; hide_watched: boolean | null;
file_size_unit: 'binary' | 'metric'; file_size_unit: 'binary' | 'metric';
show_ignored_only: boolean; show_ignored_only: boolean;
show_subed_only: boolean; show_subed_only: boolean;

View File

@ -36,7 +36,7 @@ export const SortOrderEnum = {
export type VideoTypes = 'videos' | 'streams' | 'shorts'; export type VideoTypes = 'videos' | 'streams' | 'shorts';
export type WatchTypes = 'watched' | 'unwatched' | 'continue'; export type WatchTypes = 'watched' | 'unwatched' | 'continue' | null;
export const WatchTypesEnum = { export const WatchTypesEnum = {
Watched: 'watched', Watched: 'watched',
Unwatched: 'unwatched', Unwatched: 'unwatched',

View File

@ -29,6 +29,8 @@ const Filterbar = ({ hideToggleText, viewStyle, showSort = true }: FilterbarProp
const currentViewStyle = userConfig[viewStyle]; const currentViewStyle = userConfig[viewStyle];
const isGridView = currentViewStyle === ViewStylesEnum.Grid; const isGridView = currentViewStyle === ViewStylesEnum.Grid;
console.log(hideToggleText);
useEffect(() => { useEffect(() => {
if (!showSort) { if (!showSort) {
return; return;
@ -52,7 +54,21 @@ const Filterbar = ({ hideToggleText, viewStyle, showSort = true }: FilterbarProp
return ( return (
<div className="view-controls three"> <div className="view-controls three">
<div className="toggle"> <div>
<select
value={userConfig.hide_watched === null ? '' : userConfig.hide_watched.toString()}
onChange={event => {
handleUserConfigUpdate({
hide_watched: event.target.value === '' ? null : event.target.value === 'true',
});
}}
>
<option value="">All</option>
<option value="true">Watched only</option>
<option value="false">Unwatched only</option>
</select>
</div>
{/* <div className="toggle">
<span>{hideToggleText}</span> <span>{hideToggleText}</span>
<div className="toggleBox"> <div className="toggleBox">
<input <input
@ -74,7 +90,7 @@ const Filterbar = ({ hideToggleText, viewStyle, showSort = true }: FilterbarProp
</label> </label>
)} )}
</div> </div>
</div> </div> */}
{showHidden && ( {showHidden && (
<div className="sort"> <div className="sort">

View File

@ -73,7 +73,12 @@ const ChannelVideo = ({ videoType }: ChannelVideoProps) => {
const videos = await loadVideoListByFilter({ const videos = await loadVideoListByFilter({
channel: channelId, channel: channelId,
page: currentPage, page: currentPage,
watch: userConfig.hide_watched ? (WatchTypesEnum.Unwatched as WatchTypes) : undefined, watch:
userConfig.hide_watched === null
? null
: ((userConfig.hide_watched
? WatchTypesEnum.Watched
: WatchTypesEnum.Unwatched) as WatchTypes),
sort: userConfig.sort_by, sort: userConfig.sort_by,
order: userConfig.sort_order, order: userConfig.sort_order,
type: videoType, type: videoType,

View File

@ -135,7 +135,12 @@ const Home = () => {
(async () => { (async () => {
const videos = await loadVideoListByFilter({ const videos = await loadVideoListByFilter({
page: currentPage, page: currentPage,
watch: userConfig.hide_watched ? (WatchTypesEnum.Unwatched as WatchTypes) : undefined, watch:
userConfig.hide_watched === null
? null
: ((userConfig.hide_watched
? WatchTypesEnum.Watched
: WatchTypesEnum.Unwatched) as WatchTypes),
sort: userConfig.sort_by, sort: userConfig.sort_by,
order: userConfig.sort_order, order: userConfig.sort_order,
}); });

View File

@ -72,7 +72,6 @@ const Playlist = () => {
const viewStyle = userConfig.view_style_home; // its a list of videos, so view_style_home const viewStyle = userConfig.view_style_home; // its a list of videos, so view_style_home
const gridItems = userConfig.grid_items; const gridItems = userConfig.grid_items;
const hideWatched = userConfig.hide_watched;
const isGridView = viewStyle === ViewStylesEnum.Grid; const isGridView = viewStyle === ViewStylesEnum.Grid;
const gridView = isGridView ? `boxed-${gridItems}` : ''; const gridView = isGridView ? `boxed-${gridItems}` : '';
const gridViewGrid = isGridView ? `grid-${gridItems}` : ''; const gridViewGrid = isGridView ? `grid-${gridItems}` : '';
@ -83,7 +82,12 @@ const Playlist = () => {
const video = await loadVideoListByFilter({ const video = await loadVideoListByFilter({
playlist: playlistId, playlist: playlistId,
page: currentPage, page: currentPage,
watch: hideWatched ? (WatchTypesEnum.Unwatched as WatchTypes) : undefined, watch:
userConfig.hide_watched === null
? null
: ((userConfig.hide_watched
? WatchTypesEnum.Watched
: WatchTypesEnum.Unwatched) as WatchTypes),
}); });
setPlaylistResponse(playlist); setPlaylistResponse(playlist);