From e3352b89d8d2481ada62cc7227d22b6cd41d2bd7 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 15:18:40 -0500 Subject: [PATCH 1/9] Remove "show more" CW button, display SensitiveContentOverlay instead --- app/soapbox/components/status.tsx | 8 +- app/soapbox/components/status_content.tsx | 81 +------------------ .../statuses/sensitive-content-overlay.tsx | 8 ++ .../components/scheduled_status.tsx | 1 - .../status/components/detailed-status.tsx | 12 +-- .../modals/report-modal/report-modal.tsx | 1 - .../features/ui/components/pending_status.tsx | 1 - app/soapbox/normalizers/status.ts | 8 ++ 8 files changed, 21 insertions(+), 99 deletions(-) diff --git a/app/soapbox/components/status.tsx b/app/soapbox/components/status.tsx index 35827020f..3e30a3032 100644 --- a/app/soapbox/components/status.tsx +++ b/app/soapbox/components/status.tsx @@ -105,10 +105,6 @@ const Status: React.FC = (props) => { } }; - const handleExpandedToggle = (): void => { - dispatch(toggleStatusHidden(actualStatus)); - }; - const handleHotkeyOpenMedia = (e?: KeyboardEvent): void => { const status = actualStatus; const firstAttachment = status.media_attachments.first(); @@ -301,7 +297,7 @@ const Status: React.FC = (props) => { const accountAction = props.accountAction || reblogElement; const inReview = status.visibility === 'self'; - const isSensitive = status.sensitive; + const isSensitive = status.hidden; return ( @@ -382,8 +378,6 @@ const Status: React.FC = (props) => { diff --git a/app/soapbox/components/status_content.tsx b/app/soapbox/components/status_content.tsx index 7d771ec37..d2adc181e 100644 --- a/app/soapbox/components/status_content.tsx +++ b/app/soapbox/components/status_content.tsx @@ -35,49 +35,16 @@ const ReadMoreButton: React.FC = ({ onClick }) => ( ); -interface ISpoilerButton { - onClick: React.MouseEventHandler, - hidden: boolean, - tabIndex?: number, -} - -/** Button to expand status text behind a content warning */ -const SpoilerButton: React.FC = ({ onClick, hidden, tabIndex }) => ( - -); - interface IStatusContent { status: Status, - expanded?: boolean, - onExpandedToggle?: () => void, onClick?: () => void, collapsable?: boolean, } /** Renders the text content of a status */ -const StatusContent: React.FC = ({ status, expanded = false, onExpandedToggle, onClick, collapsable = false }) => { +const StatusContent: React.FC = ({ status, onClick, collapsable = false }) => { const history = useHistory(); - const [hidden, setHidden] = useState(true); const [collapsed, setCollapsed] = useState(false); const [onlyEmoji, setOnlyEmoji] = useState(false); @@ -186,18 +153,6 @@ const StatusContent: React.FC = ({ status, expanded = false, onE startXY.current = undefined; }; - const handleSpoilerClick: React.EventHandler = (e) => { - e.preventDefault(); - e.stopPropagation(); - - if (onExpandedToggle) { - // The parent manages the state - onExpandedToggle(); - } else { - setHidden(!hidden); - } - }; - const parsedHtml = useMemo((): string => { const { contentHtml: html } = status; @@ -212,13 +167,11 @@ const StatusContent: React.FC = ({ status, expanded = false, onE return null; } - const isHidden = onExpandedToggle ? !expanded : hidden; const withSpoiler = status.spoiler_text.length > 0; const baseClassName = 'text-gray-900 dark:text-gray-100 break-words text-ellipsis overflow-hidden relative focus:outline-none'; const content = { __html: parsedHtml }; - const spoilerContent = { __html: status.spoilerHtml }; const directionStyle: React.CSSProperties = { direction: 'ltr' }; const className = classNames(baseClassName, 'status-content', { 'cursor-pointer': onClick, @@ -231,37 +184,7 @@ const StatusContent: React.FC = ({ status, expanded = false, onE directionStyle.direction = 'rtl'; } - if (status.spoiler_text.length > 0) { - return ( -
-

- - -

- -
- - {!isHidden && status.poll && typeof status.poll === 'string' && ( - - )} -
- ); - } else if (onClick) { + if (onClick) { const output = [
{ {intl.formatMessage(isUnderReview ? messages.underReviewSubtitle : messages.sensitiveSubtitle)} + + {status.spoiler_text && ( +
+ + “” + +
+ )}
diff --git a/app/soapbox/features/scheduled_statuses/components/scheduled_status.tsx b/app/soapbox/features/scheduled_statuses/components/scheduled_status.tsx index 865bbaff4..b9b90ef27 100644 --- a/app/soapbox/features/scheduled_statuses/components/scheduled_status.tsx +++ b/app/soapbox/features/scheduled_statuses/components/scheduled_status.tsx @@ -44,7 +44,6 @@ const ScheduledStatus: React.FC = ({ statusId, ...other }) => diff --git a/app/soapbox/features/status/components/detailed-status.tsx b/app/soapbox/features/status/components/detailed-status.tsx index 52bc578af..4896d1a91 100644 --- a/app/soapbox/features/status/components/detailed-status.tsx +++ b/app/soapbox/features/status/components/detailed-status.tsx @@ -37,10 +37,6 @@ const DetailedStatus: React.FC = ({ const intl = useIntl(); const node = useRef(null); - const handleExpandedToggle = () => { - onToggleHidden(status); - }; - const handleOpenCompareHistoryModal = () => { onOpenCompareHistoryModal(status); }; @@ -51,7 +47,7 @@ const DetailedStatus: React.FC = ({ if (!account || typeof account !== 'object') return null; const isUnderReview = actualStatus.visibility === 'self'; - const isSensitive = actualStatus.sensitive; + const isSensitive = actualStatus.hidden; let statusTypeIcon = null; @@ -105,11 +101,7 @@ const DetailedStatus: React.FC = ({ /> ) : null} - + { diff --git a/app/soapbox/features/ui/components/pending_status.tsx b/app/soapbox/features/ui/components/pending_status.tsx index 76b8bb47e..64f0d168b 100644 --- a/app/soapbox/features/ui/components/pending_status.tsx +++ b/app/soapbox/features/ui/components/pending_status.tsx @@ -79,7 +79,6 @@ const PendingStatus: React.FC = ({ idempotencyKey, className, mu diff --git a/app/soapbox/normalizers/status.ts b/app/soapbox/normalizers/status.ts index 4788758d3..ea971c52f 100644 --- a/app/soapbox/normalizers/status.ts +++ b/app/soapbox/normalizers/status.ts @@ -149,6 +149,13 @@ const fixFiltered = (status: ImmutableMap) => { status.delete('filtered'); }; +/** If the status contains spoiler text, treat it as sensitive. */ +const fixSensitivity = (status: ImmutableMap) => { + if (status.get('spoiler_text')) { + status.set('sensitive', true); + } +}; + export const normalizeStatus = (status: Record) => { return StatusRecord( ImmutableMap(fromJS(status)).withMutations(status => { @@ -161,6 +168,7 @@ export const normalizeStatus = (status: Record) => { addSelfMention(status); fixQuote(status); fixFiltered(status); + fixSensitivity(status); }), ); }; From aea7bdcaa03fba8ed2d20500032c097b61aa92ce Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 15:22:25 -0500 Subject: [PATCH 2/9] Preferences: media display --> sensitive content --- app/soapbox/features/preferences/index.tsx | 14 +++++++------- app/soapbox/locales/en.json | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/soapbox/features/preferences/index.tsx b/app/soapbox/features/preferences/index.tsx index bb81eb773..971582812 100644 --- a/app/soapbox/features/preferences/index.tsx +++ b/app/soapbox/features/preferences/index.tsx @@ -77,9 +77,9 @@ const languages = { const messages = defineMessages({ heading: { id: 'column.preferences', defaultMessage: 'Preferences' }, - display_media_default: { id: 'preferences.fields.display_media.default', defaultMessage: 'Hide media marked as sensitive' }, - display_media_hide_all: { id: 'preferences.fields.display_media.hide_all', defaultMessage: 'Always hide media' }, - display_media_show_all: { id: 'preferences.fields.display_media.show_all', defaultMessage: 'Always show media' }, + displayPostsDefault: { id: 'preferences.fields.display_media.default', defaultMessage: 'Hide posts marked as sensitive' }, + displayPostsHideAll: { id: 'preferences.fields.display_media.hide_all', defaultMessage: 'Always hide posts' }, + displayPostsShowAll: { id: 'preferences.fields.display_media.show_all', defaultMessage: 'Always show posts' }, privacy_public: { id: 'preferences.options.privacy_public', defaultMessage: 'Public' }, privacy_unlisted: { id: 'preferences.options.privacy_unlisted', defaultMessage: 'Unlisted' }, privacy_followers_only: { id: 'preferences.options.privacy_followers_only', defaultMessage: 'Followers-only' }, @@ -102,9 +102,9 @@ const Preferences = () => { }; const displayMediaOptions = React.useMemo(() => ({ - default: intl.formatMessage(messages.display_media_default), - hide_all: intl.formatMessage(messages.display_media_hide_all), - show_all: intl.formatMessage(messages.display_media_show_all), + default: intl.formatMessage(messages.displayPostsDefault), + hide_all: intl.formatMessage(messages.displayPostsHideAll), + show_all: intl.formatMessage(messages.displayPostsShowAll), }), []); const defaultPrivacyOptions = React.useMemo(() => ({ @@ -149,7 +149,7 @@ const Preferences = () => { /> - }> + }> Date: Mon, 31 Oct 2022 15:38:23 -0500 Subject: [PATCH 3/9] Compose: send `sensitive: true` when spoiler is enabled --- app/soapbox/reducers/compose.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/soapbox/reducers/compose.ts b/app/soapbox/reducers/compose.ts index 4523edab9..dcdc4491f 100644 --- a/app/soapbox/reducers/compose.ts +++ b/app/soapbox/reducers/compose.ts @@ -296,11 +296,8 @@ export default function compose(state = initialState, action: AnyAction) { return updateCompose(state, action.id, compose => compose.withMutations(map => { map.set('spoiler_text', ''); map.set('spoiler', !compose.spoiler); + map.set('sensitive', !compose.spoiler); map.set('idempotencyKey', uuid()); - - if (!compose.sensitive && compose.media_attachments.size >= 1) { - map.set('sensitive', true); - } })); case COMPOSE_SPOILER_TEXT_CHANGE: return updateCompose(state, action.id, compose => compose From f51f2984a5bf6741dabb6992b1b36cfcb219da89 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 16:19:51 -0500 Subject: [PATCH 4/9] Compose: overhaul Spoiler feature --- app/soapbox/components/autosuggest_input.tsx | 2 +- .../compose/components/compose-form.tsx | 45 +++-------- .../compose/components/spoiler-input.tsx | 79 +++++++++++++++++++ app/soapbox/locales/en.json | 2 +- 4 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 app/soapbox/features/compose/components/spoiler-input.tsx diff --git a/app/soapbox/components/autosuggest_input.tsx b/app/soapbox/components/autosuggest_input.tsx index 277d87f96..155cd428a 100644 --- a/app/soapbox/components/autosuggest_input.tsx +++ b/app/soapbox/components/autosuggest_input.tsx @@ -45,7 +45,7 @@ const textAtCursorMatchesToken = (str: string, caretPosition: number, searchToke } }; -interface IAutosuggestInput extends Pick, 'onChange' | 'onKeyUp' | 'onKeyDown'> { +export interface IAutosuggestInput extends Pick, 'onChange' | 'onKeyUp' | 'onKeyDown'> { value: string, suggestions: ImmutableList, disabled?: boolean, diff --git a/app/soapbox/features/compose/components/compose-form.tsx b/app/soapbox/features/compose/components/compose-form.tsx index b9968ad3e..c0b64f1d1 100644 --- a/app/soapbox/features/compose/components/compose-form.tsx +++ b/app/soapbox/features/compose/components/compose-form.tsx @@ -10,7 +10,6 @@ import { clearComposeSuggestions, fetchComposeSuggestions, selectComposeSuggestion, - changeComposeSpoilerText, insertEmojiCompose, uploadCompose, } from 'soapbox/actions/compose'; @@ -38,6 +37,7 @@ import UploadButtonContainer from '../containers/upload_button_container'; import WarningContainer from '../containers/warning_container'; import { countableText } from '../util/counter'; +import SpoilerInput from './spoiler-input'; import TextCharacterCounter from './text_character_counter'; import VisualCharacterCounter from './visual_character_counter'; @@ -48,7 +48,7 @@ const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u20 const messages = defineMessages({ placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What\'s on your mind?' }, pollPlaceholder: { id: 'compose_form.poll_placeholder', defaultMessage: 'Add a poll topic...' }, - spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' }, + spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here (optional)' }, publish: { id: 'compose_form.publish', defaultMessage: 'Post' }, publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' }, message: { id: 'compose_form.message', defaultMessage: 'Message' }, @@ -165,10 +165,6 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab dispatch(selectComposeSuggestion(id, tokenStart, token, value, ['spoiler_text'])); }; - const handleChangeSpoilerText: React.ChangeEventHandler = (e) => { - dispatch(changeComposeSpoilerText(id, e.target.value)); - }; - const setCursor = (start: number, end: number = start) => { if (!autosuggestTextareaRef.current?.textarea) return; autosuggestTextareaRef.current.textarea.setSelectionRange(start, end); @@ -265,7 +261,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab } return ( - + {scheduledStatusCount > 0 && ( ({ id, shouldCondense, autoFocus, clickab {!shouldCondense && } -
- -
- ({ id, shouldCondense, autoFocus, clickab > { !condensed && -
+ -
+ + +
} diff --git a/app/soapbox/features/compose/components/spoiler-input.tsx b/app/soapbox/features/compose/components/spoiler-input.tsx new file mode 100644 index 000000000..129b972c8 --- /dev/null +++ b/app/soapbox/features/compose/components/spoiler-input.tsx @@ -0,0 +1,79 @@ +import classNames from 'clsx'; +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { changeComposeSpoilerness, changeComposeSpoilerText } from 'soapbox/actions/compose'; +import AutosuggestInput, { IAutosuggestInput } from 'soapbox/components/autosuggest_input'; +import { Divider, Stack, Text } from 'soapbox/components/ui'; +import { useAppDispatch, useCompose } from 'soapbox/hooks'; + +const messages = defineMessages({ + title: { id: 'compose_form.spoiler_title', defaultMessage: 'Sensitive content' }, + placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here (optional)' }, + remove: { id: 'compose_form.spoiler_remove', defaultMessage: 'Remove sensitive' }, +}); + +interface ISpoilerInput extends Pick { + composeId: string extends 'default' ? never : string, +} + +/** Text input for content warning in composer. */ +const SpoilerInput: React.FC = ({ + composeId, + onSuggestionsFetchRequested, + onSuggestionsClearRequested, + onSuggestionSelected, +}) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const compose = useCompose(composeId); + + const handleChangeSpoilerText: React.ChangeEventHandler = (e) => { + dispatch(changeComposeSpoilerText(composeId, e.target.value)); + }; + + const handleRemove = () => { + dispatch(changeComposeSpoilerness(composeId)); + }; + + return ( + + + + + + {intl.formatMessage(messages.title)} + + + + +
+ +
+
+
+ ); +}; + +export default SpoilerInput; \ No newline at end of file diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 7397cc38d..f2eaf32c8 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -288,7 +288,7 @@ "compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.spoiler.marked": "Text is hidden behind warning", "compose_form.spoiler.unmarked": "Text is not hidden", - "compose_form.spoiler_placeholder": "Write your warning here", + "compose_form.spoiler_placeholder": "Write your warning here (optional)", "confirmation_modal.cancel": "Cancel", "confirmations.admin.deactivate_user.confirm": "Deactivate @{name}", "confirmations.admin.deactivate_user.heading": "Deactivate @{acct}", From 69157097dda2e5859310e53f32f2cde5db8322cd Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 16:23:17 -0500 Subject: [PATCH 5/9] SpoilerInput: fix ref --- app/soapbox/features/compose/components/compose-form.tsx | 1 + app/soapbox/features/compose/components/spoiler-input.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/soapbox/features/compose/components/compose-form.tsx b/app/soapbox/features/compose/components/compose-form.tsx index c0b64f1d1..f9eb98204 100644 --- a/app/soapbox/features/compose/components/compose-form.tsx +++ b/app/soapbox/features/compose/components/compose-form.tsx @@ -316,6 +316,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab onSuggestionsFetchRequested={onSuggestionsFetchRequested} onSuggestionsClearRequested={onSuggestionsClearRequested} onSuggestionSelected={onSpoilerSuggestionSelected} + ref={spoilerTextRef} />
} diff --git a/app/soapbox/features/compose/components/spoiler-input.tsx b/app/soapbox/features/compose/components/spoiler-input.tsx index 129b972c8..e6f53d04c 100644 --- a/app/soapbox/features/compose/components/spoiler-input.tsx +++ b/app/soapbox/features/compose/components/spoiler-input.tsx @@ -18,12 +18,12 @@ interface ISpoilerInput extends Pick = ({ +const SpoilerInput = React.forwardRef(({ composeId, onSuggestionsFetchRequested, onSuggestionsClearRequested, onSuggestionSelected, -}) => { +}, ref) => { const intl = useIntl(); const dispatch = useAppDispatch(); const compose = useCompose(composeId); @@ -63,6 +63,7 @@ const SpoilerInput: React.FC = ({ searchTokens={[':']} id='cw-spoiler-input' className='rounded-md dark:!bg-transparent !bg-transparent' + ref={ref} autoFocus /> @@ -74,6 +75,6 @@ const SpoilerInput: React.FC = ({ ); -}; +}); export default SpoilerInput; \ No newline at end of file From 9ae8fc4e03d04eeafde9342bbe85010ca24d9a0a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 16:26:58 -0500 Subject: [PATCH 6/9] Compose: clean up unused sensitivity actions --- app/soapbox/actions/compose.ts | 8 ---- .../compose/components/sensitive-button.tsx | 48 ------------------- .../compose/components/upload_form.tsx | 3 -- .../reducers/__tests__/compose.test.ts | 25 +--------- app/soapbox/reducers/compose.ts | 9 ---- 5 files changed, 2 insertions(+), 91 deletions(-) delete mode 100644 app/soapbox/features/compose/components/sensitive-button.tsx diff --git a/app/soapbox/actions/compose.ts b/app/soapbox/actions/compose.ts index d397f4026..57e7909a1 100644 --- a/app/soapbox/actions/compose.ts +++ b/app/soapbox/actions/compose.ts @@ -54,7 +54,6 @@ const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE'; const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE'; -const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'; const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'; const COMPOSE_TYPE_CHANGE = 'COMPOSE_TYPE_CHANGE'; const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'; @@ -600,11 +599,6 @@ const insertIntoTagHistory = (composeId: string, recognizedTags: APIEntity[], te dispatch(updateTagHistory(composeId, newHistory)); }; -const changeComposeSensitivity = (composeId: string) => ({ - type: COMPOSE_SENSITIVITY_CHANGE, - id: composeId, -}); - const changeComposeSpoilerness = (composeId: string) => ({ type: COMPOSE_SPOILERNESS_CHANGE, id: composeId, @@ -741,7 +735,6 @@ export { COMPOSE_SUGGESTION_SELECT, COMPOSE_SUGGESTION_TAGS_UPDATE, COMPOSE_TAG_HISTORY_UPDATE, - COMPOSE_SENSITIVITY_CHANGE, COMPOSE_SPOILERNESS_CHANGE, COMPOSE_TYPE_CHANGE, COMPOSE_SPOILER_TEXT_CHANGE, @@ -796,7 +789,6 @@ export { selectComposeSuggestion, updateSuggestionTags, updateTagHistory, - changeComposeSensitivity, changeComposeSpoilerness, changeComposeContentType, changeComposeSpoilerText, diff --git a/app/soapbox/features/compose/components/sensitive-button.tsx b/app/soapbox/features/compose/components/sensitive-button.tsx deleted file mode 100644 index 87d5103c5..000000000 --- a/app/soapbox/features/compose/components/sensitive-button.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; - -import { changeComposeSensitivity } from 'soapbox/actions/compose'; -import { FormGroup, Checkbox } from 'soapbox/components/ui'; -import { useAppDispatch, useCompose } from 'soapbox/hooks'; - -const messages = defineMessages({ - marked: { id: 'compose_form.sensitive.marked', defaultMessage: 'Media is marked as sensitive' }, - unmarked: { id: 'compose_form.sensitive.unmarked', defaultMessage: 'Media is not marked as sensitive' }, -}); - -interface ISensitiveButton { - composeId: string, -} - -/** Button to mark own media as sensitive. */ -const SensitiveButton: React.FC = ({ composeId }) => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - - const compose = useCompose(composeId); - - const active = compose.sensitive === true; - const disabled = compose.spoiler === true; - - const onClick = () => { - dispatch(changeComposeSensitivity(composeId)); - }; - - return ( -
- } - labelTitle={intl.formatMessage(active ? messages.marked : messages.unmarked)} - > - - -
- ); -}; - -export default SensitiveButton; diff --git a/app/soapbox/features/compose/components/upload_form.tsx b/app/soapbox/features/compose/components/upload_form.tsx index 7ad300528..e9c116b24 100644 --- a/app/soapbox/features/compose/components/upload_form.tsx +++ b/app/soapbox/features/compose/components/upload_form.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { useCompose } from 'soapbox/hooks'; -import SensitiveButton from './sensitive-button'; import Upload from './upload'; import UploadProgress from './upload-progress'; @@ -28,8 +27,6 @@ const UploadForm: React.FC = ({ composeId }) => { ))}
- - {!mediaIds.isEmpty() && } ); }; diff --git a/app/soapbox/reducers/__tests__/compose.test.ts b/app/soapbox/reducers/__tests__/compose.test.ts index c8da1c744..1270fb6af 100644 --- a/app/soapbox/reducers/__tests__/compose.test.ts +++ b/app/soapbox/reducers/__tests__/compose.test.ts @@ -181,30 +181,8 @@ describe('compose reducer', () => { }); }); - it('should handle COMPOSE_SENSITIVITY_CHANGE on Mark Sensitive click, don\'t toggle if spoiler active', () => { - const state = initialState.set('home', ReducerCompose({ spoiler: true, sensitive: true, idempotencyKey: '' })); - const action = { - type: actions.COMPOSE_SENSITIVITY_CHANGE, - id: 'home', - }; - expect(reducer(state, action).toJS().home).toMatchObject({ - sensitive: true, - }); - }); - - it('should handle COMPOSE_SENSITIVITY_CHANGE on Mark Sensitive click, toggle if spoiler inactive', () => { - const state = initialState.set('home', ReducerCompose({ spoiler: false, sensitive: true })); - const action = { - type: actions.COMPOSE_SENSITIVITY_CHANGE, - id: 'home', - }; - expect(reducer(state, action).toJS().home).toMatchObject({ - sensitive: false, - }); - }); - it('should handle COMPOSE_SPOILERNESS_CHANGE on CW button click', () => { - const state = initialState.set('home', ReducerCompose({ spoiler_text: 'spoiler text', spoiler: true, media_attachments: ImmutableList() })); + const state = initialState.set('home', ReducerCompose({ spoiler_text: 'spoiler text', spoiler: true, sensitive: true, media_attachments: ImmutableList() })); const action = { type: actions.COMPOSE_SPOILERNESS_CHANGE, id: 'home', @@ -212,6 +190,7 @@ describe('compose reducer', () => { expect(reducer(state, action).toJS().home).toMatchObject({ spoiler: false, spoiler_text: '', + sensitive: false, }); }); diff --git a/app/soapbox/reducers/compose.ts b/app/soapbox/reducers/compose.ts index dcdc4491f..bdfcf3009 100644 --- a/app/soapbox/reducers/compose.ts +++ b/app/soapbox/reducers/compose.ts @@ -26,7 +26,6 @@ import { COMPOSE_SUGGESTION_SELECT, COMPOSE_SUGGESTION_TAGS_UPDATE, COMPOSE_TAG_HISTORY_UPDATE, - COMPOSE_SENSITIVITY_CHANGE, COMPOSE_SPOILERNESS_CHANGE, COMPOSE_TYPE_CHANGE, COMPOSE_SPOILER_TEXT_CHANGE, @@ -279,14 +278,6 @@ export const initialState: State = ImmutableMap({ export default function compose(state = initialState, action: AnyAction) { switch (action.type) { - case COMPOSE_SENSITIVITY_CHANGE: - return updateCompose(state, action.id, compose => compose.withMutations(map => { - if (!compose.spoiler) { - map.set('sensitive', !compose.sensitive); - } - - map.set('idempotencyKey', uuid()); - })); case COMPOSE_TYPE_CHANGE: return updateCompose(state, action.id, compose => compose.withMutations(map => { map.set('content_type', action.value); From 18f73aae7c2723ee443e54bed09941398573f9f4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 16:50:06 -0500 Subject: [PATCH 7/9] Compose: don't inherit spoilerness of post being replied to --- app/soapbox/reducers/compose.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/soapbox/reducers/compose.ts b/app/soapbox/reducers/compose.ts index bdfcf3009..3f02f8cac 100644 --- a/app/soapbox/reducers/compose.ts +++ b/app/soapbox/reducers/compose.ts @@ -316,14 +316,6 @@ export default function compose(state = initialState, action: AnyAction) { map.set('caretPosition', null); map.set('idempotencyKey', uuid()); map.set('content_type', defaultCompose.content_type); - - if (action.status.get('spoiler_text', '').length > 0) { - map.set('spoiler', true); - map.set('spoiler_text', action.status.spoiler_text); - } else { - map.set('spoiler', false); - map.set('spoiler_text', ''); - } })); case COMPOSE_QUOTE: return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => { From 20f47c72c943c3235169972e4271276b98587fd9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Oct 2022 18:02:55 -0500 Subject: [PATCH 8/9] Preferences: "sensitive contnt" typofix --- app/soapbox/features/preferences/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/features/preferences/index.tsx b/app/soapbox/features/preferences/index.tsx index 971582812..3adb90861 100644 --- a/app/soapbox/features/preferences/index.tsx +++ b/app/soapbox/features/preferences/index.tsx @@ -149,7 +149,7 @@ const Preferences = () => { /> - }> + }> Date: Tue, 1 Nov 2022 13:16:25 -0500 Subject: [PATCH 9/9] Display only know notification types --- app/soapbox/actions/notifications.ts | 17 ++++++++--------- .../notifications/components/notification.tsx | 2 +- app/soapbox/reducers/notifications.js | 6 ++++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/soapbox/actions/notifications.ts b/app/soapbox/actions/notifications.ts index 79994bde5..4edd76c22 100644 --- a/app/soapbox/actions/notifications.ts +++ b/app/soapbox/actions/notifications.ts @@ -1,5 +1,4 @@ import { - List as ImmutableList, Map as ImmutableMap, } from 'immutable'; import IntlMessageFormat from 'intl-messageformat'; @@ -12,6 +11,7 @@ import { getFilters, regexFromFilters } from 'soapbox/selectors'; import { isLoggedIn } from 'soapbox/utils/auth'; import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features'; import { unescapeHTML } from 'soapbox/utils/html'; +import { NOTIFICATION_TYPES } from 'soapbox/utils/notification'; import { joinPublicPath } from 'soapbox/utils/static'; import { fetchRelationships } from './accounts'; @@ -168,11 +168,8 @@ const dequeueNotifications = () => dispatch(markReadNotifications()); }; -// const excludeTypesFromSettings = (getState: () => RootState) => (getSettings(getState()).getIn(['notifications', 'shows']) as ImmutableMap).filter(enabled => !enabled).keySeq().toJS(); - const excludeTypesFromFilter = (filter: string) => { - const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'status', 'poll', 'move', 'pleroma:emoji_reaction']); - return allTypes.filterNot(item => item === filter).toJS(); + return NOTIFICATION_TYPES.filter(item => item !== filter); }; const noOp = () => new Promise(f => f(undefined)); @@ -182,6 +179,7 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an if (!isLoggedIn(getState)) return dispatch(noOp); const state = getState(); + const features = getFeatures(state.instance); const activeFilter = getSettings(state).getIn(['notifications', 'quickFilter', 'active']) as string; const notifications = state.notifications; const isLoadingMore = !!maxId; @@ -195,10 +193,11 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an max_id: maxId, }; - if (activeFilter !== 'all') { - const instance = state.instance; - const features = getFeatures(instance); - + if (activeFilter === 'all') { + if (features.notificationsIncludeTypes) { + params.types = NOTIFICATION_TYPES; + } + } else { if (features.notificationsIncludeTypes) { params.types = [activeFilter]; } else { diff --git a/app/soapbox/features/notifications/components/notification.tsx b/app/soapbox/features/notifications/components/notification.tsx index e1fa87c5a..1871b3a89 100644 --- a/app/soapbox/features/notifications/components/notification.tsx +++ b/app/soapbox/features/notifications/components/notification.tsx @@ -268,7 +268,7 @@ const Notification: React.FC = (props) => { }; const renderContent = () => { - switch (type) { + switch (type as NotificationType) { case 'follow': case 'user_approved': return account && typeof account === 'object' ? ( diff --git a/app/soapbox/reducers/notifications.js b/app/soapbox/reducers/notifications.js index d7697d4dd..4d5dd9921 100644 --- a/app/soapbox/reducers/notifications.js +++ b/app/soapbox/reducers/notifications.js @@ -5,6 +5,7 @@ import { } from 'immutable'; import { normalizeNotification } from 'soapbox/normalizers/notification'; +import { validType } from 'soapbox/utils/notification'; import { ACCOUNT_BLOCK_SUCCESS, @@ -67,6 +68,11 @@ const fixNotification = notification => { const isValid = notification => { try { + // Ensure the notification is a known type + if (!validType(notification.type)) { + return false; + } + // https://gitlab.com/soapbox-pub/soapbox/-/issues/424 if (!notification.account.id) { return false;