From a34ccaef8d22110fc9926702ee9c5b06388c13fb Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Sun, 19 Jul 2020 12:10:14 -0500 Subject: [Feature] Add timeline-only mutes --- app/controllers/api/v1/accounts_controller.rb | 2 +- app/javascript/flavours/glitch/actions/accounts.js | 4 ++-- app/javascript/flavours/glitch/actions/mutes.js | 7 ++++++ .../glitch/features/ui/components/mute_modal.js | 27 ++++++++++++++++++---- app/javascript/flavours/glitch/reducers/mutes.js | 5 ++++ app/models/concerns/account_interactions.rb | 11 +++++---- app/models/mute.rb | 1 + app/serializers/rest/mute_serializer.rb | 6 ++--- app/services/mute_service.rb | 4 ++-- 9 files changed, 50 insertions(+), 17 deletions(-) (limited to 'app') diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 0080faf33..e9f848ac9 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -44,7 +44,7 @@ class Api::V1::AccountsController < Api::BaseController end def mute - MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications)) + MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications), timelines_only: truthy_param?(:timelines_only)) render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js index e1012a80b..32e533bd0 100644 --- a/app/javascript/flavours/glitch/actions/accounts.js +++ b/app/javascript/flavours/glitch/actions/accounts.js @@ -264,11 +264,11 @@ export function unblockAccountFail(error) { }; -export function muteAccount(id, notifications) { +export function muteAccount(id, notifications, timelinesOnly) { return (dispatch, getState) => { dispatch(muteAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => { + api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications, timelinesOnly }).then(response => { // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers dispatch(muteAccountSuccess(response.data, getState().get('statuses'))); }).catch(error => { diff --git a/app/javascript/flavours/glitch/actions/mutes.js b/app/javascript/flavours/glitch/actions/mutes.js index 927fc7415..645261627 100644 --- a/app/javascript/flavours/glitch/actions/mutes.js +++ b/app/javascript/flavours/glitch/actions/mutes.js @@ -13,6 +13,7 @@ export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL'; export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL'; export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS'; +export const MUTES_TOGGLE_TIMELINES_ONLY = 'MUTES_TOGGLE_TIMELINES_ONLY'; export function fetchMutes() { return (dispatch, getState) => { @@ -104,3 +105,9 @@ export function toggleHideNotifications() { dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS }); }; } + +export function toggleTimelinesOnly() { + return dispatch => { + dispatch({ type: MUTES_TOGGLE_TIMELINES_ONLY }); + }; +} diff --git a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js index 2aab82751..eb4bc02d2 100644 --- a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js @@ -7,19 +7,21 @@ import Button from 'flavours/glitch/components/button'; import { closeModal } from 'flavours/glitch/actions/modal'; import { muteAccount } from 'flavours/glitch/actions/accounts'; import { toggleHideNotifications } from 'flavours/glitch/actions/mutes'; +import { toggleTimelinesOnly } from 'flavours/glitch/actions/mutes'; const mapStateToProps = state => { return { account: state.getIn(['mutes', 'new', 'account']), notifications: state.getIn(['mutes', 'new', 'notifications']), + timelinesOnly: state.getIn(['mutes', 'new', 'timelines_only']), }; }; const mapDispatchToProps = dispatch => { return { - onConfirm(account, notifications) { - dispatch(muteAccount(account.get('id'), notifications)); + onConfirm(account, notifications, timelinesOnly) { + dispatch(muteAccount(account.get('id'), notifications, timelinesOnly)); }, onClose() { @@ -29,6 +31,10 @@ const mapDispatchToProps = dispatch => { onToggleNotifications() { dispatch(toggleHideNotifications()); }, + + onToggleTimelinesOnly() { + dispatch(toggleTimelinesOnly()); + }, }; }; @@ -39,9 +45,11 @@ class MuteModal extends React.PureComponent { static propTypes = { account: PropTypes.object.isRequired, notifications: PropTypes.bool.isRequired, + timelinesOnly: PropTypes.bool.isRequired, onClose: PropTypes.func.isRequired, onConfirm: PropTypes.func.isRequired, onToggleNotifications: PropTypes.func.isRequired, + onTimelinesOnly: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -51,7 +59,7 @@ class MuteModal extends React.PureComponent { handleClick = () => { this.props.onClose(); - this.props.onConfirm(this.props.account, this.props.notifications); + this.props.onConfirm(this.props.account, this.props.notifications, this.props.timelinesOnly); } handleCancel = () => { @@ -66,8 +74,12 @@ class MuteModal extends React.PureComponent { this.props.onToggleNotifications(); } + toggleTimelinesOnly = () => { + this.props.onToggleTimelinesOnly(); + } + render () { - const { account, notifications } = this.props; + const { account, notifications, timelinesOnly } = this.props; return (
@@ -91,6 +103,13 @@ class MuteModal extends React.PureComponent {
+
+ +
diff --git a/app/javascript/flavours/glitch/reducers/mutes.js b/app/javascript/flavours/glitch/reducers/mutes.js index 7111bb710..d170c2594 100644 --- a/app/javascript/flavours/glitch/reducers/mutes.js +++ b/app/javascript/flavours/glitch/reducers/mutes.js @@ -3,12 +3,14 @@ import Immutable from 'immutable'; import { MUTES_INIT_MODAL, MUTES_TOGGLE_HIDE_NOTIFICATIONS, + MUTES_TOGGLE_TIMELINES_ONLY, } from 'flavours/glitch/actions/mutes'; const initialState = Immutable.Map({ new: Immutable.Map({ account: null, notifications: true, + timelinesOnly: false, }), }); @@ -18,9 +20,12 @@ export default function mutes(state = initialState, action) { return state.withMutations((state) => { state.setIn(['new', 'account'], action.account); state.setIn(['new', 'notifications'], true); + state.setIn(['new', 'timelinesOnly'], false); }); case MUTES_TOGGLE_HIDE_NOTIFICATIONS: return state.updateIn(['new', 'notifications'], (old) => !old); + case MUTES_TOGGLE_TIMELINES_ONLY: + return state.updateIn(['new', 'timelines_only'], (old) => !old); default: return state; } diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index be7211f2c..01a711493 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -25,7 +25,7 @@ module AccountInteractions end def muting_map(target_account_ids, account_id) - Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping| + Mute.where(target_account_id: target_account_ids, account_id: account_id, timelines_only: false).each_with_object({}) do |mute, mapping| mapping[mute.target_account_id] = { notifications: mute.hide_notifications?, } @@ -125,14 +125,15 @@ module AccountInteractions .find_or_create_by!(target_account: other_account) end - def mute!(other_account, notifications: nil) + def mute!(other_account, notifications: nil, timelines_only: nil) notifications = true if notifications.nil? - mute = mute_relationships.create_with(hide_notifications: notifications).find_or_create_by!(target_account: other_account) + timelines_only = false if timelines_only.nil? + mute = mute_relationships.create_with(hide_notifications: notifications, timelines_only: timelines_only).find_or_create_by!(target_account: other_account) remove_potential_friendship(other_account) # When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't. if mute.hide_notifications? != notifications - mute.update!(hide_notifications: notifications) + mute.update!(hide_notifications: notifications, timelines_only: timelines_only) end mute @@ -184,7 +185,7 @@ module AccountInteractions end def muting?(other_account) - mute_relationships.where(target_account: other_account).exists? + mute_relationships.where(target_account: other_account, timelines_only: false).exists? end def muting_conversation?(conversation) diff --git a/app/models/mute.rb b/app/models/mute.rb index 639120f7d..11f833d8e 100644 --- a/app/models/mute.rb +++ b/app/models/mute.rb @@ -9,6 +9,7 @@ # hide_notifications :boolean default(TRUE), not null # account_id :bigint(8) not null # target_account_id :bigint(8) not null +# timelines_only :boolean default(FALSE), not null # class Mute < ApplicationRecord diff --git a/app/serializers/rest/mute_serializer.rb b/app/serializers/rest/mute_serializer.rb index 043a2f059..db33f8574 100644 --- a/app/serializers/rest/mute_serializer.rb +++ b/app/serializers/rest/mute_serializer.rb @@ -2,8 +2,8 @@ class REST::MuteSerializer < ActiveModel::Serializer include RoutingHelper - - attributes :id, :account, :target_account, :created_at, :hide_notifications + + attributes :id, :account, :target_account, :created_at, :hide_notifications, :timelines_only def account REST::AccountSerializer.new(object.account) @@ -12,4 +12,4 @@ class REST::MuteSerializer < ActiveModel::Serializer def target_account REST::AccountSerializer.new(object.target_account) end -end \ No newline at end of file +end diff --git a/app/services/mute_service.rb b/app/services/mute_service.rb index 676804cb9..1a3f4981f 100644 --- a/app/services/mute_service.rb +++ b/app/services/mute_service.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true class MuteService < BaseService - def call(account, target_account, notifications: nil) + def call(account, target_account, notifications: nil, timelines_only: nil) return if account.id == target_account.id - mute = account.mute!(target_account, notifications: notifications) + mute = account.mute!(target_account, notifications: notifications, timelines_only: timelines_only) if mute.hide_notifications? BlockWorker.perform_async(account.id, target_account.id) -- cgit