diff --git a/app/javascript/flavours/glitch/components/status.jsx b/app/javascript/flavours/glitch/components/status.jsx index 42076f0890..32a34a086a 100644 --- a/app/javascript/flavours/glitch/components/status.jsx +++ b/app/javascript/flavours/glitch/components/status.jsx @@ -20,6 +20,7 @@ import Card from '../features/status/components/card'; // to use the progress bar to show download progress import Bundle from '../features/ui/components/bundle'; import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; +import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_context'; import { displayMedia } from '../initial_state'; import AttachmentList from './attachment_list'; @@ -72,6 +73,8 @@ export const defaultMediaVisibility = (status, settings) => { class Status extends ImmutablePureComponent { + static contextType = SensitiveMediaContext; + static propTypes = { containerId: PropTypes.string, id: PropTypes.string, @@ -125,8 +128,7 @@ class Status extends ImmutablePureComponent { isCollapsed: false, autoCollapsed: false, isExpanded: undefined, - showMedia: undefined, - statusId: undefined, + showMedia: defaultMediaVisibility(this.props.status, this.props.settings) && !(this.context?.hideMediaByDefault), revealBehindCW: undefined, showCard: false, forceFilter: undefined, @@ -211,12 +213,6 @@ class Status extends ImmutablePureComponent { updated = true; } - if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) { - update.showMedia = defaultMediaVisibility(nextProps.status, nextProps.settings); - update.statusId = nextProps.status.get('id'); - updated = true; - } - if (nextProps.settings.getIn(['media', 'reveal_behind_cw']) !== prevState.revealBehindCW) { update.revealBehindCW = nextProps.settings.getIn(['media', 'reveal_behind_cw']); if (update.revealBehindCW) { @@ -312,6 +308,18 @@ class Status extends ImmutablePureComponent { if (snapshot !== null && this.props.updateScrollBottom && this.node.offsetTop < snapshot.top) { this.props.updateScrollBottom(snapshot.height - snapshot.top); } + + // This will potentially cause a wasteful redraw, but in most cases `Status` components are used + // with a `key` directly depending on their `id`, preventing re-use of the component across + // different IDs. + // But just in case this does change, reset the state on status change. + + if (this.props.status?.get('id') !== prevProps.status?.get('id')) { + this.setState({ + showMedia: defaultMediaVisibility(this.props.status, this.props.settings) && !(this.context?.hideMediaByDefault), + forceFilter: undefined, + }); + } } componentWillUnmount() { diff --git a/app/javascript/flavours/glitch/features/notifications/request.jsx b/app/javascript/flavours/glitch/features/notifications/request.jsx index d89527f69a..4aca0af7f6 100644 --- a/app/javascript/flavours/glitch/features/notifications/request.jsx +++ b/app/javascript/flavours/glitch/features/notifications/request.jsx @@ -15,6 +15,7 @@ import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; import { IconButton } from 'flavours/glitch/components/icon_button'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { SensitiveMediaContextProvider } from 'flavours/glitch/features/ui/util/sensitive_media_context'; import NotificationContainer from './containers/notification_container'; @@ -106,25 +107,27 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => { )} /> - - {notifications.map(item => ( - item && - ))} - + + + {notifications.map(item => ( + item && + ))} + + {columnTitle} diff --git a/app/javascript/flavours/glitch/features/ui/util/sensitive_media_context.tsx b/app/javascript/flavours/glitch/features/ui/util/sensitive_media_context.tsx new file mode 100644 index 0000000000..408154c31b --- /dev/null +++ b/app/javascript/flavours/glitch/features/ui/util/sensitive_media_context.tsx @@ -0,0 +1,28 @@ +import { createContext, useContext, useMemo } from 'react'; + +export const SensitiveMediaContext = createContext<{ + hideMediaByDefault: boolean; +}>({ + hideMediaByDefault: false, +}); + +export function useSensitiveMediaContext() { + return useContext(SensitiveMediaContext); +} + +type ContextValue = React.ContextType; + +export const SensitiveMediaContextProvider: React.FC< + React.PropsWithChildren<{ hideMediaByDefault: boolean }> +> = ({ hideMediaByDefault, children }) => { + const contextValue = useMemo( + () => ({ hideMediaByDefault }), + [hideMediaByDefault], + ); + + return ( + + {children} + + ); +};