Add a user setting to show/hide domains on remote usernames (#1254)

Adds a user toggle in the preferences menu:

> Show full username (including domain) for remote users

It only shortens the username of local accounts. The main reason for this is so that there is a clear visual indicator of who is local on a thread -- this is important for local-only posting reasons. But we've been using it on Friend Camp for 3 years now and it's actually really nice for getting a sense of who is on what server, too.

The bulk of this work was done by Callie on Friend Camp in October 2019.

Fixes #1247
This commit is contained in:
Darius Kazemi 2022-12-28 10:45:04 -08:00 committed by GitHub
parent 60746ab437
commit 6281823df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 49 additions and 9 deletions

View File

@ -70,6 +70,8 @@ Metrics/AbcSize:
Max: 115
Exclude:
- 'lib/mastodon/*_cli.rb'
AllowedMethods:
- process_update
Metrics/BlockLength:
Max: 55
@ -92,6 +94,8 @@ Metrics/CyclomaticComplexity:
Max: 25
Exclude:
- 'lib/mastodon/*_cli.rb'
AllowedMethods:
- process_update
Layout/LineLength:
AllowURI: true
@ -113,6 +117,8 @@ Metrics/ParameterLists:
Metrics/PerceivedComplexity:
Max: 25
AllowedMethods:
- process_update
Naming/MemoizedInstanceVariableName:
Enabled: false

View File

@ -57,6 +57,7 @@ class Settings::PreferencesController < Settings::BaseController
:setting_trends,
:setting_crop_images,
:setting_always_send_emails,
:setting_expand_usernames,
notification_emails: %i(follow follow_request reblog favourite mention report pending_account trending_tag appeal),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)

View File

