Fix sentry found issues (#699)

This commit is contained in:
enahum 2017-07-03 18:09:04 -04:00 committed by GitHub
parent 3bb50ff96e
commit 7dbac06983
30 changed files with 237 additions and 70 deletions

View file

@ -1090,3 +1090,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## react-native-status-bar-size
This product contains 'react-native-status-bar-size', Watch and respond to changes in the iOS status bar height.
* HOMEPAGE:
* https://github.com/jgkim/react-native-status-bar-size
* LICENSE:
The MIT License (MIT)
Copyright (c) 2015 Brent Vatne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---

View file

@ -120,12 +120,15 @@ public class CustomPushNotification extends PushNotification {
notification
.setContentTitle(title)
.setContentText(message)
.setGroup(GROUP_KEY_MESSAGES)
.setGroupSummary(true)
.setSmallIcon(smallIconResId)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
notification.setGroup(GROUP_KEY_MESSAGES);
}
if (numMessages > 1) {
notification.setNumber(numMessages);
}

View file

@ -194,7 +194,7 @@ export function selectInitialChannel(teamId) {
// Handle case when the default channel cannot be found
// so we need to get the first available channel of the team
const channelsInTeam = Object.values(channels).filter((c) => c.team_id === teamId);
const firstChannel = channelsInTeam[0].id;
const firstChannel = channelsInTeam.length ? channelsInTeam[0].id : {id: ''};
dispatch(setChannelDisplayName(''));
await handleSelectChannel(firstChannel.id)(dispatch, getState);
}

View file

@ -64,9 +64,17 @@ export function goToNotification(notification) {
};
}
export function setStatusBarHeight(height = 20) {
return {
type: ViewTypes.STATUSBAR_HEIGHT_CHANGED,
data: height
};
}
export default {
loadConfigAndLicense,
queueNotification,
clearNotification,
goToNotification
goToNotification,
setStatusBarHeight
};

View file

