Remove local timeline for fedibird.com

This commit is contained in:
noellabo 2019-08-15 23:45:25 +09:00
parent 9b1a64e931
commit ce29732518
33 changed files with 43 additions and 342 deletions

View file

@ -40,7 +40,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
any: params[:any],
all: params[:all],
none: params[:none],
local: truthy_param?(:local),
local: false,
remote: truthy_param?(:remote),
only_media: truthy_param?(:only_media)
)
@ -51,7 +51,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
end
def pagination_params(core_params)
params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params)
params.slice(:limit, :only_media).permit(:limit, :only_media).merge(core_params)
end
def next_path

View file

@ -43,7 +43,7 @@ class TagsController < ApplicationController
end
def set_local
@local = truthy_param?(:local)
@local = false
end
def set_statuses

View file

@ -200,7 +200,6 @@ export function submitCompose(routerHistory) {
}
if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
insertIfOnline('community');
insertIfOnline('public');
insertIfOnline(`account:${response.data.account.id}`);
}

View file

@ -117,14 +117,6 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
export const connectUserStream = () =>
connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification });
/**
* @param {Object} options
* @param {boolean} [options.onlyMedia]
* @return {function(): void}
*/
export const connectCommunityStream = ({ onlyMedia } = {}) =>
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
/**
* @param {string} domain
* @param {Object} options
@ -146,12 +138,11 @@ export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
/**
* @param {string} columnId
* @param {string} tagName
* @param {boolean} onlyLocal
* @param {function(object): boolean} accept
* @return {function(): void}
*/
export const connectHashtagStream = (columnId, tagName, onlyLocal, accept) =>
connectTimelineStream(`hashtag:${columnId}${onlyLocal ? ':local' : ''}`, `hashtag${onlyLocal ? ':local' : ''}`, { tag: tagName }, { accept });
export const connectHashtagStream = (columnId, tagName, accept) =>
connectTimelineStream(`hashtag:${columnId}`, `hashtag`, { tag: tagName }, { accept });
/**
* @return {function(): void}

View file

@ -130,19 +130,17 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
export const expandDomainTimeline = (domain, { maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`domain${onlyMedia ? ':media' : ''}:${domain}`, '/api/v1/timelines/public', { local: false, domain: domain, max_id: maxId, only_media: !!onlyMedia }, done);
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => {
return expandTimeline(`hashtag:${hashtag}${local ? ':local' : ''}`, `/api/v1/timelines/tag/${hashtag}`, {
export const expandHashtagTimeline = (hashtag, { maxId, tags } = {}, done = noOp) => {
return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {
max_id: maxId,
any: parseTags(tags, 'any'),
all: parseTags(tags, 'all'),
none: parseTags(tags, 'none'),
local: local,
}, done);
};

View file

@ -1,29 +0,0 @@
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']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
</div>
</div>
);
}
}

View file

@ -1,28 +0,0 @@
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', 'community']),
};
};
const mapDispatchToProps = (dispatch, { columnId }) => {
return {
onChange (key, checked) {
if (columnId) {
dispatch(changeColumnParams(columnId, key, checked));
} else {
dispatch(changeSetting(['community', ...key], checked));
}
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);

View file

@ -1,135 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../../components/column';
import ColumnHeader from '../../components/column_header';
import { expandCommunityTimeline } from '../../actions/timelines';
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
import ColumnSettingsContainer from './containers/column_settings_container';
import { connectCommunityStream } from '../../actions/streaming';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Local timeline' },
});
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', 'community', 'other', 'onlyMedia']);
const timelineState = state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`]);
return {
hasUnread: !!timelineState && timelineState.get('unread') > 0,
onlyMedia,
};
};
export default @connect(mapStateToProps)
@injectIntl
class CommunityTimeline extends React.PureComponent {
static contextTypes = {
router: PropTypes.object,
};
static defaultProps = {
onlyMedia: false,
};
static propTypes = {
dispatch: PropTypes.func.isRequired,
columnId: PropTypes.string,
intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool,
multiColumn: PropTypes.bool,
onlyMedia: PropTypes.bool,
};
handlePin = () => {
const { columnId, dispatch, onlyMedia } = this.props;
if (columnId) {
dispatch(removeColumn(columnId));
} else {
dispatch(addColumn('COMMUNITY', { other: { onlyMedia } }));
}
}
handleMove = (dir) => {
const { columnId, dispatch } = this.props;
dispatch(moveColumn(columnId, dir));
}
handleHeaderClick = () => {
this.column.scrollTop();
}
componentDidMount () {
const { dispatch, onlyMedia } = this.props;
dispatch(expandCommunityTimeline({ onlyMedia }));
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
}
componentDidUpdate (prevProps) {
if (prevProps.onlyMedia !== this.props.onlyMedia) {
const { dispatch, onlyMedia } = this.props;
this.disconnect();
dispatch(expandCommunityTimeline({ onlyMedia }));
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
}
}
componentWillUnmount () {
if (this.disconnect) {
this.disconnect();
this.disconnect = null;
}
}
setRef = c => {
this.column = c;
}
handleLoadMore = maxId => {
const { dispatch, onlyMedia } = this.props;
dispatch(expandCommunityTimeline({ maxId, onlyMedia }));
}
render () {
const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props;
const pinned = !!columnId;
return (
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='users'
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}
onMove={this.handleMove}
onClick={this.handleHeaderClick}
pinned={pinned}
multiColumn={multiColumn}
>
<ColumnSettingsContainer columnId={columnId} />
</ColumnHeader>
<StatusListContainer
trackScroll={!pinned}
scrollKey={`community_timeline-${columnId}`}
timelineId={`community${onlyMedia ? ':media' : ''}`}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
bindToDocument={!multiColumn}
/>
</Column>
);
}
}

View file

@ -23,7 +23,7 @@ const messages = defineMessages({
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
@ -105,9 +105,6 @@ class Compose extends React.PureComponent {
{!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
<Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'COMMUNITY') && (
<Link to='/timelines/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'PUBLIC') && (
<Link to='/timelines/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>
)}

View file

@ -20,7 +20,6 @@ const messages = defineMessages({
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
@ -98,11 +97,10 @@ class GettingStarted extends ImmutablePureComponent {
if (multiColumn) {
navItems.push(
<ColumnSubheading key='header-discover' text={intl.formatMessage(messages.discover)} />,
<ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />,
<ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />,
);
height += 34 + 48*2;
height += 34 + 48;
if (profile_directory) {
navItems.push(

View file

@ -5,7 +5,6 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Toggle from 'react-toggle';
import AsyncSelect from 'react-select/async';
import { NonceProvider } from 'react-select';
import SettingToggle from '../../notifications/components/setting_toggle';
const messages = defineMessages({
placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' },
@ -112,10 +111,6 @@ class ColumnSettings extends React.PureComponent {
{this.modeSelect('none')}
</div>
)}
<div className='column-settings__row'>
<SettingToggle settings={settings} settingPath={['local']} onChange={onChange} label={<FormattedMessage id='community.column_settings.local_only' defaultMessage='Local only' />} />
</div>
</div>
);
}

View file

@ -12,7 +12,7 @@ import { connectHashtagStream } from '../../actions/streaming';
import { isEqual } from 'lodash';
const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}${props.params.local ? ':local' : ''}`, 'unread']) > 0,
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
});
export default @connect(mapStateToProps)
@ -75,13 +75,13 @@ class HashtagTimeline extends React.PureComponent {
this.column.scrollTop();
}
_subscribe (dispatch, id, tags = {}, local) {
_subscribe (dispatch, id, tags = {}) {
let any = (tags.any || []).map(tag => tag.value);
let all = (tags.all || []).map(tag => tag.value);
let none = (tags.none || []).map(tag => tag.value);
[id, ...any].map(tag => {
this.disconnects.push(dispatch(connectHashtagStream(id, tag, local, status => {
this.disconnects.push(dispatch(connectHashtagStream(id, tag, status => {
let tags = status.tags.map(tag => tag.name);
return all.filter(tag => tags.includes(tag)).length === all.length &&
@ -97,21 +97,21 @@ class HashtagTimeline extends React.PureComponent {
componentDidMount () {
const { dispatch } = this.props;
const { id, tags, local } = this.props.params;
const { id, tags } = this.props.params;
this._subscribe(dispatch, id, tags, local);
dispatch(expandHashtagTimeline(id, { tags, local }));
this._subscribe(dispatch, id, tags);
dispatch(expandHashtagTimeline(id, { tags }));
}
componentWillReceiveProps (nextProps) {
const { dispatch, params } = this.props;
const { id, tags, local } = nextProps.params;
const { id, tags } = nextProps.params;
if (id !== params.id || !isEqual(tags, params.tags) || !isEqual(local, params.local)) {
if (id !== params.id || !isEqual(tags, params.tags)) {
this._unsubscribe();
this._subscribe(dispatch, id, tags, local);
dispatch(clearTimeline(`hashtag:${id}${local ? ':local' : ''}`));
dispatch(expandHashtagTimeline(id, { tags, local }));
this._subscribe(dispatch, id, tags);
dispatch(clearTimeline(`hashtag:${id}`));
dispatch(expandHashtagTimeline(id, { tags }));
}
}
@ -124,13 +124,13 @@ class HashtagTimeline extends React.PureComponent {
}
handleLoadMore = maxId => {
const { id, tags, local } = this.props.params;
this.props.dispatch(expandHashtagTimeline(id, { maxId, tags, local }));
const { id, tags } = this.props.params;
this.props.dispatch(expandHashtagTimeline(id, { maxId, tags }));
}
render () {
const { hasUnread, columnId, multiColumn } = this.props;
const { id, local } = this.props.params;
const { id } = this.props.params;
const pinned = !!columnId;
return (
@ -152,7 +152,7 @@ class HashtagTimeline extends React.PureComponent {
<StatusListContainer
trackScroll={!pinned}
scrollKey={`hashtag_timeline-${columnId}`}
timelineId={`hashtag:${id}${local ? ':local' : ''}`}
timelineId={`hashtag:${id}`}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
bindToDocument={!multiColumn}

View file

@ -45,11 +45,6 @@ const FrameFederation = ({ onNext }) => (
<p><FormattedMessage id='introduction.federation.home.text' defaultMessage='Posts from people you follow will appear in your home feed. You can follow anyone on any server!' /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.federation.local.headline' defaultMessage='Local' /></h3>
<p><FormattedMessage id='introduction.federation.local.text' defaultMessage='Public posts from people on the same server as you will appear in the local timeline.' /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.federation.federated.headline' defaultMessage='Federated' /></h3>
<p><FormattedMessage id='introduction.federation.federated.text' defaultMessage='Public posts from other servers of the fediverse will appear in the federated timeline.' /></p>

View file

@ -112,10 +112,6 @@ class KeyboardShortcuts extends ImmutablePureComponent {
<td><kbd>g</kbd>+<kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.notifications' defaultMessage='to open notifications column' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>l</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.local' defaultMessage='to open local timeline' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>t</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.federated' defaultMessage='to open federated timeline' /></td>

View file

@ -24,25 +24,20 @@ class HashtagTimeline extends React.PureComponent {
isLoading: PropTypes.bool.isRequired,
hasMore: PropTypes.bool.isRequired,
hashtag: PropTypes.string.isRequired,
local: PropTypes.bool.isRequired,
};
static defaultProps = {
local: false,
};
componentDidMount () {
const { dispatch, hashtag, local } = this.props;
const { dispatch, hashtag } = this.props;
dispatch(expandHashtagTimeline(hashtag, { local }));
dispatch(expandHashtagTimeline(hashtag));
}
handleLoadMore = () => {
const { dispatch, hashtag, local, statusIds } = this.props;
const { dispatch, hashtag, statusIds } = this.props;
const maxId = statusIds.last();
if (maxId) {
dispatch(expandHashtagTimeline(hashtag, { maxId, local }));
dispatch(expandHashtagTimeline(hashtag, { maxId }));
}
}

View file

@ -2,15 +2,15 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
import { expandPublicTimeline } from 'mastodon/actions/timelines';
import Masonry from 'react-masonry-infinite';
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
import DetailedStatusContainer from 'mastodon/features/status/containers/detailed_status_container';
import { debounce } from 'lodash';
import LoadingIndicator from 'mastodon/components/loading_indicator';
const mapStateToProps = (state, { local }) => {
const timeline = state.getIn(['timelines', local ? 'community' : 'public'], ImmutableMap());
const mapStateToProps = (state) => {
const timeline = state.getIn(['timelines', 'public'], ImmutableMap());
return {
statusIds: timeline.get('items', ImmutableList()),
@ -27,7 +27,6 @@ class PublicTimeline extends React.PureComponent {
statusIds: ImmutablePropTypes.list.isRequired,
isLoading: PropTypes.bool.isRequired,
hasMore: PropTypes.bool.isRequired,
local: PropTypes.bool,
};
componentDidMount () {
@ -35,23 +34,20 @@ class PublicTimeline extends React.PureComponent {
}
componentDidUpdate (prevProps) {
if (prevProps.local !== this.props.local) {
this._connect();
}
}
_connect () {
const { dispatch, local } = this.props;
const { dispatch } = this.props;
dispatch(local ? expandCommunityTimeline() : expandPublicTimeline());
dispatch(expandPublicTimeline());
}
handleLoadMore = () => {
const { dispatch, statusIds, local } = this.props;
const { dispatch, statusIds } = this.props;
const maxId = statusIds.last();
if (maxId) {
dispatch(local ? expandCommunityTimeline({ maxId }) : expandPublicTimeline({ maxId }));
dispatch(expandPublicTimeline({ maxId }));
}
}

View file

@ -18,7 +18,6 @@ import {
Compose,
Notifications,
HomeTimeline,
CommunityTimeline,
PublicTimeline,
DomainTimeline,
HashtagTimeline,
@ -42,7 +41,6 @@ const componentMap = {
'NOTIFICATIONS': Notifications,
'PUBLIC': PublicTimeline,
'REMOTE': PublicTimeline,
'COMMUNITY': CommunityTimeline,
'DOMAIN': DomainTimeline,
'HASHTAG': HashtagTimeline,
'DIRECT': DirectTimeline,

View file

@ -14,7 +14,6 @@ const NavigationPanel = () => (
<NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>
<FollowRequestsNavLink />
<NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>
<NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' id='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink>

View file

@ -10,7 +10,6 @@ import NotificationsCounterIcon from './notifications_counter_icon';
export const links = [
<NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
<NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
<NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
<NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
<NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,

View file

@ -28,7 +28,6 @@ import {
GettingStarted,
KeyboardShortcuts,
PublicTimeline,
CommunityTimeline,
DomainTimeline,
AccountTimeline,
AccountGallery,
@ -94,7 +93,6 @@ const keyMap = {
back: 'backspace',
goToHome: 'g h',
goToNotifications: 'g n',
goToLocal: 'g l',
goToFederated: 'g t',
goToDirect: 'g d',
goToStart: 'g s',
@ -156,7 +154,6 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} />
<WrappedRoute path='/timelines/public/domain/:domain' exact component={DomainTimeline} content={children} />
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
@ -462,10 +459,6 @@ class UI extends React.PureComponent {
this.context.router.history.push('/notifications');
}
handleHotkeyGoToLocal = () => {
this.context.router.history.push('/timelines/public/local');
}
handleHotkeyGoToFederated = () => {
this.context.router.history.push('/timelines/public');
}
@ -516,7 +509,6 @@ class UI extends React.PureComponent {
back: this.handleHotkeyBack,
goToHome: this.handleHotkeyGoToHome,
goToNotifications: this.handleHotkeyGoToNotifications,
goToLocal: this.handleHotkeyGoToLocal,
goToFederated: this.handleHotkeyGoToFederated,
goToDirect: this.handleHotkeyGoToDirect,
goToStart: this.handleHotkeyGoToStart,

View file

@ -18,10 +18,6 @@ export function PublicTimeline () {
return import(/* webpackChunkName: "features/public_timeline" */'../../public_timeline');
}
export function CommunityTimeline () {
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
}
export function DomainTimeline () {
return import(/* webpackChunkName: "features/domain_timeline" */'../../domain_timeline');
}

