Add secondary post button back

main-rebase-security-fix
Claire 2024-02-23 00:26:54 +01:00
parent 61559a42a9
commit 118bb5bc81
5 changed files with 97 additions and 8 deletions

View File

@ -179,7 +179,7 @@ export function directCompose(account, routerHistory) {
}; };
} }
export function submitCompose(routerHistory) { export function submitCompose(routerHistory, overridePrivacy = null) {
return function (dispatch, getState) { return function (dispatch, getState) {
let status = getState().getIn(['compose', 'text'], ''); let status = getState().getIn(['compose', 'text'], '');
const media = getState().getIn(['compose', 'media_attachments']); const media = getState().getIn(['compose', 'media_attachments']);
@ -228,7 +228,7 @@ export function submitCompose(routerHistory) {
media_attributes, media_attributes,
sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0), sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0),
spoiler_text: spoilerText, spoiler_text: spoilerText,
visibility: getState().getIn(['compose', 'privacy']), visibility: overridePrivacy || getState().getIn(['compose', 'privacy']),
poll: getState().getIn(['compose', 'poll'], null), poll: getState().getIn(['compose', 'poll'], null),
language: getState().getIn(['compose', 'language']), language: getState().getIn(['compose', 'language']),
}, },

View File

@ -31,6 +31,7 @@ import { EditIndicator } from './edit_indicator';
import { NavigationBar } from './navigation_bar'; import { NavigationBar } from './navigation_bar';
import { PollForm } from "./poll_form"; import { PollForm } from "./poll_form";
import { ReplyIndicator } from './reply_indicator'; import { ReplyIndicator } from './reply_indicator';
import { SecondaryPrivacyButton } from './secondary_privacy_button';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d'; const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
@ -50,6 +51,7 @@ class ComposeForm extends ImmutablePureComponent {
spoiler: PropTypes.bool, spoiler: PropTypes.bool,
spoilerAlwaysOn: PropTypes.bool, spoilerAlwaysOn: PropTypes.bool,
privacy: PropTypes.string, privacy: PropTypes.string,
sideArm: PropTypes.string,
spoilerText: PropTypes.string, spoilerText: PropTypes.string,
focusDate: PropTypes.instanceOf(Date), focusDate: PropTypes.instanceOf(Date),
caretPosition: PropTypes.number, caretPosition: PropTypes.number,
@ -96,6 +98,10 @@ class ComposeForm extends ImmutablePureComponent {
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
this.handleSubmit(); this.handleSubmit();
} }
if (e.keyCode === 13 && e.altKey) {
this.handleSecondarySubmit();
}
}; };
getFulltextForCharacterCounting = () => { getFulltextForCharacterCounting = () => {
@ -110,7 +116,7 @@ class ComposeForm extends ImmutablePureComponent {
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxChars || (isOnlyWhitespace && !anyMedia)); return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxChars || (isOnlyWhitespace && !anyMedia));
}; };
handleSubmit = (e) => { handleSubmit = (e, overridePrivacy = null) => {
if (this.props.text !== this.textareaRef.current.value) { if (this.props.text !== this.textareaRef.current.value) {
// Something changed the text inside the textarea (e.g. browser extensions like Grammarly) // Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
// Update the state to match the current text // Update the state to match the current text
@ -121,13 +127,18 @@ class ComposeForm extends ImmutablePureComponent {
return; return;
} }
this.props.onSubmit(this.props.history || null); this.props.onSubmit(this.props.history || null, overridePrivacy);
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
}; };
handleSecondarySubmit = () => {
const { sideArm } = this.props;
this.handleSubmit(null, sideArm === 'none' ? null : sideArm);
};
onSuggestionsClearRequested = () => { onSuggestionsClearRequested = () => {
this.props.onClearSuggestions(); this.props.onClearSuggestions();
}; };
@ -303,6 +314,12 @@ class ComposeForm extends ImmutablePureComponent {
</div> </div>
<div className='compose-form__submit'> <div className='compose-form__submit'>
<SecondaryPrivacyButton
disabled={!this.canSubmit()}
privacy={this.props.sideArm}
isEditing={this.props.isEditing}
onClick={this.handleSecondarySubmit}
/>
<Button <Button
type='submit' type='submit'
text={intl.formatMessage(this.props.isEditing ? messages.saveChanges : (this.props.isInReply ? messages.reply : messages.publish))} text={intl.formatMessage(this.props.isEditing ? messages.saveChanges : (this.props.isInReply ? messages.reply : messages.publish))}

View File

@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import { useIntl, defineMessages } from 'react-intl';
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
import MailIcon from '@/material-icons/400-24px/mail.svg?react';
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
import { Button } from 'flavours/glitch/components/button';
import { Icon } from 'flavours/glitch/components/icon';
const messages = defineMessages({
public: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted: { id: 'privacy.unlisted.short', defaultMessage: 'Quiet public' },
private: { id: 'privacy.private.short', defaultMessage: 'Followers' },
direct: { id: 'privacy.direct.short', defaultMessage: 'Specific people' },
});
export const SecondaryPrivacyButton = ({ disabled, privacy, isEditing, onClick }) => {
const intl = useIntl();
if (isEditing || !privacy || privacy === 'none') {
return null;
}
const privacyProps = {
direct: { icon: 'envelope', iconComponent: MailIcon, title: messages.direct },
private: { icon: 'lock', iconComponent: LockIcon, title: messages.private },
public: { icon: 'globe', iconComponent: PublicIcon, title: messages.public },
unlisted: { icon: 'unlock', iconComponent: QuietTimeIcon, title: messages.unlisted },
};
return (
<Button className='secondary-post-button' disabled={disabled} onClick={onClick} title={intl.formatMessage(privacyProps[privacy].title)}>
<Icon id={privacyProps[privacy].id} icon={privacyProps[privacy].iconComponent} />
</Button>
);
};
SecondaryPrivacyButton.propTypes = {
disabled: PropTypes.bool,
privacy: PropTypes.string,
isEditing: PropTypes.bool,
onClick: PropTypes.func.isRequired,
};

View File

@ -1,5 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { privacyPreference } from 'flavours/glitch/utils/privacy_preference';
import { import {
changeCompose, changeCompose,
submitCompose, submitCompose,
@ -12,6 +14,23 @@ import {
} from '../../../actions/compose'; } from '../../../actions/compose';
import ComposeForm from '../components/compose_form'; import ComposeForm from '../components/compose_form';
const sideArmPrivacy = state => {
const inReplyTo = state.getIn(['compose', 'in_reply_to']);
const replyPrivacy = inReplyTo ? state.getIn(['statuses', inReplyTo, 'visibility']) : null;
const sideArmBasePrivacy = state.getIn(['local_settings', 'side_arm']);
const sideArmRestrictedPrivacy = replyPrivacy ? privacyPreference(replyPrivacy, sideArmBasePrivacy) : null;
let sideArmPrivacy = null;
switch (state.getIn(['local_settings', 'side_arm_reply_mode'])) {
case 'copy':
sideArmPrivacy = replyPrivacy;
break;
case 'restrict':
sideArmPrivacy = sideArmRestrictedPrivacy;
break;
}
return sideArmPrivacy || sideArmBasePrivacy;
};
const mapStateToProps = state => ({ const mapStateToProps = state => ({
text: state.getIn(['compose', 'text']), text: state.getIn(['compose', 'text']),
suggestions: state.getIn(['compose', 'suggestions']), suggestions: state.getIn(['compose', 'suggestions']),
@ -29,6 +48,7 @@ const mapStateToProps = state => ({
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
isInReply: state.getIn(['compose', 'in_reply_to']) !== null, isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
lang: state.getIn(['compose', 'language']), lang: state.getIn(['compose', 'language']),
sideArm: sideArmPrivacy(state),
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
@ -37,8 +57,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(changeCompose(text)); dispatch(changeCompose(text));
}, },
onSubmit (router) { onSubmit (router, overridePrivacy = null) {
dispatch(submitCompose(router)); dispatch(submitCompose(router, overridePrivacy));
}, },
onClearSuggestions () { onClearSuggestions () {

View File

@ -750,10 +750,17 @@ body > [data-popper-placement] {
&__submit { &__submit {
display: flex; display: flex;
align-items: center; flex: 1 0 100%; // glitch: always on its own line
flex: 1 1 auto;
max-width: 100%; max-width: 100%;
overflow: hidden; overflow: hidden;
gap: 5px; // glitch: handle secondary post privacy
align-items: stretch; // glitch: handle secondary post privacy
.button.secondary-post-button {
flex: 0 1 auto;
padding-top: 0;
padding-bottom: 0;
}
} }
&__buttons { &__buttons {