Initial work on 'blur' filter for posts

pull/1120/head
Lim Chee Aun 2025-04-09 08:26:09 +08:00
rodzic 75a35b7e27
commit ed41d4c22e
6 zmienionych plików z 89 dodań i 21 usunięć

Wyświetl plik

@ -653,6 +653,7 @@
display: flex;
gap: 4px;
align-items: center;
text-align: start;
}
.status .content-container.has-spoiler:not(.show-spoiler) .spoiler-button {
~ *:not(
@ -1374,7 +1375,8 @@ body:has(#modal-container .carousel) .status .media img:hover {
width: 100%;
height: 100%;
min-height: var(--min-dimension);
background-image: radial-gradient(
background-image:
radial-gradient(
circle at center center,
transparent,
var(--bg-faded-color)

Wyświetl plik

@ -54,6 +54,7 @@ import htmlContentLength from '../utils/html-content-length';
import isRTL from '../utils/is-rtl';
import isMastodonLinkMaybe from '../utils/isMastodonLinkMaybe';
import localeMatch from '../utils/locale-match';
import mem from '../utils/mem';
import niceDateTime from '../utils/nice-date-time';
import openCompose from '../utils/open-compose';
import pmem from '../utils/pmem';
@ -317,6 +318,24 @@ const checkDifferentLanguage = (
return different;
};
const getCurrentAccID = mem(
() => {
return getCurrentAccountID();
},
{
maxAge: 60 * 1000, // 1 minute
},
);
const getPrefs = mem(
() => {
return store.account.get('preferences') || {};
},
{
maxAge: 60 * 1000, // 1 minute
},
);
function Status({
statusID,
status,
@ -330,7 +349,7 @@ function Status({
enableTranslate,
forceTranslate: _forceTranslate,
previewMode,
// allowFilters,
allowFilters,
onMediaClick,
quoted,
onStatusLinkClick = () => {},
@ -447,16 +466,16 @@ function Status({
const hasMediaAttachments = !!mediaAttachments?.length;
if (mediaFirst && hasMediaAttachments) size = 's';
const currentAccount = useMemo(() => {
return getCurrentAccountID();
}, []);
const currentAccount = getCurrentAccID();
const isSelf = useMemo(() => {
return currentAccount && currentAccount === accountId;
}, [accountId, currentAccount]);
const filterContext = useContext(FilterContext);
const filterInfo =
!isSelf && !readOnly && !previewMode && isFiltered(filtered, filterContext);
!isSelf &&
((!readOnly && !previewMode) || allowFilters) &&
isFiltered(filtered, filterContext);
if (filterInfo?.action === 'hide') {
return null;
@ -472,7 +491,11 @@ function Status({
}
};
if (/*allowFilters && */ size !== 'l' && filterInfo) {
if (
(allowFilters || size !== 'l') &&
filterInfo &&
filterInfo.action !== 'blur'
) {
return (
<FilteredStatus
status={status}
@ -515,13 +538,13 @@ function Status({
mentions?.find((mention) => mention.id === currentAccount);
const readingExpandSpoilers = useMemo(() => {
const prefs = store.account.get('preferences') || {};
const prefs = getPrefs();
return !!prefs['reading:expand:spoilers'];
}, []);
const readingExpandMedia = useMemo(() => {
// default | show_all | hide_all
// Ignore hide_all because it means hide *ALL* media including non-sensitive ones
const prefs = store.account.get('preferences') || {};
const prefs = getPrefs();
return prefs['reading:expand:media']?.toLowerCase() || 'default';
}, []);
// FOR TESTING:
@ -2011,7 +2034,9 @@ function Status({
)}
<div
class={`content-container ${
spoilerText || sensitive ? 'has-spoiler' : ''
spoilerText || sensitive || filterInfo?.action === 'blur'
? 'has-spoiler'
: ''
} ${showSpoiler ? 'show-spoiler' : ''} ${
showSpoilerMedia ? 'show-media' : ''
}`}
@ -2184,7 +2209,7 @@ function Status({
/>
)}
{!previewMode &&
sensitive &&
(sensitive || filterInfo?.action === 'blur') &&
!!mediaAttachments.length &&
readingExpandMedia !== 'show_all' && (
<button
@ -2206,7 +2231,15 @@ function Status({
<Icon
icon={showSpoilerMedia ? 'eye-open' : 'eye-close'}
/>{' '}
{showSpoilerMedia ? t`Show less` : t`Show media`}
<span>
{filterInfo?.action === 'blur' && (
<small>
<Trans>Filtered: {filterInfo?.titlesStr}</Trans>
<br />
</small>
)}
{showSpoilerMedia ? t`Show less` : t`Show media`}
</span>
</button>
)}
{!!mediaAttachments.length &&

Wyświetl plik

@ -608,8 +608,12 @@ const TimelineItem = memo(
// }
const aFiltered = isFiltered(a.filtered, filterContext);
const bFiltered = isFiltered(b.filtered, filterContext);
if (aFiltered) filteredItemsIDs.add(a.id);
if (bFiltered) filteredItemsIDs.add(b.id);
if (aFiltered && aFiltered?.action !== 'blur') {
filteredItemsIDs.add(a.id);
}
if (bFiltered && bFiltered?.action !== 'blur') {
filteredItemsIDs.add(b.id);
}
if (aFiltered && !bFiltered) {
return 1;
}

Wyświetl plik

@ -309,7 +309,7 @@ function Catchup() {
original = 0;
const links = {};
for (const post of posts) {
if (post._filtered) {
if (post._filtered && post._filtered?.action !== 'blur') {
filtered++;
post.__FILTER = 'filtered';
} else if (post.group) {
@ -1711,7 +1711,7 @@ const PostLine = memo(
__BOOSTERS,
} = post;
const isReplyTo = inReplyToId && inReplyToAccountId !== account.id;
const isFiltered = !!filterInfo;
const isFiltered = !!filterInfo && filterInfo?.action !== 'blur';
const debugHover = (e) => {
if (e.shiftKey) {
@ -1853,7 +1853,9 @@ function PostPeek({ post, filterInfo }) {
return !!prefs['reading:expand:spoilers'];
}, []);
// const readingExpandSpoilers = true;
const showMedia = readingExpandSpoilers || (!spoilerText && !sensitive);
const showMedia =
readingExpandSpoilers ||
(!spoilerText && !sensitive && filterInfo?.action !== 'blur');
const postText = content ? statusPeek(post) : '';
const showPostContent = !spoilerText || readingExpandSpoilers;
@ -1866,7 +1868,7 @@ function PostPeek({ post, filterInfo }) {
<span class="post-peek-tag post-peek-thread">Thread</span>{' '}
</>
)}
{!!filterInfo ? (
{!!filterInfo && filterInfo?.action !== 'blur' ? (
<span class="post-peek-filtered">
{/* Filtered{filterInfo?.titlesStr ? `: ${filterInfo.titlesStr}` : ''} */}
{filterInfo?.titlesStr
@ -1918,7 +1920,7 @@ function PostPeek({ post, filterInfo }) {
</>
)}
</span>
{!filterInfo && (
{(!filterInfo || filterInfo?.action === 'blur') && (
<span class="post-peek-post-content">
{!!poll && (
<span class="post-peek-tag post-peek-poll">

Wyświetl plik

@ -13,6 +13,7 @@ import NavMenu from '../components/nav-menu';
import RelativeTime from '../components/relative-time';
import { api } from '../utils/api';
import i18nDuration from '../utils/i18n-duration';
import { getAPIVersions } from '../utils/store-utils';
import useInterval from '../utils/useInterval';
import useTitle from '../utils/useTitle';
@ -525,12 +526,27 @@ function FiltersAddEdit({ filter, onClose }) {
<p>
<Trans>Filtered post will be</Trans>
<br />
{getAPIVersions()?.mastodon >= 5 && (
<label class="ib">
<input
type="radio"
name="filter_action"
value="blur"
defaultChecked={filterAction === 'blur'}
disabled={uiState === 'loading'}
/>{' '}
<Trans>obscured (media only)</Trans>
</label>
)}{' '}
<label class="ib">
<input
type="radio"
name="filter_action"
value="warn"
defaultChecked={filterAction === 'warn' || !editMode}
defaultChecked={
(filterAction !== 'hide' && filterAction !== 'blur') ||
!editMode
}
disabled={uiState === 'loading'}
/>{' '}
<Trans>minimized</Trans>

Wyświetl plik

@ -16,7 +16,18 @@ function _isFiltered(filtered, filterContext) {
return {
action: 'hide',
};
const isWarn = appliedFilters.some((f) => f.filter.filterAction === 'warn');
const isBlur = appliedFilters.every((f) => f.filter.filterAction === 'blur');
if (isBlur) {
const filterTitles = appliedFilters.map((f) => f.filter.title);
return {
action: 'blur',
titles: filterTitles,
titlesStr: filterTitles.join(' • '),
};
}
// const isWarn = appliedFilters.some((f) => f.filter.filterAction === 'warn');
const isWarn = appliedFilters.some((f) => !!f.filter.filterAction);
// Re: spec; unknown values for filter_action should be treated as warn.
if (isWarn) {
const filterTitles = appliedFilters.map((f) => f.filter.title);
return {