Add setting to hide post count and follow count

This commit is contained in:
noellabo 2022-02-08 13:50:44 +09:00
parent 324d402d70
commit 1128e473c6
31 changed files with 274 additions and 66 deletions

View file

@ -35,7 +35,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: outbox_url, id: outbox_url,
type: :ordered, type: :ordered,
size: @account.statuses_count, size: @account.public_statuses_count,
first: outbox_url(page: true), first: outbox_url(page: true),
last: outbox_url(page: true, min_id: 0) last: outbox_url(page: true, min_id: 0)
) )

View file

@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
end end
def hide_results? def hide_results?
@account.suspended? || (@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) @account.suspended? || (@account.hide_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
end end
def default_accounts def default_accounts

View file

@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
end end
def hide_results? def hide_results?
@account.suspended? || (@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) @account.suspended? || (@account.hide_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
end end
def default_accounts def default_accounts

View file

@ -15,13 +15,13 @@ class FollowerAccountsController < ApplicationController
format.html do format.html do
expires_in 0, public: true unless user_signed_in? expires_in 0, public: true unless user_signed_in?
next if @account.user_hides_network? next if @account.hide_network?
follows follows
end end
format.json do format.json do
raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network? raise Mastodon::NotPermittedError if page_requested? && @account.hide_network?
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?) expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
@ -65,7 +65,7 @@ class FollowerAccountsController < ApplicationController
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account, page: params.fetch(:page, 1)), id: account_followers_url(@account, page: params.fetch(:page, 1)),
type: :ordered, type: :ordered,
size: @account.followers_count, size: @account.public_followers_count,
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) }, items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
part_of: account_followers_url(@account), part_of: account_followers_url(@account),
next: next_page_url, next: next_page_url,
@ -75,14 +75,14 @@ class FollowerAccountsController < ApplicationController
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account), id: account_followers_url(@account),
type: :ordered, type: :ordered,
size: @account.followers_count, size: @account.public_followers_count,
first: page_url(1) first: page_url(1)
) )
end end
end end
def restrict_fields_to def restrict_fields_to
if page_requested? || !@account.user_hides_network? if page_requested? || !@account.hide_network?
# Return all fields # Return all fields
else else
%i(id type total_items) %i(id type total_items)

View file

@ -15,13 +15,13 @@ class FollowingAccountsController < ApplicationController
format.html do format.html do
expires_in 0, public: true unless user_signed_in? expires_in 0, public: true unless user_signed_in?
next if @account.user_hides_network? next if @account.hide_network?
follows follows
end end
format.json do format.json do
raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network? raise Mastodon::NotPermittedError if page_requested? && @account.hide_network?
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?) expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
@ -65,7 +65,7 @@ class FollowingAccountsController < ApplicationController
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account, page: params.fetch(:page, 1)), id: account_following_index_url(@account, page: params.fetch(:page, 1)),
type: :ordered, type: :ordered,
size: @account.following_count, size: @account.public_following_count,
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) }, items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
part_of: account_following_index_url(@account), part_of: account_following_index_url(@account),
next: next_page_url, next: next_page_url,
@ -75,14 +75,14 @@ class FollowingAccountsController < ApplicationController
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account), id: account_following_index_url(@account),
type: :ordered, type: :ordered,
size: @account.following_count, size: @account.public_following_count,
first: page_url(1) first: page_url(1)
) )
end end
end end
def restrict_fields_to def restrict_fields_to
if page_requested? || !@account.user_hides_network? if page_requested? || !@account.hide_network?
# Return all fields # Return all fields
else else
%i(id type total_items) %i(id type total_items)

View file

@ -1,10 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class Settings::PreferencesController < Settings::BaseController class Settings::PreferencesController < Settings::BaseController
before_action :set_account, only: [:update]
def show; end def show; end
def update def update
user_settings.update(user_settings_params.to_h) if user_settings.update(user_settings_params.to_h)
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
end
if current_user.update(user_params) if current_user.update(user_params)
I18n.locale = current_user.locale I18n.locale = current_user.locale
@ -69,8 +73,15 @@ class Settings::PreferencesController < Settings::BaseController
:setting_enable_limited_timeline, :setting_enable_limited_timeline,
:setting_enable_reaction, :setting_enable_reaction,
:setting_show_reply_tree_button, :setting_show_reply_tree_button,
:setting_hide_statuses_count,
:setting_hide_following_count,
:setting_hide_followers_count,
notification_emails: %i(follow follow_request reblog favourite emoji_reaction mention digest report pending_account trending_tag), notification_emails: %i(follow follow_request reblog favourite emoji_reaction mention digest report pending_account trending_tag),
interactions: %i(must_be_follower must_be_following must_be_following_dm) interactions: %i(must_be_follower must_be_following must_be_following_dm)
) )
end end
def set_account
@account = current_account
end
end end

