make number of displayed reactions a setting

This adds an extra item to the local settings for
specifying the number of reactions shown in toots.
The detailed status view always shows all
reactions.
This commit is contained in:
fef 2022-11-30 13:20:20 +00:00
parent f535ddc445
commit 6d2ad83c02
No known key found for this signature in database
GPG key ID: EC22E476DC2D3D84
9 changed files with 42 additions and 16 deletions

View file

@ -270,7 +270,7 @@ MAX_POLL_OPTIONS=5
MAX_POLL_OPTION_CHARS=100 MAX_POLL_OPTION_CHARS=100
# Maximum number of emoji reactions per toot and user (minimum 1) # Maximum number of emoji reactions per toot and user (minimum 1)
MAX_REACTIONS=8 MAX_REACTIONS=1
# Maximum image and video/audio upload sizes # Maximum image and video/audio upload sizes
# Units are in bytes # Units are in bytes

View file

@ -808,6 +808,7 @@ class Status extends ImmutablePureComponent {
<StatusReactions <StatusReactions
statusId={status.get('id')} statusId={status.get('id')}
reactions={status.get('reactions')} reactions={status.get('reactions')}
numVisible={settings.get('num_visible_reactions')}
addReaction={this.props.onReactionAdd} addReaction={this.props.onReactionAdd}
removeReaction={this.props.onReactionRemove} removeReaction={this.props.onReactionRemove}
emojiMap={this.props.emojiMap} emojiMap={this.props.emojiMap}

View file

@ -1,7 +1,7 @@
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { maxReactions, reduceMotion } from '../initial_state'; import { reduceMotion } from '../initial_state';
import spring from 'react-motion/lib/spring'; import spring from 'react-motion/lib/spring';
import TransitionMotion from 'react-motion/lib/TransitionMotion'; import TransitionMotion from 'react-motion/lib/TransitionMotion';
import classNames from 'classnames'; import classNames from 'classnames';
@ -16,16 +16,12 @@ export default class StatusReactions extends ImmutablePureComponent {
static propTypes = { static propTypes = {
statusId: PropTypes.string.isRequired, statusId: PropTypes.string.isRequired,
reactions: ImmutablePropTypes.list.isRequired, reactions: ImmutablePropTypes.list.isRequired,
numVisible: PropTypes.number,
addReaction: PropTypes.func.isRequired, addReaction: PropTypes.func.isRequired,
removeReaction: PropTypes.func.isRequired, removeReaction: PropTypes.func.isRequired,
emojiMap: ImmutablePropTypes.map.isRequired, emojiMap: ImmutablePropTypes.map.isRequired,
}; };
handleEmojiPick = data => {
const { addReaction, statusId } = this.props;
addReaction(statusId, data.native.replace(/:/g, ''));
}
willEnter() { willEnter() {
return { scale: reduceMotion ? 1 : 0 }; return { scale: reduceMotion ? 1 : 0 };
} }
@ -35,11 +31,18 @@ export default class StatusReactions extends ImmutablePureComponent {
} }
render() { render() {
const { reactions } = this.props; const { reactions, numVisible } = this.props;
const visibleReactions = reactions let visibleReactions = reactions
.filter(x => x.get('count') > 0) .filter(x => x.get('count') > 0)
.sort((a, b) => b.get('count') - a.get('count')) .sort((a, b) => b.get('count') - a.get('count'));
.filter((_, i) => i < maxReactions);
// numVisible might be NaN because it's pulled from local settings
// which doesn't do a whole lot of input validation, but that's okay
// because NaN >= 0 evaluates false.
// Still, this should be improved at some point.
if (numVisible >= 0) {
visibleReactions = visibleReactions.filter((_, i) => i < numVisible);
}
const styles = visibleReactions.map(reaction => ({ const styles = visibleReactions.map(reaction => ({
key: reaction.get('name'), key: reaction.get('name'),

View file

@ -29,6 +29,8 @@ const messages = defineMessages({
rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage: 'Rewrite with username' }, rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage: 'Rewrite with username' },
pop_in_left: { id: 'settings.pop_in_left', defaultMessage: 'Left' }, pop_in_left: { id: 'settings.pop_in_left', defaultMessage: 'Left' },
pop_in_right: { id: 'settings.pop_in_right', defaultMessage: 'Right' }, pop_in_right: { id: 'settings.pop_in_right', defaultMessage: 'Right' },
visible_reactions_count: { id: 'settings.visible_reactions_count', defaultMessage: 'Number of visible reactions' },
enter_amount_prompt: { id: 'settings.enter_amount_prompt', defaultMessage: 'Enter an amount' },
}); });
export default @injectIntl export default @injectIntl
@ -92,6 +94,16 @@ class LocalSettingsPage extends React.PureComponent {
> >
<FormattedMessage id='settings.rewrite_mentions' defaultMessage='Rewrite mentions in displayed statuses' /> <FormattedMessage id='settings.rewrite_mentions' defaultMessage='Rewrite mentions in displayed statuses' />
</LocalSettingsPageItem> </LocalSettingsPageItem>
<LocalSettingsPageItem
settings={settings}
item={['num_visible_reactions']}
id='mastodon-settings--num_visible_reactions'
onChange={onChange}
placeholder={intl.formatMessage(messages.enter_amount_prompt)}
number
>
<FormattedMessage id='settings.num_visible_reactions' defaultMessage='Number of visible reaction badges:' />
</LocalSettingsPageItem>
<section> <section>
<h2><FormattedMessage id='settings.notifications_opts' defaultMessage='Notifications options' /></h2> <h2><FormattedMessage id='settings.notifications_opts' defaultMessage='Notifications options' /></h2>
<LocalSettingsPageItem <LocalSettingsPageItem

View file

@ -21,20 +21,21 @@ export default class LocalSettingsPageItem extends React.PureComponent {
})), })),
settings: ImmutablePropTypes.map.isRequired, settings: ImmutablePropTypes.map.isRequired,
placeholder: PropTypes.string, placeholder: PropTypes.string,
number: PropTypes.bool,
disabled: PropTypes.bool, disabled: PropTypes.bool,
}; };
handleChange = e => { handleChange = e => {
const { target } = e; const { target } = e;
const { item, onChange, options, placeholder } = this.props; const { item, onChange, options, placeholder, number } = this.props;
if (options && options.length > 0) onChange(item, target.value); if (options && options.length > 0) onChange(item, target.value);
else if (placeholder) onChange(item, target.value); else if (placeholder) onChange(item, number ? parseInt(target.value) : target.value);
else onChange(item, target.checked); else onChange(item, target.checked);
} }
render () { render () {
const { handleChange } = this; const { handleChange } = this;
const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, disabled } = this.props; const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, number, disabled } = this.props;
let enabled = !disabled; let enabled = !disabled;
if (dependsOn) { if (dependsOn) {
@ -76,7 +77,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
</fieldset> </fieldset>
</div> </div>
); );
} else if (placeholder) { } else if (placeholder || number) {
return ( return (
<div className='glitch local-settings__page__item string'> <div className='glitch local-settings__page__item string'>
<label htmlFor={id}> <label htmlFor={id}>
@ -84,7 +85,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
<p> <p>
<input <input
id={id} id={id}
type='text' type={number ? 'number' : 'text'}
value={settings.getIn(item)} value={settings.getIn(item)}
placeholder={placeholder} placeholder={placeholder}
onChange={handleChange} onChange={handleChange}

View file

@ -6,6 +6,9 @@ const messages = {
'tooltips.reactions': 'Reaktionen', 'tooltips.reactions': 'Reaktionen',
'settings.enter_amount_prompt': 'Gib eine Zahl ein',
'settings.num_visible_reactions': 'Anzahl sichtbarer Reaktionen',
'status.react': 'Reagieren', 'status.react': 'Reagieren',
}; };

View file

@ -22,6 +22,7 @@ const messages = {
'settings.close': 'Close', 'settings.close': 'Close',
'settings.collapsed_statuses': 'Collapsed toots', 'settings.collapsed_statuses': 'Collapsed toots',
'settings.enable_collapsed': 'Enable collapsed toots', 'settings.enable_collapsed': 'Enable collapsed toots',
'settings.enter_amount_prompt': 'Enter an amount',
'settings.general': 'General', 'settings.general': 'General',
'settings.image_backgrounds': 'Image backgrounds', 'settings.image_backgrounds': 'Image backgrounds',
'settings.image_backgrounds_media': 'Preview collapsed toot media', 'settings.image_backgrounds_media': 'Preview collapsed toot media',
@ -29,6 +30,7 @@ const messages = {
'settings.media': 'Media', 'settings.media': 'Media',
'settings.media_letterbox': 'Letterbox media', 'settings.media_letterbox': 'Letterbox media',
'settings.media_fullwidth': 'Full-width media previews', 'settings.media_fullwidth': 'Full-width media previews',
'settings.num_visible_reactions': 'Number of visible reactions',
'settings.preferences': 'User preferences', 'settings.preferences': 'User preferences',
'settings.wide_view': 'Wide view (Desktop mode only)', 'settings.wide_view': 'Wide view (Desktop mode only)',
'settings.navbar_under': 'Navbar at the bottom (Mobile only)', 'settings.navbar_under': 'Navbar at the bottom (Mobile only)',

View file

@ -6,6 +6,9 @@ const messages = {
'tooltips.reactions': 'Réactions', 'tooltips.reactions': 'Réactions',
'settings.enter_amount_prompt': 'Entrez un montant',
'settings.num_visible_reactions': 'Nombre de réactions visibles',
'status.react': 'Réagir', 'status.react': 'Réagir',
}; };

View file

@ -23,6 +23,7 @@ const initialState = ImmutableMap({
show_content_type_choice: false, show_content_type_choice: false,
tag_misleading_links: true, tag_misleading_links: true,
rewrite_mentions: 'no', rewrite_mentions: 'no',
num_visible_reactions: 6,
content_warnings : ImmutableMap({ content_warnings : ImmutableMap({
filter : null, filter : null,
media_outside: false, media_outside: false,