Merge branch 'chat_notifications' into 'develop'

Chat notifications

Closes #398 and #354

See merge request soapbox-pub/soapbox-fe!211
better-alerts
Alex Gleason 2020-09-18 04:40:27 +00:00
commit efe66d4301
11 zmienionych plików z 124 dodań i 12 usunięć

Wyświetl plik

@ -188,6 +188,8 @@ Customization details can be found in the [Customization doc](docs/customization
Soapbox FE is based on [Gab Social](https://code.gab.com/gab/social/gab-social)'s frontend which is in turn based on [Mastodon](https://github.com/tootsuite/mastodon/)'s frontend.
- `static/sounds/chat.mp3` and `static/sounds/chat.oga` are from [notificationsounds.com](https://notificationsounds.com/notification-sounds/intuition-561) licensed under CC BY 4.0.
Soapbox FE is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or

Wyświetl plik

@ -32,6 +32,7 @@ const defaultSettings = ImmutableMap({
chats: ImmutableMap({
panes: ImmutableList(),
mainWindow: 'minimized',
sound: true,
}),
home: ImmutableMap({

Wyświetl plik

@ -55,7 +55,17 @@ export function connectTimelineStream(timelineId, path, pollingRefresh = null, a
dispatch(fetchFilters());
break;
case 'pleroma:chat_update':
dispatch({ type: STREAMING_CHAT_UPDATE, chat: JSON.parse(data.payload), me: getState().get('me') });
dispatch((dispatch, getState) => {
const chat = JSON.parse(data.payload);
const messageOwned = !(chat.last_message && chat.last_message.account_id !== getState().get('me'));
dispatch({
type: STREAMING_CHAT_UPDATE,
chat,
// Only play sounds for recipient messages
meta: !messageOwned && getSettings(getState()).getIn(['chats', 'sound']) && { sound: 'chat' },
});
});
break;
}
},

Wyświetl plik

@ -36,6 +36,7 @@ class SoapboxHelmet extends React.Component {
<Helmet
titleTemplate={this.addCounter(`%s | ${siteTitle}`)}
defaultTitle={this.addCounter(siteTitle)}
defer={false}
>
{children}
</Helmet>

Wyświetl plik

@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, defineMessages } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Icon from 'soapbox/components/icon';
import { changeSetting, getSettings } from 'soapbox/actions/settings';
import SettingToggle from 'soapbox/features/notifications/components/setting_toggle';
const messages = defineMessages({
switchToOn: { id: 'chats.audio_toggle_on', defaultMessage: 'Audio notification on' },
switchToOff: { id: 'chats.audio_toggle_off', defaultMessage: 'Audio notification off' },
});
const mapStateToProps = state => {
return {
settings: getSettings(state),
};
};
const mapDispatchToProps = (dispatch) => ({
toggleAudio(setting) {
dispatch(changeSetting(['chats', 'sound'], setting));
},
});
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class AudioToggle extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
settings: ImmutablePropTypes.map.isRequired,
toggleAudio: PropTypes.func,
showLabel: PropTypes.bool,
};
handleToggleAudio = () => {
this.props.toggleAudio(this.props.settings.getIn(['chats', 'sound']) === true ? false : true);
}
render() {
const { intl, settings, showLabel } = this.props;
let toggle = (
<SettingToggle settings={settings} settingPath={['chats', 'sound']} onChange={this.handleToggleAudio} icons={{ checked: <Icon id='volume-up' />, unchecked: <Icon id='volume-off' /> }} ariaLabel={settings.get('chats', 'sound') === true ? intl.formatMessage(messages.switchToOff) : intl.formatMessage(messages.switchToOn)} />
);
if (showLabel) {
toggle = (
<SettingToggle settings={settings} settingPath={['chats', 'sound']} onChange={this.handleToggleAudio} icons={{ checked: <Icon id='volume-up' />, unchecked: <Icon id='volume-off' /> }} label={settings.get('chats', 'sound') === true ? intl.formatMessage(messages.switchToOff) : intl.formatMessage(messages.switchToOn)} />
);
}
return (
<div className='audio-toggle react-toggle--mini'>
{toggle}
</div>
);
}
}

Wyświetl plik

@ -94,6 +94,7 @@ class ChatBox extends ImmutablePureComponent {
}
handleKeyDown = (e) => {
this.markRead();
if (e.key === 'Enter' && e.shiftKey) {
this.insertLine();
e.preventDefault();
@ -122,17 +123,6 @@ class ChatBox extends ImmutablePureComponent {
onSetInputRef(el);
};
componentDidUpdate(prevProps) {
const markReadConditions = [
() => this.props.chat !== undefined,
() => document.activeElement === this.inputElem,
() => this.props.chat.get('unread') > 0,
];
if (markReadConditions.every(c => c() === true))
this.markRead();
}
handleRemoveFile = (e) => {
this.setState({ attachment: undefined, resetFileKey: fileKeyGen() });
}

Wyświetl plik

@ -11,6 +11,7 @@ import { makeGetChat } from 'soapbox/selectors';
import { openChat, toggleMainWindow } from 'soapbox/actions/chats';
import ChatWindow from './chat_window';
import { shortNumberFormat } from 'soapbox/utils/numbers';
import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
const addChatsToPanes = (state, panesData) => {
const getChat = makeGetChat();
@ -62,6 +63,7 @@ class ChatPanes extends ImmutablePureComponent {
<button className='pane__title' onClick={this.handleMainWindowToggle}>
<FormattedMessage id='chat_panels.main_window.title' defaultMessage='Chats' />
</button>
<AudioToggle />
</div>
<div className='pane__content'>
<ChatList

Wyświetl plik

@ -36,6 +36,16 @@ export default function soundsMiddleware() {
type: 'audio/mpeg',
},
]),
chat: createAudio([
{
src: '/sounds/chat.oga',
type: 'audio/ogg',
},
{
src: '/sounds/chat.mp3',
type: 'audio/mpeg',
},
]),
};
return () => next => action => {

Wyświetl plik

@ -94,6 +94,41 @@
overflow: hidden;
}
}
.audio-toggle .react-toggle-thumb {
height: 14px;
width: 14px;
border: 1px solid var(--brand-color--med);
}
.audio-toggle .react-toggle {
height: 16px;
top: 4px;
}
.audio-toggle .react-toggle-track {
height: 16px;
width: 34px;
background-color: var(--accent-color);
}
.audio-toggle .react-toggle-track-check {
left: 4px;
bottom: 4px;
}
.react-toggle--checked .react-toggle-thumb {
left: 19px;
}
.audio-toggle .react-toggle-track-x {
right: 4px;
bottom: 4px;
}
.fa {
font-size: 14px;
}
}
.chat-messages {

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.