View file

@ -68,12 +68,6 @@ const initialState = ImmutableMap({
}),
}),
community: ImmutableMap({
regex: ImmutableMap({
body: '',
}),
}),
domain: ImmutableMap({
regex: ImmutableMap({
body: '',

View file

@ -99,7 +99,7 @@ const sharedCallbacks = {
const streamIdentifier = stream[1];
if (['hashtag', 'hashtag:local'].includes(channelName)) {
if (channelName === 'hashtag') {
return channelName === streamChannelName && params.tag === streamIdentifier;
} else if (channelName === 'list') {
return channelName === streamChannelName && params.list === streamIdentifier;

View file

@ -45,7 +45,7 @@ class PublicFeed
end
def local_only?
options[:local]
false
end
def remote_only?

View file

@ -28,7 +28,6 @@ class TagFeed < PublicFeed
scope.merge!(tagged_with_any_scope)
scope.merge!(tagged_with_all_scope)
scope.merge!(tagged_with_none_scope)
scope.merge!(local_only_scope) if local_only?
scope.merge!(remote_only_scope) if remote_only?
scope.merge!(account_filters_scope) if account?
scope.merge!(media_only_scope) if media_only?

View file

@ -81,7 +81,6 @@ class BatchedRemoveStatusService < BaseService
redis.pipelined do
redis.publish('timeline:public', payload)
if status.local?
redis.publish('timeline:public:local', payload)
else
redis.publish('timeline:public:remote', payload)
redis.publish("timeline:public:domain:#{domain}", payload)
@ -90,7 +89,6 @@ class BatchedRemoveStatusService < BaseService
if status.media_attachments.any?
redis.publish('timeline:public:media', payload)
if status.local?
redis.publish('timeline:public:local:media', payload)
else
redis.publish('timeline:public:remote:media', payload)
redis.publish("timeline:public:domain:media:#{domain}", payload)
@ -99,7 +97,6 @@ class BatchedRemoveStatusService < BaseService
status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag|
redis.publish("timeline:hashtag:#{hashtag}", payload)
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
end
end
end

View file

@ -161,7 +161,6 @@ class FanOutOnWriteService < BaseService
status.tags.pluck(:name).each do |hashtag|
Redis.current.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload)
Redis.current.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @payload) if status.local?
end
end
@ -189,7 +188,6 @@ class FanOutOnWriteService < BaseService
Redis.current.publish('timeline:public', @payload)
if status.local?
Redis.current.publish('timeline:public:local', @payload)
else
Redis.current.publish('timeline:public:remote', @payload)
Redis.current.publish("timeline:public:domain:#{status.account.domain.mb_chars.downcase}", @payload)
@ -201,7 +199,6 @@ class FanOutOnWriteService < BaseService
Redis.current.publish('timeline:public:media', @payload)
if status.local?
Redis.current.publish('timeline:public:local:media', @payload)
else
Redis.current.publish('timeline:public:remote:media', @payload)
Redis.current.publish("timeline:public:domain:media:#{status.account.domain.mb_chars.downcase}", @payload)

View file

@ -116,7 +116,6 @@ class RemoveStatusService < BaseService
@status.tags.map(&:name).each do |hashtag|
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload)
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @payload) if @status.local?
end
end
@ -125,7 +124,6 @@ class RemoveStatusService < BaseService
redis.publish('timeline:public', @payload)
if @status.local?
redis.publish('timeline:public:local', @payload)
else
redis.publish('timeline:public:remote', @payload)
redis.publish("timeline:public:domain:#{@account.domain.mb_chars.downcase}", @payload)
@ -137,7 +135,6 @@ class RemoveStatusService < BaseService
redis.publish('timeline:public:media', @payload)
if @status.local?
redis.publish('timeline:public:local:media', @payload)
else
redis.publish('timeline:public:remote:media', @payload)
redis.publish("timeline:public:domain:media:#{@account.domain.mb_chars.downcase}", @payload)

View file

@ -138,7 +138,5 @@
%span= t 'user_mailer.welcome.tip_mobile_webapp'
%li
%span= t 'user_mailer.welcome.tip_following'
%li
%span= t 'user_mailer.welcome.tip_local_timeline', instance: @instance
%li
%span= t 'user_mailer.welcome.tip_federated_timeline'

View file

@ -25,5 +25,4 @@
* <%= t 'user_mailer.welcome.tip_mobile_webapp' %>
* <%= t 'user_mailer.welcome.tip_following' %>
* <%= t 'user_mailer.welcome.tip_local_timeline', instance: @instance %>
* <%= t 'user_mailer.welcome.tip_federated_timeline' %>

View file

@ -1572,8 +1572,8 @@ en:
review_preferences_action: Change preferences
review_preferences_step: Make sure to set your preferences, such as which emails you'd like to receive, or what privacy level youd like your posts to default to. If you dont have motion sickness, you could choose to enable GIF autoplay.
subject: Welcome to Mastodon
tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbours are subscribed to, so it's not complete.
tip_following: You follow your server's admin(s) by default. To find more interesting people, check the local and federated timelines.
tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbors are subscribed to or posts sent via relay, so it's not complete.
tip_following: "Initially, the administrator of the server is following the specified account. To find more interesting people, check the #introductions tag and federated timelines."
tip_local_timeline: The local timeline is a firehose view of people on %{instance}. These are your immediate neighbours!
tip_mobile_webapp: If your mobile browser offers you to add Mastodon to your homescreen, you can receive push notifications. It acts like a native app in many ways!
tips: Tips

View file

@ -1469,14 +1469,14 @@ ja:
edit_profile_step: アイコンやヘッダーの画像をアップロードしたり、表示名を変更したりして、自分のプロフィールをカスタマイズすることができます。また、誰かからの新規フォローを許可する前にその人の様子を見ておきたい場合、アカウントを承認制にすることもできます。
explanation: 始めるにあたってのアドバイスです
final_action: 始めましょう
final_step: 'さあ、始めましょう! たとえフォロワーがまだいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどを通じて誰かの目にとまるはずです。自己紹介をしたいときには #introductions ハッシュタグが便利かもしれません。'
final_step: 'さあ、始めましょう! たとえフォロワーがまだいなくても、あなたの公開した投稿は連合タイムラインやハッシュタグなどを通じて誰かの目にとまるはずです。自己紹介をしたいときには #introductions ハッシュタグが便利かもしれません。'
full_handle: あなたの正式なユーザーID
full_handle_hint: 別のサーバーの友達とフォローやメッセージをやり取りする際には、これを伝えることになります。
review_preferences_action: 設定の変更
review_preferences_step: 受け取りたいメールの種類や投稿のデフォルト公開範囲など、ユーザー設定を必ず済ませておきましょう。目が回らない自信があるなら、アニメーション GIF を自動再生する設定もご検討ください。
subject: Mastodon へようこそ
tip_federated_timeline: 連合タイムラインは Mastodon ネットワークの流れを見られるものです。ただしあなたと同じサーバーの人がフォローしている人だけが含まれるので、それが全てではありません。
tip_following: 最初は、サーバーの管理者をフォローした状態になっています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してみましょう。
tip_federated_timeline: 連合タイムラインは Mastodon ネットワークの流れを見られるものです。ただしあなたと同じサーバーの人がフォローしている人や、リレーを経由して送られてくる投稿だけが含まれるので、それが全てではありません。
tip_following: 最初は、サーバーの管理者が指定したアカウントをフォローした状態になっています。もっと興味のある人たちを見つけるには、#introductions ハッシュタグタイムラインと連合タイムラインを確認してみましょう。
tip_local_timeline: ローカルタイムラインは %{instance} にいる人々の流れを見られるものです。彼らはあなたと同じサーバーにいる隣人のようなものです!
tip_mobile_webapp: お使いのモバイル端末で、ブラウザから Mastodon をホーム画面に追加できますか? もし追加できる場合、プッシュ通知の受け取りなど、まるで「普通の」アプリのような機能が楽しめます!
tips: 豆知識

View file

@ -365,16 +365,12 @@ const startWorker = (workerId) => {
return 'user:notification';
case '/api/v1/streaming/public':
return onlyMedia ? 'public:media' : 'public';
case '/api/v1/streaming/public/local':
return onlyMedia ? 'public:local:media' : 'public:local';
case '/api/v1/streaming/public/remote':
return onlyMedia ? 'public:remote:media' : 'public:remote';
case '/api/v1/streaming/public/domain':
return onlyMedia ? 'public:domain:media' : 'public:domain';
case '/api/v1/streaming/hashtag':
return 'hashtag';
case '/api/v1/streaming/hashtag/local':
return 'hashtag:local';
case '/api/v1/streaming/direct':
return 'direct';
case '/api/v1/streaming/list':
@ -387,14 +383,11 @@ const startWorker = (workerId) => {
const PUBLIC_CHANNELS = [
'public',
'public:media',
'public:local',
'public:local:media',
'public:remote',
'public:remote:media',
'public:domain',
'public:domain:media',
'hashtag',
'hashtag:local',
];
/**
@ -808,13 +801,6 @@ const startWorker = (workerId) => {
options: { needsFiltering: true, notificationOnly: false },
});
break;
case 'public:local':
resolve({
channelIds: ['timeline:public:local'],
options: { needsFiltering: true, notificationOnly: false },
});
break;
case 'public:remote':
resolve({
@ -840,13 +826,6 @@ const startWorker = (workerId) => {
options: { needsFiltering: true, notificationOnly: false },
});
break;
case 'public:local:media':
resolve({
channelIds: ['timeline:public:local:media'],
options: { needsFiltering: true, notificationOnly: false },
});
break;
case 'public:remote:media':
resolve({
@ -883,17 +862,6 @@ const startWorker = (workerId) => {
});
}
break;
case 'hashtag:local':
if (!params.tag || params.tag.length === 0) {
reject('No tag for stream provided');
} else {
resolve({
channelIds: [`timeline:hashtag:${params.tag.toLowerCase()}:local`],
options: { needsFiltering: true, notificationOnly: false },
});
}
break;
case 'list':
authorizeListAccess(params.list, req).then(() => {
@ -919,7 +887,7 @@ const startWorker = (workerId) => {
const streamNameFromChannelName = (channelName, params) => {
if (channelName === 'list') {
return [channelName, params.list];
} else if (['hashtag', 'hashtag:local'].includes(channelName)) {
} else if (channelName === 'hashtag') {
return [channelName, params.tag];
} else if (['public:domain', 'public:domain:media'].includes(channelName)) {
return [channelName, params.domain];