Add media filter to bookmark, favorite, emoji_reaction and personal column
This commit is contained in:
parent
45986dc4dc
commit
fc11b20384
23 changed files with 484 additions and 79 deletions
|
@ -28,20 +28,43 @@ class Api::V1::BookmarksController < Api::BaseController
|
|||
end
|
||||
|
||||
def results
|
||||
@_results ||= account_bookmarks.joins(:status).eager_load(:status).to_a_paginated_by_id(
|
||||
@_results ||= filtered_account_bookmarks.to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
end
|
||||
|
||||
def filtered_account_bookmarks
|
||||
account_bookmarks.joins(:status).eager_load(:status).tap do |scope|
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
scope.merge!(without_media_scope) if without_media?
|
||||
end
|
||||
end
|
||||
|
||||
def account_bookmarks
|
||||
current_account.bookmarks
|
||||
end
|
||||
|
||||
def media_only?
|
||||
truthy_param?(:only_media)
|
||||
end
|
||||
|
||||
def without_media?
|
||||
truthy_param?(:without_media)
|
||||
end
|
||||
|
||||
def compact?
|
||||
truthy_param?(:compact)
|
||||
end
|
||||
|
||||
def media_only_scope
|
||||
Status.joins(:media_attachments)
|
||||
end
|
||||
|
||||
def without_media_scope
|
||||
Status.left_joins(:media_attachments).where(media_attachments: {status_id: nil})
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
@ -67,6 +90,6 @@ class Api::V1::BookmarksController < Api::BaseController
|
|||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit, :compact).permit(:limi, :compact).merge(core_params)
|
||||
params_slice(:limit, :compact, :only_media, :without_media).merge(core_params)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,15 +28,17 @@ class Api::V1::EmojiReactionsController < Api::BaseController
|
|||
end
|
||||
|
||||
def results
|
||||
@_results ||= filtered_emoji_reactions.joins(:status).eager_load(:status).to_a_paginated_by_id(
|
||||
@_results ||= filtered_emoji_reactions.to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
end
|
||||
|
||||
def filtered_emoji_reactions
|
||||
account_emoji_reactions.tap do |emoji_reactions|
|
||||
account_emoji_reactions.joins(:status).eager_load(:status).tap do |emoji_reactions|
|
||||
emoji_reactions.merge!(emojis_scope) if emojis_requested?
|
||||
emoji_reactions.merge!(media_only_scope) if media_only?
|
||||
emoji_reactions.merge!(without_media_scope) if without_media?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -44,10 +46,43 @@ class Api::V1::EmojiReactionsController < Api::BaseController
|
|||
current_account.emoji_reactions
|
||||
end
|
||||
|
||||
def emojis_requested?
|
||||
emoji_reactions_params[:emojis].present?
|
||||
end
|
||||
|
||||
def media_only?
|
||||
truthy_param?(:only_media)
|
||||
end
|
||||
|
||||
def without_media?
|
||||
truthy_param?(:without_media)
|
||||
end
|
||||
|
||||
def compact?
|
||||
truthy_param?(:compact)
|
||||
end
|
||||
|
||||
def emojis_scope
|
||||
emoji_reactions = EmojiReaction.none
|
||||
|
||||
emoji_reactions_params[:emojis].each do |emoji|
|
||||
shortcode, domain = emoji.split('@')
|
||||
custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: domain)
|
||||
|
||||
emoji_reactions = emoji_reactions.or(EmojiReaction.where(name: shortcode, custom_emoji: custom_emoji))
|
||||
end
|
||||
|
||||
emoji_reactions
|
||||
end
|
||||
|
||||
def media_only_scope
|
||||
Status.joins(:media_attachments)
|
||||
end
|
||||
|
||||
def without_media_scope
|
||||
Status.left_joins(:media_attachments).where(media_attachments: {status_id: nil})
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
@ -72,25 +107,8 @@ class Api::V1::EmojiReactionsController < Api::BaseController
|
|||
results.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
||||
end
|
||||
|
||||
def emojis_requested?
|
||||
emoji_reactions_params[:emojis].present?
|
||||
end
|
||||
|
||||
def emojis_scope
|
||||
emoji_reactions = EmojiReaction.none
|
||||
|
||||
emoji_reactions_params[:emojis].each do |emoji|
|
||||
shortcode, domain = emoji.split('@')
|
||||
custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: domain)
|
||||
|
||||
emoji_reactions = emoji_reactions.or(EmojiReaction.where(name: shortcode, custom_emoji: custom_emoji))
|
||||
end
|
||||
|
||||
emoji_reactions
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit, :compact).permit(:limit, :compact).merge(core_params)
|
||||
params_slice(:limit, :compact, :only_media, :without_media).merge(core_params)
|
||||
end
|
||||
|
||||
def emoji_reactions_params
|
||||
|
|
|
@ -28,20 +28,43 @@ class Api::V1::FavouritesController < Api::BaseController
|
|||
end
|
||||
|
||||
def results
|
||||
@_results ||= account_favourites.joins(:status).eager_load(:status).to_a_paginated_by_id(
|
||||
@_results ||= filtered_account_favourites.to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
end
|
||||
|
||||
def filtered_account_favourites
|
||||
account_favourites.joins(:status).eager_load(:status).tap do |scope|
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
scope.merge!(without_media_scope) if without_media?
|
||||
end
|
||||
end
|
||||
|
||||
def account_favourites
|
||||
current_account.favourites
|
||||
end
|
||||
|
||||
def media_only?
|
||||
truthy_param?(:only_media)
|
||||
end
|
||||
|
||||
def without_media?
|
||||
truthy_param?(:without_media)
|
||||
end
|
||||
|
||||
def compact?
|
||||
truthy_param?(:compact)
|
||||
end
|
||||
|
||||
def media_only_scope
|
||||
Status.joins(:media_attachments)
|
||||
end
|
||||
|
||||
def without_media_scope
|
||||
Status.left_joins(:media_attachments).where(media_attachments: {status_id: nil})
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
@ -71,6 +94,6 @@ class Api::V1::FavouritesController < Api::BaseController
|
|||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit, :compact).permit(:limit, :compact).merge(core_params)
|
||||
params_slice(:limit, :compact, :only_media, :without_media).merge(core_params)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,7 +37,19 @@ class Api::V1::Timelines::PersonalController < Api::BaseController
|
|||
end
|
||||
|
||||
def personal_feed
|
||||
PersonalFeed.new(current_account)
|
||||
PersonalFeed.new(
|
||||
current_account,
|
||||
only_media: media_only?,
|
||||
without_media: without_media?,
|
||||
)
|
||||
end
|
||||
|
||||
def media_only?
|
||||
truthy_param?(:only_media)
|
||||
end
|
||||
|
||||
def without_media?
|
||||
truthy_param?(:without_media)
|
||||
end
|
||||
|
||||
def compact?
|
||||
|
@ -49,7 +61,7 @@ class Api::V1::Timelines::PersonalController < Api::BaseController
|
|||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :limit).permit(:local, :limit).merge(core_params)
|
||||
params_slice(:limit, :compact, :only_media, :without_media).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
|
|
|
@ -10,15 +10,18 @@ export const BOOKMARKED_STATUSES_EXPAND_REQUEST = 'BOOKMARKED_STATUSES_EXPAND_RE
|
|||
export const BOOKMARKED_STATUSES_EXPAND_SUCCESS = 'BOOKMARKED_STATUSES_EXPAND_SUCCESS';
|
||||
export const BOOKMARKED_STATUSES_EXPAND_FAIL = 'BOOKMARKED_STATUSES_EXPAND_FAIL';
|
||||
|
||||
export function fetchBookmarkedStatuses() {
|
||||
export function fetchBookmarkedStatuses({ onlyMedia, withoutMedia } = {}) {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = ['compact=true', onlyMedia ? 'only_media=true' : null, withoutMedia ? 'without_media=true' : null];
|
||||
const param_string = params.filter(e => !!e).join('&');
|
||||
|
||||
dispatch(fetchBookmarkedStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/bookmarks?compact=true').then(response => {
|
||||
api(getState).get(`/api/v1/bookmarks?${param_string}`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
if ('statuses' in response.data && 'accounts' in response.data) {
|
||||
const { statuses, referenced_statuses, accounts, relationships } = response.data;
|
||||
|
|
|
@ -10,15 +10,18 @@ export const EMOJI_REACTIONED_STATUSES_EXPAND_REQUEST = 'EMOJI_REACTIONED_STATUS
|
|||
export const EMOJI_REACTIONED_STATUSES_EXPAND_SUCCESS = 'EMOJI_REACTIONED_STATUSES_EXPAND_SUCCESS';
|
||||
export const EMOJI_REACTIONED_STATUSES_EXPAND_FAIL = 'EMOJI_REACTIONED_STATUSES_EXPAND_FAIL';
|
||||
|
||||
export function fetchEmojiReactionedStatuses() {
|
||||
export function fetchEmojiReactionedStatuses({ onlyMedia, withoutMedia } = {}) {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'emoji_reactions', 'isLoading'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = ['compact=true', onlyMedia ? 'only_media=true' : null, withoutMedia ? 'without_media=true' : null];
|
||||
const param_string = params.filter(e => !!e).join('&');
|
||||
|
||||
dispatch(fetchEmojiReactionedStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/emoji_reactions?compact=true').then(response => {
|
||||
api(getState).get(`/api/v1/emoji_reactions?${param_string}`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
if ('statuses' in response.data && 'accounts' in response.data) {
|
||||
const { statuses, referenced_statuses, accounts, relationships } = response.data;
|
||||
|
|
|
@ -10,15 +10,18 @@ export const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_RE
|
|||
export const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
||||
export const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FAIL';
|
||||
|
||||
export function fetchFavouritedStatuses() {
|
||||
export function fetchFavouritedStatuses({ onlyMedia, withoutMedia } = {}) {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'favourites', 'isLoading'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = ['compact=true', onlyMedia ? 'only_media=true' : null, withoutMedia ? 'without_media=true' : null];
|
||||
const param_string = params.filter(e => !!e).join('&');
|
||||
|
||||
dispatch(fetchFavouritedStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/favourites?compact=true').then(response => {
|
||||
api(getState).get(`/api/v1/favourites?${param_string}`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
if ('statuses' in response.data && 'accounts' in response.data) {
|
||||
const { statuses, referenced_statuses, accounts, relationships } = response.data;
|
||||
|
|
|
@ -183,7 +183,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|||
|
||||
export const expandHomeTimeline = ({ maxId, visibilities } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId, visibilities: visibilities }, done);
|
||||
export const expandLimitedTimeline = ({ maxId, visibilities } = {}, done = noOp) => expandTimeline('limited', '/api/v1/timelines/home', { max_id: maxId, visibilities: visibilities }, done);
|
||||
export const expandPersonalTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('personal', '/api/v1/timelines/personal', { max_id: maxId}, done);
|
||||
export const expandPersonalTimeline = ({ maxId, onlyMedia, withoutMedia } = {}, done = noOp) => expandTimeline(`personal${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/personal', { max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia }, done);
|
||||
export const expandPublicTimeline = ({ maxId, onlyMedia, withoutMedia, withoutBot, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, without_bot: !!withoutBot }, done);
|
||||
export const expandDomainTimeline = (domain, { maxId, onlyMedia, withoutMedia, withoutBot } = {}, done = noOp) => expandTimeline(`domain${withoutBot ? ':nobot' : ':bot'}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}:${domain}`, '/api/v1/timelines/public', { local: false, domain: domain, max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, without_bot: !!withoutBot }, done);
|
||||
export const expandGroupTimeline = (id, { maxId, onlyMedia, withoutMedia, tagged } = {}, done = noOp) => expandTimeline(`group:${id}${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/timelines/group/${id}`, { max_id: maxId, only_media: !!onlyMedia, without_media: !!withoutMedia, tagged: tagged }, done);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} exclusiveSettingPaths={[['other', 'withoutMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
<SettingToggle settings={settings} settingPath={['other', 'withoutMedia']} exclusiveSettingPaths={[['other', 'onlyMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.without_media' defaultMessage='Without media' />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeColumnParams } from '../../../actions/columns';
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'bookmarked_statuses']),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['bookmarked_statuses', ...key], checked));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
|
@ -6,6 +6,7 @@ import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from '../../actions
|
|||
import Column from '../ui/components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import StatusList from '../../components/status_list';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -22,12 +23,16 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'bookmarked_statuses', 'other', 'onlyMedia']);
|
||||
const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'bookmarked_statuses', 'other', 'withoutMedia']);
|
||||
const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'bookmarked_statuses', 'columnWidth']);
|
||||
|
||||
return {
|
||||
statusIds: state.getIn(['status_lists', 'bookmarks', 'items']),
|
||||
isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
|
||||
onlyMedia,
|
||||
withoutMedia,
|
||||
columnWidth: columnWidth ?? defaultColumnWidth,
|
||||
};
|
||||
};
|
||||
|
@ -43,21 +48,38 @@ class Bookmarks extends ImmutablePureComponent {
|
|||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
columnWidth: PropTypes.string,
|
||||
onlyMedia: PropTypes.bool,
|
||||
withoutMedia: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchBookmarkedStatuses());
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
withoutMedia: false,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
dispatch(fetchBookmarkedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (prevProps.onlyMedia !== onlyMedia || prevProps.withoutMedia !== withoutMedia) {
|
||||
dispatch(fetchBookmarkedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('BOOKMARKS', {}));
|
||||
dispatch(addColumn('BOOKMARKS', { other: { onlyMedia, withoutMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +111,7 @@ class Bookmarks extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth } = this.props;
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth, withoutMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.bookmarked_statuses' defaultMessage="You don't have any bookmarked toots yet. When you bookmark one, it will show up here." />;
|
||||
|
@ -107,7 +129,9 @@ class Bookmarks extends ImmutablePureComponent {
|
|||
columnWidth={columnWidth}
|
||||
onWidthChange={this.handleWidthChange}
|
||||
showBackButton
|
||||
/>
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusList
|
||||
trackScroll={!pinned}
|
||||
|
@ -118,6 +142,7 @@ class Bookmarks extends ImmutablePureComponent {
|
|||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
showCard={!withoutMedia}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} exclusiveSettingPaths={[['other', 'withoutMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
<SettingToggle settings={settings} settingPath={['other', 'withoutMedia']} exclusiveSettingPaths={[['other', 'onlyMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.without_media' defaultMessage='Without media' />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeColumnParams } from '../../../actions/columns';
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'emoji_reactioned_statuses']),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['emoji_reactioned_statuses', ...key], checked));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
|
@ -6,6 +6,7 @@ import { fetchEmojiReactionedStatuses, expandEmojiReactionedStatuses } from '../
|
|||
import Column from '../ui/components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import StatusList from '../../components/status_list';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -22,12 +23,16 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'emoji_reactioned_statuses', 'other', 'onlyMedia']);
|
||||
const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'emoji_reactioned_statuses', 'other', 'withoutMedia']);
|
||||
const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'emoji_reactioned_statuses', 'columnWidth']);
|
||||
|
||||
return {
|
||||
statusIds: state.getIn(['status_lists', 'emoji_reactions', 'items']),
|
||||
isLoading: state.getIn(['status_lists', 'emoji_reactions', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'emoji_reactions', 'next']),
|
||||
onlyMedia,
|
||||
withoutMedia,
|
||||
columnWidth: columnWidth ?? defaultColumnWidth,
|
||||
};
|
||||
};
|
||||
|
@ -43,21 +48,38 @@ class EmojiReactions extends ImmutablePureComponent {
|
|||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
columnWidth: PropTypes.string,
|
||||
onlyMedia: PropTypes.bool,
|
||||
withoutMedia: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchEmojiReactionedStatuses());
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
withoutMedia: false,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
dispatch(fetchEmojiReactionedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (prevProps.onlyMedia !== onlyMedia || prevProps.withoutMedia !== withoutMedia) {
|
||||
dispatch(fetchEmojiReactionedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('EMOJI_REACTIONS', {}));
|
||||
dispatch(addColumn('EMOJI_REACTIONS', { other: { onlyMedia, withoutMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +111,7 @@ class EmojiReactions extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth } = this.props;
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth, withoutMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.emoji_reactioned_statuses' defaultMessage="You don't have any reaction posts yet. When you reaction one, it will show up here." />;
|
||||
|
@ -107,7 +129,9 @@ class EmojiReactions extends ImmutablePureComponent {
|
|||
columnWidth={columnWidth}
|
||||
onWidthChange={this.handleWidthChange}
|
||||
showBackButton
|
||||
/>
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusList
|
||||
trackScroll={!pinned}
|
||||
|
@ -118,6 +142,7 @@ class EmojiReactions extends ImmutablePureComponent {
|
|||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
showCard={!withoutMedia}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} exclusiveSettingPaths={[['other', 'withoutMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
<SettingToggle settings={settings} settingPath={['other', 'withoutMedia']} exclusiveSettingPaths={[['other', 'onlyMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.without_media' defaultMessage='Without media' />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeColumnParams } from '../../../actions/columns';
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'favourited_statuses']),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['favourited_statuses', ...key], checked));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
|
@ -6,6 +6,7 @@ import { fetchFavouritedStatuses, expandFavouritedStatuses } from '../../actions
|
|||
import Column from '../ui/components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import StatusList from '../../components/status_list';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -22,12 +23,16 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'favourited_statuses', 'other', 'onlyMedia']);
|
||||
const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'favourited_statuses', 'other', 'withoutMedia']);
|
||||
const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'favourited_statuses', 'columnWidth']);
|
||||
|
||||
return {
|
||||
statusIds: state.getIn(['status_lists', 'favourites', 'items']),
|
||||
isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
|
||||
onlyMedia,
|
||||
withoutMedia,
|
||||
columnWidth: columnWidth ?? defaultColumnWidth,
|
||||
};
|
||||
};
|
||||
|
@ -43,21 +48,38 @@ class Favourites extends ImmutablePureComponent {
|
|||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
columnWidth: PropTypes.string,
|
||||
onlyMedia: PropTypes.bool,
|
||||
withoutMedia: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchFavouritedStatuses());
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
withoutMedia: false,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
dispatch(fetchFavouritedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (prevProps.onlyMedia !== onlyMedia || prevProps.withoutMedia !== withoutMedia) {
|
||||
dispatch(fetchFavouritedStatuses({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('FAVOURITES', {}));
|
||||
dispatch(addColumn('FAVOURITES', { other: { onlyMedia, withoutMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +111,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth } = this.props;
|
||||
const { intl, statusIds, columnId, multiColumn, hasMore, isLoading, columnWidth, withoutMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite posts yet. When you favourite one, it will show up here." />;
|
||||
|
@ -107,7 +129,9 @@ class Favourites extends ImmutablePureComponent {
|
|||
columnWidth={columnWidth}
|
||||
onWidthChange={this.handleWidthChange}
|
||||
showBackButton
|
||||
/>
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusList
|
||||
trackScroll={!pinned}
|
||||
|
@ -118,6 +142,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
showCard={!withoutMedia}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -10,7 +10,6 @@ class ColumnSettings extends React.PureComponent {
|
|||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onChangeClear: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
@ -22,7 +21,8 @@ class ColumnSettings extends React.PureComponent {
|
|||
<span className='column-settings__section'><FormattedMessage id='personal.column_settings.basic' defaultMessage='Basic' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='personal_timeline' settings={settings} settingPath={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='personal.column_settings.show_replies' defaultMessage='Show replies' />} />
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} exclusiveSettingPaths={[['other', 'withoutMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
<SettingToggle settings={settings} settingPath={['other', 'withoutMedia']} exclusiveSettingPaths={[['other', 'onlyMedia']]} onChange={onChange} label={<FormattedMessage id='community.column_settings.without_media' defaultMessage='Without media' />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting, saveSettings } from '../../../actions/settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeColumnParams } from '../../../actions/columns';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'personal']),
|
||||
});
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'personal']),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['personal', ...key], checked));
|
||||
}
|
||||
},
|
||||
|
||||
onSave () {
|
||||
dispatch(saveSettings());
|
||||
},
|
||||
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
||||
|
|
|
@ -20,10 +20,14 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'personal', 'other', 'onlyMedia']);
|
||||
const withoutMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'withoutMedia']) : state.getIn(['settings', 'personal', 'other', 'withoutMedia']);
|
||||
const columnWidth = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'columnWidth']) : state.getIn(['settings', 'personal', 'columnWidth']);
|
||||
|
||||
return {
|
||||
hasUnread: state.getIn(['timelines', 'personal', 'unread']) > 0,
|
||||
onlyMedia,
|
||||
withoutMedia,
|
||||
columnWidth: columnWidth ?? defaultColumnWidth,
|
||||
};
|
||||
};
|
||||
|
@ -37,17 +41,24 @@ class PersonalTimeline extends React.PureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
columnId: PropTypes.string,
|
||||
onlyMedia: PropTypes.bool,
|
||||
withoutMedia: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
columnWidth: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
withoutMedia: false,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('PERSONAL', {}));
|
||||
dispatch(addColumn('PERSONAL', { other: { onlyMedia, withoutMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,15 +76,23 @@ class PersonalTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
dispatch(expandPersonalTimeline({ maxId }));
|
||||
dispatch(expandPersonalTimeline({ maxId, onlyMedia, withoutMedia }));
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
dispatch(expandPersonalTimeline({}));
|
||||
dispatch(expandPersonalTimeline({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { dispatch, onlyMedia, withoutMedia } = this.props;
|
||||
|
||||
if (prevProps.onlyMedia !== onlyMedia || prevProps.withoutMedia !== withoutMedia) {
|
||||
dispatch(expandPersonalTimeline({ onlyMedia, withoutMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
handleWidthChange = (value) => {
|
||||
|
@ -87,7 +106,7 @@ class PersonalTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn, columnWidth } = this.props;
|
||||
const { intl, hasUnread, columnId, multiColumn, columnWidth, onlyMedia, withoutMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
|
@ -103,15 +122,18 @@ class PersonalTimeline extends React.PureComponent {
|
|||
multiColumn={multiColumn}
|
||||
columnWidth={columnWidth}
|
||||
onWidthChange={this.handleWidthChange}
|
||||
/>
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
timelineId={`personal${withoutMedia ? ':nomedia' : ''}${onlyMedia ? ':media' : ''}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`personal_timeline-${columnId}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
timelineId='personal'
|
||||
emptyMessage={<FormattedMessage id='empty_column.personal' defaultMessage='Personal posts unavailable' />}
|
||||
bindToDocument={!multiColumn}
|
||||
showCard={!withoutMedia}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
@ -140,6 +140,24 @@ const initialState = ImmutableMap({
|
|||
body: '',
|
||||
}),
|
||||
}),
|
||||
|
||||
bookmarked_statuses: ImmutableMap({
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
}),
|
||||
}),
|
||||
|
||||
favourited_statuses: ImmutableMap({
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
}),
|
||||
}),
|
||||
|
||||
emoji_reactioned_statuses: ImmutableMap({
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const defaultColumns = fromJS([
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
class PersonalFeed
|
||||
# @param [Account] account
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :with_replies
|
||||
# @option [Boolean] :only_media
|
||||
# @option [Boolean] :without_media
|
||||
def initialize(account, options = {})
|
||||
@account = account
|
||||
@options = options
|
||||
|
@ -17,6 +18,9 @@ class PersonalFeed
|
|||
def get(limit, max_id = nil, since_id = nil, min_id = nil)
|
||||
scope = personal_scope
|
||||
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
scope.merge!(without_media_scope) if without_media?
|
||||
|
||||
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||
end
|
||||
|
||||
|
@ -24,6 +28,22 @@ class PersonalFeed
|
|||
|
||||
attr_reader :account, :options
|
||||
|
||||
def media_only?
|
||||
options[:only_media]
|
||||
end
|
||||
|
||||
def without_media?
|
||||
options[:without_media]
|
||||
end
|
||||
|
||||
def media_only_scope
|
||||
Status.joins(:media_attachments).group(:id)
|
||||
end
|
||||
|
||||
def without_media_scope
|
||||
Status.left_joins(:media_attachments).where(media_attachments: {status_id: nil})
|
||||
end
|
||||
|
||||
def personal_scope
|
||||
Status.include_expired.where(account_id: account.id).without_reblogs.with_personal_visibility
|
||||
end
|
||||
|
|
|
@ -150,6 +150,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
:account_conversations,
|
||||
:enable_wide_emoji,
|
||||
:enable_wide_emoji_reaction,
|
||||
:timeline_bookmark_media_option,
|
||||
:timeline_favourite_media_option,
|
||||
:timeline_emoji_reaction_media_option,
|
||||
:timeline_personal_media_option,
|
||||
]
|
||||
|
||||
capabilities << :profile_search unless Chewy.enabled?
|
||||
|
|
Loading…
Reference in a new issue