View file

@ -79,21 +79,21 @@ module AccountsHelper
def account_description(account) def account_description(account)
prepend_str = [ prepend_str = [
[ account.hide_statuses_count? ? nil : [
number_to_human(account.statuses_count, precision: 3, strip_insignificant_zeros: true), number_to_human(account.public_statuses_count, precision: 3, strip_insignificant_zeros: true),
I18n.t('accounts.posts', count: account.statuses_count), I18n.t('accounts.posts', count: account.public_statuses_count),
].join(' '), ].join(' '),
[ account.hide_following_count? ? nil : [
number_to_human(account.following_count, precision: 3, strip_insignificant_zeros: true), number_to_human(account.public_following_count, precision: 3, strip_insignificant_zeros: true),
I18n.t('accounts.following', count: account.following_count), I18n.t('accounts.following', count: account.public_following_count),
].join(' '), ].join(' '),
[ account.hide_followers_count? ? nil : [
number_to_human(account.followers_count, precision: 3, strip_insignificant_zeros: true), number_to_human(account.public_followers_count, precision: 3, strip_insignificant_zeros: true),
I18n.t('accounts.followers', count: account.followers_count), I18n.t('accounts.followers', count: account.public_followers_count),
].join(' '), ].join(' '),
].join(', ') ].compact.join(', ')
[prepend_str, account.note].join(' · ') [prepend_str, account.note].join(' · ')
end end

View file

