about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/settings/preferences_controller.rb1
-rw-r--r--app/lib/feed_manager.rb12
-rw-r--r--app/lib/user_settings_decorator.rb5
-rw-r--r--app/models/user.rb6
-rw-r--r--app/views/settings/preferences/show.html.haml3
-rw-r--r--config/locales/simple_form.en.yml2
-rw-r--r--config/settings.yml1
7 files changed, 23 insertions, 7 deletions
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 7bb5fb112..70e71b4a2 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -48,6 +48,7 @@ class Settings::PreferencesController < ApplicationController
       :setting_noindex,
       :setting_theme,
       :setting_hide_network,
+      :setting_aggregate_reblogs,
       notification_emails: %i(follow follow_request reblog favourite mention digest report),
       interactions: %i(must_be_follower must_be_following)
     )
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 31ff53860..f99df33e5 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -27,7 +27,7 @@ class FeedManager
   end
 
   def push_to_home(account, status)
-    return false unless add_to_feed(:home, account.id, status)
+    return false unless add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?)
     trim(:home, account.id)
     PushUpdateWorker.perform_async(account.id, status.id, "timeline:#{account.id}") if push_update_required?("timeline:#{account.id}")
     true
@@ -45,7 +45,7 @@ class FeedManager
       should_filter &&= !ListAccount.where(list_id: list.id, account_id: status.in_reply_to_account_id).exists?
       return false if should_filter
     end
-    return false unless add_to_feed(:list, list.id, status)
+    return false unless add_to_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?)
     trim(:list, list.id)
     PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}") if push_update_required?("timeline:list:#{list.id}")
     true
@@ -93,7 +93,7 @@ class FeedManager
 
     query.each do |status|
       next if status.direct_visibility? || status.limited_visibility? || filter?(:home, status, into_account)
-      add_to_feed(:home, into_account.id, status)
+      add_to_feed(:home, into_account.id, status, into_account.user&.aggregates_reblogs?)
     end
 
     trim(:home, into_account.id)
@@ -131,7 +131,7 @@ class FeedManager
 
       statuses.each do |status|
         next if filter_from_home?(status, account)
-        added += 1 if add_to_feed(:home, account.id, status)
+        added += 1 if add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?)
       end
 
       break unless added.zero?
@@ -230,11 +230,11 @@ class FeedManager
   # added, and false if it was not added to the feed. Note that this is
   # an internal helper: callers must call trim or push updates if
   # either action is appropriate.
-  def add_to_feed(timeline_type, account_id, status)
+  def add_to_feed(timeline_type, account_id, status, aggregate_reblogs = true)
     timeline_key = key(timeline_type, account_id)
     reblog_key   = key(timeline_type, account_id, 'reblogs')
 
-    if status.reblog?
+    if status.reblog? && (aggregate_reblogs.nil? || aggregate_reblogs)
       # If the original status or a reblog of it is within
       # REBLOG_FALLOFF statuses from the top, do not re-insert it into
       # the feed
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index 40973c707..19b854410 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -31,6 +31,7 @@ class UserSettingsDecorator
     user.settings['noindex']             = noindex_preference if change?('setting_noindex')
     user.settings['theme']               = theme_preference if change?('setting_theme')
     user.settings['hide_network']        = hide_network_preference if change?('setting_hide_network')
+    user.settings['aggregate_reblogs']   = aggregate_reblogs_preference if change?('setting_aggregate_reblogs')
   end
 
   def merged_notification_emails
@@ -97,6 +98,10 @@ class UserSettingsDecorator
     settings['setting_default_language']
   end
 
+  def aggregate_reblogs_preference
+    boolean_cast_setting 'setting_aggregate_reblogs'
+  end
+
   def boolean_cast_setting(key)
     ActiveModel::Type::Boolean.new.cast(settings[key])
   end
diff --git a/app/models/user.rb b/app/models/user.rb
index 453ffa8b0..f4130d7b1 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -95,7 +95,7 @@ class User < ApplicationRecord
 
   delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
            :reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
-           :expand_spoilers, :default_language, to: :settings, prefix: :setting, allow_nil: false
+           :expand_spoilers, :default_language, :aggregate_reblogs, to: :settings, prefix: :setting, allow_nil: false
 
   attr_reader :invite_code
 
@@ -231,6 +231,10 @@ class User < ApplicationRecord
     @hides_network ||= settings.hide_network
   end
 
+  def aggregates_reblogs?
+    @aggregates_reblogs ||= settings.aggregate_reblogs
+  end
+
   def token_for_app(a)
     return nil if a.nil? || a.owner != self
     Doorkeeper::AccessToken
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index ecb789f93..a2c61c9a6 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -48,6 +48,9 @@
     = f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
 
   .fields-group
+    = f.input :setting_aggregate_reblogs, as: :boolean, wrapper: :with_label
+
+  .fields-group
     = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label
     = f.input :setting_expand_spoilers, as: :boolean, wrapper: :with_label
     = f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index e24d8f4e6..ce6a62e87 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -19,6 +19,7 @@ en:
         password: Use at least 8 characters
         phrase: Will be matched regardless of casing in text or content warning of a toot
         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 toots that have been recently boosted (only affects newly-received boosts)
         setting_default_language: The language of your toots can be detected automatically, but it's not always accurate
         setting_display_media_default: Hide media marked as sensitive
         setting_display_media_hide_all: Always hide all media
@@ -65,6 +66,7 @@ en:
         otp_attempt: Two-factor code
         password: Password
         phrase: Keyword or phrase
+        setting_aggregate_reblogs: Group boosts in timelines
         setting_auto_play_gif: Auto-play animated GIFs
         setting_boost_modal: Show confirmation dialog before boosting
         setting_default_language: Posting language
diff --git a/config/settings.yml b/config/settings.yml
index 2bc9fe289..4036d419f 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -33,6 +33,7 @@ defaults: &defaults
   system_font_ui: false
   noindex: false
   theme: 'default'
+  aggregate_reblogs: true
   notification_emails:
     follow: false
     reblog: false