Add show followed_by to WebUI
This commit is contained in:
parent
f40706037b
commit
2b7d1d9941
42 changed files with 632 additions and 111 deletions
|
@ -39,7 +39,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
end
|
||||
|
||||
def subscribe
|
||||
AccountSubscribeService.new.call(current_user.account, @account)
|
||||
AccountSubscribeService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), list_id: params[:list_id])
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
end
|
||||
|
||||
|
@ -59,7 +59,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
end
|
||||
|
||||
def unsubscribe
|
||||
UnsubscribeAccountService.new.call(current_user.account, @account)
|
||||
UnsubscribeAccountService.new.call(current_user.account, @account, params[:list_id])
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
end
|
||||
|
||||
|
|
97
app/controllers/api/v1/lists/subscribes_controller.rb
Normal file
97
app/controllers/api/v1/lists/subscribes_controller.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Lists::SubscribesController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show]
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show]
|
||||
|
||||
before_action :require_user!
|
||||
before_action :set_list
|
||||
|
||||
after_action :insert_pagination_headers, only: :show
|
||||
|
||||
def show
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
ApplicationRecord.transaction do
|
||||
list_accounts.each do |account|
|
||||
@list.subscribes << account
|
||||
end
|
||||
end
|
||||
|
||||
render_empty
|
||||
end
|
||||
|
||||
def destroy
|
||||
AccountSubscribe.where(list: @list, target_account_id: account_ids).destroy_all
|
||||
render_empty
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_list
|
||||
@list = List.where(account: current_account).find(params[:list_id])
|
||||
end
|
||||
|
||||
def load_accounts
|
||||
if unlimited?
|
||||
@list.subscribes.includes(:account_stat).all
|
||||
else
|
||||
@list.subscribes.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
|
||||
end
|
||||
end
|
||||
|
||||
def list_accounts
|
||||
Account.find(account_ids)
|
||||
end
|
||||
|
||||
def account_ids
|
||||
Array(resource_params[:account_ids])
|
||||
end
|
||||
|
||||
def resource_params
|
||||
params.permit(account_ids: [])
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def next_path
|
||||
return if unlimited?
|
||||
|
||||
if records_continue?
|
||||
api_v1_list_subscribes_url pagination_params(max_id: pagination_max_id)
|
||||
end
|
||||
end
|
||||
|
||||
def prev_path
|
||||
return if unlimited?
|
||||
|
||||
unless @accounts.empty?
|
||||
api_v1_list_subscribes_url pagination_params(since_id: pagination_since_id)
|
||||
end
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@accounts.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@accounts.first.id
|
||||
end
|
||||
|
||||
def records_continue?
|
||||
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit).permit(:limit).merge(core_params)
|
||||
end
|
||||
|
||||
def unlimited?
|
||||
params[:limit] == '0'
|
||||
end
|
||||
end
|
|
@ -38,7 +38,7 @@ class Settings::AccountSubscribesController < Settings::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
UnsubscribeAccountService.new.call(current_account, @account_subscribing.target_account)
|
||||
UnsubscribeAccountService.new.call(current_account, @account_subscribing.target_account, @account_subscribing.list_id)
|
||||
redirect_to settings_account_subscribes_path
|
||||
end
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_crop_images,
|
||||
:setting_show_follow_button_on_timeline,
|
||||
:setting_show_subscribe_button_on_timeline,
|
||||
:setting_show_followed_by,
|
||||
:setting_follow_button_to_list_adder,
|
||||
:setting_show_target,
|
||||
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
|
||||
interactions: %i(must_be_follower must_be_following must_be_following_dm)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { importFetchedAccount, importFetchedAccounts } from './importer';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
||||
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
|
||||
|
@ -125,7 +126,7 @@ export function fetchAccountFail(id, error) {
|
|||
};
|
||||
};
|
||||
|
||||
export function followAccount(id, options = { reblogs: true }) {
|
||||
export function followAccount(id, options = { reblogs: true, delivery: true }) {
|
||||
return (dispatch, getState) => {
|
||||
const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
|
||||
const locked = getState().getIn(['accounts', id, 'locked'], false);
|
||||
|
@ -204,14 +205,14 @@ export function unfollowAccountFail(error) {
|
|||
};
|
||||
};
|
||||
|
||||
export function subscribeAccount(id, reblogs = true) {
|
||||
export function subscribeAccount(id, reblogs = true, list_id = null) {
|
||||
return (dispatch, getState) => {
|
||||
const alreadySubscribe = getState().getIn(['relationships', id, 'subscribing']);
|
||||
const alreadySubscribe = (list_id ? getState().getIn(['relationships', id, 'subscribing', list_id], new Map) : getState().getIn(['relationships', id, 'subscribing'], new Map)).size > 0;
|
||||
const locked = getState().getIn(['accounts', id, 'locked'], false);
|
||||
|
||||
dispatch(subscribeAccountRequest(id, locked));
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/subscribe`).then(response => {
|
||||
api(getState).post(`/api/v1/accounts/${id}/subscribe`, { reblogs, list_id }).then(response => {
|
||||
dispatch(subscribeAccountSuccess(response.data, alreadySubscribe));
|
||||
}).catch(error => {
|
||||
dispatch(subscribeAccountFail(error, locked));
|
||||
|
@ -219,11 +220,11 @@ export function subscribeAccount(id, reblogs = true) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unsubscribeAccount(id) {
|
||||
export function unsubscribeAccount(id, list_id = null) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unsubscribeAccountRequest(id));
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/unsubscribe`).then(response => {
|
||||
api(getState).post(`/api/v1/accounts/${id}/unsubscribe`, { list_id }).then(response => {
|
||||
dispatch(unsubscribeAccountSuccess(response.data, getState().get('statuses')));
|
||||
}).catch(error => {
|
||||
dispatch(unsubscribeAccountFail(error));
|
||||
|
|
|
@ -7,8 +7,9 @@ import Permalink from './permalink';
|
|||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { me } from '../initial_state';
|
||||
import { me, show_followed_by, follow_button_to_list_adder } from '../initial_state';
|
||||
import RelativeTimestamp from './relative_timestamp';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
|
@ -29,6 +30,7 @@ class Account extends ImmutablePureComponent {
|
|||
account: ImmutablePropTypes.map.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
onMuteNotifications: PropTypes.func.isRequired,
|
||||
|
@ -39,12 +41,20 @@ class Account extends ImmutablePureComponent {
|
|||
onActionClick: PropTypes.func,
|
||||
};
|
||||
|
||||
handleFollow = () => {
|
||||
handleFollow = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onFollow(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubscribe = () => {
|
||||
handleSubscribe = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleBlock = () => {
|
||||
|
@ -91,7 +101,10 @@ class Account extends ImmutablePureComponent {
|
|||
}
|
||||
} else if (account.get('id') !== me && account.get('relationship', null) !== null) {
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const subscribing = account.getIn(['relationship', 'subscribing']);
|
||||
const delivery = account.getIn(['relationship', 'delivery_following']);
|
||||
const followed_by = account.getIn(['relationship', 'followed_by']) && show_followed_by;
|
||||
const subscribing = account.getIn(['relationship', 'subscribing'], new Map).size > 0;
|
||||
const subscribing_home = account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0;
|
||||
const requested = account.getIn(['relationship', 'requested']);
|
||||
const blocking = account.getIn(['relationship', 'blocking']);
|
||||
const muting = account.getIn(['relationship', 'muting']);
|
||||
|
@ -116,10 +129,10 @@ class Account extends ImmutablePureComponent {
|
|||
} else {
|
||||
let following_buttons, subscribing_buttons;
|
||||
if (!account.get('moved') || subscribing ) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} />;
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} no_delivery={subscribing && !subscribing_home} />;
|
||||
}
|
||||
if (!account.get('moved') || following) {
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} />;
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} passive={followed_by} no_delivery={following && !delivery} />;
|
||||
}
|
||||
buttons = <span>{subscribing_buttons}{following_buttons}</span>
|
||||
}
|
||||
|
|
|
@ -4,7 +4,13 @@ import PropTypes from 'prop-types';
|
|||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { me, show_follow_button_on_timeline, show_subscribe_button_on_timeline } from '../initial_state';
|
||||
import {
|
||||
me,
|
||||
show_follow_button_on_timeline,
|
||||
show_subscribe_button_on_timeline,
|
||||
show_followed_by,
|
||||
follow_button_to_list_adder,
|
||||
} from '../initial_state';
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
|
@ -21,6 +27,7 @@ class AccountActionBar extends ImmutablePureComponent {
|
|||
account: ImmutablePropTypes.map.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
@ -28,12 +35,20 @@ class AccountActionBar extends ImmutablePureComponent {
|
|||
'account',
|
||||
]
|
||||
|
||||
handleFollow = () => {
|
||||
handleFollow = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onFollow(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubscribe = () => {
|
||||
handleSubscribe = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -47,17 +62,20 @@ class AccountActionBar extends ImmutablePureComponent {
|
|||
|
||||
if (account.get('id') !== me && account.get('relationship', null) !== null) {
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const subscribing = account.getIn(['relationship', 'subscribing']);
|
||||
const delivery = account.getIn(['relationship', 'delivery_following']);
|
||||
const followed_by = account.getIn(['relationship', 'followed_by']) && show_followed_by;
|
||||
const subscribing = account.getIn(['relationship', 'subscribing'], new Map).size > 0;
|
||||
const subscribing_home = account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0;
|
||||
const requested = account.getIn(['relationship', 'requested']);
|
||||
|
||||
if (show_subscribe_button_on_timeline && (!account.get('moved') || subscribing)) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} />;
|
||||
if (!account.get('moved') || subscribing) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} no_delivery={subscribing && !subscribing_home} />;
|
||||
}
|
||||
if (show_follow_button_on_timeline && (!account.get('moved') || following)) {
|
||||
if (!account.get('moved') || following) {
|
||||
if (requested) {
|
||||
following_buttons = <IconButton disabled icon='hourglass' title={intl.formatMessage(messages.requested)} />;
|
||||
following_buttons = <IconButton disabled icon='hourglass' title={intl.formatMessage(messages.requested)} active={followed_by} />;
|
||||
} else {
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} />;
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} passive={followed_by} no_delivery={following && !delivery} />;
|
||||
}
|
||||
}
|
||||
buttons = <span>{subscribing_buttons}{following_buttons}</span>
|
||||
|
|
|
@ -16,6 +16,8 @@ export default class IconButton extends React.PureComponent {
|
|||
onKeyPress: PropTypes.func,
|
||||
size: PropTypes.number,
|
||||
active: PropTypes.bool,
|
||||
passive: PropTypes.bool,
|
||||
no_delivery: PropTypes.bool,
|
||||
pressed: PropTypes.bool,
|
||||
expanded: PropTypes.bool,
|
||||
style: PropTypes.object,
|
||||
|
@ -32,6 +34,8 @@ export default class IconButton extends React.PureComponent {
|
|||
static defaultProps = {
|
||||
size: 18,
|
||||
active: false,
|
||||
passive: false,
|
||||
no_delivery: false,
|
||||
disabled: false,
|
||||
animate: false,
|
||||
overlay: false,
|
||||
|
@ -92,11 +96,13 @@ export default class IconButton extends React.PureComponent {
|
|||
const {
|
||||
active,
|
||||
className,
|
||||
no_delivery,
|
||||
disabled,
|
||||
expanded,
|
||||
icon,
|
||||
inverted,
|
||||
overlay,
|
||||
passive,
|
||||
pressed,
|
||||
tabIndex,
|
||||
title,
|
||||
|
@ -111,6 +117,8 @@ export default class IconButton extends React.PureComponent {
|
|||
|
||||
const classes = classNames(className, 'icon-button', {
|
||||
active,
|
||||
passive,
|
||||
no_delivery,
|
||||
disabled,
|
||||
inverted,
|
||||
activate,
|
||||
|
|
|
@ -113,8 +113,7 @@ class Status extends ImmutablePureComponent {
|
|||
onToggleHidden: PropTypes.func,
|
||||
onToggleCollapsed: PropTypes.func,
|
||||
onQuoteToggleHidden: PropTypes.func,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
muted: PropTypes.bool,
|
||||
hidden: PropTypes.bool,
|
||||
unread: PropTypes.bool,
|
||||
|
@ -349,14 +348,6 @@ class Status extends ImmutablePureComponent {
|
|||
this.node = c;
|
||||
}
|
||||
|
||||
handleFollow = () => {
|
||||
this.props.onFollow(this._properStatus().get('account'));
|
||||
}
|
||||
|
||||
handleSubscribe = () => {
|
||||
this.props.onSubscribe(this._properStatus().get('account'));
|
||||
}
|
||||
|
||||
render () {
|
||||
let media = null;
|
||||
let statusAvatar, prepend, rebloggedByText;
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { openModal } from '../actions/modal';
|
||||
import { initMuteModal } from '../actions/mutes';
|
||||
import { unfollowModal, unsubscribeModal } from '../initial_state';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
|
@ -51,7 +52,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onSubscribe (account) {
|
||||
if (account.getIn(['relationship', 'subscribing'])) {
|
||||
if (account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0) {
|
||||
if (unsubscribeModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unsubscribe.message' defaultMessage='Are you sure you want to unsubscribe {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
|
@ -66,6 +67,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
onAddToList (account){
|
||||
dispatch(openModal('LIST_ADDER', {
|
||||
accountId: account.get('id'),
|
||||
}));
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
|
|
|
@ -50,6 +50,7 @@ import { deployPictureInPicture } from '../actions/picture_in_picture';
|
|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { boostModal, deleteModal, unfollowModal, unsubscribeModal } from '../initial_state';
|
||||
import { showAlertForError } from '../actions/alerts';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
|
@ -268,7 +269,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onSubscribe (account) {
|
||||
if (account.getIn(['relationship', 'subscribing'])) {
|
||||
if (account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0) {
|
||||
if (unsubscribeModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unsubscribe.message' defaultMessage='Are you sure you want to unsubscribe {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
|
@ -282,6 +283,13 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
dispatch(subscribeAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onAddToList (account){
|
||||
dispatch(openModal('LIST_ADDER', {
|
||||
accountId: account.get('id'),
|
||||
}));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));
|
||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Button from 'mastodon/components/button';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { autoPlayGif, me, isStaff } from 'mastodon/initial_state';
|
||||
import { autoPlayGif, me, isStaff, show_followed_by, follow_button_to_list_adder } from 'mastodon/initial_state';
|
||||
import classNames from 'classnames';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
import IconButton from 'mastodon/components/icon_button';
|
||||
|
@ -14,6 +14,7 @@ import ShortNumber from 'mastodon/components/short_number';
|
|||
import { NavLink } from 'react-router-dom';
|
||||
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
||||
import AccountNoteContainer from '../containers/account_note_container';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
|
@ -71,6 +72,7 @@ class Header extends ImmutablePureComponent {
|
|||
identity_props: ImmutablePropTypes.list,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
|
@ -125,6 +127,26 @@ class Header extends ImmutablePureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
handleFollow = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onFollow(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubscribe = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
setRef = (c) => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, intl, domain, identity_proofs } = this.props;
|
||||
|
||||
|
@ -212,9 +234,10 @@ class Header extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
|
||||
menu.push(null);
|
||||
}
|
||||
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
|
||||
menu.push(null);
|
||||
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.props.onMute });
|
||||
|
@ -264,17 +287,20 @@ class Header extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const subscribing = account.getIn(['relationship', 'subscribing']);
|
||||
const delivery = account.getIn(['relationship', 'delivery_following']);
|
||||
const followed_by = account.getIn(['relationship', 'followed_by']) && show_followed_by;
|
||||
const subscribing = account.getIn(['relationship', 'subscribing'], new Map).size > 0;
|
||||
const subscribing_home = account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0;
|
||||
const blockd_by = account.getIn(['relationship', 'blocked_by']);
|
||||
let buttons;
|
||||
|
||||
if(me !== account.get('id') && !blockd_by) {
|
||||
let following_buttons, subscribing_buttons;
|
||||
if(!account.get('moved') || subscribing) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.props.onSubscribe} active={subscribing} />;
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} no_delivery={subscribing && !subscribing_home} />;
|
||||
}
|
||||
if(!account.get('moved') || following) {
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} active={following} />;
|
||||
following_buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} passive={followed_by} no_delivery={following && !delivery} />;
|
||||
}
|
||||
buttons = <span>{subscribing_buttons}{following_buttons}</span>
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import PropTypes from 'prop-types';
|
||||
import InnerHeader from '../../account/components/header';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { follow_button_to_list_adder } from 'mastodon/initial_state';
|
||||
import MovedNote from './moved_note';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
@ -14,6 +15,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
identity_proofs: ImmutablePropTypes.list,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
|
@ -32,12 +34,20 @@ export default class Header extends ImmutablePureComponent {
|
|||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
handleFollow = () => {
|
||||
handleFollow = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onFollow(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubscribe = () => {
|
||||
handleSubscribe = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
}
|
||||
|
||||
handleBlock = () => {
|
||||
|
|
|
@ -62,7 +62,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onSubscribe (account) {
|
||||
if (account.getIn(['relationship', 'subscribing'])) {
|
||||
if (account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0) {
|
||||
if (unsubscribeModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unsubscribe.message' defaultMessage='Are you sure you want to unsubscribe {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
|
@ -77,6 +77,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
onAddToList (account){
|
||||
dispatch(openModal('LIST_ADDER', {
|
||||
accountId: account.get('id'),
|
||||
}));
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
|
|
|
@ -10,7 +10,7 @@ import Permalink from 'mastodon/components/permalink';
|
|||
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
|
||||
import IconButton from 'mastodon/components/icon_button';
|
||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
import { autoPlayGif, me, unfollowModal, unsubscribeModal } from 'mastodon/initial_state';
|
||||
import { autoPlayGif, me, unfollowModal, unsubscribeModal, show_followed_by } from 'mastodon/initial_state';
|
||||
import ShortNumber from 'mastodon/components/short_number';
|
||||
import {
|
||||
followAccount,
|
||||
|
@ -23,6 +23,7 @@ import {
|
|||
} from 'mastodon/actions/accounts';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { initMuteModal } from 'mastodon/actions/mutes';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
|
@ -36,6 +37,10 @@ const messages = defineMessages({
|
|||
id: 'confirmations.unfollow.confirm',
|
||||
defaultMessage: 'Unfollow',
|
||||
},
|
||||
unsubscribeConfirm: {
|
||||
id: 'confirmations.unsubscribe.confirm',
|
||||
defaultMessage: 'Unsubscribe'
|
||||
},
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
|
@ -77,7 +82,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onSubscribe(account) {
|
||||
if (account.getIn(['relationship', 'subscribing'])) {
|
||||
if (account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0) {
|
||||
if (unsubscribeModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unsubscribe.message' defaultMessage='Are you sure you want to unsubscribe {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
|
@ -92,6 +97,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
onAddToList(account){
|
||||
dispatch(openModal('LIST_ADDER', {
|
||||
accountId: account.get('id'),
|
||||
}));
|
||||
},
|
||||
|
||||
onBlock(account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
|
@ -119,6 +130,7 @@ class AccountCard extends ImmutablePureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
};
|
||||
|
@ -149,13 +161,21 @@ class AccountCard extends ImmutablePureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
handleFollow = () => {
|
||||
handleFollow = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onFollow(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
handleSubscribe = () => {
|
||||
handleSubscribe = (e) => {
|
||||
if ((e && e.shiftKey) || !follow_button_to_list_adder) {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
} else {
|
||||
this.props.onAddToList(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
handleBlock = () => {
|
||||
this.props.onBlock(this.props.account);
|
||||
|
@ -175,7 +195,10 @@ class AccountCard extends ImmutablePureComponent {
|
|||
account.get('relationship', null) !== null
|
||||
) {
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const subscribing = account.getIn(['relationship', 'subscribing']);
|
||||
const delivery = account.getIn(['relationship', 'delivery_following']);
|
||||
const followed_by = account.getIn(['relationship', 'followed_by']) && show_followed_by;
|
||||
const subscribing = account.getIn(['relationship', 'subscribing'], new Map).size > 0;
|
||||
const subscribing_home = account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0;
|
||||
const requested = account.getIn(['relationship', 'requested']);
|
||||
const blocking = account.getIn(['relationship', 'blocking']);
|
||||
const muting = account.getIn(['relationship', 'muting']);
|
||||
|
@ -221,6 +244,7 @@ class AccountCard extends ImmutablePureComponent {
|
|||
)}
|
||||
onClick={this.handleSubscribe}
|
||||
active={subscribing}
|
||||
no_delivery={subscribing && !subscribing_home}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -233,6 +257,8 @@ class AccountCard extends ImmutablePureComponent {
|
|||
)}
|
||||
onClick={this.handleFollow}
|
||||
active={following}
|
||||
passive={followed_by}
|
||||
no_delivery={following && !delivery}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,33 +1,79 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import { unfollowAccount, followAccount } from '../../../actions/accounts';
|
||||
import { me, show_followed_by, unfollowModal } from '../../../initial_state';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { accountId }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
const MapStateToProps = (state) => ({
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
}
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(makeMapStateToProps)
|
||||
export default @connect(MapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleFollow = () => {
|
||||
this.props.onFollow(this.props.account);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account } = this.props;
|
||||
const { account, intl } = this.props;
|
||||
|
||||
let buttons;
|
||||
|
||||
if (account.get('id') !== me && account.get('relationship', null) !== null) {
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const delivery = account.getIn(['relationship', 'delivery_following']);
|
||||
const followed_by = account.getIn(['relationship', 'followed_by']) && show_followed_by;
|
||||
const requested = account.getIn(['relationship', 'requested']);
|
||||
|
||||
if (!account.get('moved') || following) {
|
||||
if (requested) {
|
||||
buttons = <IconButton icon='hourglass' title={intl.formatMessage(messages.requested)} active={followed_by} onClick={this.handleFollow} />;
|
||||
} else {
|
||||
buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} passive={followed_by} no_delivery={following && !delivery} />;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
|
@ -35,6 +81,10 @@ class Account extends ImmutablePureComponent {
|
|||
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||
<DisplayName account={account} />
|
||||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{buttons}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
108
app/javascript/mastodon/features/list_adder/components/home.js
Normal file
108
app/javascript/mastodon/features/list_adder/components/home.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { followAccount, unsubscribeAccount, subscribeAccount } from '../../../actions/accounts';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.home', defaultMessage: 'Home' },
|
||||
remove: { id: 'home.account.remove', defaultMessage: 'Remove from home' },
|
||||
add: { id: 'home.account.add', defaultMessage: 'Add to home' },
|
||||
unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe' },
|
||||
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe' },
|
||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||
});
|
||||
|
||||
const MapStateToProps = (state, { account }) => ({
|
||||
added: account.getIn(['relationship', 'delivery_following'], false),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onRemove (account) {
|
||||
dispatch(followAccount(account.get('id'), { delivery: false }));
|
||||
},
|
||||
|
||||
onAdd (account) {
|
||||
dispatch(followAccount(account.get('id'), { delivery: true }));
|
||||
},
|
||||
|
||||
onSubscribe (account) {
|
||||
if (account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0) {
|
||||
dispatch(unsubscribeAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(subscribeAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(MapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Home extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
disabled: true,
|
||||
};
|
||||
|
||||
handleRemove = () => {
|
||||
this.props.onRemove(this.props.account);
|
||||
}
|
||||
|
||||
handleAdd = () => {
|
||||
this.props.onAdd(this.props.account);
|
||||
}
|
||||
|
||||
handleSubscribe = () => {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, intl, added, disabled } = this.props;
|
||||
|
||||
const subscribing_home = account.getIn(['relationship', 'subscribing', '-1'], new Map).size > 0;
|
||||
|
||||
let button, subscribing_buttons;
|
||||
|
||||
if (!account.get('moved') || subscribing_home) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing_home ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing_home} />;
|
||||
}
|
||||
if (added) {
|
||||
button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={this.handleRemove} active />;
|
||||
} else if (disabled) {
|
||||
button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={this.handleAdd} />;
|
||||
} else {
|
||||
button = '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='list'>
|
||||
<div className='list__wrapper'>
|
||||
<div className='list__display-name'>
|
||||
<Icon id='home' className='column-link__icon' fixedWidth />
|
||||
{intl.formatMessage(messages.title)}
|
||||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{subscribing_buttons}
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,12 +5,16 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { unsubscribeAccount, subscribeAccount } from '../../../actions/accounts';
|
||||
import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
add: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe' },
|
||||
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe' },
|
||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||
});
|
||||
|
||||
const MapStateToProps = (state, { listId, added }) => ({
|
||||
|
@ -21,6 +25,14 @@ const MapStateToProps = (state, { listId, added }) => ({
|
|||
const mapDispatchToProps = (dispatch, { listId }) => ({
|
||||
onRemove: () => dispatch(removeFromListAdder(listId)),
|
||||
onAdd: () => dispatch(addToListAdder(listId)),
|
||||
|
||||
onSubscribe (account) {
|
||||
if (account.getIn(['relationship', 'subscribing', listId], new Map).size > 0) {
|
||||
dispatch(unsubscribeAccount(account.get('id'), listId));
|
||||
} else {
|
||||
dispatch(subscribeAccount(account.get('id'), true, listId));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(MapStateToProps, mapDispatchToProps)
|
||||
|
@ -28,26 +40,41 @@ export default @connect(MapStateToProps, mapDispatchToProps)
|
|||
class List extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
list: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
onSubscribe: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
disabled: true,
|
||||
};
|
||||
|
||||
handleSubscribe = () => {
|
||||
this.props.onSubscribe(this.props.account);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { list, intl, onRemove, onAdd, added } = this.props;
|
||||
const { account, list, intl, onRemove, onAdd, added, disabled } = this.props;
|
||||
|
||||
let button;
|
||||
const subscribing = account.getIn(['relationship', 'subscribing', list.get('id')], new Map).size > 0;
|
||||
|
||||
let button, subscribing_buttons;
|
||||
|
||||
if (!account.get('moved') || subscribing) {
|
||||
subscribing_buttons = <IconButton icon='rss-square' title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe)} onClick={this.handleSubscribe} active={subscribing} />;
|
||||
}
|
||||
if (added) {
|
||||
button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
|
||||
} else {
|
||||
button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} active />;
|
||||
} else if (disabled) {
|
||||
button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
|
||||
} else {
|
||||
button = '';
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -59,6 +86,7 @@ class List extends ImmutablePureComponent {
|
|||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{subscribing_buttons}
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { injectIntl } from 'react-intl';
|
||||
import { setupListAdder, resetListAdder } from '../../actions/lists';
|
||||
import { createSelector } from 'reselect';
|
||||
import { makeGetAccount } from '../../selectors';
|
||||
import Home from './components/home';
|
||||
import List from './components/list';
|
||||
import Account from './components/account';
|
||||
import NewListForm from '../lists/components/new_list_form';
|
||||
|
@ -19,7 +21,10 @@ const getOrderedLists = createSelector([state => state.get('lists')], lists => {
|
|||
return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { accountId }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
listIds: getOrderedLists(state).map(list=>list.get('id')),
|
||||
});
|
||||
|
||||
|
@ -33,7 +38,7 @@ export default @connect(mapStateToProps, mapDispatchToProps)
|
|||
class ListAdder extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
accountId: PropTypes.string.isRequired,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
|
@ -42,8 +47,8 @@ class ListAdder extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { onInitialize, accountId } = this.props;
|
||||
onInitialize(accountId);
|
||||
const { onInitialize, account } = this.props;
|
||||
onInitialize(account.get('id'));
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -52,19 +57,21 @@ class ListAdder extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { accountId, listIds } = this.props;
|
||||
const { account, listIds, intl } = this.props;
|
||||
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal list-adder'>
|
||||
<div className='list-adder__account'>
|
||||
<Account accountId={accountId} />
|
||||
<Account account={account} intl={intl} />
|
||||
</div>
|
||||
|
||||
<NewListForm />
|
||||
|
||||
|
||||
<div className='list-adder__lists'>
|
||||
{listIds.map(ListId => <List key={ListId} listId={ListId} />)}
|
||||
<Home account={account} disabled={following} intl={intl} />
|
||||
{listIds.map(ListId => <List key={ListId} account={account} listId={ListId} disabled={following} intl={intl} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,6 +30,8 @@ export const cropImages = getMeta('crop_images');
|
|||
export const disableSwiping = getMeta('disable_swiping');
|
||||
export const show_follow_button_on_timeline = getMeta('show_follow_button_on_timeline');
|
||||
export const show_subscribe_button_on_timeline = getMeta('show_subscribe_button_on_timeline');
|
||||
export const show_followed_by = getMeta('show_followed_by');
|
||||
export const follow_button_to_list_adder = getMeta('follow_button_to_list_adder');
|
||||
export const show_target = getMeta('show_target');
|
||||
|
||||
export default initialState;
|
||||
|
|
|
@ -209,6 +209,8 @@
|
|||
"hashtag.column_settings.tag_mode.any": "Any of these",
|
||||
"hashtag.column_settings.tag_mode.none": "None of these",
|
||||
"hashtag.column_settings.tag_toggle": "Include additional tags for this column",
|
||||
"home.account.add": "Add to home",
|
||||
"home.account.remove": "Remove from home",
|
||||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.show_reblogs": "Show boosts",
|
||||
"home.column_settings.show_replies": "Show replies",
|
||||
|
|
|
@ -209,6 +209,8 @@
|
|||
"hashtag.column_settings.tag_mode.any": "いずれかを含む",
|
||||
"hashtag.column_settings.tag_mode.none": "これらを除く",
|
||||
"hashtag.column_settings.tag_toggle": "このカラムに追加のタグを含める",
|
||||
"home.account.add": "ホームに追加",
|
||||
"home.account.remove": "ホームから外す",
|
||||
"home.column_settings.basic": "基本設定",
|
||||
"home.column_settings.show_reblogs": "ブースト表示",
|
||||
"home.column_settings.show_replies": "返信表示",
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {
|
||||
ACCOUNT_FOLLOW_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
ACCOUNT_SUBSCRIBE_SUCCESS,
|
||||
ACCOUNT_UNSUBSCRIBE_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
@ -33,6 +35,11 @@ export default function accountsCounters(state = initialState, action) {
|
|||
state.updateIn([action.relationship.id, 'followers_count'], num => num + 1);
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
return state.updateIn([action.relationship.id, 'followers_count'], num => Math.max(0, num - 1));
|
||||
case ACCOUNT_SUBSCRIBE_SUCCESS:
|
||||
return action.alreadySubscribe ? state :
|
||||
state.updateIn([action.relationship.id, 'subscribing_count'], num => num + 1);
|
||||
case ACCOUNT_UNSUBSCRIBE_SUCCESS:
|
||||
return state.updateIn([action.relationship.id, 'subscribing_count'], num => Math.max(0, num - 1));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -202,6 +202,24 @@
|
|||
color: $highlight-text-color;
|
||||
}
|
||||
|
||||
&.passive {
|
||||
color: $passive-text-color;
|
||||
}
|
||||
|
||||
&.active.passive {
|
||||
color: $active-passive-text-color;
|
||||
}
|
||||
|
||||
&.active.no_delivery {
|
||||
color: rgba($highlight-text-color, 33%);
|
||||
-webkit-text-stroke: 1px $highlight-text-color;
|
||||
}
|
||||
|
||||
&.active.passive.no_delivery {
|
||||
color: rgba($active-passive-text-color, 33%);
|
||||
-webkit-text-stroke: 1px $active-passive-text-color;
|
||||
}
|
||||
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
@ -1630,6 +1648,13 @@ a.account__display-name {
|
|||
top: 60px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
|
||||
&.account__action-bar_home,
|
||||
&.account__action-bar_list {
|
||||
left: unset;
|
||||
right: 10px;
|
||||
top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.status__avatar {
|
||||
|
@ -6564,6 +6589,7 @@ noscript {
|
|||
|
||||
.list__wrapper {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.list__display-name {
|
||||
|
|
|
@ -185,6 +185,16 @@ body.rtl {
|
|||
left: 0;
|
||||
}
|
||||
|
||||
.account__action-bar {
|
||||
right: 10px;
|
||||
|
||||
&.account__action-bar_home,
|
||||
&.account__action-bar_list {
|
||||
left: 10px;
|
||||
right: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.status__relative-time,
|
||||
.status__visibility-icon,
|
||||
.activity-stream .status.light .status__header .status__meta {
|
||||
|
|
|
@ -236,7 +236,7 @@ class FeedManager
|
|||
add_to_feed(:home, account.id, status, aggregate)
|
||||
end
|
||||
|
||||
account.following.includes(:account_stat).find_each do |target_account|
|
||||
account.delivery_following.includes(:account_stat).find_each do |target_account|
|
||||
if redis.zcard(timeline_key) >= limit
|
||||
oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i
|
||||
last_status_score = Mastodon::Snowflake.id_at(account.last_status_at)
|
||||
|
|
|
@ -42,6 +42,8 @@ class UserSettingsDecorator
|
|||
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
|
||||
user.settings['show_follow_button_on_timeline'] = show_follow_button_on_timeline_preference if change?('setting_show_follow_button_on_timeline')
|
||||
user.settings['show_subscribe_button_on_timeline'] = show_subscribe_button_on_timeline_preference if change?('setting_show_subscribe_button_on_timeline')
|
||||
user.settings['show_followed_by'] = show_followed_by_preference if change?('setting_show_followed_by')
|
||||
user.settings['follow_button_to_list_adder'] = follow_button_to_list_adder_preference if change?('setting_follow_button_to_list_adder')
|
||||
user.settings['show_target'] = show_target_preference if change?('setting_show_target')
|
||||
end
|
||||
|
||||
|
@ -153,6 +155,14 @@ class UserSettingsDecorator
|
|||
boolean_cast_setting 'setting_show_subscribe_button_on_timeline'
|
||||
end
|
||||
|
||||
def show_followed_by_preference
|
||||
boolean_cast_setting 'setting_show_followed_by'
|
||||
end
|
||||
|
||||
def follow_button_to_list_adder_preference
|
||||
boolean_cast_setting 'setting_follow_button_to_list_adder'
|
||||
end
|
||||
|
||||
def show_target_preference
|
||||
boolean_cast_setting 'setting_show_target'
|
||||
end
|
||||
|
|
|
@ -24,7 +24,13 @@ module AccountInteractions
|
|||
end
|
||||
|
||||
def subscribing_map(target_account_ids, account_id)
|
||||
follow_mapping(AccountSubscribe.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id)
|
||||
AccountSubscribe.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |subscribe, mapping|
|
||||
mapping[subscribe.target_account_id] = (mapping[subscribe.target_account_id] || {}).merge({
|
||||
subscribe.list_id || -1 => {
|
||||
reblogs: subscribe.show_reblogs?,
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def blocking_map(target_account_ids, account_id)
|
||||
|
@ -135,7 +141,7 @@ module AccountInteractions
|
|||
rel
|
||||
end
|
||||
|
||||
def request_follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false, bypass_limit: false)
|
||||
def request_follow!(other_account, reblogs: nil, notify: nil, delivery: nil, uri: nil, rate_limit: false, bypass_limit: false)
|
||||
rel = follow_requests.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, delivery: delivery.nil? ? true : delivery, uri: uri, rate_limit: rate_limit, bypass_follow_limit: bypass_limit)
|
||||
.find_or_create_by!(target_account: other_account)
|
||||
|
||||
|
@ -205,9 +211,11 @@ module AccountInteractions
|
|||
block&.destroy
|
||||
end
|
||||
|
||||
def subscribe!(other_account, show_reblogs = true, list_id = nil)
|
||||
rel = active_subscribes.find_or_create_by!(target_account: other_account, show_reblogs: show_reblogs, list_id: list_id)
|
||||
def subscribe!(other_account, reblogs = true, list_id = nil)
|
||||
rel = active_subscribes.create_with(show_reblogs: reblogs)
|
||||
.find_or_create_by!(target_account: other_account, list_id: list_id)
|
||||
|
||||
rel.update!(show_reblogs: reblogs)
|
||||
remove_potential_friendship(other_account)
|
||||
|
||||
rel
|
||||
|
|
|
@ -23,6 +23,15 @@ class List < ApplicationRecord
|
|||
has_many :list_accounts, inverse_of: :list, dependent: :destroy
|
||||
has_many :accounts, through: :list_accounts
|
||||
|
||||
has_many :account_subscribes, inverse_of: :list, dependent: :destroy
|
||||
has_many :subscribes, through: :account_subscribes, source: :target_account
|
||||
|
||||
has_many :follow_tags, inverse_of: :list, dependent: :destroy
|
||||
has_many :tags, through: :follow_tags, source: :tag
|
||||
|
||||
has_many :domain_subscribes, inverse_of: :list, dependent: :destroy
|
||||
has_many :keyword_subscribes, inverse_of: :list, dependent: :destroy
|
||||
|
||||
validates :title, presence: true
|
||||
|
||||
validates_each :account_id, on: :create do |record, _attr, value|
|
||||
|
|
|
@ -127,6 +127,8 @@ class User < ApplicationRecord
|
|||
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
||||
:disable_swiping,
|
||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
|
||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
|
||||
:follow_button_to_list_adder,
|
||||
to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
attr_reader :invite_code, :sign_in_token_attempt
|
||||
|
|
|
@ -44,6 +44,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:crop_images] = object.current_account.user.setting_crop_images
|
||||
store[:show_follow_button_on_timeline] = object.current_account.user.setting_show_follow_button_on_timeline
|
||||
store[:show_subscribe_button_on_timeline] = object.current_account.user.setting_show_subscribe_button_on_timeline
|
||||
store[:show_followed_by] = object.current_account.user.setting_show_followed_by
|
||||
store[:follow_button_to_list_adder] = object.current_account.user.setting_follow_button_to_list_adder
|
||||
store[:show_target] = object.current_account.user.setting_show_target
|
||||
else
|
||||
store[:auto_play_gif] = Setting.auto_play_gif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class REST::RelationshipSerializer < ActiveModel::Serializer
|
||||
attributes :id, :following, :showing_reblogs, :notifying, :followed_by, :subscribing,
|
||||
attributes :id, :following, :delivery_following, :showing_reblogs, :notifying, :followed_by, :subscribing,
|
||||
:blocking, :blocked_by, :muting, :muting_notifications, :requested,
|
||||
:domain_blocking, :endorsed, :note
|
||||
|
||||
|
@ -13,6 +13,12 @@ class REST::RelationshipSerializer < ActiveModel::Serializer
|
|||
instance_options[:relationships].following[object.id] ? true : false
|
||||
end
|
||||
|
||||
def delivery_following
|
||||
(instance_options[:relationships].following[object.id] || {})[:delivery] ||
|
||||
(instance_options[:relationships].requested[object.id] || {})[:delivery] ||
|
||||
false
|
||||
end
|
||||
|
||||
def showing_reblogs
|
||||
(instance_options[:relationships].following[object.id] || {})[:reblogs] ||
|
||||
(instance_options[:relationships].requested[object.id] || {})[:reblogs] ||
|
||||
|
@ -30,7 +36,7 @@ class REST::RelationshipSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def subscribing
|
||||
instance_options[:relationships].subscribing[object.id] ? true : false
|
||||
instance_options[:relationships].subscribing[object.id] || {}
|
||||
end
|
||||
|
||||
def blocking
|
||||
|
|
|
@ -4,7 +4,9 @@ class AccountSubscribeService < BaseService
|
|||
# Subscribe a remote user
|
||||
# @param [Account] source_account From which to subscribe
|
||||
# @param [String, Account] uri User URI to subscribe in the form of username@domain (or account record)
|
||||
def call(source_account, target_acct, show_reblogs = true, list_id = nil)
|
||||
def call(source_account, target_acct, options = {})
|
||||
@options = { show_reblogs: true, list_id: nil }.merge(options)
|
||||
|
||||
if target_acct.class.name == 'Account'
|
||||
target_account = target_acct
|
||||
else
|
||||
|
@ -19,14 +21,14 @@ class AccountSubscribeService < BaseService
|
|||
raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
|
||||
raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || (!target_account.local? && target_account.ostatus?) || source_account.domain_blocking?(target_account.domain)
|
||||
|
||||
if source_account.subscribing?(target_account, list_id)
|
||||
if source_account.subscribing?(target_account, @options[:list_id])
|
||||
return
|
||||
end
|
||||
|
||||
ActivityTracker.increment('activity:interactions')
|
||||
|
||||
subscribe = source_account.subscribe!(target_account, show_reblogs, list_id)
|
||||
MergeWorker.perform_async(target_account.id, source_account.id, true) if list_id.nil?
|
||||
subscribe = source_account.subscribe!(target_account, @options[:show_reblogs], @options[:list_id])
|
||||
MergeWorker.perform_async(target_account.id, source_account.id, true) if @options[:list_id].nil?
|
||||
subscribe
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,10 +14,11 @@ class FollowService < BaseService
|
|||
# @option [Boolean] :bypass_locked
|
||||
# @option [Boolean] :bypass_limit Allow following past the total follow number
|
||||
# @option [Boolean] :with_rate_limit
|
||||
# @option [Boolean] :delivery
|
||||
def call(source_account, target_account, options = {})
|
||||
@source_account = source_account
|
||||
@target_account = target_account
|
||||
@options = { bypass_locked: false, bypass_limit: false, with_rate_limit: false }.merge(options)
|
||||
@options = { bypass_locked: false, delivery: true, bypass_limit: false, with_rate_limit: false }.merge(options)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if following_not_possible?
|
||||
raise Mastodon::NotPermittedError if following_not_allowed?
|
||||
|
|
|
@ -4,13 +4,13 @@ class UnsubscribeAccountService < BaseService
|
|||
# UnsubscribeAccount
|
||||
# @param [Account] source_account Where to unsubscribe from
|
||||
# @param [Account] target_account Which to unsubscribe
|
||||
def call(source_account, target_account)
|
||||
subscribe = AccountSubscribe.find_by(account: source_account, target_account: target_account)
|
||||
def call(source_account, target_account, list_id = nil)
|
||||
subscribe = AccountSubscribe.find_by(account: source_account, target_account: target_account, list_id: list_id)
|
||||
|
||||
return unless subscribe
|
||||
|
||||
subscribe.destroy!
|
||||
UnmergeWorker.perform_async(target_account.id, source_account.id)
|
||||
UnmergeWorker.perform_async(target_account.id, source_account.id) if list_id.nil?
|
||||
subscribe
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
.fields-group
|
||||
= f.input :setting_show_subscribe_button_on_timeline, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_show_followed_by, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_follow_button_to_list_adder, as: :boolean, wrapper: :with_label
|
||||
|
||||
-# .fields-group
|
||||
-# = f.input :setting_show_target, as: :boolean, wrapper: :with_label
|
||||
|
||||
|
|
|
@ -51,11 +51,13 @@ en:
|
|||
setting_display_media_default: Hide media marked as sensitive
|
||||
setting_display_media_hide_all: Always hide media
|
||||
setting_display_media_show_all: Always show media
|
||||
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_network: Who you follow and who follows you will be hidden on your profile
|
||||
setting_noindex: Affects your public profile and post pages
|
||||
setting_show_application: The application you use to post will be displayed in the detailed view of your posts
|
||||
setting_show_follow_button_on_timeline: You can easily check the follow status and build a follow list quickly
|
||||
setting_show_subscribe_button_on_timeline: You can easily check the status of your subscriptions and quickly build a subscription list
|
||||
setting_show_followed_by: "The color of the follow button changes according to the follow status (gray: no follow relationship, yellow: followed, blue: following, green: mutual follow)"
|
||||
setting_show_target: Enable the function to switch between posting target and follow / subscribe target
|
||||
setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details
|
||||
setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
|
||||
|
@ -176,12 +178,14 @@ 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_follow_button_to_list_adder: Open list add dialog with follow button
|
||||
setting_hide_network: Hide your social graph
|
||||
setting_noindex: Opt-out of search engine indexing
|
||||
setting_reduce_motion: Reduce motion in animations
|
||||
setting_show_application: Disclose application used to send posts
|
||||
setting_show_follow_button_on_timeline: Show follow button on timeline
|
||||
setting_show_subscribe_button_on_timeline: Show subscribe button on timeline
|
||||
setting_show_followed_by: Reflect the following status on the follow button
|
||||
setting_show_target: Enable targeting features
|
||||
setting_system_font_ui: Use system's default font
|
||||
setting_theme: Site theme
|
||||
|
|
|
@ -51,11 +51,13 @@ ja:
|
|||
setting_display_media_default: 閲覧注意としてマークされたメディアは隠す
|
||||
setting_display_media_hide_all: メディアを常に隠す
|
||||
setting_display_media_show_all: メディアを常に表示する
|
||||
setting_follow_button_to_list_adder: フォロー・購読ボタンの動作を変更し、フォロー・購読するリストを選択したり、ホームで受け取らないよう設定するダイアログを開きます
|
||||
setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
|
||||
setting_noindex: 公開プロフィールおよび各投稿ページに影響します
|
||||
setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります
|
||||
setting_show_follow_button_on_timeline: フォロー状態を確認し易くなり、素早くフォローリストを構築できます
|
||||
setting_show_subscribe_button_on_timeline: 購読状態を確認し易くなり、素早く購読リストを構築できます
|
||||
setting_show_followed_by: フォロー状態に応じてフォローボタンの色が変わります(灰色:フォロー関係なし、黄色:フォローされている、青色:フォローしている、緑色:相互フォロー)
|
||||
setting_show_target: 投稿対象と、フォロー・購読の対象を切り替える機能を有効にします
|
||||
setting_use_blurhash: ぼかしはメディアの色を元に生成されますが、細部は見えにくくなっています
|
||||
setting_use_pending_items: 新着があってもタイムラインを自動的にスクロールしないようにします
|
||||
|
@ -176,12 +178,14 @@ ja:
|
|||
setting_display_media_hide_all: 非表示
|
||||
setting_display_media_show_all: 表示
|
||||
setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する
|
||||
setting_follow_button_to_list_adder: フォローボタンでリスト追加ダイアログを開く
|
||||
setting_hide_network: 繋がりを隠す
|
||||
setting_noindex: 検索エンジンによるインデックスを拒否する
|
||||
setting_reduce_motion: アニメーションの動きを減らす
|
||||
setting_show_application: 送信したアプリを開示する
|
||||
setting_show_follow_button_on_timeline: タイムライン上にフォローボタンを表示する
|
||||
setting_show_subscribe_button_on_timeline: タイムライン上に購読ボタンを表示する
|
||||
setting_show_followed_by: 被フォロー状態をフォローボタンに反映する
|
||||
setting_show_target: ターゲット機能を有効にする
|
||||
setting_system_font_ui: システムのデフォルトフォントを使う
|
||||
setting_theme: サイトテーマ
|
||||
|
|
|
@ -480,6 +480,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :lists, only: [:index, :create, :show, :update, :destroy] do
|
||||
resource :accounts, only: [:show, :create, :destroy], controller: 'lists/accounts'
|
||||
resource :subscribes, only: [:show, :create, :destroy], controller: 'lists/subscribes'
|
||||
end
|
||||
|
||||
namespace :featured_tags do
|
||||
|
|
|
@ -41,6 +41,8 @@ defaults: &defaults
|
|||
crop_images: true
|
||||
show_follow_button_on_timeline: false
|
||||
show_subscribe_button_on_timeline: false
|
||||
show_followed_by: false
|
||||
follow_button_to_list_adder: false
|
||||
show_target: false
|
||||
notification_emails:
|
||||
follow: false
|
||||
|
|
9
db/migrate/20200312020757_add_index_url_to_statuses.rb
Normal file
9
db/migrate/20200312020757_add_index_url_to_statuses.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexUrlToStatuses < ActiveRecord::Migration[5.2]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :statuses, :url, algorithm: :concurrently
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue