nicolium: a bugged filtering implementation

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-03-08 13:36:34 +01:00
parent f1f3c3932a
commit c8e380a572
4 changed files with 60 additions and 11 deletions

View File

@ -32,9 +32,11 @@ import {
usePublicTimeline,
useWrenchedTimeline,
} from '@/queries/timelines/use-timelines';
import { useSettings } from '@/stores/settings';
import { selectChild } from '@/utils/scroll-utils';
import type { FilterContextType } from '@/queries/settings/use-filters';
import type { Settings } from '@/schemas/frontend-settings';
import type { TimelineEntry } from '@/stores/timelines';
import type { VirtuosoHandle } from 'react-virtuoso';
@ -368,6 +370,7 @@ type IBaseTimeline = Pick<
'emptyMessageIcon' | 'emptyMessageText' | 'onTopItemChanged'
> & {
featuredStatusIds?: Array<string>;
filters?: Settings['timelines'][string];
};
interface ITimeline extends IBaseTimeline {
@ -379,6 +382,7 @@ const Timeline: React.FC<ITimeline> = ({
query,
contextType = 'public',
featuredStatusIds,
filters,
...props
}) => {
const node = useRef<VirtuosoHandle | null>(null);
@ -426,6 +430,15 @@ const Timeline: React.FC<ITimeline> = ({
const renderEntry = (entry: TimelineEntry, index: number) => {
if (entry.type === 'status') {
if (
(filters?.showDirect === false && entry.isDirect) ||
(filters?.showReblogs === false && entry.isReblog) ||
(filters?.showReplies === false && entry.isReply) ||
(filters?.showQuotes === false && entry.isQuote) ||
(filters?.showNonMedia === false && !entry.hasMedia)
) {
return null;
}
return (
<TimelineStatus
key={entry.id}
@ -480,7 +493,7 @@ const Timeline: React.FC<ITimeline> = ({
}
return rendered;
}, [entries, contextType, timelineId, featuredStatusIds]);
}, [entries, contextType, timelineId, featuredStatusIds, filters]);
return (
<>
@ -533,6 +546,8 @@ const getRestoredPosition = (me: string) => {
const HomeTimelineColumn: React.FC<IBaseTimeline> = (props) => {
const me = useAppSelector((state) => state.me);
const timelineFilters = useSettings().timelines.home;
const maxId = useMemo(() => {
if (!me) return undefined;
@ -563,6 +578,7 @@ const HomeTimelineColumn: React.FC<IBaseTimeline> = (props) => {
query={timelineQuery}
contextType='home'
onTopItemChanged={handleTopItemChanged}
filters={timelineFilters}
{...props}
/>
);

View File

@ -318,7 +318,7 @@ const Preferences = () => {
>
<SettingToggle
settings={settings}
settingPath={['timelines', 'home', 'shows', 'reblog']}
settingPath={['timelines', 'home', 'showReblogs']}
defaultValue
onChange={onToggleChange}
/>
@ -334,7 +334,39 @@ const Preferences = () => {
>
<SettingToggle
settings={settings}
settingPath={['timelines', 'home', 'shows', 'reply']}
settingPath={['timelines', 'home', 'showReplies']}
defaultValue
onChange={onToggleChange}
/>
</ListItem>
<ListItem
label={
<FormattedMessage
id='home.column_settings.show_quotes'
defaultMessage='Show quotes in home timeline'
/>
}
>
<SettingToggle
settings={settings}
settingPath={['timelines', 'home', 'showQuotes']}
defaultValue
onChange={onToggleChange}
/>
</ListItem>
<ListItem
label={
<FormattedMessage
id='home.column_settings.show_direct'
defaultMessage='Show direct messages in home timeline'
/>
}
>
<SettingToggle
settings={settings}
settingPath={['timelines', 'home', 'showDirect']}
defaultValue
onChange={onToggleChange}
/>

View File

@ -78,14 +78,11 @@ const settingsSchema = v.object({
v.record(
v.string(),
coerceObject({
shows: coerceObject({
reblog: v.optional(v.boolean(), true),
reply: v.optional(v.boolean(), true),
direct: v.optional(v.boolean(), false),
}),
other: coerceObject({
onlyMedia: v.optional(v.boolean(), false),
}),
showReblogs: v.optional(v.boolean(), true),
showReplies: v.optional(v.boolean(), true),
showQuotes: v.optional(v.boolean(), true),
showDirect: v.optional(v.boolean(), true),
showNonMedia: v.optional(v.boolean(), true),
}),
),
{},

View File

@ -20,6 +20,7 @@ type TimelineEntry =
// this actually indicates whether the status exclusively appeared as a reblog on the processed page
isReblog: boolean;
isQuote: boolean;
isDirect: boolean;
hasMedia: boolean;
}
| {
@ -128,6 +129,7 @@ const processPage = (statuses: Array<Status>): Array<TimelineEntry> => {
isReply: status.reblog.in_reply_to_id !== null,
isReblog: true,
isQuote: status.reblog.quote !== null,
isDirect: status.reblog.visibility === 'direct',
hasMedia: status.reblog.media_attachments.length > 0,
});
}
@ -144,6 +146,7 @@ const processPage = (statuses: Array<Status>): Array<TimelineEntry> => {
isReply: status.in_reply_to_id !== null,
isReblog: false,
isQuote: status.quote !== null,
isDirect: status.visibility === 'direct',
hasMedia: status.media_attachments.length > 0,
});
@ -346,6 +349,7 @@ const useTimelinesStore = create<State>()(
isReply: status.in_reply_to_id !== null,
isReblog: false,
isQuote: status.quote !== null,
isDirect: status.visibility === 'direct',
hasMedia: status.media_attachments.length > 0,
};
}