@ -6,7 +6,12 @@ import Permalink from './permalink';
import classnames from 'classnames';
import PollContainer from 'mastodon/containers/poll_container';
import Icon from 'mastodon/components/icon';
import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'mastodon/initial_state';
import {
autoPlayGif,
languages as preloadedLanguages,
translationEnabled,
expandUsernames,
} from 'mastodon/initial_state';
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
@ -96,6 +101,14 @@ class StatusContent extends React.PureComponent {
if (mention) {
link.addEventListener('click', this.onMentionClick.bind(this, mention), false);
link.setAttribute('title', mention.get('acct'));
// Hometown: make remote usernames
if (expandUsernames) {
if (mention.get('acct') === mention.get('username')) {
link.innerHTML = `@<span class="hometown-mention-local">${mention.get('username')}</span>`;
} else {
link.innerHTML = `@<span class="hometown-mention-remote">${mention.get('acct')}</span>`;
}
}
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
} else {
@ -254,7 +267,9 @@ class StatusContent extends React.PureComponent {
const mentionLinks = status.get('mentions').map(item => (
<Permalink to={`/@${item.get('acct')}`} href={item.get('url')} key={item.get('id')} className='status-link mention'>
@<span>{item.get('username')}</span>
@<span className={item.get('acct') === item.get('username') ? 'fc_mention_local' : 'fc_mention_remote'}>
{expandUsernames ? item.get('acct') : item.get('username')}
</span>
</Permalink>
)).reduce((aggregate, item) => [...aggregate, item, ' '], []);
@ -277,7 +292,7 @@ class StatusContent extends React.PureComponent {
<div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''} ${status.get('activity_pub_type') === 'Article' ? 'article-type' : ''} translate`} lang={lang} dangerouslySetInnerHTML={content} />
{!hidden && poll}
{!hidden && translateButton}
</div>
</div>,
];
if (status.get('activity_pub_type') === 'Article' && !this.props.expanded) {

View File

@ -111,6 +111,8 @@ export const disabledAccountId = getMeta('disabled_account_id');
export const displayMedia = getMeta('display_media');
export const domain = getMeta('domain');
export const expandSpoilers = getMeta('expand_spoilers');
// Hometown: expand usernames
export const expandUsernames = getMeta('expand_usernames');
export const forceSingleColumn = !getMeta('advanced_layout');
export const limitedFederationMode = getMeta('limited_federation_mode');
export const mascot = getMeta('mascot');

View File

@ -25,6 +25,7 @@ class UserSettingsDecorator
user.settings['boost_modal'] = boost_modal_preference if change?('setting_boost_modal')
user.settings['delete_modal'] = delete_modal_preference if change?('setting_delete_modal')
user.settings['auto_play_gif'] = auto_play_gif_preference if change?('setting_auto_play_gif')
user.settings['expand_usernames'] = expand_usernames_preference if change?('setting_expand_usernames')
user.settings['display_media'] = display_media_preference if change?('setting_display_media')
user.settings['expand_spoilers'] = expand_spoilers_preference if change?('setting_expand_spoilers')
user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion')
@ -83,6 +84,10 @@ class UserSettingsDecorator
boolean_cast_setting 'setting_auto_play_gif'
end
def expand_usernames_preference
boolean_cast_setting 'setting_expand_usernames'
end
def display_media_preference
settings['setting_display_media']
end

View File

@ -135,7 +135,7 @@ class User < ApplicationRecord
:reduce_motion, :system_font_ui, :noindex, :norss, :theme, :display_media,
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
:disable_swiping, :default_federation, :always_send_emails,
:disable_swiping, :default_federation, :always_send_emails, :expand_usernames,
to: :settings, prefix: :setting, allow_nil: false
delegate :can?, to: :role

View File

@ -44,6 +44,7 @@ class InitialStateSerializer < ActiveModel::Serializer
store[:boost_modal] = object.current_account.user.setting_boost_modal
store[:delete_modal] = object.current_account.user.setting_delete_modal
store[:auto_play_gif] = object.current_account.user.setting_auto_play_gif
store[:expand_usernames] = object.current_account.user.setting_expand_usernames
store[:display_media] = object.current_account.user.setting_display_media
store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
store[:reduce_motion] = object.current_account.user.setting_reduce_motion
@ -76,11 +77,11 @@ class InitialStateSerializer < ActiveModel::Serializer
store = {}
if object.current_account
store[:me] = object.current_account.id.to_s
store[:default_privacy] = object.visibility || object.current_account.user.setting_default_privacy
store[:default_sensitive] = object.current_account.user.setting_default_sensitive
store[:me] = object.current_account.id.to_s
store[:default_privacy] = object.visibility || object.current_account.user.setting_default_privacy
store[:default_sensitive] = object.current_account.user.setting_default_sensitive
store[:default_federation] = object.current_account.user.setting_default_federation
store[:default_language] = object.current_account.user.preferred_posting_language
store[:default_language] = object.current_account.user.preferred_posting_language
end
store[:text] = object.text if object.text

View File

@ -32,6 +32,7 @@
= f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label
= f.input :setting_disable_swiping, as: :boolean, wrapper: :with_label
= f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label
= f.input :setting_expand_usernames, as: :boolean, wrapper: :with_label
%h4= t 'appearance.toot_layout'

View File

@ -205,6 +205,7 @@ en:
setting_display_media_hide_all: Hide all
setting_display_media_show_all: Show all
setting_expand_spoilers: Always expand posts marked with content warnings
setting_expand_usernames: Show full username (including domain) for remote users
setting_hide_network: Hide your social graph
setting_noindex: Opt-out of search engine indexing for your profile page
setting_norss: Opt-out of an RSS feed for your public posts

View File

@ -24,6 +24,7 @@ defaults: &defaults
auto_play_gif: false
display_media: 'default'
expand_spoilers: false
expand_usernames: true
preview_sensitive_media: false
reduce_motion: false
disable_swiping: false

View File

@ -6,7 +6,7 @@ RSpec.describe Settings::ScopedSettings do
let(:object) { Fabricate(:user) }
let(:scoped_setting) { described_class.new(object) }
let(:val) { 'whatever' }
let(:methods) { %i(auto_play_gif default_sensitive unfollow_modal boost_modal delete_modal reduce_motion system_font_ui noindex theme) }
let(:methods) { %i(auto_play_gif expand_usernames default_sensitive unfollow_modal boost_modal delete_modal reduce_motion system_font_ui noindex theme) }
describe '.initialize' do
it 'sets @object' do

View File

@ -63,6 +63,13 @@ describe UserSettingsDecorator do
expect(user.settings['auto_play_gif']).to eq false
end
it 'updates the user settings value for username expansion' do
values = { 'setting_expand_usernames' => '0'}
settings.update(values)
expect(user.settings['expand_usernames'].to eq false)
end
it 'updates the user settings value for system font in UI' do
values = { 'setting_system_font_ui' => '0' }