Add preferences for notification badges

This commit is contained in:
Thibaut Girka 2018-09-06 20:55:11 +02:00 committed by ThibG
parent 46fcc9fd96
commit 3dc5051f03
6 changed files with 39 additions and 6 deletions

View file

@ -47,6 +47,7 @@ const messages = defineMessages({
export default function DrawerHeader ({ export default function DrawerHeader ({
columns, columns,
unreadNotifications, unreadNotifications,
showNotificationsBadge,
intl, intl,
onSettingsClick, onSettingsClick,
}) { }) {
@ -81,7 +82,7 @@ export default function DrawerHeader ({
> >
<span className='icon-badge-wrapper'> <span className='icon-badge-wrapper'>
<Icon icon='bell' /> <Icon icon='bell' />
{ unreadNotifications > 0 && <div className='icon-badge' />} { showNotificationsBadge && unreadNotifications > 0 && <div className='icon-badge' />}
</span> </span>
</Link> </Link>
))} ))}
@ -119,6 +120,7 @@ export default function DrawerHeader ({
DrawerHeader.propTypes = { DrawerHeader.propTypes = {
columns: ImmutablePropTypes.list, columns: ImmutablePropTypes.list,
unreadNotifications: PropTypes.number, unreadNotifications: PropTypes.number,
showNotificationsBadge: PropTypes.bool,
intl: PropTypes.object, intl: PropTypes.object,
onSettingsClick: PropTypes.func, onSettingsClick: PropTypes.func,
}; };

View file

@ -35,6 +35,7 @@ const mapStateToProps = state => ({
searchValue: state.getIn(['search', 'value']), searchValue: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']), submitted: state.getIn(['search', 'submitted']),
unreadNotifications: state.getIn(['notifications', 'unread']), unreadNotifications: state.getIn(['notifications', 'unread']),
showNotificationsBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
}); });
// Dispatch mapping. // Dispatch mapping.
@ -89,6 +90,7 @@ class Drawer extends React.Component {
submitted, submitted,
isSearchPage, isSearchPage,
unreadNotifications, unreadNotifications,
showNotificationsBadge,
} = this.props; } = this.props;
const computedClass = classNames('drawer', `mbstobon-${elefriend}`); const computedClass = classNames('drawer', `mbstobon-${elefriend}`);
@ -99,6 +101,7 @@ class Drawer extends React.Component {
<DrawerHeader <DrawerHeader
columns={columns} columns={columns}
unreadNotifications={unreadNotifications} unreadNotifications={unreadNotifications}
showNotificationsBadge={showNotificationsBadge}
intl={intl} intl={intl}
onSettingsClick={onOpenSettings} onSettingsClick={onOpenSettings}
/> />
@ -143,6 +146,7 @@ Drawer.propTypes = {
searchValue: PropTypes.string, searchValue: PropTypes.string,
submitted: PropTypes.bool, submitted: PropTypes.bool,
unreadNotifications: PropTypes.number, unreadNotifications: PropTypes.number,
showNotificationsBadge: PropTypes.bool,
// Dispatch props. // Dispatch props.
onChange: PropTypes.func, onChange: PropTypes.func,

View file

@ -42,6 +42,25 @@ export default class LocalSettingsPage extends React.PureComponent {
> >
<FormattedMessage id='settings.show_reply_counter' defaultMessage='Display an estimate of the reply count' /> <FormattedMessage id='settings.show_reply_counter' defaultMessage='Display an estimate of the reply count' />
</LocalSettingsPageItem> </LocalSettingsPageItem>
<section>
<h2><FormattedMessage id='settings.notifications_opts' defaultMessage='Notifications options' /></h2>
<LocalSettingsPageItem
settings={settings}
item={['notifications', 'tab_badge']}
id='mastodon-settings--notifications-tab_badge'
onChange={onChange}
>
<FormattedMessage id='settings.notifications.tab_badge' defaultMessage="Display a badge for unread notifications if the notifications column isn't open" />
</LocalSettingsPageItem>
<LocalSettingsPageItem
settings={settings}
item={['notifications', 'favicon_badge']}
id='mastodon-settings--notifications-favicon_badge'
onChange={onChange}
>
<FormattedMessage id='settings.notifications.favicon_badge' defaultMessage='Display unread notifications count in the favicon' />
</LocalSettingsPageItem>
</section>
<section> <section>
<h2><FormattedMessage id='settings.layout_opts' defaultMessage='Layout options' /></h2> <h2><FormattedMessage id='settings.layout_opts' defaultMessage='Layout options' /></h2>
<LocalSettingsPageItem <LocalSettingsPageItem
@ -78,7 +97,6 @@ export default class LocalSettingsPage extends React.PureComponent {
), ),
({ intl, onChange, settings }) => ( ({ intl, onChange, settings }) => (
<div className='glitch local-settings_page compose_box_opts'> <div className='glitch local-settings_page compose_box_opts'>
<section>
<h1><FormattedMessage id='settings.compose_box_opts' defaultMessage='Compose box options' /></h1> <h1><FormattedMessage id='settings.compose_box_opts' defaultMessage='Compose box options' /></h1>
<LocalSettingsPageItem <LocalSettingsPageItem
settings={settings} settings={settings}

View file

@ -8,20 +8,22 @@ import { connect } from 'react-redux';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
unreadNotifications: state.getIn(['notifications', 'unread']), unreadNotifications: state.getIn(['notifications', 'unread']),
showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
}); });
@connect(mapStateToProps) @connect(mapStateToProps)
class NotificationsIcon extends React.PureComponent { class NotificationsIcon extends React.PureComponent {
static propTypes = { static propTypes = {
unreadNotifications: PropTypes.number, unreadNotifications: PropTypes.number,
showBadge: PropTypes.bool,
}; };
render() { render() {
const { unreadNotifications } = this.props; const { unreadNotifications, showBadge } = this.props;
return ( return (
<span className='icon-badge-wrapper'> <span className='icon-badge-wrapper'>
<i className='fa fa-fw fa-bell' /> <i className='fa fa-fw fa-bell' />
{ unreadNotifications > 0 && <div className='icon-badge' />} { showBadge && unreadNotifications > 0 && <div className='icon-badge' />}
</span> </span>
); );
} }

View file

@ -66,6 +66,7 @@ const mapStateToProps = state => ({
navbarUnder: state.getIn(['local_settings', 'navbar_under']), navbarUnder: state.getIn(['local_settings', 'navbar_under']),
dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
unreadNotifications: state.getIn(['notifications', 'unread']), unreadNotifications: state.getIn(['notifications', 'unread']),
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
}); });
const keyMap = { const keyMap = {
@ -118,6 +119,7 @@ export default class UI extends React.Component {
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
dropdownMenuIsOpen: PropTypes.bool, dropdownMenuIsOpen: PropTypes.bool,
unreadNotifications: PropTypes.number, unreadNotifications: PropTypes.number,
showFaviconBadge: PropTypes.bool,
}; };
state = { state = {
@ -272,9 +274,10 @@ export default class UI extends React.Component {
if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) {
this.columnsAreaNode.handleChildrenContentChange(); this.columnsAreaNode.handleChildrenContentChange();
} }
if (this.props.unreadNotifications != prevProps.unreadNotifications) { if (this.props.unreadNotifications != prevProps.unreadNotifications ||
this.props.showFaviconBadge != prevProps.showFaviconBadge) {
if (this.favicon) { if (this.favicon) {
this.favicon.badge(this.props.unreadNotifications); this.favicon.badge(this.props.showFaviconBadge ? this.props.unreadNotifications : 0);
} }
} }
} }

View file

@ -37,6 +37,10 @@ const initialState = ImmutableMap({
letterbox : true, letterbox : true,
fullwidth : true, fullwidth : true,
}), }),
notifications : ImmutableMap({
favicon_badge : false,
tab_badge : true,
}),
}); });
const hydrate = (state, localSettings) => state.mergeDeep(localSettings); const hydrate = (state, localSettings) => state.mergeDeep(localSettings);