Merge branch 'origin/master' into sync/upstream
Conflicts: app/javascript/mastodon/components/status_list.js app/javascript/mastodon/features/notifications/index.js app/javascript/mastodon/features/ui/components/modal_root.js app/javascript/mastodon/features/ui/components/onboarding_modal.js app/javascript/mastodon/features/ui/index.js app/javascript/styles/about.scss app/javascript/styles/accounts.scss app/javascript/styles/components.scss app/presenters/instance_presenter.rb app/services/post_status_service.rb app/services/reblog_service.rb app/views/about/more.html.haml app/views/about/show.html.haml app/views/accounts/_header.html.haml config/webpack/loaders/babel.js spec/controllers/api/v1/accounts/credentials_controller_spec.rb
This commit is contained in:
@@ -32,7 +32,7 @@ const makeMapStateToProps = () => {
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||
if (this.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> }} />,
|
||||
|
39
app/javascript/mastodon/containers/compose_container.js
Normal file
39
app/javascript/mastodon/containers/compose_container.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import configureStore from '../store/configureStore';
|
||||
import { hydrateStore } from '../actions/store';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
import Compose from '../features/standalone/compose';
|
||||
|
||||
const { localeData, messages } = getLocale();
|
||||
addLocaleData(localeData);
|
||||
|
||||
const store = configureStore();
|
||||
const initialStateContainer = document.getElementById('initial-state');
|
||||
|
||||
if (initialStateContainer !== null) {
|
||||
const initialState = JSON.parse(initialStateContainer.textContent);
|
||||
store.dispatch(hydrateStore(initialState));
|
||||
}
|
||||
|
||||
export default class TimelineContainer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { locale } = this.props;
|
||||
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Provider store={store}>
|
||||
<Compose />
|
||||
</Provider>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -2,21 +2,13 @@ import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import configureStore from '../store/configureStore';
|
||||
import {
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
refreshHomeTimeline,
|
||||
connectTimeline,
|
||||
disconnectTimeline,
|
||||
} from '../actions/timelines';
|
||||
import { showOnboardingOnce } from '../actions/onboarding';
|
||||
import { updateNotifications, refreshNotifications } from '../actions/notifications';
|
||||
import BrowserRouter from 'react-router-dom/BrowserRouter';
|
||||
import Route from 'react-router-dom/Route';
|
||||
import ScrollContext from 'react-router-scroll/lib/ScrollBehaviorContext';
|
||||
import UI from '../features/ui';
|
||||
import { hydrateStore } from '../actions/store';
|
||||
import createStream from '../stream';
|
||||
import { connectUserStream } from '../actions/streaming';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
const { localeData, messages } = getLocale();
|
||||
@@ -39,74 +31,28 @@ export default class Mastodon extends React.PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { locale } = this.props;
|
||||
const streamingAPIBaseURL = store.getState().getIn(['meta', 'streaming_api_base_url']);
|
||||
const accessToken = store.getState().getIn(['meta', 'access_token']);
|
||||
|
||||
const setupPolling = () => {
|
||||
this.polling = setInterval(() => {
|
||||
store.dispatch(refreshHomeTimeline());
|
||||
store.dispatch(refreshNotifications());
|
||||
}, 20000);
|
||||
};
|
||||
|
||||
const clearPolling = () => {
|
||||
clearInterval(this.polling);
|
||||
this.polling = undefined;
|
||||
};
|
||||
|
||||
this.subscription = createStream(streamingAPIBaseURL, accessToken, 'user', {
|
||||
|
||||
connected () {
|
||||
clearPolling();
|
||||
store.dispatch(connectTimeline('home'));
|
||||
},
|
||||
|
||||
disconnected () {
|
||||
setupPolling();
|
||||
store.dispatch(disconnectTimeline('home'));
|
||||
},
|
||||
|
||||
received (data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
store.dispatch(updateTimeline('home', JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
store.dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
case 'notification':
|
||||
store.dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
reconnected () {
|
||||
clearPolling();
|
||||
store.dispatch(connectTimeline('home'));
|
||||
store.dispatch(refreshHomeTimeline());
|
||||
store.dispatch(refreshNotifications());
|
||||
},
|
||||
|
||||
});
|
||||
this.disconnect = store.dispatch(connectUserStream());
|
||||
|
||||
// Desktop notifications
|
||||
// Ask after 1 minute
|
||||
if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') {
|
||||
Notification.requestPermission();
|
||||
window.setTimeout(() => Notification.requestPermission(), 60 * 1000);
|
||||
}
|
||||
|
||||
// Protocol handler
|
||||
// Ask after 5 minutes
|
||||
if (typeof navigator.registerProtocolHandler !== 'undefined') {
|
||||
const handlerUrl = window.location.protocol + '//' + window.location.host + '/intent?uri=%s';
|
||||
window.setTimeout(() => navigator.registerProtocolHandler('web+mastodon', handlerUrl, 'Mastodon'), 5 * 60 * 1000);
|
||||
}
|
||||
|
||||
store.dispatch(showOnboardingOnce());
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (typeof this.subscription !== 'undefined') {
|
||||
this.subscription.close();
|
||||
this.subscription = null;
|
||||
}
|
||||
|
||||
if (typeof this.polling !== 'undefined') {
|
||||
clearInterval(this.polling);
|
||||
this.polling = null;
|
||||
if (this.disconnect) {
|
||||
this.disconnect();
|
||||
this.disconnect = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,8 @@ import {
|
||||
favourite,
|
||||
unreblog,
|
||||
unfavourite,
|
||||
pin,
|
||||
unpin,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
blockAccount,
|
||||
@@ -75,6 +77,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
}
|
||||
},
|
||||
|
||||
onPin (status) {
|
||||
if (status.get('pinned')) {
|
||||
dispatch(unpin(status));
|
||||
} else {
|
||||
dispatch(pin(status));
|
||||
}
|
||||
},
|
||||
|
||||
onEmbed (status) {
|
||||
dispatch(openModal('EMBED', { url: status.get('url') }));
|
||||
},
|
||||
|
||||
onDelete (status) {
|
||||
if (!this.deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id')));
|
||||
|
Reference in New Issue
Block a user