diff --git a/src/pages/account-statuses.jsx b/src/pages/account-statuses.jsx index 7166ac9423..31f7cca305 100644 --- a/src/pages/account-statuses.jsx +++ b/src/pages/account-statuses.jsx @@ -28,6 +28,7 @@ import { isMediaFirstInstance, } from '../utils/store-utils'; import supports from '../utils/supports'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; @@ -160,13 +161,17 @@ function AccountStatuses() { .values() .next(); if (value?.length && !tagged && !media) { - const pinnedStatuses = value.map((status) => { + let pinnedStatuses = value.map((status) => { saveStatus(status, instance); return { ...status, _pinned: true, }; }); + pinnedStatuses = applyTimelineFilters( + pinnedStatuses, + snapStates.settings, + ); if (pinnedStatuses.length >= 3) { const pinnedStatusesIds = pinnedStatuses.map((status) => status.id); results.push({ @@ -216,9 +221,10 @@ function AccountStatuses() { } } - results.push(...value); + const filteredValue = applyTimelineFilters(value, snapStates.settings); + results.push(...filteredValue); - value.forEach((item) => { + filteredValue.forEach((item) => { saveStatus(item, instance); }); } diff --git a/src/pages/bookmarks.jsx b/src/pages/bookmarks.jsx index 4bd5b4d806..ff2a0cf856 100644 --- a/src/pages/bookmarks.jsx +++ b/src/pages/bookmarks.jsx @@ -1,14 +1,18 @@ import { useLingui } from '@lingui/react/macro'; import { useRef } from 'preact/hooks'; +import { useSnapshot } from 'valtio'; import Timeline from '../components/timeline'; import { api } from '../utils/api'; +import states from '../utils/states'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; function Bookmarks() { const { t } = useLingui(); + const snapStates = useSnapshot(states); useTitle(t`Bookmarks`, '/b'); const { masto, instance } = api(); const bookmarksIterator = useRef(); @@ -18,7 +22,15 @@ function Bookmarks() { .list({ limit: LIMIT }) .values(); } - return await bookmarksIterator.current.next(); + const results = await bookmarksIterator.current.next(); + let { value } = results; + if (value?.length) { + value = applyTimelineFilters(value, snapStates.settings); + } + return { + ...results, + value, + }; } return ( diff --git a/src/pages/favourites.jsx b/src/pages/favourites.jsx index 4f274d7a03..d4d70c6d94 100644 --- a/src/pages/favourites.jsx +++ b/src/pages/favourites.jsx @@ -1,14 +1,18 @@ import { Trans, useLingui } from '@lingui/react/macro'; import { useRef } from 'preact/hooks'; +import { useSnapshot } from 'valtio'; import Timeline from '../components/timeline'; import { api } from '../utils/api'; +import states from '../utils/states'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; function Favourites() { const { t } = useLingui(); + const snapStates = useSnapshot(states); useTitle(t`Likes`, '/favourites'); const { masto, instance } = api(); const favouritesIterator = useRef(); @@ -18,7 +22,15 @@ function Favourites() { .list({ limit: LIMIT }) .values(); } - return await favouritesIterator.current.next(); + const results = await favouritesIterator.current.next(); + let { value } = results; + if (value?.length) { + value = applyTimelineFilters(value, snapStates.settings); + } + return { + ...results, + value, + }; } return ( diff --git a/src/pages/following.jsx b/src/pages/following.jsx index 3d0bdd411d..d833d54601 100644 --- a/src/pages/following.jsx +++ b/src/pages/following.jsx @@ -8,6 +8,7 @@ import { filteredItems } from '../utils/filters'; import states, { getStatus, saveStatus } from '../utils/states'; import supports from '../utils/supports'; import { + applyTimelineFilters, assignFollowedTags, clearFollowedTagsState, dedupeBoosts, @@ -77,6 +78,7 @@ function Following({ title, path, id, ...props }) { saveStatus(item, instance); }); value = dedupeBoosts(value, instance); + value = applyTimelineFilters(value, snapStates.settings); if (firstLoad && latestItemChanged) clearFollowedTagsState(); setTimeout(() => { assignFollowedTags(value, instance); @@ -110,6 +112,7 @@ function Following({ title, path, id, ...props }) { if (value?.length && !valueContainsLatestItem) { latestItem.current = value[0].id; value = dedupeBoosts(value, instance); + value = applyTimelineFilters(value, snapStates.settings); value = filteredItems(value, 'home'); if (value.some((item) => !item.reblog)) { return true; diff --git a/src/pages/hashtag.jsx b/src/pages/hashtag.jsx index d19a36905e..bfde05b0c1 100644 --- a/src/pages/hashtag.jsx +++ b/src/pages/hashtag.jsx @@ -9,6 +9,7 @@ import { } from '@szhsin/react-menu'; import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; +import { useSnapshot } from 'valtio'; import Icon from '../components/icon'; import MenuConfirm from '../components/menu-confirm'; @@ -20,6 +21,7 @@ import { filteredItems } from '../utils/filters'; import showToast from '../utils/show-toast'; import states, { saveStatus } from '../utils/states'; import { isMediaFirstInstance } from '../utils/store-utils'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; @@ -32,6 +34,7 @@ const TOTAL_TAGS_LIMIT = TAGS_LIMIT_PER_MODE + 1; function Hashtags({ media: mediaView, columnMode, ...props }) { const { t } = useLingui(); + const snapStates = useSnapshot(states); // const navigate = useNavigate(); let { hashtag, ...params } = columnMode ? {} : useParams(); if (props.hashtag) hashtag = props.hashtag; @@ -97,6 +100,7 @@ function Hashtags({ media: mediaView, columnMode, ...props }) { skipThreading: media || mediaFirst, // If media view, no need to form threads }); }); + value = applyTimelineFilters(value, snapStates.settings); maxID.current = value[value.length - 1].id; } @@ -121,6 +125,7 @@ function Hashtags({ media: mediaView, columnMode, ...props }) { let { value } = results; const valueContainsLatestItem = value[0]?.id === latestItem.current; // since_id might not be supported if (value?.length && !valueContainsLatestItem) { + value = applyTimelineFilters(value, snapStates.settings); value = filteredItems(value, 'public'); return true; } diff --git a/src/pages/list.jsx b/src/pages/list.jsx index c72dd1cc03..6246e8fe3f 100644 --- a/src/pages/list.jsx +++ b/src/pages/list.jsx @@ -20,6 +20,7 @@ import { api } from '../utils/api'; import { filteredItems } from '../utils/filters'; import { getList, getLists } from '../utils/lists'; import states, { saveStatus } from '../utils/states'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; @@ -54,6 +55,7 @@ function List(props) { value.forEach((item) => { saveStatus(item, instance); }); + value = applyTimelineFilters(value, snapStates.settings); } return { ...results, @@ -70,6 +72,7 @@ function List(props) { let { value } = results; const valueContainsLatestItem = value[0]?.id === latestItem.current; // since_id might not be supported if (value?.length && !valueContainsLatestItem) { + value = applyTimelineFilters(value, snapStates.settings); value = filteredItems(value, 'home'); return true; } diff --git a/src/pages/mentions.jsx b/src/pages/mentions.jsx index cde15d9885..0e186c96ba 100644 --- a/src/pages/mentions.jsx +++ b/src/pages/mentions.jsx @@ -1,12 +1,14 @@ import { Trans, useLingui } from '@lingui/react/macro'; import { useMemo, useRef, useState } from 'preact/hooks'; import { useSearchParams } from 'react-router-dom'; +import { useSnapshot } from 'valtio'; import Link from '../components/link'; import Timeline from '../components/timeline'; import { api } from '../utils/api'; import { fixNotifications } from '../utils/group-notifications'; -import { saveStatus } from '../utils/states'; +import states, { saveStatus } from '../utils/states'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; @@ -14,6 +16,7 @@ const emptySearchParams = new URLSearchParams(); function Mentions({ columnMode, ...props }) { const { t } = useLingui(); + const snapStates = useSnapshot(states); const { masto, instance } = api(); const [searchParams] = columnMode ? [emptySearchParams] : useSearchParams(); const [stateType, setStateType] = useState(null); @@ -45,6 +48,17 @@ function Mentions({ columnMode, ...props }) { value.forEach(({ status: item }) => { saveStatus(item, instance); }); + + const statuses = value?.map((item) => item.status); + const filteredStatuses = applyTimelineFilters( + statuses, + snapStates.settings, + ); + + return { + ...results, + value: filteredStatuses, + }; } return { ...results, @@ -74,6 +88,17 @@ function Mentions({ columnMode, ...props }) { value.forEach(({ lastStatus: item }) => { saveStatus(item, instance); }); + + const statuses = value?.map((item) => item.lastStatus); + const filteredStatuses = applyTimelineFilters( + statuses, + snapStates.settings, + ); + + return { + ...results, + value: filteredStatuses, + }; } console.log('results', results); return { diff --git a/src/pages/public.jsx b/src/pages/public.jsx index ddac68a7f2..606642c851 100644 --- a/src/pages/public.jsx +++ b/src/pages/public.jsx @@ -11,6 +11,7 @@ import { api } from '../utils/api'; import { filteredItems } from '../utils/filters'; import states, { saveStatus } from '../utils/states'; import supports from '../utils/supports'; +import { applyTimelineFilters } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const LIMIT = 20; @@ -54,6 +55,7 @@ function Public({ local, columnMode, ...props }) { value.forEach((item) => { saveStatus(item, instance); }); + value = applyTimelineFilters(value, snapStates.settings); } return { ...results, @@ -74,6 +76,7 @@ function Public({ local, columnMode, ...props }) { let { value } = results; const valueContainsLatestItem = value[0]?.id === latestItem.current; // since_id might not be supported if (value?.length && !valueContainsLatestItem) { + value = applyTimelineFilters(value, snapStates.settings); value = filteredItems(value, 'public'); return true; } diff --git a/src/pages/settings.jsx b/src/pages/settings.jsx index 66202d7ca3..00f0033ffa 100644 --- a/src/pages/settings.jsx +++ b/src/pages/settings.jsx @@ -437,6 +437,47 @@ function Settings({ onClose }) { Boosts carousel +
  • + +
    + + + Hides all boosted posts from timelines. Individual status + pages still show boosts in threads. + + +
    +
  • +
  • + +
    + + + Hides all reply posts from timelines, including + self-replies. Individual status pages still show replies in + threads. + + +
    +
  • {!!TRANSLANG_INSTANCES && (