Add the ability to compact the display of Emoji reactions

This commit is contained in:
noellabo 2022-06-01 22:43:20 +09:00
parent 0b857ad422
commit a89569c3a8
14 changed files with 41 additions and 10 deletions

View file

@ -72,6 +72,7 @@ class Settings::PreferencesController < Settings::BaseController
:setting_show_target,
:setting_enable_limited_timeline,
:setting_enable_reaction,
:setting_compact_reaction,
:setting_show_reply_tree_button,
:setting_hide_statuses_count,
:setting_hide_following_count,

View file

@ -316,6 +316,7 @@ export default class ReactionPickerDropdown extends React.PureComponent {
onClose: PropTypes.func.isRequired,
skinTone: PropTypes.number.isRequired,
frequentlyUsedEmojis: PropTypes.arrayOf(PropTypes.string),
counter: PropTypes.number,
};
static defaultProps = {
@ -387,7 +388,7 @@ export default class ReactionPickerDropdown extends React.PureComponent {
}
render () {
const { icon, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard, active, pressed, iconButtonClass } = this.props;
const { icon, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard, active, pressed, iconButtonClass, counter } = this.props;
const { custom_emojis, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis } = this.props;
const open = this.state.id === openDropdownId;
@ -406,6 +407,7 @@ export default class ReactionPickerDropdown extends React.PureComponent {
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
onKeyPress={this.handleKeyPress}
counter={counter}
/>
<Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>

View file

@ -19,7 +19,7 @@ import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import EmojiReactionsBar from 'mastodon/components/emoji_reactions_bar';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { displayMedia, enableReaction, show_reply_tree_button, enableStatusReference } from 'mastodon/initial_state';
import { displayMedia, enableReaction, compactReaction, show_reply_tree_button, enableStatusReference } from 'mastodon/initial_state';
import { List as ImmutableList } from 'immutable';
// We use the component (and not the container) since we do not want
@ -766,7 +766,7 @@ class Status extends ImmutablePureComponent {
{quote}
{media}
{enableReaction && <EmojiReactionsBar
{enableReaction && (contextType == 'thread' || !compactReaction) && <EmojiReactionsBar
status={status}
addEmojiReaction={this.props.addEmojiReaction}
removeEmojiReaction={this.props.removeEmojiReaction}

View file

@ -6,7 +6,7 @@ import IconButton from './icon_button';
import DropdownMenuContainer from '../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, isStaff, show_bookmark_button, show_quote_button, enableReaction, enableStatusReference, maxReferences, matchVisibilityOfReferences, addReferenceModal } from '../initial_state';
import { me, isStaff, show_bookmark_button, show_quote_button, enableReaction, compactReaction, enableStatusReference, maxReferences, matchVisibilityOfReferences, addReferenceModal } from '../initial_state';
import classNames from 'classnames';
import { openModal } from '../actions/modal';
@ -84,6 +84,7 @@ class StatusActionBar extends ImmutablePureComponent {
referenceCountLimit: PropTypes.bool,
selected: PropTypes.bool,
composePrivacy: PropTypes.string,
contextType: PropTypes.string,
onReply: PropTypes.func,
onFavourite: PropTypes.func,
onReblog: PropTypes.func,
@ -326,7 +327,7 @@ class StatusActionBar extends ImmutablePureComponent {
}
render () {
const { status, relationship, intl, withDismiss, scrollKey, expired, referenced, contextReferenced, referenceCountLimit } = this.props;
const { status, relationship, intl, withDismiss, scrollKey, expired, referenced, contextReferenced, referenceCountLimit, contextType } = this.props;
const anonymousAccess = !me;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
@ -469,6 +470,8 @@ class StatusActionBar extends ImmutablePureComponent {
const referenceDisabled = expired || !referenced && referenceCountLimit || ['limited', 'direct'].includes(status.get('visibility'));
const reactionsCounter = compactReaction && contextType != 'thread' && status.get('emoji_reactions_count') > 0 ? status.get('emoji_reactions_count') : undefined;
return (
<div className='status__action-bar'>
<IconButton className='status__action-bar-button' disabled={expired} title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount />
@ -479,7 +482,7 @@ class StatusActionBar extends ImmutablePureComponent {
{shareButton}
{show_bookmark_button && <IconButton className='status__action-bar-button bookmark-icon' disabled={!bookmarked && expired} active={bookmarked} pressed={bookmarked} title={intl.formatMessage(bookmarked ? messages.removeBookmark : messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />}
{enableReaction && <div className='status__action-bar-dropdown'>
{enableReaction && <div className={classNames('status__action-bar-dropdown', {'icon-button--with-counter': reactionsCounter})}>
<ReactionPickerDropdownContainer
scrollKey={scrollKey}
disabled={expired}
@ -492,6 +495,7 @@ class StatusActionBar extends ImmutablePureComponent {
icon='smile-o'
size={18}
direction='right'
counter={reactionsCounter}
onPickEmoji={this.handleEmojiPick}
onRemoveEmoji={this.handleEmojiRemove}
/>

View file

@ -43,6 +43,7 @@ export const place_tab_bar_at_bottom = getMeta('place_tab_bar_at_bottom');
export const show_tab_bar_label = getMeta('show_tab_bar_label');
export const enable_limited_timeline = getMeta('enable_limited_timeline');
export const enableReaction = getMeta('enable_reaction');
export const compactReaction = getMeta('compact_reaction');
export const show_reply_tree_button = getMeta('show_reply_tree_button');
export const disable_joke_appearance = getMeta('disable_joke_appearance');
export const new_features_policy = getMeta('new_features_policy');

View file

@ -69,6 +69,7 @@ class UserSettingsDecorator
user.settings['show_tab_bar_label'] = show_tab_bar_label_preference if change?('setting_show_tab_bar_label')
user.settings['enable_limited_timeline'] = enable_limited_timeline_preference if change?('setting_enable_limited_timeline')
user.settings['enable_reaction'] = enable_reaction_preference if change?('setting_enable_reaction')
user.settings['compact_reaction'] = compact_reaction_preference if change?('setting_compact_reaction')
user.settings['show_reply_tree_button'] = show_reply_tree_button_preference if change?('setting_show_reply_tree_button')
user.settings['hide_statuses_count'] = hide_statuses_count_preference if change?('setting_hide_statuses_count')
user.settings['hide_following_count'] = hide_following_count_preference if change?('setting_hide_following_count')
@ -242,6 +243,10 @@ end
boolean_cast_setting 'setting_enable_reaction'
end
def compact_reaction_preference
boolean_cast_setting 'setting_compact_reaction'
end
def show_reply_tree_button_preference
boolean_cast_setting 'setting_show_reply_tree_button'
end

View file

@ -129,7 +129,7 @@ class User < ApplicationRecord
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
:follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button,
:place_tab_bar_at_bottom,:show_tab_bar_label, :enable_limited_timeline, :enable_reaction,
:place_tab_bar_at_bottom,:show_tab_bar_label, :enable_limited_timeline, :enable_reaction, :compact_reaction,
:show_reply_tree_button,
:hide_statuses_count, :hide_following_count, :hide_followers_count, :disable_joke_appearance,
:new_features_policy,

View file

@ -54,6 +54,7 @@ class InitialStateSerializer < ActiveModel::Serializer
store[:show_tab_bar_label] = object.current_account.user.setting_show_tab_bar_label
store[:enable_limited_timeline] = object.current_account.user.setting_enable_limited_timeline
store[:enable_reaction] = object.current_account.user.setting_enable_reaction
store[:compact_reaction] = object.current_account.user.setting_compact_reaction
store[:show_reply_tree_button] = object.current_account.user.setting_show_reply_tree_button
store[:disable_joke_appearance] = object.current_account.user.setting_disable_joke_appearance
store[:new_features_policy] = object.current_account.user.setting_new_features_policy

View file

@ -79,6 +79,9 @@
.fields-group
= f.input :setting_enable_reaction, as: :boolean, wrapper: :with_label, fedibird_features: true
.fields-group
= f.input :setting_compact_reaction, as: :boolean, wrapper: :with_label, fedibird_features: true
.fields-group
= f.input :setting_show_reply_tree_button, as: :boolean, wrapper: :with_label, fedibird_features: true

View file

@ -1,3 +1,7 @@
:ruby
enable_reaction = current_account.nil? || current_account&.user&.setting_enable_reaction
compact_reaction = !current_account.nil? && current_account&.user&.setting_compact_reaction
.detailed-status.detailed-status--flex{ class: "detailed-status-#{status.visibility}" }
.p-author.h-card
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
@ -38,7 +42,7 @@
- elsif status.preview_card
= render_card_component(status)
- if status.emoji_reaction?
- if enable_reaction && status.emoji_reaction?
.reactions-bar.emoji-reactions-bar
= render partial: 'statuses/reaction_item', collection: status.grouped_emoji_reactions(current_account), as: :reaction_item

View file

@ -4,7 +4,8 @@
has_ancestor = has_reference || !hide_show_thread && (current_account.nil? || current_account&.user&.setting_show_reply_tree_button) && status.reply?
has_descendant = !hide_show_thread && (current_account.nil? || current_account&.user&.setting_show_reply_tree_button) && status.replies_count > 0
thread_mark_type = (has_ancestor && has_descendant) ? 'both' : (has_ancestor ? 'ancestor' : (has_descendant ? 'descendant' : ''))
enable_reaction = current_account.nil? || current_account&.user&.setting_enable_reaction
compact_reaction = !hide_show_thread && !current_account.nil? && current_account&.user&.setting_compact_reaction
.status{ class: "status-#{status.visibility}" }
.status__info
@ -58,7 +59,7 @@
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__content__read-more-button', target: stream_link_target, rel: 'noopener noreferrer' do
= t 'statuses.show_thread'
- if status.emoji_reaction?
- if enable_reaction && !compact_reaction && status.emoji_reaction?
.reactions-bar.emoji-reactions-bar
= render partial: 'statuses/reaction_item', collection: status.grouped_emoji_reactions(current_account), as: :reaction_item
@ -78,3 +79,7 @@
= fa_icon 'envelope fw'
= link_to remote_interaction_path(status, type: :favourite), class: 'status__action-bar-button icon-button modal-button' do
= fa_icon 'star fw'
- if enable_reaction && compact_reaction && status.emoji_reaction?
.status__action-bar-button.icon-button.icon-button--with-counter.disabled
= fa_icon 'smile-o'
%span.icon-button__counter= obscured_counter status.emoji_reactions_count

View file

@ -54,6 +54,7 @@ en:
phrase: Will be matched regardless of casing in text or content warning of a post
scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones.
setting_aggregate_reblogs: Do not show new boosts for posts that have been recently boosted (only affects newly-received boosts)
setting_compact_reaction: Emoji reaction display to be only the number of cases, except for the detail display
setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click
setting_disable_joke_appearance: Disable April Fools' Day and other joke functions
setting_display_media_default: Hide media marked as sensitive
@ -206,6 +207,7 @@ en:
setting_aggregate_reblogs: Group boosts in timelines
setting_auto_play_gif: Auto-play animated GIFs
setting_boost_modal: Show confirmation dialog before boosting
setting_compact_reaction: Compact display of reaction
setting_crop_images: Crop images in non-expanded posts to 16x9
setting_default_language: Posting language
setting_default_privacy: Posting privacy

View file

@ -54,6 +54,7 @@ ja:
phrase: 投稿内容の大文字小文字や閲覧注意に関係なく一致
scopes: アプリの API に許可するアクセス権を選択してください。最上位のスコープを選択する場合、個々のスコープを選択する必要はありません。
setting_aggregate_reblogs: 最近ブーストされた投稿が新たにブーストされても表示しません (設定後受信したものにのみ影響)
setting_compact_reaction: 詳細表示以外の絵文字リアクション表示を件数のみにする
setting_default_sensitive: 閲覧注意状態のメディアはデフォルトでは内容が伏せられ、クリックして初めて閲覧できるようになります
setting_disable_joke_appearance: エイプリルフール等のジョーク機能を無効にします
setting_display_media_default: 閲覧注意としてマークされたメディアは隠す
@ -206,6 +207,7 @@ ja:
setting_aggregate_reblogs: ブーストをまとめる
setting_auto_play_gif: アニメーションGIFを自動再生する
setting_boost_modal: ブーストする前に確認ダイアログを表示する
setting_compact_reaction: リアクションをコンパクトに表示
setting_crop_images: 投稿の詳細以外では画像を16:9に切り抜く
setting_default_language: 投稿する言語
setting_default_privacy: 投稿の公開範囲

View file

@ -52,6 +52,7 @@ defaults: &defaults
show_tab_bar_label: false
enable_limited_timeline: false
enable_reaction: true
compact_reaction: false
show_reply_tree_button: true
hide_statuses_count: false
hide_following_count: false