@ -16,9 +16,15 @@ function mapStateToProps(state, ownProps) {
let postDraft;
if (ownProps.rootId.length) {
postDraft = state.views.thread.drafts[ownProps.rootId].draft;
const threadDraft = state.views.thread.drafts[ownProps.rootId];
if (threadDraft) {
postDraft = threadDraft.draft;
}
} else if (currentChannelId) {
postDraft = state.views.channel.drafts[currentChannelId].draft;
const channelDraft = state.views.channel.drafts[currentChannelId];
if (channelDraft) {
postDraft = channelDraft.draft;
}
}
return {

View file

@ -17,9 +17,15 @@ function mapStateToProps(state, ownProps) {
let postDraft;
if (ownProps.rootId.length) {
postDraft = state.views.thread.drafts[ownProps.rootId].draft;
const threadDraft = state.views.thread.drafts[ownProps.rootId];
if (threadDraft) {
postDraft = threadDraft.draft;
}
} else if (currentChannelId) {
postDraft = state.views.channel.drafts[currentChannelId].draft;
const channelDraft = state.views.channel.drafts[currentChannelId];
if (channelDraft) {
postDraft = channelDraft.draft;
}
}
const autocompleteChannels = {

View file

@ -20,8 +20,8 @@ function mapStateToProps(state, ownProps) {
return {
...ownProps,
currentTeam: getCurrentTeam(state),
currentChannel: getCurrentChannel(state),
currentTeam: getCurrentTeam(state) || {},
currentChannel: getCurrentChannel(state) || {},
currentDisplayName: state.views.channel.displayName,
currentUserId,
channels: getChannelsWithUnreadSection(state),

View file

@ -101,18 +101,23 @@ class ChannelIntro extends PureComponent {
buildDMContent = () => {
const {currentChannelMembers, intl, theme} = this.props;
const style = getStyleSheet(theme);
const teammate = this.getDisplayName(currentChannelMembers[0]);
return (
<Text style={style.message}>
{intl.formatMessage({
id: 'mobile.intro_messages.DM',
defaultMessage: 'This is the start of your direct message history with {teammate}. Direct messages and files shared here are not shown to people outside this area.'
}, {
teammate
})}
</Text>
);
if (currentChannelMembers.length) {
const teammate = this.getDisplayName(currentChannelMembers[0]);
return (
<Text style={style.message}>
{intl.formatMessage({
id: 'mobile.intro_messages.DM',
defaultMessage: 'This is the start of your direct message history with {teammate}. Direct messages and files shared here are not shown to people outside this area.'
}, {
teammate
})}
</Text>
);
}
return null;
};
buildGMContent = () => {

View file

@ -12,15 +12,18 @@ import {getTheme} from 'app/selectors/preferences';
import ChannelIntro from './channel_intro';
function mapStateToProps(state) {
const currentChannel = getCurrentChannel(state);
const currentUser = getCurrentUser(state);
const currentChannel = getCurrentChannel(state) || {};
const currentUser = getCurrentUser(state) || {};
let currentChannelMembers = [];
if (currentChannel.type === General.DM_CHANNEL) {
const otherChannelMember = currentChannel.name.split('__').find((m) => m !== currentUser.id);
currentChannelMembers.push(state.entities.users.profiles[otherChannelMember]);
const otherProfile = state.entities.users.profiles[otherChannelMember];
if (otherProfile) {
currentChannelMembers.push(otherProfile);
}
} else {
currentChannelMembers = getProfilesInCurrentChannel(state);
currentChannelMembers = getProfilesInCurrentChannel(state) || [];
currentChannelMembers = currentChannelMembers.filter((m) => m.id !== currentUser.id);
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {Component} from 'react';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
View,
@ -35,7 +35,7 @@ const ICON_PATH_FROM_FILE_TYPE = {
word: wordIcon
};
export default class FileAttachmentIcon extends Component {
export default class FileAttachmentIcon extends PureComponent {
static propTypes = {
file: PropTypes.object.isRequired,
iconHeight: PropTypes.number,
@ -49,7 +49,7 @@ export default class FileAttachmentIcon extends Component {
iconWidth: 60,
wrapperHeight: 100,
wrapperWidth: 100
}
};
getFileIconPath(file) {
const fileType = Utils.getFileType(file);

View file

@ -47,7 +47,9 @@ const ViewTypes = keyMirror({
INCREASE_POST_VISIBILITY: null,
RECEIVED_FOCUSED_POST: null,
LOADING_POSTS: null
LOADING_POSTS: null,
STATUSBAR_HEIGHT_CHANGED: null
});
export default {

View file

@ -10,21 +10,24 @@ import {
Alert,
AppState,
InteractionManager,
NativeModules,
Platform
} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import {setJSExceptionHandler} from 'react-native-exception-handler';
import StatusBarSizeIOS from 'react-native-status-bar-size';
import semver from 'semver';
import {setAppState, setDeviceToken, setServerVersion} from 'mattermost-redux/actions/general';
import {markChannelAsRead} from 'mattermost-redux/actions/channels';
import {logError} from 'mattermost-redux/actions/errors';
import {logout} from 'mattermost-redux/actions/users';
import {close as closeWebSocket} from 'mattermost-redux/actions/websocket';
import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {goToNotification, loadConfigAndLicense, queueNotification} from 'app/actions/views/root';
import {goToNotification, loadConfigAndLicense, queueNotification, setStatusBarHeight} from 'app/actions/views/root';
import {setChannelDisplayName} from 'app/actions/views/channel';
import {NavigationTypes, ViewTypes} from 'app/constants';
import {getTranslations} from 'app/i18n';
@ -35,6 +38,7 @@ import configureStore from 'app/store';
import Config from 'assets/config';
const {StatusBarManager} = NativeModules;
const store = configureStore(initialState);
registerScreens(store, Provider);
@ -52,10 +56,20 @@ export default class Mattermost {
this.handleAppStateChange(AppState.currentState);
Client4.setUserAgent(DeviceInfo.getUserAgent());
if (Platform.OS === 'ios') {
StatusBarSizeIOS.addEventListener('willChange', this.handleStatusBarHeightChange);
StatusBarManager.getHeight(
(data) => {
this.handleStatusBarHeightChange(data.height);
}
);
}
}
errorHandler = (e, isFatal) => {
const intl = this.getIntl();
closeWebSocket()(store.dispatch, store.getState);
logError(e)(store.dispatch);
if (isFatal) {
@ -126,6 +140,10 @@ export default class Mattermost {
store.dispatch(setChannelDisplayName(displayName));
};
handleStatusBarHeightChange = (nextStatusBarHeight) => {
store.dispatch(setStatusBarHeight(nextStatusBarHeight));
};
handleVersionUpgrade = async () => {
const {dispatch, getState} = store;

View file

@ -37,8 +37,18 @@ function purge(state = false, action) {
}
}
function statusBarHeight(state = 20, action) {
switch (action.type) {
case ViewTypes.STATUSBAR_HEIGHT_CHANGED:
return action.data;
default:
return state;
}
}
export default combineReducers({
appInitializing,
hydrationComplete,
purge
purge,
statusBarHeight
});

View file

@ -161,6 +161,10 @@ class AccountNotifications extends PureComponent {
});
};
focusMentionKeys = () => {
this.refs.mention_keys.getWrappedInstance().focus();
};
updateMentionKeys = (text) => {
this.setState({
mention_keys: text
@ -280,6 +284,7 @@ class AccountNotifications extends PureComponent {
labelId='user.settings.notifications.sensitiveWords'
labelDefaultMessage='Other non-case sensitive words, separated by commas'
theme={theme}
action={this.focusMentionKeys}
>
<TextInputWithLocalizedPlaceholder
ref='mention_keys'

View file

@ -110,6 +110,7 @@ sectionItem.propTypes = {
};
sectionItem.defaultProps = {
action: () => true,
actionType: ActionTypes.DEFAULT
};

View file

@ -20,6 +20,7 @@ import KeyboardLayout from 'app/components/layout/keyboard_layout';
import Loading from 'app/components/loading';
import OfflineIndicator from 'app/components/offline_indicator';
import PostTextbox from 'app/components/post_textbox';
import PostListRetry from 'app/components/post_list_retry';
import StatusBar from 'app/components/status_bar';
import {preventDoubleTap} from 'app/utils/tap';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
@ -51,7 +52,9 @@ class Channel extends PureComponent {
theme: PropTypes.object.isRequired,
subscribeToHeaderEvent: PropTypes.func,
unsubscribeFromHeaderEvent: PropTypes.func,
webSocketRequest: PropTypes.object
webSocketRequest: PropTypes.object,
statusBarHeight: PropTypes.number,
channelsRequestStatus: PropTypes.string
};
componentWillMount() {
@ -163,18 +166,32 @@ class Channel extends PureComponent {
});
};
retryLoadChannels = () => {
this.loadChannels(this.props.currentTeam.id);
};
render() {
const {
currentTeam,
channelsRequestStatus,
currentChannel,
drafts,
intl,
navigator,
statusBarHeight,
theme
} = this.props;
const style = getStyleFromTheme(theme);
if (!currentTeam || !currentChannel) {
if (!currentChannel.hasOwnProperty('id')) {
if (channelsRequestStatus === RequestStatus.FAILURE) {
return (
<PostListRetry
retry={this.retryLoadChannels}
theme={theme}
/>
);
}
return (
<View style={style.loading}>
<Loading/>
@ -182,7 +199,12 @@ class Channel extends PureComponent {
);
}
const channelDraft = this.props.drafts[currentChannel.id] || {};
const channelDraft = drafts[currentChannel.id] || {};
let height = 0;
if (statusBarHeight > 20) {
height = statusBarHeight - 20;
}
return (
<ChannelDrawer
@ -194,7 +216,7 @@ class Channel extends PureComponent {
<KeyboardLayout
behavior='padding'
style={style.keyboardLayout}
keyboardVerticalOffset={0}
keyboardVerticalOffset={height}
>
<View style={style.postList}>
<ChannelPostList
@ -265,7 +287,8 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
},
keyboardLayout: {
backgroundColor: theme.centerChannelBg,
flex: 1
flex: 1,
paddingBottom: 0
}
});
});

View file

@ -55,6 +55,7 @@ class ChannelPostList extends PureComponent {
}
componentDidMount() {
this.mounted = true;
this.loadPosts(this.props.channel.id);
}
@ -71,17 +72,25 @@ class ChannelPostList extends PureComponent {
this.loadPosts(nextProps.channel.id);
}
const showLoadMore = nextProps.posts.length === this.props.posts.length && nextProps.posts.length > nextProps.postVisibility;
const showLoadMore = nextProps.posts.length >= nextProps.postVisibility;
this.setState({
showLoadMore
});
}
componentWillUnmount() {
this.mounted = false;
}
channelLoaded = () => {
Animated.timing(this.state.loaderOpacity, {
toValue: 0,
duration: 500
}).start(() => this.setState({channelLoaded: true}));
}).start(() => {
if (this.mounted) {
this.setState({channelLoaded: true});
}
});
};
goToThread = (post) => {

View file

@ -72,7 +72,7 @@ ChannelTitle.defaultProps = {
function mapStateToProps(state) {
return {
applicationInitializing: state.views.root.appInitializing,
currentChannel: getCurrentChannel(state),
currentChannel: getCurrentChannel(state) || {},
displayName: state.views.channel.displayName,
theme: getTheme(state)
};

View file

@ -27,14 +27,18 @@ import Channel from './channel';
function mapStateToProps(state, ownProps) {
const {websocket} = state.requests.general;
const {myChannels: channelsRequest} = state.requests.channels;
const {statusBarHeight} = state.views.root;
return {
...ownProps,
...state.views.channel,
currentTeam: getCurrentTeam(state),
currentChannel: getCurrentChannel(state),
currentTeam: getCurrentTeam(state) || {},
currentChannel: getCurrentChannel(state) || {},
theme: getTheme(state),
webSocketRequest: websocket
webSocketRequest: websocket,
statusBarHeight,
channelsRequestStatus: channelsRequest.status
};
}

View file

@ -18,9 +18,9 @@ import ChannelAddMembers from './channel_add_members';
function mapStateToProps(state) {
return {
theme: getTheme(state),
currentChannel: getCurrentChannel(state),
currentChannel: getCurrentChannel(state) || {},
membersNotInChannel: getProfilesNotInCurrentChannel(state),
currentTeam: getCurrentTeam(state),
currentTeam: getCurrentTeam(state) || {},
preferences: getMyPreferences(state),
loadMoreRequestStatus: state.requests.users.getProfilesNotInChannel.status,
addChannelMemberRequestStatus: state.requests.channels.addChannelMember,

View file

@ -29,7 +29,7 @@ import ChannelInfo from './channel_info';
function mapStateToProps(state, ownProps) {
const {config, license} = state.entities.general;
const currentChannel = getCurrentChannel(state);
const currentChannel = getCurrentChannel(state) || {};
const currentChannelCreator = getUser(state, currentChannel.creator_id);
const currentChannelCreatorName = currentChannelCreator && currentChannelCreator.username;
const currentChannelStats = getCurrentChannelStats(state);

View file

@ -16,7 +16,7 @@ import ChannelMembers from './channel_members';
function mapStateToProps(state) {
return {
theme: getTheme(state),
currentChannel: getCurrentChannel(state),
currentChannel: getCurrentChannel(state) || {},
currentChannelMembers: getProfilesInCurrentChannel(state),
currentUserId: state.entities.users.currentUserId,
preferences: getMyPreferences(state),

View file

@ -44,6 +44,7 @@ export default class ImagePreview extends PureComponent {
fileId: PropTypes.string.isRequired,
files: PropTypes.array.isRequired,
navigator: PropTypes.object,
statusBarHeight: PropTypes.number,
theme: PropTypes.object.isRequired
};
@ -209,6 +210,17 @@ export default class ImagePreview extends PureComponent {
render() {
const maxImageHeight = this.state.deviceHeight - STATUSBAR_HEIGHT;
const marginStyle = {
...Platform.select({
ios: {
marginTop: this.props.statusBarHeight
},
android: {
marginTop: 10
}
})
};
return (
<View
style={style.wrapper}
@ -278,7 +290,7 @@ export default class ImagePreview extends PureComponent {
pointerEvents='box-none'
>
<View style={style.header}>
<View style={style.headerControls}>
<View style={[style.headerControls, marginStyle]}>
<TouchableOpacity
onPress={this.handleClose}
style={style.headerIcon}
@ -353,15 +365,7 @@ const style = StyleSheet.create({
headerControls: {
alignItems: 'center',
justifyContent: 'space-around',
flexDirection: 'row',
...Platform.select({
ios: {
marginTop: 20
},
android: {
marginTop: 10
}
})
flexDirection: 'row'
},
headerIcon: {
height: 44,

View file

@ -3,6 +3,7 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Platform} from 'react-native';
import {addFileToFetchCache} from 'app/actions/views/file_preview';
import {getTheme} from 'app/selectors/preferences';
@ -10,6 +11,8 @@ import {makeGetFilesForPost} from 'mattermost-redux/selectors/entities/files';
import ImagePreview from './image_preview';
const STATUSBAR_HEIGHT = 20;
function makeMapStateToProps() {
const getFilesForPost = makeGetFilesForPost();
return function mapStateToProps(state, ownProps) {
@ -17,7 +20,8 @@ function makeMapStateToProps() {
...ownProps,
fetchCache: state.views.fetchCache,
files: getFilesForPost(state, ownProps.post),
theme: getTheme(state)
theme: getTheme(state),
statusBarHeight: Platform.OS === 'ios' ? state.views.root.statusBarHeight : STATUSBAR_HEIGHT
};
};
}

View file

@ -21,6 +21,7 @@ function makeMapStateToProps() {
return function mapStateToProps(state, ownProps) {
const posts = getPostsForThread(state, ownProps);
const threadDraft = state.views.thread.drafts[ownProps.rootId];
const {statusBarHeight} = state.views.root;
return {
...ownProps,
@ -30,6 +31,7 @@ function makeMapStateToProps() {
draft: threadDraft.draft,
files: threadDraft.files,
posts,
statusBarHeight,
theme: getTheme(state)
};
};

View file

@ -24,7 +24,8 @@ export default class Thread extends PureComponent {
rootId: PropTypes.string.isRequired,
draft: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
posts: PropTypes.array.isRequired
posts: PropTypes.array.isRequired,
statusBarHeight: PropTypes.number
};
state = {};
@ -44,14 +45,29 @@ export default class Thread extends PureComponent {
};
render() {
const {channelId, draft, files, myMember, navigator, posts, rootId, theme} = this.props;
const {
channelId,
draft,
files,
myMember,
navigator,
posts,
rootId,
statusBarHeight,
theme
} = this.props;
const style = getStyle(theme);
let height = 0;
if (statusBarHeight > 20) {
height = statusBarHeight - 20;
}
return (
<KeyboardLayout
behavior='padding'
style={style.container}
keyboardVerticalOffset={65}
keyboardVerticalOffset={65 + height}
>
<StatusBar/>
<PostList

View file

@ -22,7 +22,7 @@ function mapStateToProps(state, ownProps) {
navigator: ownProps.navigator,
config,
createChannelRequest,
currentChannel: getCurrentChannel(state),
currentChannel: getCurrentChannel(state) || {},
currentDisplayName: state.views.channel.displayName,
currentUserId: getCurrentUserId(state),
user: state.entities.users.profiles[ownProps.userId],

View file

@ -17,7 +17,7 @@ export function makeStyleSheetFromTheme(getStyleFromTheme) {
export function changeOpacity(oldColor, opacity) {
let color = oldColor;
if (color[0] === '#') {
if (color.length && color[0] === '#') {
color = color.slice(1);
}

View file

@ -26,9 +26,10 @@
"react-native-image-picker": "jp928/react-native-image-picker#6ee35b69f3dbd6c7c66f580fd4d9eabf398703d4",
"react-native-keyboard-aware-scroll-view": "0.2.8",
"react-native-linear-gradient": "2.0.0",
"react-native-navigation": "1.1.88",
"react-native-navigation": "1.1.131",
"react-native-notifications": "enahum/react-native-notifications.git",
"react-native-orientation": "yamill/react-native-orientation.git",
"react-native-orientation": "enahum/react-native-orientation.git",
"react-native-status-bar-size": "0.3.2",
"react-native-svg": "5.1.8",
"react-native-swiper": "1.5.4",
"react-native-tooltip": "enahum/react-native-tooltip",

View file

@ -3645,7 +3645,7 @@ makeerror@1.0.x:
mattermost-redux@mattermost/mattermost-redux#master:
version "0.0.1"
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/5e3133b5041e45252baa23b5a0c2e5b298198c4c"
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/92ed855365d0f014961fcd780a2d93762180ef5e"
dependencies:
deep-equal "1.0.1"
harmony-reflect "1.5.1"
@ -4528,9 +4528,9 @@ react-native-mock@^0.2.7:
react-timer-mixin "^0.13.3"
warning "^2.1.0"
react-native-navigation@1.1.88:
version "1.1.88"
resolved "https://registry.yarnpkg.com/react-native-navigation/-/react-native-navigation-1.1.88.tgz#22239c8c722b13a8750a5b99debd45bded13c2f5"
react-native-navigation@1.1.131:
version "1.1.131"
resolved "https://registry.yarnpkg.com/react-native-navigation/-/react-native-navigation-1.1.131.tgz#79b0583def2310e93305048f7149ad1970666f51"
dependencies:
lodash "4.x.x"
@ -4541,9 +4541,13 @@ react-native-notifications@enahum/react-native-notifications.git:
core-js "^1.0.0"
uuid "^2.0.3"
react-native-orientation@yamill/react-native-orientation.git:
react-native-orientation@enahum/react-native-orientation.git:
version "1.17.0"
resolved "https://codeload.github.com/yamill/react-native-orientation/tar.gz/ef221b5720ced0d9ed0c9de14082a5eabba4db7a"
resolved "https://codeload.github.com/enahum/react-native-orientation/tar.gz/8b8495c91d8e63598874a141279cf5409e26ad3a"
react-native-status-bar-size@0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/react-native-status-bar-size/-/react-native-status-bar-size-0.3.2.tgz#e3ffd906f021220c256857a8de6b945f8ea3fabc"
react-native-svg-mock@1.0.2:
version "1.0.2"