From 6281823df02c8cfe396adc624123f0f688b71127 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Wed, 28 Dec 2022 10:45:04 -0800 Subject: [PATCH] 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 --- .rubocop.yml | 6 ++++++ .../settings/preferences_controller.rb | 1 + .../mastodon/components/status_content.js | 21 ++++++++++++++++--- app/javascript/mastodon/initial_state.js | 2 ++ app/lib/user_settings_decorator.rb | 5 +++++ app/models/user.rb | 2 +- app/serializers/initial_state_serializer.rb | 9 ++++---- .../preferences/appearance/show.html.haml | 1 + config/locales/simple_form.en.yml | 1 + config/settings.yml | 1 + spec/lib/settings/scoped_settings_spec.rb | 2 +- spec/lib/user_settings_decorator_spec.rb | 7 +++++++ 12 files changed, 49 insertions(+), 9 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 8dc2d1c47..dfda150f9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -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 diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index 3aea517a8..4be581ca3 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -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) ) diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index 5737144f0..e16bac854 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -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 = `@${mention.get('username')}`; + } else { + link.innerHTML = `@${mention.get('acct')}`; + } + } } 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 => ( - @{item.get('username')} + @ + {expandUsernames ? item.get('acct') : item.get('username')} + )).reduce((aggregate, item) => [...aggregate, item, ' '], []); @@ -277,7 +292,7 @@ class StatusContent extends React.PureComponent {
{!hidden && poll} {!hidden && translateButton} -
+ , ]; if (status.get('activity_pub_type') === 'Article' && !this.props.expanded) { diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 1bc47690a..e72a4d44f 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -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'); diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index d529de5a9..f079f542f 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index 29aff60ec..d5a81588f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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 diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index 190df2e23..dfa68b8a0 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -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 diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index 9e3964f21..49775b8c2 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -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' diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index abfb2b623..76fcd1242 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -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 diff --git a/config/settings.yml b/config/settings.yml index cd1de06b4..ee01130d0 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -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 diff --git a/spec/lib/settings/scoped_settings_spec.rb b/spec/lib/settings/scoped_settings_spec.rb index 7566685b4..3faf3f41e 100644 --- a/spec/lib/settings/scoped_settings_spec.rb +++ b/spec/lib/settings/scoped_settings_spec.rb @@ -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 diff --git a/spec/lib/user_settings_decorator_spec.rb b/spec/lib/user_settings_decorator_spec.rb index 462c5b124..1bb44d380 100644 --- a/spec/lib/user_settings_decorator_spec.rb +++ b/spec/lib/user_settings_decorator_spec.rb @@ -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' }