Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Commit

Permalink
When streaming API is disconnected, poll home/notifications (mastodon…
Browse files Browse the repository at this point in the history
…#2776)

* When streaming API is disconnected, poll home/notifications
Display slightly different empty home timeline message if user is following others
Cull notifications to 20 items when over 40 get added in real-time
Run manage:translations

* Optimize <HomeTimeline /> a little
  • Loading branch information
Gargron authored May 4, 2017
1 parent 84eb425 commit eddb95b
Show file tree
Hide file tree
Showing 31 changed files with 124 additions and 45 deletions.
35 changes: 24 additions & 11 deletions app/javascript/mastodon/actions/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,62 +54,75 @@ const excludeTypesFromSettings = state => state.getIn(['settings', 'notification

export function refreshNotifications() {
return (dispatch, getState) => {
dispatch(refreshNotificationsRequest());

const params = {};
const ids = getState().getIn(['notifications', 'items']);

let skipLoading = false;

if (ids.size > 0) {
params.since_id = ids.first().get('id');
}

if (getState().getIn(['notifications', 'loaded'])) {
skipLoading = true;
}

params.exclude_types = excludeTypesFromSettings(getState());

dispatch(refreshNotificationsRequest(skipLoading));

api(getState).get('/api/v1/notifications', { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');

dispatch(refreshNotificationsSuccess(response.data, next ? next.uri : null));
dispatch(refreshNotificationsSuccess(response.data, skipLoading, next ? next.uri : null));
fetchRelatedRelationships(dispatch, response.data);
}).catch(error => {
dispatch(refreshNotificationsFail(error));
dispatch(refreshNotificationsFail(error, skipLoading));
});
};
};

export function refreshNotificationsRequest() {
export function refreshNotificationsRequest(skipLoading) {
return {
type: NOTIFICATIONS_REFRESH_REQUEST
type: NOTIFICATIONS_REFRESH_REQUEST,
skipLoading
};
};

export function refreshNotificationsSuccess(notifications, next) {
export function refreshNotificationsSuccess(notifications, skipLoading, next) {
return {
type: NOTIFICATIONS_REFRESH_SUCCESS,
notifications,
accounts: notifications.map(item => item.account),
statuses: notifications.map(item => item.status).filter(status => !!status),
skipLoading,
next
};
};

export function refreshNotificationsFail(error) {
export function refreshNotificationsFail(error, skipLoading) {
return {
type: NOTIFICATIONS_REFRESH_FAIL,
error
error,
skipLoading
};
};

export function expandNotifications() {
return (dispatch, getState) => {
const url = getState().getIn(['notifications', 'next'], null);
const url = getState().getIn(['notifications', 'next'], null);
const lastId = getState().getIn(['notifications', 'items']).last();

if (url === null || getState().getIn(['notifications', 'isLoading'])) {
return;
}

dispatch(expandNotificationsRequest());

const params = {};
const params = {
max_id: lastId,
limit: 20
};

params.exclude_types = excludeTypesFromSettings(getState());

Expand Down
2 changes: 2 additions & 0 deletions app/javascript/mastodon/actions/timelines.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export function refreshTimeline(timeline, id = null) {

params = { ...params, since_id: newestId };
skipLoading = true;
} else if (getState().getIn(['timelines', timeline, 'loaded'])) {
skipLoading = true;
}

dispatch(refreshTimelineRequest(timeline, id, skipLoading));
Expand Down
22 changes: 21 additions & 1 deletion app/javascript/mastodon/containers/mastodon.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,20 +217,34 @@ Container.propTypes = {
children: PropTypes.node,
};

class Mastodon extends React.Component {
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(refreshTimeline('home'));
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'));
},

Expand All @@ -249,6 +263,7 @@ class Mastodon extends React.Component {
},

reconnected () {
clearPolling();
store.dispatch(connectTimeline('home'));
store.dispatch(refreshTimeline('home'));
store.dispatch(refreshNotifications());
Expand All @@ -269,6 +284,11 @@ class Mastodon extends React.Component {
this.subscription.close();
this.subscription = null;
}

if (typeof this.polling !== 'undefined') {
clearInterval(this.polling);
this.polling = null;
}
}

render () {
Expand Down
24 changes: 20 additions & 4 deletions app/javascript/mastodon/features/home_timeline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,33 @@ const messages = defineMessages({
});

const mapStateToProps = state => ({
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
hasFollows: state.getIn(['accounts_counters', state.getIn(['meta', 'me']), 'following_count']) > 0
});

class HomeTimeline extends React.PureComponent {

render () {
const { intl, hasUnread } = this.props;
const { intl, hasUnread, hasFollows } = this.props;

let emptyMessage;

if (hasFollows) {
emptyMessage = <FormattedMessage id='empty_column.home.inactivity' defaultMessage="Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon." />
} else {
emptyMessage = <FormattedMessage id='empty_column.home' defaultMessage="You aren't following anyone yet. Visit {public} or use search to get started and meet other users." values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />;
}

return (
<Column icon='home' active={hasUnread} heading={intl.formatMessage(messages.title)}>
<ColumnSettingsContainer />
<StatusListContainer {...this.props} scrollKey='home_timeline' type='home' emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage="You aren't following anyone yet. Visit {public} or use search to get started and meet other users." values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />} />

<StatusListContainer
{...this.props}
scrollKey='home_timeline'
type='home'
emptyMessage={emptyMessage}
/>
</Column>
);
}
Expand All @@ -32,7 +47,8 @@ class HomeTimeline extends React.PureComponent {

HomeTimeline.propTypes = {
intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool
hasUnread: PropTypes.bool,
hasFollows: PropTypes.bool
};

export default connect(mapStateToProps)(injectIntl(HomeTimeline));
20 changes: 6 additions & 14 deletions app/javascript/mastodon/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.",
"compose_form.lock_disclaimer.lock": "مقفل",
"compose_form.placeholder": "فيمَ تفكّر؟",
"compose_form.privacy_disclaimer": "Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.",
"compose_form.publish": "بوّق !",
"compose_form.sensitive": "ضع علامة على الوسيط باعتباره حسّاس",
"compose_form.spoiler": "أخفِ النص واعرض تحذيرا",
Expand All @@ -53,6 +54,7 @@
"empty_column.community": "الخط الزمني المحلي فارغ. اكتب شيئا ما للعامة كبداية.",
"empty_column.hashtag": "ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.",
"empty_column.home": "إنك لا تتبع بعد أي شخص إلى حد الآن. زر {public} أو استخدام حقل البحث لكي تبدأ على التعرف على مستخدمين آخرين.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "الخيط العام",
"empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.",
"empty_column.public": "لا يوجد شيء هنا ! قم بتحرير شيء ما بشكل عام، أو اتبع مستخدمين آخرين في الخوادم المثيلة الأخرى لملء خيط المحادثات العام.",
Expand Down Expand Up @@ -149,24 +151,14 @@
"tabs_bar.compose": "تحرير",
"tabs_bar.federated_timeline": "Federated",
"tabs_bar.home": "الرئيسية",
"tabs_bar.mentions": "الإشارات",
"tabs_bar.public": "الخيط العام الموحد",
"tabs_bar.local_timeline": "Local",
"tabs_bar.notifications": "الإخطارات",
"upload_area.title": "Drag & drop to upload",
"upload_button.label": "إضافة وسائط",
"upload_form.undo": "إلغاء",
"upload_progress.label": "يرفع...",
"notification.follow": "{name} يتبعك",
"notification.favourite": "{name} أعجب بمنشورك",
"notification.reblog": "{name} قام بترقية تبويقك",
"notification.mention": "{name} ذكرك",
"notifications.column_settings.alert": "إشعارات سطح المكتب",
"notifications.column_settings.show": "إعرِضها في عمود",
"notifications.column_settings.follow": "متابعُون جُدُد :",
"notifications.column_settings.favourite": "المُفَضَّلة :",
"notifications.column_settings.mention": "الإشارات :",
"notifications.column_settings.reblog": "الترقيّات:",
"video_player.expand": "وسّع الفيديو",
"video_player.toggle_sound": "تبديل الصوت",
"video_player.toggle_visible": "إظهار / إخفاء الفيديو",
"video_player.expand": "وسّع الفيديو",
"video_player.video_error": "تعذر تشغيل الفيديو"
}
}
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "the public timeline",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe etwas öffentlich, um den Ball ins Rollen zu bringen!",
"empty_column.hashtag": "Es gibt noch nichts unter diesem Hashtag.",
"empty_column.home": "Du folgst noch niemandem. Besuche {public} oder benutze die Suche, um zu starten oder andere Benutzer anzutreffen.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "die öffentliche Zeitleiste",
"empty_column.notifications": "Du hast noch keine Mitteilungen. Interagiere mit anderen, um die Konversation zu starten.",
"empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Benutzern von anderen Instanzen, um es aufzufüllen.",
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/mastodon/locales/defaultMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,10 @@
{
"defaultMessage": "the public timeline",
"id": "empty_column.home.public_timeline"
},
{
"defaultMessage": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"id": "empty_column.home.inactivity"
}
],
"path": "app/javascript/mastodon/features/home_timeline/index.json"
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "the public timeline",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/eo.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "the public timeline",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "the public timeline",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/fa.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "فهرست نوشته‌های محلی خالی است. چیزی بنویسید تا چرخش بچرخد!",
"empty_column.hashtag": "هنوز هیچ چیزی با این هشتگ نیست.",
"empty_column.home": "شما هنوز پیگیر کسی نیستید. {public} را ببینید یا چیزی را جستجو کنید تا کاربران دیگر را ببینید.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "فهرست نوشته‌های همه‌جا",
"empty_column.notifications": "هنوز هیچ اعلانی ندارید. به نوشته‌های دیگران واکنش نشان دهید تا گفتگو آغاز شود.",
"empty_column.public": "این‌جا هنوز چیزی نیست! خودتان چیزی بنویسید یا کاربران دیگر را پی بگیرید تا این‌جا پر شود",
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "the public timeline",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
Expand Down
7 changes: 4 additions & 3 deletions app/javascript/mastodon/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Qu’avez-vous en tête ?",
"compose_form.privacy_disclaimer": "Votre statut privé va être transmis aux personnes mentionnées sur {domains}. Avez-vous confiance en {domainsCount, plural, one {ce serveur} other {ces serveurs}} pour ne pas divulguer votre statut ? Les statuts privés ne fonctionnent que sur les instances de Mastodon. Si {domains} {domainsCount, plural, one {n’est pas une instance de Mastodon} other {ne sont pas des instances de Mastodon}}, il n’y aura aucune indication que votre statut est privé, et il pourrait être partagé ou rendu visible d’une autre manière à d’autres personnes imprévues.",
"compose_form.private": "Rendre privé",
"compose_form.publish": "Pouet ",
"compose_form.sensitive": "Marquer le média comme délicat",
"compose_form.spoiler": "Masquer le texte derrière un avertissement",
Expand All @@ -54,8 +53,9 @@
"emoji_button.travel": "Travel & Places",
"empty_column.community": "Le fil public local est vide. Écrivez-donc quelque chose pour le remplir !",
"empty_column.hashtag": "Il n’y a encore aucun contenu relatif à ce hashtag",
"empty_column.home.public_timeline": "le fil public",
"empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateurs⋅trices.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "le fil public",
"empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateurs⋅trices pour débuter la conversation.",
"empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateurs⋅trices d’autres instances pour remplir le fil public.",
"follow_request.authorize": "Autoriser",
Expand Down Expand Up @@ -106,6 +106,7 @@
"onboarding.page_one.welcome": "Bienvenue sur Mastodon !",
"onboarding.page_six.admin": "L’administrateur⋅trice de votre instance est {admin}",
"onboarding.page_six.almost_done": "Nous y sommes presque…",
"onboarding.page_six.appetoot": "Bon Appetoot!",
"onboarding.page_six.apps_available": "De nombreuses {apps} sont disponibles pour iOS, Android et autres. Et maintenant… Bon Appetoot!",
"onboarding.page_six.github": "Mastodon est un logiciel libre, gratuit et open-source. Vous pouvez rapporter des bogues, suggérer des fonctionnalités, ou contribuer à son développement sur {github}.",
"onboarding.page_six.guidelines": "règles de la communauté",
Expand Down Expand Up @@ -160,4 +161,4 @@
"video_player.toggle_sound": "Mettre/Couper le son",
"video_player.toggle_visible": "Afficher/Cacher la vidéo",
"video_player.video_error": "Video could not be played"
}
}
1 change: 1 addition & 0 deletions app/javascript/mastodon/locales/hr.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!",
"empty_column.hashtag": "Još ne postoji ništa s ovim hashtagom.",
"empty_column.home": "Još ne slijediš nikoga. Posjeti {public} ili koristi tražilicu kako bi počeo i upoznao druge korisnike.",
"empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.",
"empty_column.home.public_timeline": "javni timeline",
"empty_column.notifications": "Još nemaš notifikacija. Komuniciraj sa drugima kako bi započeo razgovor.",
"empty_column.public": "Ovdje nema ništa! Napiši nešto javno, ili ručno slijedi korisnike sa drugih instanci kako bi popunio",
Expand Down
Loading

0 comments on commit eddb95b

Please sign in to comment.