@ -14,6 +14,7 @@ import { FormattedMessage, FormattedNumber } from 'react-intl';
/** /**
* @typedef {object} ShortNumberProps * @typedef {object} ShortNumberProps
* @property {number} value Number to display in short variant * @property {number} value Number to display in short variant
* @property {boolean} hide Hide the number
* @property {ShortNumberRenderer} [renderer] * @property {ShortNumberRenderer} [renderer]
* Custom renderer for numbers, provided as a prop. If another renderer * Custom renderer for numbers, provided as a prop. If another renderer
* passed as a child of this component, this prop won't be used. * passed as a child of this component, this prop won't be used.
@ -28,7 +29,8 @@ import { FormattedMessage, FormattedNumber } from 'react-intl';
* @param {ShortNumberProps} param0 Props for the component * @param {ShortNumberProps} param0 Props for the component
* @returns {JSX.Element} Rendered number * @returns {JSX.Element} Rendered number
*/ */
function ShortNumber({ value, renderer, children }) { function ShortNumber({ value, hide, renderer, children }) {
value = hide ? 0 : value;
const shortNumber = toShortNumber(value); const shortNumber = toShortNumber(value);
const [, division] = shortNumber; const [, division] = shortNumber;
@ -40,7 +42,7 @@ function ShortNumber({ value, renderer, children }) {
// eslint-disable-next-line eqeqeq // eslint-disable-next-line eqeqeq
const customRenderer = children != null ? children : renderer; const customRenderer = children != null ? children : renderer;
const displayNumber = <ShortNumberCounter value={shortNumber} />; const displayNumber = hide ? '-' : <ShortNumberCounter value={shortNumber} />;
// eslint-disable-next-line eqeqeq // eslint-disable-next-line eqeqeq
return customRenderer != null return customRenderer != null
@ -50,10 +52,15 @@ function ShortNumber({ value, renderer, children }) {
ShortNumber.propTypes = { ShortNumber.propTypes = {
value: PropTypes.number.isRequired, value: PropTypes.number.isRequired,
hide: PropTypes.bool,
renderer: PropTypes.func, renderer: PropTypes.func,
children: PropTypes.func, children: PropTypes.func,
}; };
ShortNumber.defaultProps = {
hide: false,
};
/** /**
* @typedef {object} ShortNumberCounterProps * @typedef {object} ShortNumberCounterProps
* @property {import('../utils/number').ShortNumber} value Short number * @property {import('../utils/number').ShortNumber} value Short number

View file

@ -54,6 +54,7 @@ const messages = defineMessages({
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' }, add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
add_or_remove_from_circle: { id: 'account.add_or_remove_from_circle', defaultMessage: 'Add or Remove from circles' }, add_or_remove_from_circle: { id: 'account.add_or_remove_from_circle', defaultMessage: 'Add or Remove from circles' },
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
secret: { id: 'account.secret', defaultMessage: 'Secret' },
}); });
const dateFormatOptions = { const dateFormatOptions = {
@ -333,6 +334,10 @@ class Header extends ImmutablePureComponent {
buttons = <Fragment>{subscribing_buttons}{following_buttons}</Fragment>; buttons = <Fragment>{subscribing_buttons}{following_buttons}</Fragment>;
} }
const hide_statuses_count = account.getIn(['other_settings', 'hide_statuses_count'], false);
const hide_following_count = account.getIn(['other_settings', 'hide_following_count'], false);
const hide_followers_count = account.getIn(['other_settings', 'hide_followers_count'], false);
return ( return (
<div className={classNames('account__header', { inactive: !!account.get('moved') })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> <div className={classNames('account__header', { inactive: !!account.get('moved') })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<div className='account__header__image'> <div className='account__header__image'>
@ -408,22 +413,25 @@ class Header extends ImmutablePureComponent {
{!suspended && ( {!suspended && (
<div className='account__header__extra__links'> <div className='account__header__extra__links'>
<NavLink isActive={this.isStatusesPageActive} activeClassName='active' to={`/accounts/${account.get('id')}`} title={intl.formatNumber(account.get('statuses_count'))}> <NavLink isActive={this.isStatusesPageActive} activeClassName='active' to={`/accounts/${account.get('id')}`} title={hide_statuses_count ? intl.formatMessage(messages.secret) : intl.formatNumber(account.get('statuses_count'))}>
<ShortNumber <ShortNumber
hide={hide_statuses_count}
value={account.get('statuses_count')} value={account.get('statuses_count')}
renderer={counterRenderer('statuses')} renderer={counterRenderer('statuses')}
/> />
</NavLink> </NavLink>
<NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/following`} title={intl.formatNumber(account.get('following_count'))}> <NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/following`} title={hide_following_count ? intl.formatMessage(messages.secret) : intl.formatNumber(account.get('following_count'))}>
<ShortNumber <ShortNumber
hide={hide_following_count}
value={account.get('following_count')} value={account.get('following_count')}
renderer={counterRenderer('following')} renderer={counterRenderer('following')}
/> />
</NavLink> </NavLink>
<NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/followers`} title={intl.formatNumber(account.get('followers_count'))}> <NavLink exact activeClassName='active' to={`/accounts/${account.get('id')}/followers`} title={hide_followers_count ? intl.formatMessage(messages.secret) : intl.formatNumber(account.get('followers_count'))}>
<ShortNumber <ShortNumber
hide={hide_followers_count}
value={account.get('followers_count')} value={account.get('followers_count')}
renderer={counterRenderer('followers')} renderer={counterRenderer('followers')}
/> />

View file

@ -272,6 +272,9 @@ class AccountCard extends ImmutablePureComponent {
} }
} }
const hide_statuses_count = account.getIn(['other_settings', 'hide_statuses_count'], false);
const hide_followers_count = account.getIn(['other_settings', 'hide_followers_count'], false);
return ( return (
<div className='directory__card'> <div className='directory__card'>
<div className='directory__card__img'> <div className='directory__card__img'>
@ -307,13 +310,13 @@ class AccountCard extends ImmutablePureComponent {
<div className='directory__card__extra'> <div className='directory__card__extra'>
<div className='accounts-table__count'> <div className='accounts-table__count'>
<ShortNumber value={account.get('statuses_count')} /> {hide_statuses_count ? '-' : <ShortNumber value={account.get('statuses_count')} />}
<small> <small>
<FormattedMessage id='account.posts' defaultMessage='Toots' /> <FormattedMessage id='account.posts' defaultMessage='Toots' />
</small> </small>
</div> </div>
<div className='accounts-table__count'> <div className='accounts-table__count'>
<ShortNumber value={account.get('followers_count')} />{' '} {hide_followers_count ? '-' : <ShortNumber value={account.get('followers_count')} />}{' '}
<small> <small>
<FormattedMessage <FormattedMessage
id='account.followers' id='account.followers'

View file

@ -287,6 +287,9 @@ class AccountCard extends ImmutablePureComponent {
} }
} }
const hide_statuses_count = account.getIn(['other_settings', 'hide_statuses_count'], false);
const hide_followers_count = account.getIn(['other_settings', 'hide_followers_count'], false);
return ( return (
<div className='directory__card'> <div className='directory__card'>
<div className='directory__card__img'> <div className='directory__card__img'>
@ -322,13 +325,13 @@ class AccountCard extends ImmutablePureComponent {
<div className='directory__card__extra'> <div className='directory__card__extra'>
<div className='accounts-table__count'> <div className='accounts-table__count'>
<ShortNumber value={account.get('statuses_count')} /> {hide_statuses_count ? '-' : <ShortNumber value={account.get('statuses_count')} />}
<small> <small>
<FormattedMessage id='account.posts' defaultMessage='Toots' /> <FormattedMessage id='account.posts' defaultMessage='Toots' />
</small> </small>
</div> </div>
<div className='accounts-table__count'> <div className='accounts-table__count'>
<ShortNumber value={account.get('followers_count')} />{' '} {hide_followers_count ? '-' : <ShortNumber value={account.get('followers_count')} />}{' '}
<small> <small>
<FormattedMessage <FormattedMessage
id='account.members' id='account.members'

View file

@ -46,6 +46,7 @@ const messages = defineMessages({
id: 'confirmations.unsubscribe.confirm', id: 'confirmations.unsubscribe.confirm',
defaultMessage: 'Unsubscribe' defaultMessage: 'Unsubscribe'
}, },
secret: { id: 'account.secret', defaultMessage: 'Secret' },
}); });
const makeMapStateToProps = () => { const makeMapStateToProps = () => {
@ -286,6 +287,9 @@ class GroupDetail extends ImmutablePureComponent {
} }
} }
const hide_statuses_count = account.getIn(['other_settings', 'hide_statuses_count'], false);
const hide_followers_count = account.getIn(['other_settings', 'hide_followers_count'], false);
return ( return (
<div className='group__detail'> <div className='group__detail'>
<div className='group__detail__img'> <div className='group__detail__img'>
@ -317,14 +321,16 @@ class GroupDetail extends ImmutablePureComponent {
<div className='group__detail__extra'> <div className='group__detail__extra'>
<div className='group__header__links'> <div className='group__header__links'>
<a title={intl.formatNumber(account.get('statuses_count'))}> <a title={hide_statuses_count ? intl.formatMessage(messages.secret) : intl.formatNumber(account.get('statuses_count'))}>
<ShortNumber <ShortNumber
hide={hide_statuses_count}
value={account.get('statuses_count')} value={account.get('statuses_count')}
renderer={counterRenderer('statuses')} renderer={counterRenderer('statuses')}
/> />
</a> </a>
<a title={intl.formatNumber(account.get('followers_count'))}> <a title={hide_followers_count ? intl.formatMessage(messages.secret) : intl.formatNumber(account.get('followers_count'))}>
<ShortNumber <ShortNumber
hide={hide_followers_count}
value={account.get('followers_count')} value={account.get('followers_count')}
renderer={counterRenderer('members')} renderer={counterRenderer('members')}
/> />

View file

@ -42,6 +42,7 @@
"account.posts_with_replies": "Posts and replies", "account.posts_with_replies": "Posts and replies",
"account.report": "Report @{name}", "account.report": "Report @{name}",
"account.requested": "Awaiting approval. Click to cancel follow request", "account.requested": "Awaiting approval. Click to cancel follow request",
"account.secret": "Secret",
"account.share": "Share @{name}'s profile", "account.share": "Share @{name}'s profile",
"account.show_reblogs": "Show boosts from @{name}", "account.show_reblogs": "Show boosts from @{name}",
"account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Posts}}", "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Posts}}",

View file

@ -40,6 +40,7 @@
"account.open_domain_timeline": "{domain}タイムラインを表示", "account.open_domain_timeline": "{domain}タイムラインを表示",
"account.posts": "投稿", "account.posts": "投稿",
"account.posts_with_replies": "投稿と返信", "account.posts_with_replies": "投稿と返信",
"account.secret": "非公開",
"account.report": "@{name}さんを通報", "account.report": "@{name}さんを通報",
"account.requested": "フォロー承認待ちです。クリックしてキャンセル", "account.requested": "フォロー承認待ちです。クリックしてキャンセル",
"account.share": "@{name}さんのプロフィールを共有する", "account.share": "@{name}さんのプロフィールを共有する",

View file

@ -10,10 +10,24 @@ class UserSettingsDecorator
def update(settings) def update(settings)
@settings = settings @settings = settings
process_update process_update
profile_change?
end end
private private
PROFILE_KEYS = %w(
setting_noindex
setting_hide_network
setting_hide_statuses_count
setting_hide_following_count
setting_hide_followers_count
setting_enable_reaction
).freeze
def profile_change?
settings.keys.intersection(PROFILE_KEYS).any?
end
def process_update def process_update
user.settings['notification_emails'] = merged_notification_emails if change?('notification_emails') user.settings['notification_emails'] = merged_notification_emails if change?('notification_emails')
user.settings['interactions'] = merged_interactions if change?('interactions') user.settings['interactions'] = merged_interactions if change?('interactions')
@ -53,6 +67,9 @@ class UserSettingsDecorator
user.settings['enable_limited_timeline'] = enable_limited_timeline_preference if change?('setting_enable_limited_timeline') 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['enable_reaction'] = enable_reaction_preference if change?('setting_enable_reaction')
user.settings['show_reply_tree_button'] = show_reply_tree_button_preference if change?('setting_show_reply_tree_button') 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')
user.settings['hide_followers_count'] = hide_followers_count_preference if change?('setting_hide_followers_count')
end end
def merged_notification_emails def merged_notification_emails
@ -207,6 +224,18 @@ class UserSettingsDecorator
boolean_cast_setting 'setting_show_reply_tree_button' boolean_cast_setting 'setting_show_reply_tree_button'
end end
def hide_statuses_count_preference
boolean_cast_setting 'setting_hide_statuses_count'
end
def hide_following_count_preference
boolean_cast_setting 'setting_hide_following_count'
end
def hide_followers_count_preference
boolean_cast_setting 'setting_hide_followers_count'
end
def boolean_cast_setting(key) def boolean_cast_setting(key)
ActiveModel::Type::Boolean.new.cast(settings[key]) ActiveModel::Type::Boolean.new.cast(settings[key])
end end

View file

@ -74,6 +74,7 @@ class Account < ApplicationRecord
include DomainNormalizable include DomainNormalizable
include DomainMaterializable include DomainMaterializable
include AccountMerging include AccountMerging
include AccountSettings
TRUST_LEVELS = { TRUST_LEVELS = {
untrusted: 0, untrusted: 0,
@ -137,7 +138,11 @@ class Account < ApplicationRecord
:moderator?, :moderator?,
:staff?, :staff?,
:locale, :locale,
:hides_network?, :noindex?,
:hide_network?,
:hide_statuses_count?,
:hide_followers_count?,
:hide_following_count?,
:shows_application?, :shows_application?,
to: :user, to: :user,
prefix: true, prefix: true,
@ -187,6 +192,18 @@ class Account < ApplicationRecord
"#{username}@#{Rails.configuration.x.local_domain}" "#{username}@#{Rails.configuration.x.local_domain}"
end end
def public_statuses_count
hide_statuses_count? ? 0 : statuses_count
end
def public_followers_count
hide_followers_count? ? 0 : followers_count
end
def public_following_count
hide_following_count? ? 0 : following_count
end
def local_followers_count def local_followers_count
Follow.where(target_account_id: id).count Follow.where(target_account_id: id).count
end end
@ -351,12 +368,12 @@ class Account < ApplicationRecord
save! save!
end end
def hides_followers? def hide_followers?
hide_collections? || user_hides_network? hide_collections? || hide_network?
end end
def hides_following? def hide_following?
hide_collections? || user_hides_network? hide_collections? || hide_network?
end end
def object_type def object_type
@ -402,7 +419,16 @@ class Account < ApplicationRecord
end end
def other_settings def other_settings
settings local? && user ? settings.merge(
{
'noindex' => user.setting_noindex,
'hide_network' => user.setting_hide_network,
'hide_statuses_count' => user.setting_hide_statuses_count,
'hide_following_count' => user.setting_hide_following_count,
'hide_followers_count' => user.setting_hide_followers_count,
'enable_reaction' => user.setting_enable_reaction,
}
) : settings
end end
class Field < ActiveModelSerializers::Model class Field < ActiveModelSerializers::Model

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
module AccountSettings
extend ActiveSupport::Concern
def noindex?
local? ? user&.noindex? : settings['noindex']
end
def hide_network?
local? ? user&.hide_network? : settings['hide_network']
end
def hide_statuses_count?
local? ? user&.hide_statuses_count? : settings['hide_statuses_count']
end
def hide_following_count?
local? ? user&.hide_following_count? : settings['hide_following_count']
end
def hide_followers_count?
local? ? user&.hide_followers_count? : settings['hide_followers_count']
end
end

View file

@ -131,6 +131,7 @@ class User < ApplicationRecord
:follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button, :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,
:show_reply_tree_button, :show_reply_tree_button,
:hide_statuses_count, :hide_following_count, :hide_followers_count,
to: :settings, prefix: :setting, allow_nil: false to: :settings, prefix: :setting, allow_nil: false
@ -271,8 +272,24 @@ class User < ApplicationRecord
settings.notification_emails['trending_tag'] settings.notification_emails['trending_tag']
end end
def hides_network? def noindex?
@hides_network ||= settings.hide_network @noindex ||= settings.noindex
end
def hide_network?
@hide_network ||= settings.hide_network
end
def hide_statuses_count?
@hide_statuses_count ||= settings.hide_statuses_count
end
def hide_following_count?
@hide_following_count ||= settings.hide_following_count
end
def hide_followers_count?
@hide_followers_count ||= settings.hide_followers_count
end end
def aggregates_reblogs? def aggregates_reblogs?

View file

@ -64,6 +64,18 @@ class REST::AccountSerializer < ActiveModel::Serializer
object.last_status_at&.to_date&.iso8601 object.last_status_at&.to_date&.iso8601
end end
def statuses_count
object.public_statuses_count
end
def following_count
object.public_following_count
end
def followers_count
object.public_followers_count
end
def display_name def display_name
object.suspended? ? '' : object.display_name object.suspended? ? '' : object.display_name
end end

View file

@ -213,6 +213,7 @@ class ActivityPub::ProcessAccountService < BaseService
end end
DEFER_SETTINGS_KEYS = %w( DEFER_SETTINGS_KEYS = %w(
noindex
).freeze ).freeze
def defer_settings def defer_settings

View file

@ -14,19 +14,34 @@
.public-account-header__tabs__tabs .public-account-header__tabs__tabs
.details-counters .details-counters
.counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) } .counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) }
= link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do - if account.hide_statuses_count?
%span.counter-number= friendly_number_to_human account.statuses_count = link_to short_account_url(account), class: 'u-url u-uid', title: t('accounts.secret') do
%span.counter-label= t('accounts.posts', count: account.statuses_count) %span.counter-number= '-'
%span.counter-label= t('accounts.posts', count: 0)
- else
= link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.public_statuses_count) do
%span.counter-number= friendly_number_to_human account.public_statuses_count
%span.counter-label= t('accounts.posts', count: account.public_statuses_count)
.counter{ class: active_nav_class(account_following_index_url(account)) } .counter{ class: active_nav_class(account_following_index_url(account)) }
= link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do - if account.hide_following_count?
%span.counter-number= friendly_number_to_human account.following_count = link_to account_following_index_url(account), title: t('accounts.secret') do
%span.counter-label= t('accounts.following', count: account.following_count) %span.counter-number= '-'
%span.counter-label= t('accounts.following', count: 0)
- else
= link_to account_following_index_url(account), title: number_with_delimiter(account.public_following_count) do
%span.counter-number= friendly_number_to_human account.public_following_count
%span.counter-label= t('accounts.following', count: account.public_following_count)
.counter{ class: active_nav_class(account_followers_url(account)) } .counter{ class: active_nav_class(account_followers_url(account)) }
= link_to account_followers_url(account), title: number_with_delimiter(account.followers_count) do - if account.hide_followers_count?
%span.counter-number= friendly_number_to_human account.followers_count = link_to account_followers_url(account), title: t('accounts.secret') do
%span.counter-label= t('accounts.followers', count: account.followers_count) %span.counter-number= '-'
%span.counter-label= t('accounts.followers', count: 0)
- else
= link_to account_followers_url(account), title: number_with_delimiter(account.public_followers_count) do
%span.counter-number= friendly_number_to_human account.public_followers_count
%span.counter-label= t('accounts.followers', count: account.public_followers_count)
.spacer .spacer
.public-account-header__tabs__tabs__buttons .public-account-header__tabs__tabs__buttons
= account_action_button(account) = account_action_button(account)
@ -36,8 +51,8 @@
.public-account-header__extra__links .public-account-header__extra__links
= link_to account_following_index_url(account) do = link_to account_following_index_url(account) do
%strong= friendly_number_to_human account.following_count %strong= friendly_number_to_human account.public_following_count
= t('accounts.following', count: account.following_count) = t('accounts.following', count: account.public_following_count)
= link_to account_followers_url(account) do = link_to account_followers_url(account) do
%strong= friendly_number_to_human account.followers_count %strong= friendly_number_to_human account.public_followers_count
= t('accounts.followers', count: account.followers_count) = t('accounts.followers', count: account.public_followers_count)

View file

@ -39,11 +39,19 @@
.directory__card__extra .directory__card__extra
.accounts-table__count .accounts-table__count
= friendly_number_to_human account.statuses_count - if account.hide_statuses_count?
%small= t('accounts.posts', count: account.statuses_count).downcase = '-'
%small= t('accounts.posts', count: 0).downcase
- else
= friendly_number_to_human account.public_statuses_count
%small= t('accounts.posts', count: account.public_statuses_count).downcase
.accounts-table__count .accounts-table__count
= friendly_number_to_human account.followers_count - if account.hide_followers_count?
%small= t('accounts.followers', count: account.followers_count).downcase = '-'
%small= t('accounts.followers', count: 0).downcase
- else
= friendly_number_to_human account.public_followers_count
%small= t('accounts.followers', count: account.public_followers_count).downcase
.accounts-table__count .accounts-table__count
- if account.last_status_at.present? - if account.last_status_at.present?
%time.time-ago{ datetime: account.last_status_at.to_date.iso8601, title: l(account.last_status_at.to_date) }= l account.last_status_at.to_date %time.time-ago{ datetime: account.last_status_at.to_date.iso8601, title: l(account.last_status_at.to_date) }= l account.last_status_at.to_date

View file

@ -7,7 +7,7 @@
= render 'accounts/header', account: @account = render 'accounts/header', account: @account
- if @account.user_hides_network? - if @account.hide_network?
.nothing-here= t('accounts.network_hidden') .nothing-here= t('accounts.network_hidden')
- elsif user_signed_in? && @account.blocking?(current_account) - elsif user_signed_in? && @account.blocking?(current_account)
.nothing-here= t('accounts.unavailable') .nothing-here= t('accounts.unavailable')

View file

@ -7,7 +7,7 @@
= render 'accounts/header', account: @account = render 'accounts/header', account: @account
- if @account.user_hides_network? - if @account.hide_network?
.nothing-here= t('accounts.network_hidden') .nothing-here= t('accounts.network_hidden')
- elsif user_signed_in? && @account.blocking?(current_account) - elsif user_signed_in? && @account.blocking?(current_account)
.nothing-here= t('accounts.unavailable') .nothing-here= t('accounts.unavailable')

View file

@ -9,11 +9,19 @@
= interrelationships_icon(@relationships, account.id) = interrelationships_icon(@relationships, account.id)
%td= account_link_to account %td= account_link_to account
%td.accounts-table__count.optional %td.accounts-table__count.optional
= friendly_number_to_human account.statuses_count - if account.hide_statuses_count?
%small= t('accounts.posts', count: account.statuses_count).downcase = '-'
%small= t('accounts.posts', count: 0)
- else
= friendly_number_to_human account.public_statuses_count
%small= t('accounts.posts', count: account.public_statuses_count).downcase
%td.accounts-table__count.optional %td.accounts-table__count.optional
= friendly_number_to_human account.followers_count - if account.hide_followers_count?
%small= t('accounts.followers', count: account.followers_count).downcase = '-'
%small= t('accounts.followers', count: 0)
- else
= friendly_number_to_human account.public_followers_count
%small= t('accounts.followers', count: account.public_followers_count).downcase
%td.accounts-table__count %td.accounts-table__count
- if account.last_status_at.present? - if account.last_status_at.present?
%time.time-ago{ datetime: account.last_status_at.to_date.iso8601, title: l(account.last_status_at.to_date) }= l account.last_status_at %time.time-ago{ datetime: account.last_status_at.to_date.iso8601, title: l(account.last_status_at.to_date) }= l account.last_status_at

View file

@ -13,6 +13,15 @@
.fields-group .fields-group
= f.input :setting_hide_network, as: :boolean, wrapper: :with_label = f.input :setting_hide_network, as: :boolean, wrapper: :with_label
.fields-group
= f.input :setting_hide_statuses_count, as: :boolean, wrapper: :with_label, fedibird_features: true
.fields-group
= f.input :setting_hide_following_count, as: :boolean, wrapper: :with_label, fedibird_features: true
.fields-group
= f.input :setting_hide_followers_count, as: :boolean, wrapper: :with_label, fedibird_features: true
.fields-group .fields-group
= f.input :setting_aggregate_reblogs, as: :boolean, wrapper: :with_label, recommended: true = f.input :setting_aggregate_reblogs, as: :boolean, wrapper: :with_label, recommended: true

View file

@ -85,6 +85,7 @@ en:
bot: Bot bot: Bot
group: Group group: Group
moderator: Mod moderator: Mod
secret: Secret
unavailable: Profile unavailable unavailable: Profile unavailable
unfollow: Unfollow unfollow: Unfollow
account_subscribes: account_subscribes:

View file

@ -79,6 +79,7 @@ ja:
bot: Bot bot: Bot
group: Group group: Group
moderator: Mod moderator: Mod
secret: 非公開
unavailable: プロフィールは利用できません unavailable: プロフィールは利用できません
unfollow: フォロー解除 unfollow: フォロー解除
account_subscribes: account_subscribes:

View file

@ -55,7 +55,10 @@ en:
setting_enable_limited_timeline: Enable a limited home to display private and circle and direct message setting_enable_limited_timeline: Enable a limited home to display private and circle and direct message
setting_enable_reaction: Enable the reaction display on the timeline and display the reaction button setting_enable_reaction: Enable the reaction display on the timeline and display the reaction button
setting_follow_button_to_list_adder: Change the behavior of the Follow / Subscribe button, open a dialog where you can select a list to follow / subscribe, or opt out of receiving at home setting_follow_button_to_list_adder: Change the behavior of the Follow / Subscribe button, open a dialog where you can select a list to follow / subscribe, or opt out of receiving at home
setting_hide_followers_count: The number of followers will be hidden in your profile
setting_hide_following_count: The number of following will be hidden in your profile
setting_hide_network: Who you follow and who follows you will be hidden on your profile setting_hide_network: Who you follow and who follows you will be hidden on your profile
setting_hide_statuses_count: The number of post will be hidden in your profile
setting_noindex: Affects your public profile and post pages setting_noindex: Affects your public profile and post pages
setting_place_tab_bar_at_bottom: When using a touch device, you can operate tabs within the reach of your fingers. setting_place_tab_bar_at_bottom: When using a touch device, you can operate tabs within the reach of your fingers.
setting_show_application: The application you use to post will be displayed in the detailed view of your posts setting_show_application: The application you use to post will be displayed in the detailed view of your posts
@ -194,7 +197,10 @@ en:
setting_enable_reaction: Enable reaction setting_enable_reaction: Enable reaction
setting_expand_spoilers: Always expand posts marked with content warnings setting_expand_spoilers: Always expand posts marked with content warnings
setting_follow_button_to_list_adder: Open list add dialog with follow button setting_follow_button_to_list_adder: Open list add dialog with follow button
setting_hide_followers_count: Hide your followers count
setting_hide_following_count: Hide your following count
setting_hide_network: Hide your social graph setting_hide_network: Hide your social graph
setting_hide_statuses_count: Hide your post count
setting_noindex: Opt-out of search engine indexing setting_noindex: Opt-out of search engine indexing
setting_place_tab_bar_at_bottom: Place the tab bar at the bottom setting_place_tab_bar_at_bottom: Place the tab bar at the bottom
setting_reduce_motion: Reduce motion in animations setting_reduce_motion: Reduce motion in animations

View file

@ -55,7 +55,10 @@ ja:
setting_enable_limited_timeline: フォロワー限定・サークル・ダイレクトメッセージを表示する限定ホームを有効にします setting_enable_limited_timeline: フォロワー限定・サークル・ダイレクトメッセージを表示する限定ホームを有効にします
setting_enable_reaction: タイムラインでリアクションの表示を有効にし、リアクションボタンを表示する setting_enable_reaction: タイムラインでリアクションの表示を有効にし、リアクションボタンを表示する
setting_follow_button_to_list_adder: フォロー・購読ボタンの動作を変更し、フォロー・購読するリストを選択したり、ホームで受け取らないよう設定するダイアログを開きます setting_follow_button_to_list_adder: フォロー・購読ボタンの動作を変更し、フォロー・購読するリストを選択したり、ホームで受け取らないよう設定するダイアログを開きます
setting_hide_followers_count: フォロワー数をプロフィールページで見られないようにします
setting_hide_following_count: フォロー数をプロフィールページで見られないようにします
setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
setting_hide_statuses_count: 投稿数をプロフィールページで見られないようにします
setting_noindex: 公開プロフィールおよび各投稿ページに影響します setting_noindex: 公開プロフィールおよび各投稿ページに影響します
setting_place_tab_bar_at_bottom: タッチデバイス使用時に、タブの操作を指の届く範囲で行えます setting_place_tab_bar_at_bottom: タッチデバイス使用時に、タブの操作を指の届く範囲で行えます
setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります
@ -194,7 +197,10 @@ ja:
setting_enable_reaction: リアクションを有効にする setting_enable_reaction: リアクションを有効にする
setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する
setting_follow_button_to_list_adder: フォローボタンでリスト追加ダイアログを開く setting_follow_button_to_list_adder: フォローボタンでリスト追加ダイアログを開く
setting_hide_followers_count: フォロワー数を隠す
setting_hide_following_count: フォロー数を隠す
setting_hide_network: 繋がりを隠す setting_hide_network: 繋がりを隠す
setting_hide_statuses_count: 投稿数を隠す
setting_noindex: 検索エンジンによるインデックスを拒否する setting_noindex: 検索エンジンによるインデックスを拒否する
setting_place_tab_bar_at_bottom: タブバーを下に配置する setting_place_tab_bar_at_bottom: タブバーを下に配置する
setting_reduce_motion: アニメーションの動きを減らす setting_reduce_motion: アニメーションの動きを減らす

View file

@ -52,6 +52,9 @@ defaults: &defaults
enable_limited_timeline: false enable_limited_timeline: false
enable_reaction: true enable_reaction: true
show_reply_tree_button: true show_reply_tree_button: true
hide_statuses_count: false
hide_following_count: false
hide_followers_count: false
notification_emails: notification_emails:
follow: false follow: false
reblog: false reblog: false