[IMPROVEMENT] Reusable toast (#1065)
This commit is contained in:
parent
266ae3bac7
commit
aac6da34af
|
@ -21,6 +21,8 @@ import I18n from '../i18n';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import Navigation from '../lib/Navigation';
|
import Navigation from '../lib/Navigation';
|
||||||
import { getMessageTranslation } from './message/utils';
|
import { getMessageTranslation } from './message/utils';
|
||||||
|
import { LISTENER } from './Toast';
|
||||||
|
import EventEmitter from '../utils/events';
|
||||||
|
|
||||||
@connect(
|
@connect(
|
||||||
state => ({
|
state => ({
|
||||||
|
@ -48,7 +50,6 @@ export default class MessageActions extends React.Component {
|
||||||
actionsHide: PropTypes.func.isRequired,
|
actionsHide: PropTypes.func.isRequired,
|
||||||
room: PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
actionMessage: PropTypes.object,
|
actionMessage: PropTypes.object,
|
||||||
toast: PropTypes.element,
|
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
deleteRequest: PropTypes.func.isRequired,
|
deleteRequest: PropTypes.func.isRequired,
|
||||||
editInit: PropTypes.func.isRequired,
|
editInit: PropTypes.func.isRequired,
|
||||||
|
@ -275,9 +276,9 @@ export default class MessageActions extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCopy = async() => {
|
handleCopy = async() => {
|
||||||
const { actionMessage, toast } = this.props;
|
const { actionMessage } = this.props;
|
||||||
await Clipboard.setString(actionMessage.msg);
|
await Clipboard.setString(actionMessage.msg);
|
||||||
toast.show(I18n.t('Copied_to_clipboard'));
|
EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShare = async() => {
|
handleShare = async() => {
|
||||||
|
@ -294,10 +295,10 @@ export default class MessageActions extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePermalink = async() => {
|
handlePermalink = async() => {
|
||||||
const { actionMessage, toast } = this.props;
|
const { actionMessage } = this.props;
|
||||||
const permalink = await this.getPermalink(actionMessage);
|
const permalink = await this.getPermalink(actionMessage);
|
||||||
Clipboard.setString(permalink);
|
Clipboard.setString(permalink);
|
||||||
toast.show(I18n.t('Permalink_copied_to_clipboard'));
|
EventEmitter.emit(LISTENER, { message: I18n.t('Permalink_copied_to_clipboard') });
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePin = () => {
|
handlePin = () => {
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import EasyToast from 'react-native-easy-toast';
|
||||||
|
|
||||||
|
import { COLOR_TOAST, COLOR_WHITE } from '../constants/colors';
|
||||||
|
import sharedStyles from '../views/Styles';
|
||||||
|
import EventEmitter from '../utils/events';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
toast: {
|
||||||
|
backgroundColor: COLOR_TOAST,
|
||||||
|
maxWidth: 300,
|
||||||
|
padding: 10
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
color: COLOR_WHITE,
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: 'center'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const LISTENER = 'Toast';
|
||||||
|
|
||||||
|
export default class Toast extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
EventEmitter.addEventListener(LISTENER, this.showToast);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
EventEmitter.removeListener(LISTENER);
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast = ({ message }) => {
|
||||||
|
this.toast.show(message, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<EasyToast
|
||||||
|
ref={toast => this.toast = toast}
|
||||||
|
position='center'
|
||||||
|
style={styles.toast}
|
||||||
|
textStyle={styles.text}
|
||||||
|
opacity={0.9}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import { initializePushNotifications, onNotification } from './notifications/pus
|
||||||
import store from './lib/createStore';
|
import store from './lib/createStore';
|
||||||
import NotificationBadge from './notifications/inApp';
|
import NotificationBadge from './notifications/inApp';
|
||||||
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
||||||
|
import Toast from './containers/Toast';
|
||||||
|
|
||||||
useScreens();
|
useScreens();
|
||||||
|
|
||||||
|
@ -231,6 +232,7 @@ class CustomInsideStack extends React.Component {
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<InsideStackModal navigation={navigation} />
|
<InsideStackModal navigation={navigation} />
|
||||||
<NotificationBadge navigation={navigation} />
|
<NotificationBadge navigation={navigation} />
|
||||||
|
<Toast />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,3 @@
|
||||||
import React from 'react';
|
import { Alert } from 'react-native';
|
||||||
import { Alert, StyleSheet } from 'react-native';
|
|
||||||
import EasyToast from 'react-native-easy-toast';
|
|
||||||
|
|
||||||
import { COLOR_TOAST, COLOR_WHITE } from '../constants/colors';
|
|
||||||
import { isNotch } from './deviceInfo';
|
|
||||||
import sharedStyles from '../views/Styles';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
toast: {
|
|
||||||
backgroundColor: COLOR_TOAST
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
...sharedStyles.textRegular,
|
|
||||||
color: COLOR_WHITE,
|
|
||||||
fontSize: 14
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const positionValue = isNotch ? 230 : 200;
|
|
||||||
|
|
||||||
export const Toast = React.forwardRef((props, ref) => (
|
|
||||||
<EasyToast
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
positionValue={positionValue}
|
|
||||||
style={styles.toast}
|
|
||||||
textStyle={styles.text}
|
|
||||||
opacity={0.8}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
export const showErrorAlert = (message, title, onPress = () => {}) => Alert.alert(title, message, [{ text: 'OK', onPress }], { cancelable: true });
|
export const showErrorAlert = (message, title, onPress = () => {}) => Alert.alert(title, message, [{ text: 'OK', onPress }], { cancelable: true });
|
||||||
|
|
|
@ -13,7 +13,9 @@ import KeyboardView from '../../presentation/KeyboardView';
|
||||||
import sharedStyles from '../Styles';
|
import sharedStyles from '../Styles';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
import { showErrorAlert, Toast } from '../../utils/info';
|
import { showErrorAlert } from '../../utils/info';
|
||||||
|
import { LISTENER } from '../../containers/Toast';
|
||||||
|
import EventEmitter from '../../utils/events';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
import RCTextInput from '../../containers/TextInput';
|
import RCTextInput from '../../containers/TextInput';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
|
@ -222,7 +224,7 @@ export default class ProfileView extends React.Component {
|
||||||
setUser({ ...params });
|
setUser({ ...params });
|
||||||
}
|
}
|
||||||
this.setState({ saving: false, showPasswordAlert: false });
|
this.setState({ saving: false, showPasswordAlert: false });
|
||||||
this.toast.show(I18n.t('Profile_saved_successfully'));
|
EventEmitter.emit(LISTENER, { message: I18n.t('Profile_saved_successfully') });
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -235,7 +237,7 @@ export default class ProfileView extends React.Component {
|
||||||
try {
|
try {
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
await RocketChat.resetAvatar(user.id);
|
await RocketChat.resetAvatar(user.id);
|
||||||
this.toast.show(I18n.t('Avatar_changed_successfully'));
|
EventEmitter.emit(LISTENER, { message: I18n.t('Avatar_changed_successfully') });
|
||||||
this.init();
|
this.init();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.handleError(e, 'resetAvatar', 'changing_avatar');
|
this.handleError(e, 'resetAvatar', 'changing_avatar');
|
||||||
|
@ -386,7 +388,6 @@ export default class ProfileView extends React.Component {
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
>
|
>
|
||||||
<StatusBar />
|
<StatusBar />
|
||||||
<Toast ref={toast => this.toast = toast} />
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
contentContainerStyle={sharedStyles.containerScrollView}
|
contentContainerStyle={sharedStyles.containerScrollView}
|
||||||
testID='profile-view-list'
|
testID='profile-view-list'
|
||||||
|
|
|
@ -12,7 +12,9 @@ import KeyboardView from '../../presentation/KeyboardView';
|
||||||
import sharedStyles from '../Styles';
|
import sharedStyles from '../Styles';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
import { showErrorAlert, Toast } from '../../utils/info';
|
import { showErrorAlert } from '../../utils/info';
|
||||||
|
import { LISTENER } from '../../containers/Toast';
|
||||||
|
import EventEmitter from '../../utils/events';
|
||||||
import database, { safeAddListener } from '../../lib/realm';
|
import database, { safeAddListener } from '../../lib/realm';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
import RCTextInput from '../../containers/TextInput';
|
import RCTextInput from '../../containers/TextInput';
|
||||||
|
@ -215,7 +217,7 @@ export default class RoomInfoEditView extends React.Component {
|
||||||
if (error) {
|
if (error) {
|
||||||
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_settings') }));
|
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_settings') }));
|
||||||
} else {
|
} else {
|
||||||
this.toast.show(I18n.t('Settings_succesfully_changed'));
|
EventEmitter.emit(LISTENER, { message: I18n.t('Settings_succesfully_changed') });
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
@ -428,7 +430,6 @@ export default class RoomInfoEditView extends React.Component {
|
||||||
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text>
|
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Loading visible={saving} />
|
<Loading visible={saving} />
|
||||||
<Toast ref={toast => this.toast = toast} />
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</KeyboardView>
|
</KeyboardView>
|
||||||
|
|
|
@ -12,7 +12,8 @@ import UserItem from '../../presentation/UserItem';
|
||||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
import database, { safeAddListener } from '../../lib/realm';
|
import database, { safeAddListener } from '../../lib/realm';
|
||||||
import { Toast } from '../../utils/info';
|
import { LISTENER } from '../../containers/Toast';
|
||||||
|
import EventEmitter from '../../utils/events';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import SearchBox from '../../containers/SearchBox';
|
import SearchBox from '../../containers/SearchBox';
|
||||||
|
@ -232,7 +233,7 @@ export default class RoomMembersView extends React.Component {
|
||||||
const { rid, userLongPressed } = this.state;
|
const { rid, userLongPressed } = this.state;
|
||||||
try {
|
try {
|
||||||
await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
|
await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
|
||||||
this.toast.show(I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }));
|
EventEmitter.emit(LISTENER, { message: I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }) });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('err_handle_mute', e);
|
log('err_handle_mute', e);
|
||||||
}
|
}
|
||||||
|
@ -299,7 +300,6 @@ export default class RoomMembersView extends React.Component {
|
||||||
windowSize={10}
|
windowSize={10}
|
||||||
{...scrollPersistTaps}
|
{...scrollPersistTaps}
|
||||||
/>
|
/>
|
||||||
<Toast ref={toast => this.toast = toast} />
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import debounce from '../../utils/debounce';
|
||||||
import buildMessage from '../../lib/methods/helpers/buildMessage';
|
import buildMessage from '../../lib/methods/helpers/buildMessage';
|
||||||
import FileModal from '../../containers/FileModal';
|
import FileModal from '../../containers/FileModal';
|
||||||
import ReactionsModal from '../../containers/ReactionsModal';
|
import ReactionsModal from '../../containers/ReactionsModal';
|
||||||
import { Toast } from '../../utils/info';
|
import { LISTENER } from '../../containers/Toast';
|
||||||
import { isReadOnly, isBlocked } from '../../utils/room';
|
import { isReadOnly, isBlocked } from '../../utils/room';
|
||||||
|
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
|
@ -472,7 +472,7 @@ export default class RoomView extends React.Component {
|
||||||
toggleFollowThread = async(isFollowingThread) => {
|
toggleFollowThread = async(isFollowingThread) => {
|
||||||
try {
|
try {
|
||||||
await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread);
|
await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread);
|
||||||
this.toast.show(isFollowingThread ? 'Unfollowed thread' : 'Following thread');
|
EventEmitter.emit(LISTENER, { message: isFollowingThread ? 'Unfollowed thread' : 'Following thread' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('err_toggle_follow_thread', e);
|
log('err_toggle_follow_thread', e);
|
||||||
}
|
}
|
||||||
|
@ -600,7 +600,7 @@ export default class RoomView extends React.Component {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{room._id && showActions
|
{room._id && showActions
|
||||||
? <MessageActions room={room} tmid={this.tmid} user={user} toast={this.toast} />
|
? <MessageActions room={room} tmid={this.tmid} user={user} />
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
{showErrorActions ? <MessageErrorActions /> : null}
|
{showErrorActions ? <MessageErrorActions /> : null}
|
||||||
|
@ -638,7 +638,6 @@ export default class RoomView extends React.Component {
|
||||||
user={user}
|
user={user}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
/>
|
/>
|
||||||
<Toast ref={toast => this.toast = toast} />
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue