Skip to content

Commit

Permalink
[Glitch] Add reminder when about to post without alt text in web UI
Browse files Browse the repository at this point in the history
Port 1e70da5 to glitch-soc

Signed-off-by: Claire <[email protected]>
  • Loading branch information
Gargron authored and ClearlyClaire committed Feb 1, 2025
1 parent 800bea7 commit 668355a
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 75 deletions.
3 changes: 3 additions & 0 deletions app/javascript/flavours/glitch/actions/compose.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ export function directCompose(account) {
};
}

/**
* @param {null | string} overridePrivacy
*/
export function submitCompose(overridePrivacy = null) {
return function (dispatch, getState) {
let status = getState().getIn(['compose', 'text'], '');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';

import { length } from 'stringz';

import { missingAltTextModal } from 'flavours/glitch/initial_state';

import AutosuggestInput from '../../../components/autosuggest_input';
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import { Button } from '../../../components/button';
Expand Down Expand Up @@ -72,9 +74,8 @@ class ComposeForm extends ImmutablePureComponent {
autoFocus: PropTypes.bool,
withoutNavigation: PropTypes.bool,
anyMedia: PropTypes.bool,
missingAltText: PropTypes.bool,
media: ImmutablePropTypes.list,
mediaDescriptionConfirmation: PropTypes.bool,
onMediaDescriptionConfirm: PropTypes.func.isRequired,
isInReply: PropTypes.bool,
singleColumn: PropTypes.bool,
lang: PropTypes.string,
Expand Down Expand Up @@ -131,17 +132,11 @@ class ComposeForm extends ImmutablePureComponent {
return;
}

this.props.onSubmit(missingAltTextModal && this.props.missingAltText, overridePrivacy);

if (e) {
e.preventDefault();
}

// Submit unless there are media with missing descriptions
if (this.props.mediaDescriptionConfirmation && this.props.media && this.props.media.some(item => !item.get('description'))) {
const firstWithoutDescription = this.props.media.find(item => !item.get('description'));
this.props.onMediaDescriptionConfirm(firstWithoutDescription.get('id'), overridePrivacy);
} else {
this.props.onSubmit(overridePrivacy);
}
};

handleSecondarySubmit = (e) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { defineMessages, injectIntl } from 'react-intl';
import { injectIntl } from 'react-intl';

import { connect } from 'react-redux';

import { privacyPreference } from 'flavours/glitch/utils/privacy_preference';

Check failure on line 5 in app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js

View workflow job for this annotation

GitHub Actions / lint

`flavours/glitch/utils/privacy_preference` import should occur after import of `flavours/glitch/actions/modal`

import {
changeCompose,
submitCompose,
Expand All @@ -13,27 +12,10 @@ import {
changeComposeSpoilerText,
insertEmojiCompose,
uploadCompose,
} from '../../../actions/compose';
import { changeLocalSetting } from '../../../actions/local_settings';
import {
openModal,
} from '../../../actions/modal';
import ComposeForm from '../components/compose_form';
} from 'flavours/glitch/actions/compose';
import { openModal } from 'flavours/glitch/actions/modal';

const messages = defineMessages({
missingDescriptionMessage: {
id: 'confirmations.missing_media_description.message',
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.',
},
missingDescriptionConfirm: {
id: 'confirmations.missing_media_description.confirm',
defaultMessage: 'Send anyway',
},
missingDescriptionEdit: {
id: 'confirmations.missing_media_description.edit',
defaultMessage: 'Edit media',
},
});
import ComposeForm from '../components/compose_form';

const sideArmPrivacy = state => {
const inReplyTo = state.getIn(['compose', 'in_reply_to']);
Expand Down Expand Up @@ -68,22 +50,30 @@ const mapStateToProps = state => ({
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
isUploading: state.getIn(['compose', 'is_uploading']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
missingAltText: state.getIn(['compose', 'media_attachments']).some(media => ['image', 'gifv'].includes(media.get('type')) && (media.get('description') ?? '').length === 0),
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
lang: state.getIn(['compose', 'language']),
sideArm: sideArmPrivacy(state),
media: state.getIn(['compose', 'media_attachments']),
mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']),
maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500),
});

const mapDispatchToProps = (dispatch, { intl }) => ({
const mapDispatchToProps = (dispatch) => ({

onChange (text) {
dispatch(changeCompose(text));
},

onSubmit (overridePrivacy = null) {
onSubmit (missingAltText, overridePrivacy = null) {
dispatch(submitCompose(overridePrivacy));
if (missingAltText) {
dispatch(openModal({
modalType: 'CONFIRM_MISSING_ALT_TEXT',
modalProps: { overridePrivacy },
}));
} else {
dispatch(submitCompose(overridePrivacy));
}
},

onClearSuggestions () {
Expand All @@ -110,25 +100,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
dispatch(insertEmojiCompose(position, data, needsSpace));
},

onMediaDescriptionConfirm (mediaId, overridePrivacy = null) {
dispatch(openModal({
modalType: 'CONFIRM',
modalProps: {
message: intl.formatMessage(messages.missingDescriptionMessage),
confirm: intl.formatMessage(messages.missingDescriptionConfirm),
onConfirm: () => {
dispatch(submitCompose(overridePrivacy));
},
secondary: intl.formatMessage(messages.missingDescriptionEdit),
onSecondary: () => dispatch(openModal({
modalType: 'FOCAL_POINT',
modalProps: { id: mediaId },
})),
onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)),
},
}));
},

});

export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ComposeForm));
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,6 @@ class LocalSettingsPage extends PureComponent {
<FormattedMessage id='settings.preselect_on_reply' defaultMessage='Pre-select usernames on reply' />
<span className='hint'><FormattedMessage id='settings.preselect_on_reply_hint' defaultMessage='When replying to a conversation with multiple participants, pre-select usernames past the first' /></span>
</LocalSettingsPageItem>
<LocalSettingsPageItem
settings={settings}
item={['confirm_missing_media_description']}
id='mastodon-settings--confirm_missing_media_description'
onChange={onChange}
>
<FormattedMessage id='settings.confirm_missing_media_description' defaultMessage='Show confirmation dialog before sending toots lacking media descriptions' />
</LocalSettingsPageItem>
<LocalSettingsPageItem
settings={settings}
item={['confirm_before_clearing_draft']}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,22 @@ export const ConfirmationModal: React.FC<

<div className='safety-action-modal__bottom'>
<div className='safety-action-modal__actions'>
{secondary && (
<>
<Button onClick={handleSecondary}>{secondary}</Button>

<div className='spacer' />
</>
)}

<button onClick={handleCancel} className='link-button'>
<FormattedMessage
id='confirmation_modal.cancel'
defaultMessage='Cancel'
/>
</button>

{secondary && (
<>
<div className='spacer' />
<button onClick={handleSecondary} className='link-button'>
{secondary}
</button>
</>
)}

{/* eslint-disable-next-line jsx-a11y/no-autofocus -- we are in a modal and thus autofocusing is justified */}
<Button onClick={handleClick} autoFocus>
{confirm}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { ConfirmUnfollowModal } from './unfollow';
export { ConfirmClearNotificationsModal } from './clear_notifications';
export { ConfirmLogOutModal } from './log_out';
export { ConfirmFollowToListModal } from './follow_to_list';
export { ConfirmMissingAltTextModal } from './missing_alt_text';
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useCallback } from 'react';

import { defineMessages, useIntl } from 'react-intl';

import type { Map as ImmutableMap, List as ImmutableList } from 'immutable';

import { submitCompose } from 'flavours/glitch/actions/compose';
import { openModal } from 'flavours/glitch/actions/modal';
import type { MediaAttachment } from 'flavours/glitch/models/media_attachment';
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';

import type { BaseConfirmationModalProps } from './confirmation_modal';
import { ConfirmationModal } from './confirmation_modal';

const messages = defineMessages({
title: {
id: 'confirmations.missing_alt_text.title',
defaultMessage: 'Add alt text?',
},
confirm: {
id: 'confirmations.missing_alt_text.confirm',
defaultMessage: 'Add alt text',
},
message: {
id: 'confirmations.missing_alt_text.message',
defaultMessage:
'Your post contains media without alt text. Adding descriptions helps make your content accessible to more people.',
},
secondary: {
id: 'confirmations.missing_alt_text.secondary',
defaultMessage: 'Post anyway',
},
});

export const ConfirmMissingAltTextModal: React.FC<
{
overridePrivacy: null | string;
} & BaseConfirmationModalProps
> = ({ onClose, overridePrivacy }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const mediaId = useAppSelector(
(state) =>
(
(state.compose as ImmutableMap<string, unknown>).get(
'media_attachments',
) as ImmutableList<MediaAttachment>
)
.find(
(media) =>
['image', 'gifv'].includes(media.get('type') as string) &&
((media.get('description') ?? '') as string).length === 0,
)
?.get('id') as string,
);

const handleConfirm = useCallback(() => {
dispatch(
openModal({
modalType: 'FOCAL_POINT',
modalProps: {
mediaId,
},
}),
);
}, [dispatch, mediaId]);

const handleSecondary = useCallback(() => {
dispatch(submitCompose(overridePrivacy));
}, [dispatch, overridePrivacy]);

return (
<ConfirmationModal
title={intl.formatMessage(messages.title)}
message={intl.formatMessage(messages.message)}
confirm={intl.formatMessage(messages.confirm)}
secondary={intl.formatMessage(messages.secondary)}
onConfirm={handleConfirm}
onSecondary={handleSecondary}
onClose={onClose}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
ConfirmClearNotificationsModal,
ConfirmLogOutModal,
ConfirmFollowToListModal,
ConfirmMissingAltTextModal,
} from './confirmation_modals';
import DeprecatedSettingsModal from './deprecated_settings_modal';
import DoodleModal from './doodle_modal';
Expand All @@ -64,6 +65,7 @@ export const MODAL_COMPONENTS = {
'CONFIRM_CLEAR_NOTIFICATIONS': () => Promise.resolve({ default: ConfirmClearNotificationsModal }),
'CONFIRM_LOG_OUT': () => Promise.resolve({ default: ConfirmLogOutModal }),
'CONFIRM_FOLLOW_TO_LIST': () => Promise.resolve({ default: ConfirmFollowToListModal }),
'CONFIRM_MISSING_ALT_TEXT': () => Promise.resolve({ default: ConfirmMissingAltTextModal }),
'MUTE': MuteModal,
'BLOCK': BlockModal,
'DOMAIN_BLOCK': DomainBlockModal,
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/flavours/glitch/initial_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @property {boolean=} favourite_modal
* @property {boolean} crop_images
* @property {boolean=} delete_modal
* @property {boolean=} missing_alt_text_modal
* @property {boolean=} disable_swiping
* @property {boolean=} disable_hover_cards
* @property {string=} disabled_account_id
Expand Down Expand Up @@ -107,6 +108,7 @@ export const autoPlayGif = getMeta('auto_play_gif');
export const boostModal = getMeta('boost_modal');
export const cropImages = getMeta('crop_images');
export const deleteModal = getMeta('delete_modal');
export const missingAltTextModal = getMeta('missing_alt_text_modal');
export const disableSwiping = getMeta('disable_swiping');
export const disableHoverCards = getMeta('disable_hover_cards');
export const disabledAccountId = getMeta('disabled_account_id');
Expand Down
4 changes: 0 additions & 4 deletions app/javascript/flavours/glitch/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@
"confirmation_modal.do_not_ask_again": "Do not ask for confirmation again",
"confirmations.deprecated_settings.confirm": "Use Mastodon preferences",
"confirmations.deprecated_settings.message": "Some of the glitch-soc device-specific {app_settings} you are using have been replaced by Mastodon {preferences} and will be overriden:",
"confirmations.missing_media_description.confirm": "Send anyway",
"confirmations.missing_media_description.edit": "Edit media",
"confirmations.missing_media_description.message": "At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.",
"direct.group_by_conversations": "Group by conversation",
"favourite_modal.favourite": "Favourite post?",
"federation.federated.long": "Allow this post to reach other servers",
Expand All @@ -57,7 +54,6 @@
"settings.compose_box_opts": "Compose box",
"settings.confirm_before_clearing_draft": "Show confirmation dialog before overwriting the message being composed",
"settings.confirm_boost_missing_media_description": "Show confirmation dialog before boosting toots lacking media descriptions",
"settings.confirm_missing_media_description": "Show confirmation dialog before sending toots lacking media descriptions",
"settings.content_warnings": "Content Warnings",
"settings.content_warnings.regexp": "Regular expression",
"settings.content_warnings_filter": "Content warnings to not automatically unfold:",
Expand Down
1 change: 0 additions & 1 deletion app/javascript/flavours/glitch/reducers/local_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const initialState = ImmutableMap({
side_arm_reply_mode : 'keep',
show_reply_count : false,
always_show_spoilers_field: false,
confirm_missing_media_description: false,
confirm_boost_missing_media_description: false,
confirm_before_clearing_draft: true,
prepend_cw_re: true,
Expand Down

0 comments on commit 668355a

Please sign in to comment.