MM-15758 Update dependencies including Fastlane (#4272)

* Update dependencies including Fastlane and disable Flipper on iOS

* Remove EventEmitter for previous doc-viewer

* Fix android crash when setting more channels buttons

* Downgrade fuse.js

* Upgrade deps to latest

* Update Podfile.lock

* Downgrade RNN to 6.4.0

* QA Review #2

* Upgrade fuse.js to 6.0.0
This commit is contained in:
Elias Nahum 2020-05-18 14:24:47 -04:00 committed by GitHub
parent a0841e0ef1
commit d3a6e166ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
95 changed files with 5203 additions and 5372 deletions

View file

@ -1430,20 +1430,20 @@ THE SOFTWARE.
---
## react-native-cookies
## @react-native-community/cookies
This product contains 'react-native-cookies' by @joeferraro.
This product contains '@react-native-community/cookies' by @joeferraro.
Cookie manager for react native
* HOMEPAGE:
* https://github.com/joeferraro/react-native-cookies
* https://github.com/react-native-community/cookies
* LICENSE: MIT
The MIT License (MIT)
MIT License
Copyright (c) 2015 Joseph P. Ferraro
Copyright (c) 2020 React Native Community
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -1500,41 +1500,6 @@ SOFTWARE.
---
## react-native-doc-viewer
This product contains 'react-native-doc-viewer' by Philipp Hecht.
React Native Native Module Bridge Quicklock Document Viewer for IOS + Android supports pdf, png, jpg, xls, ppt, doc, docx, pptx, xlx + Video Player mp4 supported
* HOMEPAGE:
* https://github.com/philipphecht/react-native-doc-viewer/blob/master/README.md
* LICENSE: MIT
MIT License
Copyright (c) 2017 Phil Pike
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.
---
## react-native-document-picker
This product contains 'react-native-document-picker' by Elyx0.

View file

@ -5,8 +5,9 @@ import android.content.Context;
import java.util.ArrayList;
import java.util.HashMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.oblador.keychain.KeychainModule;
import com.mattermost.react_native_interface.ResolvePromise;
@ -35,7 +36,12 @@ public class MattermostCredentialsHelper {
HashMap<String, String> asyncStorageResults = asyncStorage.multiGet(asyncStorageKeys);
String serverUrl = asyncStorageResults.get(CURRENT_SERVER_URL);
final WritableMap options = Arguments.createMap();
final WritableMap authPrompt = Arguments.createMap();
authPrompt.putString("title", "Authenticate to retrieve secret");
authPrompt.putString("cancel", "Cancel");
options.putMap("authenticationPrompt", authPrompt);
keychainModule.getGenericPasswordForOptions(serverUrl, promise);
keychainModule.getInternetCredentialsForServer(serverUrl, options, promise);
}
}

View file

@ -22,7 +22,7 @@ const MOCK_CHANNEL_MARK_AS_READ = 'MOCK_CHANNEL_MARK_AS_READ';
const MOCK_CHANNEL_MARK_AS_VIEWED = 'MOCK_CHANNEL_MARK_AS_VIEWED';
jest.mock('@mm-redux/actions/channels', () => {
const channelActions = require.requireActual('@mm-redux/actions/channels');
const channelActions = jest.requireActual('../../mm-redux/actions/channels');
return {
...channelActions,
markChannelAsRead: jest.fn().mockReturnValue({type: 'MOCK_CHANNEL_MARK_AS_READ'}),
@ -31,7 +31,7 @@ jest.mock('@mm-redux/actions/channels', () => {
});
jest.mock('@mm-redux/selectors/entities/teams', () => {
const teamSelectors = require.requireActual('@mm-redux/selectors/entities/teams');
const teamSelectors = jest.requireActual('../../mm-redux/selectors/entities/teams');
return {
...teamSelectors,
getTeamByName: jest.fn(() => ({name: 'current-team-name'})),

View file

@ -14,7 +14,7 @@ import {getCurrentUserId} from '@mm-redux/selectors/entities/users';
import {setAppCredentials} from 'app/init/credentials';
import PushNotifications from 'app/push_notifications';
import {getDeviceTimezoneAsync} from 'app/utils/timezone';
import {getDeviceTimezone} from 'app/utils/timezone';
import {setCSRFFromCookie} from 'app/utils/security';
import {loadConfigAndLicense} from 'app/actions/views/root';
@ -35,7 +35,7 @@ export function handleSuccessfulLogin() {
const enableTimezone = isTimezoneEnabled(state);
if (enableTimezone) {
const timezone = await getDeviceTimezoneAsync();
const timezone = getDeviceTimezone();
dispatch(autoUpdateTimezone(timezone));
}

View file

@ -12,21 +12,6 @@ jest.mock('app/init/credentials', () => ({
setAppCredentials: () => jest.fn(),
}));
jest.mock('react-native-cookies', () => ({
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
openURL: jest.fn(),
canOpenURL: jest.fn(),
getInitialURL: jest.fn(),
get: () => Promise.resolve(({
res: {
MMCSRF: {
value: 'the cookie',
},
},
})),
}));
const mockStore = configureStore([thunk]);
describe('Actions.Views.Login', () => {

View file

@ -1,6 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-import-assign */
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';

View file

@ -17,7 +17,7 @@ import {getCurrentUserId, getStatusForUserId} from '@mm-redux/selectors/entities
import {setAppCredentials} from 'app/init/credentials';
import {setCSRFFromCookie} from '@utils/security';
import {getDeviceTimezoneAsync} from '@utils/timezone';
import {getDeviceTimezone} from '@utils/timezone';
const HTTP_UNAUTHORIZED = 401;
@ -34,7 +34,7 @@ export function completeLogin(user, deviceToken) {
// Set timezone
const enableTimezone = isTimezoneEnabled(state);
if (enableTimezone) {
const timezone = await getDeviceTimezoneAsync();
const timezone = getDeviceTimezone();
dispatch(autoUpdateTimezone(timezone));
}
@ -240,4 +240,5 @@ export function setCurrentUserStatusOffline() {
};
}
/* eslint-disable no-import-assign */
HelperActions.forceLogoutIfNecessary = forceLogoutIfNecessary;

View file

@ -1,6 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-import-assign */
import assert from 'assert';
import nock from 'nock';
import {Server, WebSocket as MockWebSocket} from 'mock-socket';

View file

@ -204,7 +204,7 @@ class WebSocketClient {
this.connectFailCount = 0;
this.sequence = 1;
if (this.conn && this.conn.readyState === WebSocket.OPEN) {
this.conn.onclose = () => {}; //eslint-disable-line no-empty-function
this.conn.onclose = () => {}; //eslint-disable-line @typescript-eslint/no-empty-function
this.conn.close();
this.conn = undefined;
console.log('websocket closed'); //eslint-disable-line no-console

View file

@ -9,17 +9,27 @@ import {
Text,
View,
} from 'react-native';
import Fuse from 'fuse.js';
import AutocompleteDivider from 'app/components/autocomplete/autocomplete_divider';
import Emoji from 'app/components/emoji';
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {BuiltInEmojis} from 'app/utils/emojis';
import {getEmojiByName, compareEmojis} from 'app/utils/emoji_utils';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import AutocompleteDivider from '@components/autocomplete/autocomplete_divider';
import Emoji from '@components/emoji';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import {BuiltInEmojis} from '@utils/emojis';
import {getEmojiByName, compareEmojis} from '@utils/emoji_utils';
import {makeStyleSheetFromTheme} from '@utils/theme';
const EMOJI_REGEX = /(^|\s|^\+|^-)(:([^:\s]*))$/i;
const EMOJI_REGEX_WITHOUT_PREFIX = /\B(:([^:\s]*))$/i;
const options = {
shouldSort: true,
threshold: 0.3,
location: 0,
distance: 100,
minMatchCharLength: 2,
maxPatternLength: 32,
};
export default class EmojiSuggestion extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
@ -30,7 +40,6 @@ export default class EmojiSuggestion extends PureComponent {
customEmojisEnabled: PropTypes.bool,
emojis: PropTypes.array.isRequired,
isSearch: PropTypes.bool,
fuse: PropTypes.object.isRequired,
maxListHeight: PropTypes.number,
theme: PropTypes.object.isRequired,
onChangeText: PropTypes.func.isRequired,
@ -54,64 +63,38 @@ export default class EmojiSuggestion extends PureComponent {
super(props);
this.matchTerm = '';
const list = props.emojis || [];
this.fuse = new Fuse(list, options);
}
componentWillReceiveProps(nextProps) {
if (nextProps.isSearch) {
componentDidUpdate(prevProps) {
if (this.props.isSearch) {
return;
}
const regex = EMOJI_REGEX;
const match = nextProps.value.substring(0, nextProps.cursorPosition).match(regex);
const {cursorPosition, emojis, value} = this.props;
const match = value.substring(0, cursorPosition).match(EMOJI_REGEX);
if (prevProps.emojis !== emojis) {
const list = emojis || [];
this.fuse = new Fuse(list, options);
}
if (!match || this.state.emojiComplete) {
this.setState({
active: false,
emojiComplete: false,
});
this.props.onResultCountChange(0);
this.resetAutocomplete();
return;
}
const oldMatchTerm = this.matchTerm;
this.matchTerm = match[3] || '';
if (this.matchTerm !== oldMatchTerm && this.matchTerm.length && nextProps.customEmojisEnabled) {
this.props.actions.autocompleteCustomEmojis(this.matchTerm);
return;
}
if (this.matchTerm.length) {
this.handleFuzzySearch(this.matchTerm, nextProps);
} else {
this.setEmojiData(nextProps.emojis);
if (this.matchTerm !== oldMatchTerm || match[2] === ':') {
if (this.props.customEmojisEnabled) {
this.props.actions.autocompleteCustomEmojis(this.matchTerm);
}
this.searchEmoji(this.matchTerm);
}
}
handleFuzzySearch = (matchTerm, props) => {
const {emojis, fuse} = props;
const results = fuse.search(matchTerm.toLowerCase());
const data = results.map((index) => emojis[index]);
this.setEmojiData(data, matchTerm);
};
setEmojiData = (data, matchTerm = null) => {
let sorter = compareEmojis;
if (matchTerm) {
sorter = (a, b) => compareEmojis(a, b, matchTerm);
}
this.setState({
active: data.length > 0,
dataSource: data.sort(sorter),
});
this.props.onResultCountChange(data.length);
};
completeSuggestion = (emoji) => {
const {actions, cursorPosition, onChangeText, value, rootId} = this.props;
const emojiPart = value.substring(0, cursorPosition);
@ -160,6 +143,19 @@ export default class EmojiSuggestion extends PureComponent {
});
};
getItemLayout = ({index}) => ({length: 40, offset: 40 * index, index})
handleFuzzySearch = (matchTerm) => {
const {emojis} = this.props;
clearTimeout(this.searchTermTimeout);
this.searchTermTimeout = setTimeout(() => {
const results = this.fuse.search(matchTerm.toLowerCase()).map((r) => r.refIndex);
const data = results.map((index) => emojis[index]);
this.setEmojiData(data, matchTerm);
}, 100);
};
keyExtractor = (item) => item;
renderItem = ({item}) => {
@ -183,7 +179,36 @@ export default class EmojiSuggestion extends PureComponent {
);
};
getItemLayout = ({index}) => ({length: 40, offset: 40 * index, index})
resetAutocomplete = () => {
this.setState({
active: false,
emojiComplete: false,
});
this.props.onResultCountChange(0);
}
searchEmoji = (matchTerm) => {
if (matchTerm.length) {
this.handleFuzzySearch(matchTerm);
} else {
this.setEmojiData(this.props.emojis);
}
}
setEmojiData = (data, matchTerm = null) => {
let sorter = compareEmojis;
if (matchTerm) {
sorter = (a, b) => compareEmojis(a, b, matchTerm);
}
this.setState({
active: data.length > 0,
dataSource: data.sort(sorter),
});
this.props.onResultCountChange(data.length);
};
render() {
const {maxListHeight, theme, nestedScrollEnabled} = this.props;

View file

@ -2,21 +2,20 @@
// See LICENSE.txt for license information.
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {bindActionCreators} from 'redux';
import {getCustomEmojisByName} from '@mm-redux/selectors/entities/emojis';
import {getConfig} from '@mm-redux/selectors/entities/general';
import {autocompleteCustomEmojis} from '@mm-redux/actions/emojis';
import {createIdsSelector} from '@mm-redux/utils/helpers';
import {addReactionToLatestPost} from 'app/actions/views/emoji';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {EmojiIndicesByAlias} from 'app/utils/emojis';
import EmojiSuggestion from './emoji_suggestion';
import Fuse from 'fuse.js';
const getEmojisByName = createSelector(
const getEmojisByName = createIdsSelector(
getCustomEmojisByName,
(customEmojis) => {
const emoticons = new Set();
@ -29,23 +28,11 @@ const getEmojisByName = createSelector(
);
function mapStateToProps(state) {
const options = {
shouldSort: true,
threshold: 0.3,
location: 0,
distance: 100,
minMatchCharLength: 2,
maxPatternLength: 32,
};
const emojis = getEmojisByName(state);
const list = emojis.length ? emojis : [];
const fuse = new Fuse(list, options);
return {
emojis,
customEmojisEnabled: getConfig(state).EnableCustomEmoji === 'true',
fuse,
theme: getTheme(state),
};
}

View file

@ -5,14 +5,14 @@ import React from 'react';
import {shallow} from 'enzyme';
import {Text} from 'react-native';
import {alertErrorWithFallback} from 'app/utils/general';
import {alertErrorWithFallback} from '@utils/general';
import ChannelLink from './channel_link';
jest.mock('react-intl');
jest.mock('app/utils/general', () => {
const general = require.requireActual('app/utils/general');
jest.mock('@utils/general', () => {
const general = jest.requireActual('../../utils/general');
return {
...general,
alertErrorWithFallback: jest.fn(),

View file

@ -17,13 +17,12 @@ exports[`ChannelLoader should match snapshot 1`] = `
]
}
>
<ForwardRef(AnimatedComponentWrapper)
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -31,30 +30,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -62,30 +70,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -93,30 +110,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -124,30 +150,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -155,30 +190,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -186,30 +230,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -217,30 +270,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -248,30 +310,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -279,30 +350,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -310,30 +390,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -341,30 +430,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -372,30 +470,39 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"flex": 1,
"flexDirection": "row",
"marginVertical": 10,
"paddingLeft": 12,
"paddingRight": 20,
@ -403,22 +510,32 @@ exports[`ChannelLoader should match snapshot 1`] = `
Object {
"backgroundColor": "#ffffff",
},
Object {
"opacity": 0.6,
},
]
}
>
<ImageContent
animate="fade"
color="rgba(61,60,64,0.15)"
firstLineWidth="80%"
hasRadius={true}
lineNumber={3}
lineSpacing={5}
size={32}
textSize={14}
/>
</ForwardRef(AnimatedComponentWrapper)>
<UNDEFINED
Animation={[Function]}
Left={[Function]}
styles={
Object {
"left": Object {
"color": "rgba(61,60,64,0.15)",
},
}
}
>
<UNDEFINED
color="rgba(61,60,64,0.15)"
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={80}
/>
<UNDEFINED
color="rgba(61,60,64,0.15)"
width={60}
/>
</UNDEFINED>
</View>
</View>
`;

View file

@ -5,30 +5,32 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Animated,
Easing,
View,
Dimensions,
} from 'react-native';
import {ImageContent} from 'rn-placeholder';
import EventEmitter from '@mm-redux/utils/event_emitter';
import * as RNPlaceholder from 'rn-placeholder';
import CustomPropTypes from 'app/constants/custom_prop_types';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
const {View: AnimatedView} = Animated;
function calculateMaxRows(height) {
return Math.round(height / 100);
}
function Media(color) {
return (
<RNPlaceholder.PlaceholderMedia
color={changeOpacity(color, 0.15)}
isRound={true}
size={32}
style={{marginRight: 10}}
/>
);
}
export default class ChannelLoader extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
handleSelectChannel: PropTypes.func.isRequired,
setChannelLoading: PropTypes.func.isRequired,
}).isRequired,
backgroundColor: PropTypes.string,
channelIsLoading: PropTypes.bool.isRequired,
style: CustomPropTypes.Style,
@ -64,89 +66,36 @@ export default class ChannelLoader extends PureComponent {
return Object.keys(state) ? state : null;
}
componentDidMount() {
EventEmitter.on('switch_channel', this.handleChannelSwitch);
}
componentWillUnmount() {
EventEmitter.off('switch_channel', this.handleChannelSwitch);
}
startLoadingAnimation = () => {
Animated.loop(
Animated.sequence([
Animated.timing(this.state.barsOpacity, {
toValue: 1,
duration: 750,
easing: Easing.quad,
useNativeDriver: true,
}),
Animated.timing(this.state.barsOpacity, {
toValue: 0.6,
duration: 750,
easing: Easing.quad,
useNativeDriver: true,
}),
]),
).start();
};
stopLoadingAnimation = () => {
Animated.timing(
this.state.barsOpacity,
).stop();
}
componentDidUpdate(prevProps) {
if (prevProps.channelIsLoading === false && this.props.channelIsLoading === true) {
this.startLoadingAnimation();
} else if (prevProps.channelIsLoading === true && this.props.channelIsLoading === false) {
this.stopLoadingAnimation();
}
if (this.state.switch) {
const {
handleSelectChannel,
setChannelLoading,
} = this.props.actions;
const {channel} = this.state;
setTimeout(() => {
handleSelectChannel(channel.id);
setChannelLoading(false);
}, 250);
}
}
buildSections({key, style, bg, color}) {
return (
<AnimatedView
<View
key={key}
style={[style.section, {backgroundColor: bg}, {opacity: this.state.barsOpacity}]}
style={[style.section, {backgroundColor: bg}]}
>
<ImageContent
size={32}
animate='fade'
lineNumber={3}
lineSpacing={5}
firstLineWidth='80%'
hasRadius={true}
textSize={14}
color={changeOpacity(color, 0.15)}
/>
</AnimatedView>
<RNPlaceholder.Placeholder
Animation={(props) => (
<RNPlaceholder.Fade
{...props}
style={{backgroundColor: changeOpacity(bg, 0.9)}}
/>
)}
Left={Media.bind(undefined, color)}
styles={{left: {color: changeOpacity(color, 0.15)}}}
>
<RNPlaceholder.PlaceholderLine color={changeOpacity(color, 0.15)}/>
<RNPlaceholder.PlaceholderLine
color={changeOpacity(color, 0.15)}
width={80}
/>
<RNPlaceholder.PlaceholderLine
color={changeOpacity(color, 0.15)}
width={60}
/>
</RNPlaceholder.Placeholder>
</View>
);
}
handleChannelSwitch = (channel, currentChannelId) => {
if (channel.id === currentChannelId) {
this.props.actions.setChannelLoading(false);
} else {
this.setState({switch: true, channel});
}
};
handleLayout = (e) => {
const {height} = e.nativeEvent.layout;
const maxRows = calculateMaxRows(height);
@ -192,7 +141,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
},
section: {
backgroundColor: theme.centerChannelBg,
flexDirection: 'row',
flex: 1,
paddingLeft: 12,
paddingRight: 20,

View file

@ -1,21 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {handleSelectChannel, setChannelLoading} from 'app/actions/views/channel';
import {isLandscape} from 'app/selectors/device';
import ChannelLoader from './channel_loader';
import {isLandscape} from 'app/selectors/device';
function mapStateToProps(state, ownProps) {
const channelIsLoading = ownProps.hasOwnProperty('channelIsLoading') ?
ownProps.channelIsLoading :
state.views.channel.loading;
const channelIsLoading = ownProps.hasOwnProperty('channelIsLoading') ? ownProps.channelIsLoading : state.views.channel.loading;
return {
channelIsLoading,
@ -24,13 +19,4 @@ function mapStateToProps(state, ownProps) {
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
handleSelectChannel,
setChannelLoading,
}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ChannelLoader);
export default connect(mapStateToProps)(ChannelLoader);

View file

@ -9,8 +9,8 @@ import Preferences from '@mm-redux/constants/preferences';
import UserListRow from './user_list_row';
jest.mock('react-intl');
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -210,7 +210,7 @@ export default class EmojiPicker extends PureComponent {
return [];
}
const results = fuse.search(searchTermLowerCase);
const results = fuse.search(searchTermLowerCase).map((r) => r.refIndex);
const sorter = (a, b) => compareEmojis(a, b, searchTerm);
const data = results.map((index) => emojis[index]).sort(sorter);

View file

@ -2,21 +2,21 @@
// See LICENSE.txt for license information.
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {bindActionCreators} from 'redux';
import {createSelector} from 'reselect';
import Fuse from 'fuse.js';
import {incrementEmojiPickerPage} from '@actions/views/emoji';
import {getCustomEmojis} from '@mm-redux/actions/emojis';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {getCustomEmojisByName} from '@mm-redux/selectors/entities/emojis';
import {getConfig} from '@mm-redux/selectors/entities/general';
import {getCustomEmojis} from '@mm-redux/actions/emojis';
import {incrementEmojiPickerPage} from 'app/actions/views/emoji';
import {getDimensions, isLandscape} from 'app/selectors/device';
import {BuiltInEmojis, CategoryNames, Emojis, EmojiIndicesByAlias, EmojiIndicesByCategory} from 'app/utils/emojis';
import {t} from 'app/utils/i18n';
import {createIdsSelector} from '@mm-redux/utils/helpers';
import {getDimensions, isLandscape} from '@selectors/device';
import {BuiltInEmojis, CategoryNames, Emojis, EmojiIndicesByAlias, EmojiIndicesByCategory} from '@utils/emojis';
import {t} from '@utils/i18n';
import EmojiPicker from './emoji_picker';
import Fuse from 'fuse.js';
const categoryToI18n = {
activity: {
@ -128,7 +128,7 @@ const getEmojisBySection = createSelector(
},
);
const getEmojisByName = createSelector(
const getEmojisByName = createIdsSelector(
getCustomEmojisByName,
(customEmojis) => {
const emoticons = new Set();

View file

@ -6,8 +6,8 @@ import {shallow} from 'enzyme';
import FileAttachment from './file_attachment.js';
import Preferences from '@mm-redux/constants/preferences';
jest.mock('react-native-doc-viewer', () => ({
openDoc: jest.fn(),
jest.mock('react-native-file-viewer', () => ({
open: jest.fn(),
}));
describe('FileAttachment', () => {

View file

@ -5,15 +5,13 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Alert,
NativeModules,
NativeEventEmitter,
Platform,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native';
import OpenFile from 'react-native-doc-viewer';
import FileViewer from 'react-native-file-viewer';
import RNFetchBlob from 'rn-fetch-blob';
import {CircularProgress} from 'react-native-circular-progress';
import {intlShape} from 'react-intl';
@ -71,13 +69,10 @@ export default class FileAttachmentDocument extends PureComponent {
componentDidMount() {
this.mounted = true;
this.eventEmitter = new NativeEventEmitter(NativeModules.RNDocViewer);
this.eventEmitter.addListener('DoneButtonEvent', this.onDonePreviewingFile);
}
componentWillUnmount() {
this.mounted = false;
this.eventEmitter.removeListener();
}
cancelDownload = () => {
@ -217,7 +212,7 @@ export default class FileAttachmentDocument extends PureComponent {
onDonePreviewingFile = () => {
if (this.mounted) {
this.setState({preview: false});
this.setState({progress: 0, downloading: false, preview: false});
}
this.setStatusBarColor();
};
@ -229,51 +224,41 @@ export default class FileAttachmentDocument extends PureComponent {
setTimeout(() => {
if (!this.state.didCancel && !this.state.preview && this.mounted) {
const {data} = file;
const prefix = Platform.OS === 'android' ? 'file:/' : '';
const path = `${DOCUMENTS_PATH}/${data.id}-${file.caption}`;
this.setState({preview: true});
this.setStatusBarColor('dark-content');
OpenFile.openDoc([{
url: `${prefix}${path}`,
fileNameOptional: file.caption,
fileName: encodeURI(data.name.split('.').slice(0, -1).join('.')),
fileType: data.extension,
cache: false,
}], (error) => {
if (error) {
const {intl} = this.context;
Alert.alert(
intl.formatMessage({
id: 'mobile.document_preview.failed_title',
defaultMessage: 'Open Document failed',
}),
intl.formatMessage({
id: 'mobile.document_preview.failed_description',
defaultMessage: 'An error occurred while opening the document. Please make sure you have a {fileType} viewer installed and try again.\n',
}, {
fileType: data.extension.toUpperCase(),
}),
[{
text: intl.formatMessage({
id: 'mobile.server_upgrade.button',
defaultMessage: 'OK',
}),
}],
);
this.onDonePreviewingFile();
RNFetchBlob.fs.unlink(path);
}
FileViewer.open(path, {
displayName: file.caption,
onDismiss: this.onDonePreviewingFile,
showOpenWithDialog: true,
showAppsSuggestions: true,
}).then(() => {
if (this.mounted) {
this.setState({downloading: false, progress: 0});
}
}).catch(() => {
const {intl} = this.context;
Alert.alert(
intl.formatMessage({
id: 'mobile.document_preview.failed_title',
defaultMessage: 'Open Document failed',
}),
intl.formatMessage({
id: 'mobile.document_preview.failed_description',
defaultMessage: 'An error occurred while opening the document. Please make sure you have a {fileType} viewer installed and try again.\n',
}, {
fileType: data.extension.toUpperCase(),
}),
[{
text: intl.formatMessage({
id: 'mobile.server_upgrade.button',
defaultMessage: 'OK',
}),
}],
);
this.onDonePreviewingFile();
RNFetchBlob.fs.unlink(path);
});
// Android does not trigger the event for DoneButtonEvent
// so we'll wait 4 seconds before enabling the tap for open the preview again
if (Platform.OS === 'android') {
setTimeout(this.onDonePreviewingFile, 4000);
}
}
}, delay);
};

View file

@ -6,8 +6,8 @@ import {shallow} from 'enzyme';
import FileAttachment from './file_attachment_list.js';
import Preferences from '@mm-redux/constants/preferences';
jest.mock('react-native-doc-viewer', () => ({
openDoc: jest.fn(),
jest.mock('react-native-file-viewer', () => ({
open: jest.fn(),
}));
describe('FileAttachmentList', () => {

View file

@ -3,10 +3,8 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import {
ActivityIndicator,
Alert,
Animated,
AppState,
Platform,
@ -61,10 +59,6 @@ export default class NetworkIndicator extends PureComponent {
isOnline: true,
};
static contextTypes = {
intl: intlShape.isRequired,
};
constructor(props) {
super(props);
@ -129,8 +123,11 @@ export default class NetworkIndicator extends PureComponent {
}
componentWillUnmount() {
const {closeWebSocket, stopPeriodicStatusUpdates} = this.props.actions;
this.mounted = false;
closeWebSocket(false);
stopPeriodicStatusUpdates();
this.networkListener.removeEventListener();
AppState.removeEventListener('change', this.handleAppStateChange);
@ -294,7 +291,6 @@ export default class NetworkIndicator extends PureComponent {
};
initializeWebSocket = async () => {
const {formatMessage} = this.context.intl;
const {actions} = this.props;
const {closeWebSocket, initWebSocket} = actions;
const platform = Platform.OS;
@ -305,21 +301,6 @@ export default class NetworkIndicator extends PureComponent {
initWebSocket({certificate, forceConnection: true}).catch(() => {
// we should dispatch a failure and show the app as disconnected
Alert.alert(
formatMessage({id: 'mobile.authentication_error.title', defaultMessage: 'Authentication Error'}),
formatMessage({
id: 'mobile.authentication_error.message',
defaultMessage: 'Mattermost has encountered an error. Please re-authenticate to start a new session.',
}),
[{
text: formatMessage({
id: 'navbar_dropdown.logout',
defaultMessage: 'Logout',
}),
onPress: actions.logout,
}],
{cancelable: false},
);
closeWebSocket(true);
});
};

View file

@ -7,7 +7,7 @@ import * as PostUtils from '@mm-redux/utils/post_utils';
import {makeMapStateToProps} from './index.js';
jest.mock('@mm-redux/selectors/entities/channels', () => {
const channels = require.requireActual('@mm-redux/selectors/entities/channels');
const channels = jest.requireActual('../../mm-redux/selectors/entities/channels');
return {
...channels,
@ -18,7 +18,7 @@ jest.mock('@mm-redux/selectors/entities/channels', () => {
});
jest.mock('@mm-redux/selectors/entities/preferences', () => {
const preferences = require.requireActual('@mm-redux/selectors/entities/preferences');
const preferences = jest.requireActual('../../mm-redux/selectors/entities/preferences');
return {
...preferences,
getTheme: jest.fn(),
@ -26,7 +26,7 @@ jest.mock('@mm-redux/selectors/entities/preferences', () => {
});
jest.mock('@mm-redux/selectors/entities/general', () => {
const general = require.requireActual('@mm-redux/selectors/entities/general');
const general = jest.requireActual('../../mm-redux/selectors/entities/general');
return {
...general,
getConfig: jest.fn(),
@ -35,7 +35,7 @@ jest.mock('@mm-redux/selectors/entities/general', () => {
});
jest.mock('@mm-redux/selectors/entities/users', () => {
const users = require.requireActual('@mm-redux/selectors/entities/users');
const users = jest.requireActual('../../mm-redux/selectors/entities/users');
return {
...users,
getCurrentUserId: jest.fn(),
@ -44,7 +44,7 @@ jest.mock('@mm-redux/selectors/entities/users', () => {
});
jest.mock('@mm-redux/selectors/entities/teams', () => {
const teams = require.requireActual('@mm-redux/selectors/entities/teams');
const teams = jest.requireActual('../../mm-redux/selectors/entities/teams');
return {
...teams,
getCurrentTeamId: jest.fn(),
@ -52,7 +52,7 @@ jest.mock('@mm-redux/selectors/entities/teams', () => {
});
jest.mock('@mm-redux/selectors/entities/emojis', () => {
const emojis = require.requireActual('@mm-redux/selectors/entities/emojis');
const emojis = jest.requireActual('../../mm-redux/selectors/entities/emojis');
return {
...emojis,
getCustomEmojisByName: jest.fn(),
@ -60,7 +60,7 @@ jest.mock('@mm-redux/selectors/entities/emojis', () => {
});
jest.mock('@mm-redux/selectors/entities/posts', () => {
const posts = require.requireActual('@mm-redux/selectors/entities/posts');
const posts = jest.requireActual('../../mm-redux/selectors/entities/posts');
return {
...posts,
makeGetReactionsForPost: () => jest.fn(),

View file

@ -1,6 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-import-assign */
import {Permissions} from '@mm-redux/constants';
import * as channelSelectors from '@mm-redux/selectors/entities/channels';
import * as userSelectors from '@mm-redux/selectors/entities/users';

View file

@ -5,6 +5,8 @@ import DeviceInfo from 'react-native-device-info';
import RNFetchBlobFS from 'rn-fetch-blob/fs';
import keyMirror from '@mm-redux/utils/key_mirror';
const DeviceModel = DeviceInfo.getModel();
const deviceTypes = keyMirror({
CONNECTION_CHANGED: null,
DEVICE_DIMENSIONS_CHANGED: null,
@ -17,7 +19,7 @@ export default {
...deviceTypes,
DOCUMENTS_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Documents`,
IMAGES_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Images`,
IS_IPHONE_WITH_INSETS: DeviceInfo.getModel().includes('iPhone X') || DeviceInfo.getModel().includes('iPhone 11'),
IS_IPHONE_WITH_INSETS: DeviceModel.includes('iPhone X') || DeviceModel.includes('iPhone 11'),
IS_TABLET: DeviceInfo.isTablet(),
VIDEOS_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Videos`,
PERMANENT_SIDEBAR_SETTINGS: '@PERMANENT_SIDEBAR_SETTINGS',

View file

@ -3,8 +3,9 @@
import {Alert, AppState, Dimensions, Linking, NativeModules, Platform} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import CookieManager from 'react-native-cookies';
import CookieManager from '@react-native-community/cookies';
import DeviceInfo from 'react-native-device-info';
import {getLocales} from 'react-native-localize';
import RNFetchBlob from 'rn-fetch-blob';
import semver from 'semver/preload';
@ -15,7 +16,7 @@ import {Client4} from '@mm-redux/client';
import {General} from '@mm-redux/constants';
import {getConfig} from '@mm-redux/selectors/entities/general';
import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
import {getCurrentUserId, getUser} from '@mm-redux/selectors/entities/users';
import {getCurrentUser, getUser} from '@mm-redux/selectors/entities/users';
import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone';
import EventEmitter from '@mm-redux/utils/event_emitter';
@ -27,16 +28,16 @@ import {loadMe, logout} from '@actions/views/user';
import LocalConfig from '@assets/config';
import {NavigationTypes, ViewTypes} from '@constants';
import {getTranslations, resetMomentLocale} from '@i18n';
import PushNotifications from 'app/push_notifications';
import {getCurrentLocale} from '@selectors/i18n';
import initialState from '@store/initial_state';
import Store from '@store/store';
import {t} from '@utils/i18n';
import {deleteFileCache} from '@utils/file';
import {getDeviceTimezoneAsync} from '@utils/timezone';
import {getDeviceTimezone} from '@utils/timezone';
import mattermostBucket from 'app/mattermost_bucket';
import mattermostManaged from 'app/mattermost_managed';
import PushNotifications from 'app/push_notifications';
import {getAppCredentials, removeAppCredentials} from './credentials';
import emmProvider from './emm_provider';
@ -162,7 +163,6 @@ class GlobalEventHandler {
onLogout = async () => {
Store.redux.dispatch(closeWebSocket(false));
Store.redux.dispatch(setServerVersion(''));
await this.resetState();
if (analytics) {
await analytics.reset();
@ -170,6 +170,7 @@ class GlobalEventHandler {
removeAppCredentials();
deleteFileCache();
await this.resetState();
resetMomentLocale();
// TODO: Handle when multi-server support is added
@ -245,28 +246,30 @@ class GlobalEventHandler {
}
};
onServerVersionChanged = (serverVersion) => {
const {dispatch, getState} = Store.redux;
const state = getState();
const match = serverVersion && serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g);
const version = match && match[0];
const locale = getCurrentLocale(state);
const translations = getTranslations(locale);
onServerVersionChanged = async (serverVersion) => {
if (Store?.redux?.dispatch) {
const {dispatch, getState} = Store.redux;
const state = getState();
const match = serverVersion && serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g);
const version = match && match[0];
const locale = getCurrentLocale(state);
const translations = getTranslations(locale);
if (serverVersion) {
if (semver.valid(version) && semver.lt(version, LocalConfig.MinServerVersion)) {
Alert.alert(
translations[t('mobile.server_upgrade.title')],
translations[t('mobile.server_upgrade.description')],
[{
text: translations[t('mobile.server_upgrade.button')],
onPress: this.serverUpgradeNeeded,
}],
{cancelable: false},
);
} else if (state.entities.users && state.entities.users.currentUserId) {
dispatch(setServerVersion(serverVersion));
dispatch(loadConfigAndLicense());
if (serverVersion) {
if (semver.valid(version) && semver.lt(version, LocalConfig.MinServerVersion)) {
Alert.alert(
translations[t('mobile.server_upgrade.title')],
translations[t('mobile.server_upgrade.description')],
[{
text: translations[t('mobile.server_upgrade.button')],
onPress: this.serverUpgradeNeeded,
}],
{cancelable: false},
);
} else if (state.entities.users && state.entities.users.currentUserId) {
dispatch(setServerVersion(serverVersion));
dispatch(loadConfigAndLicense());
}
}
}
};
@ -299,7 +302,7 @@ class GlobalEventHandler {
},
views: {
i18n: {
locale: DeviceInfo.getDeviceLocale().split('-')[0],
locale: getLocales()[0].languageCode,
},
root: {
hydrationComplete: true,
@ -368,12 +371,27 @@ class GlobalEventHandler {
setUserTimezone = async () => {
const {dispatch, getState} = Store.redux;
const state = getState();
const currentUserId = getCurrentUserId(state);
const currentUser = getCurrentUser(state);
const enableTimezone = isTimezoneEnabled(state);
if (enableTimezone && currentUserId) {
const timezone = await getDeviceTimezoneAsync();
dispatch(autoUpdateTimezone(timezone));
if (enableTimezone && currentUser.id) {
const timezone = getDeviceTimezone();
const {
automaticTimezone,
manualTimezone,
useAutomaticTimezone,
} = currentUser.timezone;
let updateTimeZone = false;
if (useAutomaticTimezone) {
updateTimeZone = timezone !== automaticTimezone;
} else {
updateTimeZone = timezone !== manualTimezone;
}
if (updateTimeZone) {
dispatch(autoUpdateTimezone(timezone));
}
}
};
}

View file

@ -1198,7 +1198,7 @@ export function updateChannelMemberRoles(channelId: string, userId: string, role
}
export function updateChannelHeader(channelId: string, header: string): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
Client4.trackEvent('action', 'action_channels_update_header', {channel_id: channelId});
dispatch({
@ -1214,7 +1214,7 @@ export function updateChannelHeader(channelId: string, header: string): ActionFu
}
export function updateChannelPurpose(channelId: string, purpose: string): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
Client4.trackEvent('action', 'action_channels_update_purpose', {channel_id: channelId});
dispatch({

View file

@ -3,11 +3,10 @@
import {Client4} from '@mm-redux/client';
import {FileTypes} from '@mm-redux/action_types';
import {Action, batchActions, DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions';
import {DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions';
import {logError} from './errors';
import {bindClientFunc, forceLogoutIfNecessary} from './helpers';
import {FileUploadResponse} from '@mm-redux/types/files';
export function getFilesForPost(postId: string): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {

View file

@ -41,7 +41,7 @@ export function getPing(): ActionFunc {
}
export function resetPing(): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
dispatch({type: GeneralTypes.PING_RESET, data: {}});
return {data: true};
@ -115,7 +115,7 @@ export function logClientError(message: string, level: logLevel = 'ERROR') {
}
export function setAppState(state: GeneralState['appState']): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
dispatch({type: GeneralTypes.RECEIVED_APP_STATE, data: state});
return {data: true};
@ -123,7 +123,7 @@ export function setAppState(state: GeneralState['appState']): ActionFunc {
}
export function setDeviceToken(token: GeneralState['deviceToken']): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
dispatch({type: GeneralTypes.RECEIVED_APP_DEVICE_TOKEN, data: token});
return {data: true};
@ -131,7 +131,7 @@ export function setDeviceToken(token: GeneralState['deviceToken']): ActionFunc {
}
export function setServerVersion(serverVersion: string): ActionFunc {
return async (dispatch, getState: GetStateFunc) => {
return async (dispatch) => {
dispatch({type: GeneralTypes.RECEIVED_SERVER_VERSION, data: serverVersion});
dispatch(loadRolesIfNeeded([]));

View file

@ -414,7 +414,7 @@ export function cacheGifs(gifs: any) {
}
export function cacheGifsRequest(gifs: any) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
dispatch(cacheRequest());
dispatch(cacheGifs(gifs));
return {data: true};

View file

@ -17,7 +17,7 @@ export function forceLogoutIfNecessary(err: Client4Error, dispatch: DispatchFunc
}
}
function dispatcher(type: ActionType, data: any, dispatch: DispatchFunc, getState: GetStateFunc) {
function dispatcher(type: ActionType, data: any, dispatch: DispatchFunc) {
if (type.indexOf('SUCCESS') === -1) { // we don't want to pass the data for the request types
dispatch(requestSuccess(type, data));
} else {
@ -93,10 +93,10 @@ export function bindClientFunc({
if (Array.isArray(onSuccess)) {
onSuccess.forEach((s) => {
dispatcher(s, data, dispatch, getState);
dispatcher(s, data, dispatch);
});
} else if (onSuccess) {
dispatcher(onSuccess, data, dispatch, getState);
dispatcher(onSuccess, data, dispatch);
}
return {data};

View file

@ -207,8 +207,8 @@ export function createPost(post: Post, files: any[] = []) {
actions.push({
type: PostTypes.RECEIVED_NEW_POST,
data: {
id: pendingPostId,
...newPost,
id: pendingPostId,
},
});
@ -305,8 +305,8 @@ export function createPostImmediately(post: Post, files: any[] = []) {
}
dispatch(receivedNewPost({
id: pendingPostId,
...newPost,
id: pendingPostId,
}));
try {
@ -316,7 +316,7 @@ export function createPostImmediately(post: Post, files: any[] = []) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(batchActions([
{type: PostTypes.CREATE_POST_FAILURE, error},
removePost({id: pendingPostId, ...newPost}) as any,
removePost({...newPost, id: pendingPostId}) as any,
logError(error),
]));
return {error};

View file

@ -3,7 +3,6 @@
import {Client4} from '@mm-redux/client';
import {RoleTypes} from '@mm-redux/action_types';
import {getRoles} from '@mm-redux/selectors/entities/roles_helpers';
import {hasNewPermissions} from '@mm-redux/selectors/entities/general';
import {DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions';
import {Role} from '@mm-redux/types/roles';

View file

@ -6,7 +6,7 @@ import {General} from '../constants';
import {Scheme, SchemeScope, SchemePatch} from '@mm-redux/types/schemes';
import {ActionFunc, batchActions, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions';
import {ActionFunc, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions';
import {bindClientFunc, forceLogoutIfNecessary} from './helpers';
import {logError} from './errors';

View file

@ -53,7 +53,7 @@ async function getProfilesAndStatusesForMembers(userIds: string[], dispatch: Dis
}
export function selectTeam(team: Team | string): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch: DispatchFunc) => {
const teamId = (typeof team === 'string') ? team : team.id;
dispatch({
type: TeamTypes.SELECT_TEAM,

View file

@ -917,14 +917,14 @@ describe('Actions.Users', () => {
post('/users').
reply(200, TestHelper.fakeUserWithId());
const {data: user} = await Actions.createUser(TestHelper.fakeUser())(store.dispatch, store.getState);
const {data: user} = await store.dispatch(Actions.createUser(TestHelper.fakeUser()));
const beforeTime = new Date().getTime();
nock(Client4.getBaseRoute()).
put(`/users/${user.id}/active`).
reply(200, OK_RESPONSE);
await Actions.updateUserActive(user.id, false)(store.dispatch, store.getState);
await store.dispatch(Actions.updateUserActive(user.id, false));
const {profiles} = store.getState().entities.users;

View file

@ -5,7 +5,7 @@ import {combineReducers} from 'redux';
import {CategoryTypes} from '../../constants/channel_categories';
import {ChannelCategoryTypes, TeamTypes} from '@mm-redux/action_types';
import {TeamTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {ChannelCategory} from '@mm-redux/types/channel_categories';

View file

@ -4,8 +4,6 @@ import {combineReducers} from 'redux';
import {GroupTypes} from '@mm-redux/action_types';
import {GroupChannel, GroupSyncables, GroupTeam, Group} from '@mm-redux/types/groups';
import {GenericAction} from '@mm-redux/types/actions';
import {Team, TeamMembership} from '@mm-redux/types/teams';
import {ChannelMembership} from '@mm-redux/types/channels';
import {Dictionary} from '@mm-redux/types/utilities';
function syncables(state: Dictionary<GroupSyncables> = {}, action: GenericAction) {

View file

@ -1170,7 +1170,7 @@ export function expandedURLs(state: Dictionary<string> = {}, action: GenericActi
}
}
export default function(state: Partial<PostsState> = {}, action: GenericAction) {
export default function reducer(state: Partial<PostsState> = {}, action: GenericAction) {
const nextPosts = handlePosts(state.posts, action);
const nextPostsInChannel = postsInChannel(state.postsInChannel, action, state.posts!, nextPosts);

View file

@ -411,7 +411,7 @@ function updateTeamMemberSchemeRoles(state: RelationOneToOne<Team, RelationOneTo
}
function updateMyTeamMemberSchemeRoles(state: RelationOneToOne<Team, TeamMembership>, action: GenericAction) {
const {teamId, userId, isSchemeUser, isSchemeAdmin} = action.data;
const {teamId, isSchemeUser, isSchemeAdmin} = action.data;
const member = state[teamId];
if (member) {
return {

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {GeneralTypes, UserTypes} from '@mm-redux/action_types';
import {GeneralTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
function getInitialState() {
@ -12,7 +12,7 @@ function getInitialState() {
};
}
export default function(state = getInitialState(), action: GenericAction) {
export default function reducer(state = getInitialState(), action: GenericAction) {
if (!state.connected && action.type === GeneralTypes.WEBSOCKET_SUCCESS) {
return {
...state,

View file

@ -8,7 +8,7 @@ import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {createShallowSelector} from '@mm-redux/utils/helpers';
import {getPreferenceKey} from '@mm-redux/utils/preference_utils';
import {GlobalState} from '@mm-redux/types/store';
import {PreferencesType, PreferenceType} from '@mm-redux/types/preferences';
import {PreferenceType} from '@mm-redux/types/preferences';
export function getMyPreferences(state: GlobalState) {
return state.entities.preferences.myPreferences;

View file

@ -4,9 +4,7 @@
import {CustomEmoji} from './emojis';
import {FileInfo} from './files';
import {Reaction} from './reactions';
import {Channel} from './channels';
import {
$ID,
RelationOneToOne,
RelationOneToMany,
IDMappedObjects,

View file

@ -7,7 +7,7 @@ let activeKey: string|null = null;
let activeSecret: string | null = null;
let instance: any = null;
export default function(key: string, secret: string): any {
export default function gifycat(key: string, secret: string): any {
if (instance && activeKey === key && activeSecret === secret) {
return instance;
}

View file

@ -1,6 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-import-assign */
import NotificationsIOS from 'react-native-notifications';
import * as ViewSelectors from '@selectors/views';

View file

@ -2,11 +2,11 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
import DeviceInfo from 'react-native-device-info';
import {getLocales} from 'react-native-localize';
import {UserTypes} from '@mm-redux/action_types';
const defaultLocale = DeviceInfo.getDeviceLocale().split('-')[0];
const defaultLocale = getLocales()[0].languageCode;
function locale(state = defaultLocale, action) {
switch (action.type) {

View file

@ -27,6 +27,10 @@ describe('ChannelAddMembers', () => {
isLandscape: false,
};
beforeEach(() => {
jest.useFakeTimers();
});
test('should render without error and call functions on mount', () => {
const setButtons = jest.spyOn(NavigationActions, 'setButtons');

View file

@ -15,7 +15,7 @@ jest.mock('@assets/images/channel_info/pin.png', () => {
});
jest.mock('@utils/theme', () => {
const original = require.requireActual('app/utils/theme');
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -8,8 +8,8 @@ import {General} from '@mm-redux/constants';
import ChannelInfoHeader from './channel_info_header.js';
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -24,6 +24,10 @@ describe('ChannelMembers', () => {
isLandscape: false,
};
beforeAll(() => {
jest.useFakeTimers();
});
test('should match snapshot', () => {
const wrapper = shallowWithIntl(
<ChannelMembers {...baseProps}/>,

View file

@ -8,8 +8,8 @@ import Preferences from '@mm-redux/constants/preferences';
import EditProfile from './edit_profile.js';
jest.mock('react-intl');
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -17,17 +17,9 @@ import ImagePreview from './image_preview';
jest.useFakeTimers();
jest.mock('react-intl');
jest.mock('react-native-doc-viewer', () => {
return {
OpenFile: jest.fn(),
};
});
// jest.mock('react-native-permissions', () => {
// return {
// check: jest.fn(),
// };
// });
jest.mock('react-native-file-viewer', () => ({
open: jest.fn(),
}));
describe('ImagePreview', () => {
const baseProps = {

View file

@ -9,8 +9,8 @@ import {shallowWithIntl} from 'test/intl-test-helper';
import LongPost from './long_post';
jest.mock('react-native-doc-viewer', () => ({
openDoc: jest.fn(),
jest.mock('react-native-file-viewer', () => ({
open: jest.fn(),
}));
describe('LongPost', () => {

View file

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {makeMapStateToProps} from './index';
/* eslint-disable no-import-assign */
import {Permissions} from '@mm-redux/constants';
import * as channelSelectors from '@mm-redux/selectors/entities/channels';
@ -13,6 +14,8 @@ import * as deviceSelectors from 'app/selectors/device';
import * as preferencesSelectors from '@mm-redux/selectors/entities/preferences';
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
import {makeMapStateToProps} from './index';
jest.mock('@mm-redux/utils/post_utils');
channelSelectors.getChannel = jest.fn();

View file

@ -211,6 +211,7 @@ export default class SelectServer extends PureComponent {
return;
}
await globalEventHandler.resetState();
if (LocalConfig.ExperimentalClientSideCertEnable && Platform.OS === 'ios') {
RNFetchBlob.cba.selectCertificate((certificate) => {
if (certificate) {

View file

@ -9,8 +9,8 @@ import {RequestStatus} from '@mm-redux/constants';
import SelectTeam from './select_team.js';
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -8,22 +8,6 @@ import Preferences from '@mm-redux/constants/preferences';
import SelectorScreen from './selector_screen.js';
jest.mock('rn-fetch-blob', () => ({
fs: {
dirs: {
DocumentDir: () => jest.fn(),
CacheDir: () => jest.fn(),
},
},
}));
jest.mock('rn-fetch-blob/fs', () => ({
dirs: {
DocumentDir: () => jest.fn(),
CacheDir: () => jest.fn(),
},
}));
const user1 = {id: 'id', username: 'username'};
const user2 = {id: 'id2', username: 'username2'};
@ -79,6 +63,10 @@ describe('SelectorScreen', () => {
isLandscape: false,
};
beforeAll(() => {
jest.useFakeTimers();
});
test('should match snapshot for explicit options', async () => {
const wrapper = shallow(
<SelectorScreen {...baseProps}/>,

View file

@ -6,12 +6,12 @@ import {shallow} from 'enzyme';
import Preferences from '@mm-redux/constants/preferences';
import SectionItem from 'app/screens/settings/section_item';
import SectionItem from '@screens/settings/section_item';
import NotificationSettingsEmailIos from './notification_settings_email.ios.js';
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -17,7 +17,7 @@ import StatusBar from 'app/components/status_bar';
import Section from 'app/screens/settings/section';
import SectionItem from 'app/screens/settings/section_item';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {getDeviceTimezoneAsync} from 'app/utils/timezone';
import {getDeviceTimezone} from 'app/utils/timezone';
import {goToScreen} from 'app/actions/navigation';
export default class Timezone extends PureComponent {
@ -61,13 +61,13 @@ export default class Timezone extends PureComponent {
}
}
updateAutomaticTimezone = async (useAutomaticTimezone) => {
updateAutomaticTimezone = (useAutomaticTimezone) => {
const {userTimezone: {manualTimezone}} = this.props;
let automaticTimezone = '';
this.setState({useAutomaticTimezone});
if (useAutomaticTimezone) {
automaticTimezone = await getDeviceTimezoneAsync();
automaticTimezone = getDeviceTimezone();
this.submitUser({
useAutomaticTimezone,
automaticTimezone,

View file

@ -10,7 +10,7 @@ import {
Platform,
} from 'react-native';
import {WebView} from 'react-native-webview';
import CookieManager from 'react-native-cookies';
import CookieManager from '@react-native-community/cookies';
import urlParse from 'url-parse';
import {Client4} from '@mm-redux/client';
@ -27,7 +27,7 @@ const HEADERS = {
'X-Mobile-App': 'mattermost',
};
const postMessageJS = "window.postMessage(document.body.innerText, '*');";
const postMessageJS = "window.ReactNativeWebView.postMessage(document.body.innerText, '*');";
// Used to make sure that OneLogin forms scale appropriately on both platforms.
const oneLoginFormScalingJS = `
@ -152,7 +152,8 @@ class SSO extends PureComponent {
const url = event.nativeEvent.url;
if (url.includes(this.completedUrl)) {
CookieManager.get(this.props.serverUrl, this.useWebkit).then((res) => {
const token = res.MMAUTHTOKEN;
const mmtoken = res.MMAUTHTOKEN;
const token = typeof mmtoken === 'object' ? mmtoken.value : mmtoken;
if (token) {
this.setState({renderWebView: false});
@ -213,7 +214,7 @@ class SSO extends PureComponent {
<WebView
ref={this.webViewRef}
source={{uri: this.loginUrl, headers: HEADERS}}
javaScriptEnabledAndroid={true}
javaScriptEnabled={true}
automaticallyAdjustContentInsets={false}
startInLoadingState={true}
onNavigationStateChange={this.onNavigationStateChange}
@ -221,7 +222,7 @@ class SSO extends PureComponent {
injectedJavaScript={jsCode}
onLoadEnd={this.onLoadEnd}
onMessage={messagingEnabled ? this.onMessage : null}
useSharedProcessPool={true}
sharedCookiesEnabled={Platform.OS === 'android'}
cacheEnabled={false}
/>
);

View file

@ -6,14 +6,14 @@ import {shallow} from 'enzyme';
import Preferences from '@mm-redux/constants/preferences';
import * as NavigationActions from 'app/actions/navigation';
import * as NavigationActions from '@actions/navigation';
import TermsOfService from './terms_of_service.js';
jest.mock('react-intl');
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -11,8 +11,8 @@ import UserProfile from './user_profile.js';
import {BotTag, GuestTag} from 'app/components/tag';
jest.mock('react-intl');
jest.mock('app/utils/theme', () => {
const original = require.requireActual('app/utils/theme');
jest.mock('@utils/theme', () => {
const original = jest.requireActual('../../utils/theme');
return {
...original,
changeOpacity: jest.fn(),

View file

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import DeviceInfo from 'react-native-device-info';
import {getLocales} from 'react-native-localize';
import {DEFAULT_LOCALE} from '@mm-redux/constants/general';
import {getCurrentUserLocale} from '@mm-redux/selectors/entities/i18n';
// Not a proper selector since the device locale isn't in the redux store
export function getCurrentLocale(state) {
const deviceLocale = DeviceInfo.getDeviceLocale().split('-')[0];
const deviceLocale = getLocales()[0].languageCode;
const defaultLocale = deviceLocale || DEFAULT_LOCALE;
return getCurrentUserLocale(state, defaultLocale);

View file

@ -113,7 +113,7 @@ class Telemetry {
});
}
save() {
async save() {
if (!this.canSendTelemetry()) {
return;
}

View file

@ -3,6 +3,7 @@
import {Dimensions} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import * as RNLocalize from 'react-native-localize';
import LocalConfig from '@assets/config';
@ -67,28 +68,28 @@ export function setTraceRecord({
};
}
export function getDeviceInfo() {
export async function getDeviceInfo() {
const {height, width} = Dimensions.get('window');
return {
api_level: DeviceInfo.getAPILevel(),
api_level: await DeviceInfo.getAPILevel(),
build_number: DeviceInfo.getBuildNumber(),
bundle_id: DeviceInfo.getBundleId(),
brand: DeviceInfo.getBrand(),
country: DeviceInfo.getDeviceCountry(),
country: RNLocalize.getCountry(),
device_id: DeviceInfo.getDeviceId(),
device_locale: DeviceInfo.getDeviceLocale().split('-')[0],
device_locale: RNLocalize.getLocales()[0].languageCode,
device_type: DeviceInfo.getDeviceType(),
device_unique_id: DeviceInfo.getUniqueID(),
height: height ? Math.floor(height) : 0,
is_emulator: DeviceInfo.isEmulator(),
is_emulator: await DeviceInfo.isEmulator(),
is_tablet: DeviceInfo.isTablet(),
manufacturer: DeviceInfo.getManufacturer(),
max_memory: DeviceInfo.getMaxMemory(),
manufacturer: await DeviceInfo.getManufacturer(),
max_memory: await DeviceInfo.getMaxMemory(),
model: DeviceInfo.getModel(),
system_name: DeviceInfo.getSystemName(),
system_version: DeviceInfo.getSystemVersion(),
timezone: DeviceInfo.getTimezone(),
timezone: RNLocalize.getTimeZone(),
app_version: DeviceInfo.getVersion(),
width: width ? Math.floor(width) : 0,
};

View file

@ -1,5 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable no-import-assign */
import RNFetchBlob from 'rn-fetch-blob';
import ImageCacheManager, {getCacheFile, hashCode} from 'app/utils/image_cache_manager';

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {Client4} from '@mm-redux/client';
import CookieManager from 'react-native-cookies';
import CookieManager from '@react-native-community/cookies';
let mfaPreflightDone = false;

View file

@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import DeviceInfo from 'react-native-device-info';
import {getTimeZone} from 'react-native-localize';
import moment from 'moment-timezone';
export function getDeviceTimezoneAsync() {
return DeviceInfo.getTimezoneAsync();
export function getDeviceTimezone() {
return getTimeZone();
}
export function getDeviceUtcOffset() {

View file

@ -145,8 +145,6 @@
"mobile.android.videos_permission_denied_description": "Upload videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your video library.",
"mobile.android.videos_permission_denied_title": "{applicationName} would like to access your videos",
"mobile.announcement_banner.title": "Announcement",
"mobile.authentication_error.message": "Mattermost has encountered an error. Please re-authenticate to start a new session.",
"mobile.authentication_error.title": "Authentication Error",
"mobile.calendar.dayNames": "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
"mobile.calendar.dayNamesShort": "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
"mobile.calendar.monthNames": "January,February,March,April,May,June,July,August,September,October,November,December",
@ -512,7 +510,6 @@
"more_channels.title": "More Channels",
"msg_typing.areTyping": "{users} and {last} are typing...",
"msg_typing.isTyping": "{user} is typing...",
"navbar_dropdown.logout": "Logout",
"navbar.channel_drawer.button": "Channels and teams",
"navbar.channel_drawer.hint": "Opens the channels and teams drawer",
"navbar.leave": "Leave Channel",

View file

@ -489,7 +489,10 @@ platform :ios do
end
def setup_code_signing
disable_automatic_code_signing(path: './ios/Mattermost.xcodeproj')
update_code_signing_settings(
use_automatic_signing: false,
path: './ios/Mattermost.xcodeproj'
)
ENV['MATCH_APP_IDENTIFIER'].split(',').each do |id|
target = 'Mattermost'
@ -500,12 +503,13 @@ platform :ios do
end
profile = "sigh_#{id}_#{ENV['MATCH_TYPE']}"
config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
update_project_provisioning(
xcodeproj: './ios/Mattermost.xcodeproj',
profile: ENV["#{profile}_profile-path"], # optional if you use sigh
target_filter: ".*#{target}$", # matches name or type of a target
build_configuration: 'Release',
build_configuration: config_mode,
code_signing_identity: 'iPhone Distribution' # optionally specify the codesigning identity
)
end

View file

@ -5,21 +5,21 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
aws-eventstream (1.0.3)
aws-partitions (1.289.0)
aws-sdk-core (3.92.0)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-eventstream (1.1.0)
aws-partitions (1.313.0)
aws-sdk-core (3.95.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.30.0)
aws-sdk-kms (1.31.0)
aws-sdk-core (~> 3, >= 3.71.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.61.1)
aws-sdk-s3 (1.64.0)
aws-sdk-core (~> 3, >= 3.83.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.1)
aws-sigv4 (1.1.3)
aws-eventstream (~> 1.0, >= 1.0.2)
babosa (1.0.3)
claide (1.0.3)
@ -35,15 +35,15 @@ GEM
dotenv (2.7.5)
emoji_regex (1.0.1)
excon (0.73.0)
faraday (0.17.3)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
http-cookie (~> 1.0.0)
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
faraday_middleware (1.0.0)
faraday (~> 1.0)
fastimage (2.1.7)
fastlane (2.144.0)
fastlane (2.147.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
aws-sdk-s3 (~> 1.0)
@ -54,9 +54,9 @@ GEM
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 2.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 0.17)
faraday (>= 0.17, < 2.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 0.13.1)
faraday_middleware (>= 0.13.1, < 2.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-api-client (>= 0.29.2, < 0.37.0)
@ -101,20 +101,20 @@ GEM
google-cloud-env (1.3.1)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.0)
google-cloud-storage (1.25.1)
google-cloud-storage (1.26.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.11.0)
googleauth (0.12.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.12)
signet (~> 0.14)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
@ -133,7 +133,7 @@ GEM
naturally (2.2.0)
nokogiri (1.10.9)
mini_portile2 (~> 2.4.0)
os (1.0.1)
os (1.1.0)
plist (3.5.0)
public_suffix (2.0.5)
representable (3.0.4)
@ -144,7 +144,7 @@ GEM
rouge (2.0.7)
rubyzip (1.3.0)
security (0.1.3)
signet (0.13.2)
signet (0.14.0)
addressable (~> 2.3)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
@ -163,10 +163,10 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.6)
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.15.0)
xcodeproj (1.16.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)

View file

@ -930,7 +930,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = EB4F0DF36537B0B21BE962FB /* Pods-Mattermost.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
@ -972,7 +972,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 25BF2BACE89201DE6E585B7E /* Pods-Mattermost.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;

View file

@ -32,12 +32,12 @@ PODS:
- libwebp/mux (1.1.0):
- libwebp/demux
- libwebp/webp (1.1.0)
- MMKV (1.1.0):
- MMKVCore (~> 1.1.0)
- MMKV (1.1.1):
- MMKVCore (~> 1.1.1)
- MMKVCore (1.1.1)
- Permission-Camera (2.0.10):
- Permission-Camera (2.1.4):
- RNPermissions
- Permission-PhotoLibrary (2.0.10):
- Permission-PhotoLibrary (2.1.4):
- RNPermissions
- RCTRequired (0.62.2)
- RCTTypeSafety (0.62.2):
@ -45,7 +45,7 @@ PODS:
- Folly (= 2018.10.22.00)
- RCTRequired (= 0.62.2)
- React-Core (= 0.62.2)
- RCTYouTube (2.0.0):
- RCTYouTube (2.0.1):
- React
- YoutubePlayer-in-WKWebView (~> 0.3.1)
- React (0.62.2):
@ -205,11 +205,11 @@ PODS:
- React-cxxreact (= 0.62.2)
- React-jsi (= 0.62.2)
- React-jsinspector (0.62.2)
- react-native-cameraroll (1.5.2):
- react-native-cameraroll (1.6.2):
- React
- react-native-cookies (3.2.0):
- react-native-cookies (2.0.9):
- React
- react-native-document-picker (3.3.2):
- react-native-document-picker (3.4.0):
- React
- react-native-hw-keyboard-event (0.0.4):
- React
@ -217,10 +217,10 @@ PODS:
- React
- react-native-local-auth (1.6.0):
- React
- react-native-mmkv-storage (0.3.1):
- MMKV (= 1.1.0)
- react-native-mmkv-storage (0.3.2):
- MMKV (= 1.1.1)
- React
- react-native-netinfo (4.4.0):
- react-native-netinfo (5.8.1):
- React
- react-native-notifications (2.1.7):
- React
@ -228,12 +228,14 @@ PODS:
- React
- react-native-safe-area (0.5.1):
- React
- react-native-safe-area-context (1.0.0):
- React
- react-native-video (5.0.2):
- React
- react-native-video/Video (= 5.0.2)
- react-native-video/Video (5.0.2):
- React
- react-native-webview (7.0.1):
- react-native-webview (9.4.0):
- React
- React-RCTActionSheet (0.62.2):
- React-Core/RCTActionSheetHeaders (= 0.62.2)
@ -296,7 +298,7 @@ PODS:
- ReactCommon/callinvoker (= 0.62.2)
- ReactNativeExceptionHandler (2.10.8):
- React
- ReactNativeKeyboardTrackingView (5.6.1):
- ReactNativeKeyboardTrackingView (5.7.0):
- React
- ReactNativeNavigation (6.4.0):
- React
@ -304,31 +306,37 @@ PODS:
- React-RCTText
- rn-fetch-blob (0.12.0):
- React-Core
- RNCAsyncStorage (1.8.1):
- RNCAsyncStorage (1.10.1):
- React
- RNDeviceInfo (2.1.2):
- RNCMaskedView (0.1.10):
- React
- RNDeviceInfo (5.5.7):
- React
- RNFastImage (8.1.5):
- React
- SDWebImage (~> 5.0)
- SDWebImageWebPCoder (~> 0.4.1)
- RNFileViewer (2.1.0):
- React
- RNGestureHandler (1.6.1):
- React
- RNKeychain (4.0.5):
- RNKeychain (6.0.0):
- React
- RNPermissions (2.0.10):
- RNLocalize (1.4.0):
- React
- RNReactNativeDocViewer (1.0.0):
- RNPermissions (2.1.4):
- React
- RNReactNativeHapticFeedback (1.9.0):
- RNReactNativeHapticFeedback (1.10.0):
- React
- RNRudderSdk (1.0.0):
- React
- Rudder (= 1.0.3-beta-4)
- RNSentry (1.3.6):
- RNScreens (2.7.0):
- React
- RNSentry (1.3.9):
- React
- Sentry (~> 4.4.0)
- RNSVG (12.0.3):
- RNSVG (12.1.0):
- React
- RNVectorIcons (6.6.0):
- React
@ -370,7 +378,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
- react-native-cookies (from `../node_modules/react-native-cookies/ios`)
- "react-native-cookies (from `../node_modules/@react-native-community/cookies`)"
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
@ -380,6 +388,7 @@ DEPENDENCIES:
- react-native-notifications (from `../node_modules/react-native-notifications`)
- react-native-passcode-status (from `../node_modules/react-native-passcode-status`)
- react-native-safe-area (from `../node_modules/react-native-safe-area`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-video (from `../node_modules/react-native-video`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
@ -398,14 +407,17 @@ DEPENDENCIES:
- ReactNativeNavigation (from `../node_modules/react-native-navigation`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNFileViewer (from `../node_modules/react-native-file-viewer`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReactNativeDocViewer (from `../node_modules/react-native-doc-viewer`)
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- "RNRudderSdk (from `../node_modules/@rudderstack/rudder-sdk-react-native/ios`)"
- RNScreens (from `../node_modules/react-native-screens`)
- "RNSentry (from `../node_modules/@sentry/react-native`)"
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
@ -469,7 +481,7 @@ EXTERNAL SOURCES:
react-native-cameraroll:
:path: "../node_modules/@react-native-community/cameraroll"
react-native-cookies:
:path: "../node_modules/react-native-cookies/ios"
:path: "../node_modules/@react-native-community/cookies"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-hw-keyboard-event:
@ -488,6 +500,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-passcode-status"
react-native-safe-area:
:path: "../node_modules/react-native-safe-area"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-video:
:path: "../node_modules/react-native-video"
react-native-webview:
@ -522,22 +536,28 @@ EXTERNAL SOURCES:
:path: "../node_modules/rn-fetch-blob"
RNCAsyncStorage:
:path: "../node_modules/@react-native-community/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNFileViewer:
:path: "../node_modules/react-native-file-viewer"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNKeychain:
:path: "../node_modules/react-native-keychain"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNPermissions:
:path: "../node_modules/react-native-permissions"
RNReactNativeDocViewer:
:path: "../node_modules/react-native-doc-viewer"
RNReactNativeHapticFeedback:
:path: "../node_modules/react-native-haptic-feedback"
RNRudderSdk:
:path: "../node_modules/@rudderstack/rudder-sdk-react-native/ios"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSentry:
:path: "../node_modules/@sentry/react-native"
RNSVG:
@ -557,13 +577,13 @@ SPEC CHECKSUMS:
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
jail-monkey: d7c5048b2336f22ee9c9e0efa145f1f917338ea9
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
MMKV: 7bb6c30f9ff2ea45bc2398c86e66dd1cb63cfe20
MMKV: 5eb44526fcf38152328ebfeff5ec585972ace00d
MMKVCore: 2748bf702287a814a6c514d054033e41e07f5c0f
Permission-Camera: 8f0e5decca5f28f70f28a8dc31f012c9bad40ad8
Permission-PhotoLibrary: b209bf23b784c9e1409a57d81c6d11ab1d3079c1
Permission-Camera: 3ed116545ee8806cd706bca0e1a9a2c3cd36c6bd
Permission-PhotoLibrary: 56e71522b008d9abca150680c1f8050f267cdffb
RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce
RCTYouTube: 5e94bfa005371c41d307f3f93c51b3e8eabfb0c8
RCTYouTube: 7ff7d42f5ed42d185198681e967fd2c2b661375d
React: 29a8b1a02bd764fb7644ef04019270849b9a7ac3
React-Core: b12bffb3f567fdf99510acb716ef1abd426e0e05
React-CoreModules: 4a9b87bbe669d6c3173c0132c3328e3b000783d0
@ -571,19 +591,20 @@ SPEC CHECKSUMS:
React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
react-native-cameraroll: 81c6c271b5b853da398ccecc7ad6a5f765fd3001
react-native-cookies: 854d59c4135c70b92a02ca4930e68e4e2eb58150
react-native-document-picker: 6acd41af22988cf349848678fdaa294d4448478e
react-native-cameraroll: 94bec91c68b94ac946c61b497b594bb38692c41b
react-native-cookies: bc1f91a504ee091f1998a1b6c7ff4b7a9ed5b80e
react-native-document-picker: d694111879537cec2c258a1dcd2243d9df746824
react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53
react-native-image-picker: 668e72d0277dc8c12ae90e835507c1eddd2e4f85
react-native-local-auth: 359af242caa1e5c501ac9dfe33b1e238ad8f08c6
react-native-mmkv-storage: d413e1e00b1f410a744e1d547a912a1f87e67260
react-native-netinfo: 892a5130be97ff8bb69c523739c424a2ffc296d1
react-native-mmkv-storage: 49389227471de5258b4e5bae7857bfe0ad02c8f7
react-native-netinfo: ae21a6ab293d6c75af0c17c562ef37a931218886
react-native-notifications: 24706907104a0f00c35c4bde7e0ca76a50f730e1
react-native-passcode-status: 88c4f6e074328bc278bd127646b6c694ad5a530a
react-native-safe-area: e8230b0017d76c00de6b01e2412dcf86b127c6a3
react-native-safe-area-context: 5f3e081f937ab7c44c179d551f332fa494cfcf8f
react-native-video: 961749da457e73bf0b5565edfbaffc25abfb8974
react-native-webview: 0d1c2b4e7ffb0543a74fa0512f2f8dc5fb0e49e2
react-native-webview: 0e2881d2e3e72ad52a82445c1a116c43205fd471
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
@ -595,20 +616,23 @@ SPEC CHECKSUMS:
React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256
ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
ReactNativeExceptionHandler: 8025d98049c25f186835a3af732dd7c9974d6dce
ReactNativeKeyboardTrackingView: a240a6a0dba852bb107109a7ec7e98b884055977
ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306
ReactNativeNavigation: 667586f6924fbd09512e2933fe70497db914b758
rn-fetch-blob: 17961aec08caae68bb8fc0e5b40f93b3acfa6932
RNCAsyncStorage: 00bdf63f7f1e0f11d3323533dba4f222e58bf092
RNDeviceInfo: fd8296de6fca8b743cdc499b896f48e8a9f1faf5
RNCAsyncStorage: f640ddf9266df777c38e112ea5881ead7188b59c
RNCMaskedView: f5c7d14d6847b7b44853f7acb6284c1da30a3459
RNDeviceInfo: 498ccbf8b1361fe858581e3c1193ecee1a031e62
RNFastImage: 35ae972d6727c84ee3f5c6897e07f84d0a3445e9
RNFileViewer: 3600e85d326dadfd0fd367eb38fcb4300b699b49
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
RNKeychain: 840f8e6f13be0576202aefcdffd26a4f54bfe7b5
RNPermissions: 8afd37dbc1be65748363c6a90caffd1806567651
RNReactNativeDocViewer: 571c6ac38483531b8fb521d02a6ba54652ed10a7
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
RNKeychain: bf2d7e9a0ae7a073c07770dd2aa6d11c67581733
RNLocalize: fc27ee5878ce5a3af73873fb2d8e866e0d1e6d84
RNPermissions: 8ca17fd6c822eea589fe84709d9426e05cc39c39
RNReactNativeHapticFeedback: 22c5ecf474428766c6b148f96f2ff6155cd7225e
RNRudderSdk: 3abdcc4b145b3db6571827b0fc7af4e75a96af13
RNSentry: d892cbdee165cc6159d71e2a7954efdb8a361918
RNSVG: 7e16ddfc6e00d5aa69c9eb83e699bcce5dcb85d4
RNScreens: cf198f915f8a2bf163de94ca9f5bfc8d326c3706
RNSentry: 9c9783b13fb5cba387fff55f085cc1da3854ce71
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
Rudder: 358a71278045a608ae4b081b37a465ffb65c129d
SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc

8070
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,119 +7,124 @@
"license": "Apache 2.0",
"private": true,
"dependencies": {
"@babel/runtime": "7.9.2",
"@react-native-community/async-storage": "1.8.1",
"@react-native-community/cameraroll": "1.5.2",
"@react-native-community/netinfo": "4.4.0",
"@babel/runtime": "7.9.6",
"@react-native-community/async-storage": "1.10.1",
"@react-native-community/cameraroll": "1.6.2",
"@react-native-community/cookies": "2.0.9",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/netinfo": "5.8.1",
"@react-navigation/native": "5.3.2",
"@react-navigation/stack": "5.3.6",
"@rudderstack/rudder-sdk-react-native": "0.1.2",
"@sentry/react-native": "1.3.6",
"@sentry/react-native": "1.3.9",
"analytics-react-native": "1.2.0",
"commonmark": "github:mattermost/commonmark.js#f6ab98dede6ce4b4e7adea140ac77249bfb2d6ce",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#3a2ac19cab725ad28b170fdc1d397dddedcf87eb",
"core-js": "3.6.4",
"deep-equal": "2.0.1",
"core-js": "3.6.5",
"deep-equal": "2.0.3",
"deepmerge": "4.2.2",
"emoji-regex": "8.0.0",
"emoji-regex": "9.0.0",
"form-data": "3.0.0",
"fuse.js": "3.6.1",
"fuse.js": "6.0.0",
"intl": "1.2.5",
"jail-monkey": "2.3.2",
"mime-db": "1.43.0",
"moment-timezone": "0.5.26",
"mime-db": "1.44.0",
"moment-timezone": "0.5.29",
"prop-types": "15.7.2",
"react": "16.13.0",
"react": "16.13.1",
"react-intl": "2.8.0",
"react-native": "0.62.2",
"react-native-android-open-settings": "1.3.0",
"react-native-animatable": "1.3.3",
"react-native-button": "2.4.0",
"react-native-calendars": "1.264.0",
"react-native-button": "3.0.1",
"react-native-calendars": "1.265.0",
"react-native-circular-progress": "1.3.6",
"react-native-cookies": "github:mattermost/react-native-cookies#b35bafc388ae09c83bd875e887daf6a0755e0b40",
"react-native-device-info": "github:mattermost/react-native-device-info#f7175f10822d8f66b9806206e3313eaf2f4aabc6",
"react-native-doc-viewer": "github:mattermost/react-native-doc-viewer#c913e54ec8e4a60753bc7dd39256fa4be8229d19",
"react-native-document-picker": "3.3.2",
"react-native-elements": "1.2.7",
"react-native-device-info": "5.5.7",
"react-native-document-picker": "3.4.0",
"react-native-elements": "2.0.0",
"react-native-exception-handler": "2.10.8",
"react-native-fast-image": "8.1.5",
"react-native-file-viewer": "2.1.0",
"react-native-gesture-handler": "1.6.1",
"react-native-haptic-feedback": "1.9.0",
"react-native-haptic-feedback": "1.10.0",
"react-native-hw-keyboard-event": "0.0.4",
"react-native-image-gallery": "github:mattermost/react-native-image-gallery#c1a9f7118e90cc87d47620bc0584c9cac4b0cf38",
"react-native-image-picker": "2.3.1",
"react-native-keyboard-aware-scroll-view": "0.9.1",
"react-native-keyboard-tracking-view": "5.6.1",
"react-native-keychain": "4.0.5",
"react-native-keyboard-tracking-view": "5.7.0",
"react-native-keychain": "6.0.0",
"react-native-linear-gradient": "2.5.6",
"react-native-local-auth": "1.6.0",
"react-native-mmkv-storage": "0.3.1",
"react-native-localize": "1.4.0",
"react-native-mmkv-storage": "0.3.2",
"react-native-navigation": "6.4.0",
"react-native-notifications": "2.1.7",
"react-native-passcode-status": "1.1.2",
"react-native-permissions": "2.0.10",
"react-native-permissions": "2.1.4",
"react-native-safe-area": "0.5.1",
"react-native-safe-area-context": "1.0.0",
"react-native-screens": "2.7.0",
"react-native-section-list-get-item-layout": "2.2.3",
"react-native-slider": "0.11.0",
"react-native-status-bar-size": "0.3.3",
"react-native-svg": "12.0.3",
"react-native-svg": "12.1.0",
"react-native-v8": "0.62.2-patch.1",
"react-native-vector-icons": "6.6.0",
"react-native-video": "5.0.2",
"react-native-webview": "github:mattermost/react-native-webview#b5e22940a613869d3999feac9451ee65352f4fbe",
"react-native-youtube": "2.0.0",
"react-navigation": "4.0.10",
"react-navigation-stack": "1.9.4",
"react-native-webview": "9.4.0",
"react-native-youtube": "2.0.1",
"react-redux": "7.2.0",
"redux": "4.0.5",
"redux-action-buffer": "1.2.0",
"redux-batched-actions": "0.4.1",
"redux-batched-actions": "0.5.0",
"redux-persist": "6.0.0",
"redux-persist-transform-filter": "0.0.20",
"redux-reset": "0.3.0",
"redux-thunk": "2.3.0",
"reselect": "4.0.0",
"rn-fetch-blob": "0.12.0",
"rn-placeholder": "github:mattermost/rn-placeholder#02c629c65d0123a2eee623ada0fd17186415d3c3",
"semver": "7.1.3",
"serialize-error": "5.0.0",
"rn-placeholder": "3.0.0",
"semver": "7.3.2",
"serialize-error": "7.0.1",
"shallow-equals": "1.0.0",
"tinycolor2": "1.4.1",
"url-parse": "1.4.7"
},
"devDependencies": {
"@babel/cli": "7.8.4",
"@babel/core": "7.9.0",
"@babel/plugin-transform-runtime": "7.9.0",
"@babel/preset-env": "7.9.0",
"@babel/core": "7.9.6",
"@babel/plugin-transform-runtime": "7.9.6",
"@babel/preset-env": "7.9.6",
"@babel/register": "7.9.0",
"@testing-library/react-native": "5.0.3",
"@types/enzyme": "3.10.5",
"@types/enzyme-adapter-react-16": "1.0.6",
"@types/jest": "25.1.4",
"@types/jest": "25.2.2",
"@types/moment-timezone": "0.5.13",
"@types/react": "16.9.27",
"@types/react-native": "0.62.0",
"@types/react": "16.9.35",
"@types/react-native": "0.62.10",
"@types/react-test-renderer": "16.9.2",
"@types/shallow-equals": "1.0.0",
"@typescript-eslint/eslint-plugin": "2.25.0",
"@typescript-eslint/parser": "2.25.0",
"@typescript-eslint/eslint-plugin": "2.33.0",
"@typescript-eslint/parser": "2.33.0",
"babel-eslint": "10.1.0",
"babel-jest": "25.2.3",
"babel-jest": "26.0.1",
"babel-plugin-module-resolver": "4.0.0",
"babel-plugin-transform-remove-console": "6.9.4",
"deep-freeze": "0.0.1",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.2",
"enzyme-to-json": "3.4.4",
"eslint": "6.8.0",
"eslint": "7.0.0",
"eslint-plugin-header": "3.0.0",
"eslint-plugin-jest": "23.8.2",
"eslint-plugin-jest": "23.13.0",
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#070ce792d105482ffb2b27cfc0b7e78b3d20acee",
"eslint-plugin-react": "7.19.0",
"eslint-plugin-react": "7.20.0",
"harmony-reflect": "1.6.1",
"husky": "4.2.3",
"husky": "4.2.5",
"isomorphic-fetch": "2.2.1",
"jest": "25.2.3",
"jest-cli": "25.2.3",
"jest": "26.0.1",
"jest-cli": "26.0.1",
"jest-enzyme": "7.1.2",
"jetifier": "1.6.5",
"jsdom-global": "3.0.2",
@ -128,17 +133,17 @@
"mock-async-storage": "2.2.0",
"mock-socket": "9.0.3",
"nock": "12.0.3",
"nyc": "15.0.0",
"patch-package": "6.2.1",
"react-dom": "16.13.0",
"react-test-renderer": "16.13.0",
"nyc": "15.0.1",
"patch-package": "6.2.2",
"react-dom": "16.13.1",
"react-test-renderer": "16.13.1",
"redux-mock-store": "1.5.4",
"redux-persist-node-storage": "2.0.0",
"socketcluster": "16.0.1",
"ts-jest": "25.5.0",
"typescript": "3.8.3",
"underscore": "1.9.2",
"util": "0.12.2"
"ts-jest": "26.0.0",
"typescript": "3.9.2",
"underscore": "1.10.2",
"util": "0.12.3"
},
"husky": {
"hooks": {

View file

@ -220,38 +220,20 @@ module.exports = [
'node_modules/@babel/runtime/helpers/typeof.js',
'node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js',
'node_modules/@babel/runtime/helpers/wrapNativeSuper.js',
'node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js',
'node_modules/@babel/runtime/regenerator/index.js',
'node_modules/@react-native-community/async-storage/lib/AsyncStorage.js',
'node_modules/@react-native-community/async-storage/lib/hooks.js',
'node_modules/@react-native-community/async-storage/lib/index.js',
'node_modules/@react-native-community/netinfo/src/index.ts',
'node_modules/@react-native-community/netinfo/src/internal/deprecatedState.ts',
'node_modules/@react-native-community/netinfo/src/internal/deprecatedTypes.ts',
'node_modules/@react-native-community/netinfo/src/internal/deprecatedUtils.ts',
'node_modules/@react-native-community/netinfo/src/internal/internetReachability.ts',
'node_modules/@react-native-community/netinfo/src/internal/nativeInterface.ts',
'node_modules/@react-native-community/netinfo/src/internal/state.ts',
'node_modules/@react-native-community/netinfo/src/internal/types.ts',
'node_modules/@react-native-community/netinfo/src/internal/utils.ts',
'node_modules/@react-native-community/cookies/index.js',
'node_modules/anser/lib/index.js',
'node_modules/base-64/base64.js',
'node_modules/base64-js/index.js',
'node_modules/buffer/index.js',
'node_modules/clone/clone.js',
'node_modules/color-convert/conversions.js',
'node_modules/color-convert/index.js',
'node_modules/color-convert/route.js',
'node_modules/color-name/index.js',
'node_modules/color-string/index.js',
'node_modules/color/index.js',
'node_modules/create-react-class/factory.js',
'node_modules/create-react-class/index.js',
'node_modules/create-react-class/node_modules/fbjs/lib/emptyFunction.js',
'node_modules/create-react-class/node_modules/fbjs/lib/emptyObject.js',
'node_modules/create-react-class/node_modules/fbjs/lib/invariant.js',
'node_modules/create-react-class/node_modules/fbjs/lib/warning.js',
'node_modules/component-emitter/index.js',
'node_modules/deepmerge/dist/cjs.js',
'node_modules/event-target-shim/dist/event-target-shim.js',
'node_modules/eventemitter3/index.js',
@ -265,7 +247,6 @@ module.exports = [
'node_modules/fbjs/lib/warning.js',
'node_modules/harmony-reflect/reflect.js',
'node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js',
'node_modules/inherits/inherits_browser.js',
'node_modules/intl-format-cache/dist/index.js',
'node_modules/intl-format-cache/index.js',
'node_modules/intl-messageformat-parser/index.js',
@ -289,8 +270,6 @@ module.exports = [
'node_modules/intl/lib/core.js',
'node_modules/intl/locale-data/complete.js',
'node_modules/invariant/browser.js',
'node_modules/is-arguments/index.js',
'node_modules/is-generator-function/index.js',
'node_modules/lodash.clonedeep/index.js',
'node_modules/lodash.forin/index.js',
'node_modules/lodash.get/index.js',
@ -379,7 +358,6 @@ module.exports = [
'node_modules/lodash/_createAssigner.js',
'node_modules/lodash/_createBaseEach.js',
'node_modules/lodash/_createBaseFor.js',
'node_modules/lodash/_createSet.js',
'node_modules/lodash/_customOmitClone.js',
'node_modules/lodash/_defineProperty.js',
'node_modules/lodash/_equalArrays.js',
@ -485,7 +463,6 @@ module.exports = [
'node_modules/lodash/map.js',
'node_modules/lodash/memoize.js',
'node_modules/lodash/merge.js',
'node_modules/lodash/noop.js',
'node_modules/lodash/omit.js',
'node_modules/lodash/pick.js',
'node_modules/lodash/property.js',
@ -519,11 +496,15 @@ module.exports = [
'node_modules/react-intl/lib/index.js',
'node_modules/react-intl/locale-data/en.js',
'node_modules/react-intl/locale-data/index.js',
'node_modules/react-is/cjs/react-is.production.js',
'node_modules/react-is/cjs/react-is.production.min.js',
'node_modules/react-is/index.js',
'node_modules/react-lifecycles-compat/react-lifecycles-compat.cjs.js',
'node_modules/react-native-cookies/index.js',
'node_modules/react-native-device-info/deviceinfo.js',
'node_modules/react-native-device-info/src/index.ts',
'node_modules/react-native-device-info/src/internal/asyncHookWrappers.ts',
'node_modules/react-native-device-info/src/internal/devicesWithNotch.ts',
'node_modules/react-native-device-info/src/internal/nativeInterface.ts',
'node_modules/react-native-gesture-handler/GestureButtons.js',
'node_modules/react-native-gesture-handler/GestureComponents.js',
'node_modules/react-native-gesture-handler/GestureHandler.js',
'node_modules/react-native-gesture-handler/GestureHandlerButton.js',
'node_modules/react-native-gesture-handler/GestureHandlerPropTypes.js',
@ -532,13 +513,14 @@ module.exports = [
'node_modules/react-native-gesture-handler/NativeViewGestureHandler.js',
'node_modules/react-native-gesture-handler/PlatformConstants.js',
'node_modules/react-native-gesture-handler/RNGestureHandlerModule.js',
'node_modules/react-native-gesture-handler/State.js',
'node_modules/react-native-gesture-handler/createHandler.js',
'node_modules/react-native-gesture-handler/createNativeWrapper.js',
'node_modules/react-native-gesture-handler/gestureHandlerRootHOC.js',
'node_modules/react-native-gesture-handler/index.js',
'node_modules/react-native-haptic-feedback/index.js',
'node_modules/react-native-keychain/index.js',
'node_modules/react-native-localize/lib/commonjs/index.js',
'node_modules/react-native-localize/lib/commonjs/module.js',
'node_modules/react-native-mmkv-storage/index.js',
'node_modules/react-native-mmkv-storage/src/api.js',
'node_modules/react-native-mmkv-storage/src/encryption.js',
@ -747,7 +729,6 @@ module.exports = [
'node_modules/react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js',
'node_modules/react-native/Libraries/ReactPrivate/ReactNativePrivateInterface.js',
'node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js',
'node_modules/react-native/Libraries/Renderer/shims/NativeMethodsMixin.js',
'node_modules/react-native/Libraries/Renderer/shims/ReactNative.js',
'node_modules/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js',
'node_modules/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js',
@ -764,6 +745,7 @@ module.exports = [
'node_modules/react-native/Libraries/TurboModule/TurboModuleRegistry.js',
'node_modules/react-native/Libraries/UTFSequence.js',
'node_modules/react-native/Libraries/Utilities/BackHandler.android.js',
'node_modules/react-native/Libraries/Utilities/DeviceInfo.js',
'node_modules/react-native/Libraries/Utilities/Dimensions.js',
'node_modules/react-native/Libraries/Utilities/GlobalPerformanceLogger.js',
'node_modules/react-native/Libraries/Utilities/HMRClient.js',
@ -911,18 +893,16 @@ module.exports = [
'node_modules/semver/ranges/min-satisfying.js',
'node_modules/semver/ranges/min-version.js',
'node_modules/semver/ranges/outside.js',
'node_modules/semver/ranges/simplify.js',
'node_modules/semver/ranges/to-comparators.js',
'node_modules/semver/ranges/valid.js',
'node_modules/serialize-error/index.js',
'node_modules/shallow-equals/index.js',
'node_modules/simple-swizzle/index.js',
'node_modules/stacktrace-parser/dist/stack-trace-parser.cjs.js',
'node_modules/simple-swizzle/node_modules/is-arrayish/index.js',
'node_modules/symbol-observable/lib/index.js',
'node_modules/symbol-observable/lib/ponyfill.js',
'node_modules/url-parse/index.js',
'node_modules/util/support/isBufferBrowser.js',
'node_modules/util/support/types.js',
'node_modules/util/util.js',
'share_extension/android/actions/index.js',
'share_extension/android/index.js',
];

View file

@ -218,28 +218,20 @@ module.exports = [
'./node_modules/node_modules/@babel/runtime/helpers/typeof.js',
'./node_modules/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js',
'./node_modules/node_modules/@babel/runtime/helpers/wrapNativeSuper.js',
'./node_modules/node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js',
'./node_modules/node_modules/@babel/runtime/regenerator/index.js',
'./node_modules/node_modules/@react-native-community/async-storage/lib/AsyncStorage.js',
'./node_modules/node_modules/@react-native-community/async-storage/lib/hooks.js',
'./node_modules/node_modules/@react-native-community/async-storage/lib/index.js',
'./node_modules/node_modules/@react-native-community/cookies/index.js',
'./node_modules/node_modules/anser/lib/index.js',
'./node_modules/node_modules/base-64/base64.js',
'./node_modules/node_modules/base64-js/index.js',
'./node_modules/node_modules/buffer/index.js',
'./node_modules/node_modules/clone/clone.js',
'./node_modules/node_modules/color-convert/conversions.js',
'./node_modules/node_modules/color-convert/index.js',
'./node_modules/node_modules/color-convert/route.js',
'./node_modules/node_modules/color-name/index.js',
'./node_modules/node_modules/color-string/index.js',
'./node_modules/node_modules/color/index.js',
'./node_modules/node_modules/create-react-class/factory.js',
'./node_modules/node_modules/create-react-class/index.js',
'./node_modules/node_modules/create-react-class/node_modules/fbjs/lib/emptyFunction.js',
'./node_modules/node_modules/create-react-class/node_modules/fbjs/lib/emptyObject.js',
'./node_modules/node_modules/create-react-class/node_modules/fbjs/lib/invariant.js',
'./node_modules/node_modules/create-react-class/node_modules/fbjs/lib/warning.js',
'./node_modules/node_modules/component-emitter/index.js',
'./node_modules/node_modules/deepmerge/dist/cjs.js',
'./node_modules/node_modules/event-target-shim/dist/event-target-shim.js',
'./node_modules/node_modules/eventemitter3/index.js',
@ -253,7 +245,6 @@ module.exports = [
'./node_modules/node_modules/fbjs/lib/warning.js',
'./node_modules/node_modules/harmony-reflect/reflect.js',
'./node_modules/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js',
'./node_modules/node_modules/inherits/inherits_browser.js',
'./node_modules/node_modules/intl-format-cache/dist/index.js',
'./node_modules/node_modules/intl-format-cache/index.js',
'./node_modules/node_modules/intl-messageformat-parser/index.js',
@ -277,8 +268,6 @@ module.exports = [
'./node_modules/node_modules/intl/lib/core.js',
'./node_modules/node_modules/intl/locale-data/complete.js',
'./node_modules/node_modules/invariant/browser.js',
'./node_modules/node_modules/is-arguments/index.js',
'./node_modules/node_modules/is-generator-function/index.js',
'./node_modules/node_modules/lodash.clonedeep/index.js',
'./node_modules/node_modules/lodash.forin/index.js',
'./node_modules/node_modules/lodash.get/index.js',
@ -367,7 +356,6 @@ module.exports = [
'./node_modules/node_modules/lodash/_createAssigner.js',
'./node_modules/node_modules/lodash/_createBaseEach.js',
'./node_modules/node_modules/lodash/_createBaseFor.js',
'./node_modules/node_modules/lodash/_createSet.js',
'./node_modules/node_modules/lodash/_customOmitClone.js',
'./node_modules/node_modules/lodash/_defineProperty.js',
'./node_modules/node_modules/lodash/_equalArrays.js',
@ -473,7 +461,6 @@ module.exports = [
'./node_modules/node_modules/lodash/map.js',
'./node_modules/node_modules/lodash/memoize.js',
'./node_modules/node_modules/lodash/merge.js',
'./node_modules/node_modules/lodash/noop.js',
'./node_modules/node_modules/lodash/omit.js',
'./node_modules/node_modules/lodash/pick.js',
'./node_modules/node_modules/lodash/property.js',
@ -506,11 +493,15 @@ module.exports = [
'./node_modules/node_modules/react-intl/lib/index.js',
'./node_modules/node_modules/react-intl/locale-data/en.js',
'./node_modules/node_modules/react-intl/locale-data/index.js',
'./node_modules/node_modules/react-is/cjs/react-is.production.js',
'./node_modules/node_modules/react-is/cjs/react-is.production.min.js',
'./node_modules/node_modules/react-is/index.js',
'./node_modules/node_modules/react-lifecycles-compat/react-lifecycles-compat.cjs.js',
'./node_modules/node_modules/react-native-cookies/index.js',
'./node_modules/node_modules/react-native-device-info/deviceinfo.js',
'./node_modules/node_modules/react-native-device-info/src/index.ts',
'./node_modules/node_modules/react-native-device-info/src/internal/asyncHookWrappers.ts',
'./node_modules/node_modules/react-native-device-info/src/internal/devicesWithNotch.ts',
'./node_modules/node_modules/react-native-device-info/src/internal/nativeInterface.ts',
'./node_modules/node_modules/react-native-gesture-handler/GestureButtons.js',
'./node_modules/node_modules/react-native-gesture-handler/GestureComponents.js',
'./node_modules/node_modules/react-native-gesture-handler/GestureHandler.js',
'./node_modules/node_modules/react-native-gesture-handler/GestureHandlerButton.js',
'./node_modules/node_modules/react-native-gesture-handler/GestureHandlerPropTypes.js',
@ -519,13 +510,14 @@ module.exports = [
'./node_modules/node_modules/react-native-gesture-handler/NativeViewGestureHandler.js',
'./node_modules/node_modules/react-native-gesture-handler/PlatformConstants.js',
'./node_modules/node_modules/react-native-gesture-handler/RNGestureHandlerModule.js',
'./node_modules/node_modules/react-native-gesture-handler/State.js',
'./node_modules/node_modules/react-native-gesture-handler/createHandler.js',
'./node_modules/node_modules/react-native-gesture-handler/createNativeWrapper.js',
'./node_modules/node_modules/react-native-gesture-handler/gestureHandlerRootHOC.js',
'./node_modules/node_modules/react-native-gesture-handler/index.js',
'./node_modules/node_modules/react-native-haptic-feedback/index.js',
'./node_modules/node_modules/react-native-keychain/index.js',
'./node_modules/node_modules/react-native-localize/lib/commonjs/index.js',
'./node_modules/node_modules/react-native-localize/lib/commonjs/module.js',
'./node_modules/node_modules/react-native-mmkv-storage/index.js',
'./node_modules/node_modules/react-native-mmkv-storage/src/api.js',
'./node_modules/node_modules/react-native-mmkv-storage/src/encryption.js',
@ -734,7 +726,6 @@ module.exports = [
'./node_modules/node_modules/react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js',
'./node_modules/node_modules/react-native/Libraries/ReactPrivate/ReactNativePrivateInterface.js',
'./node_modules/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js',
'./node_modules/node_modules/react-native/Libraries/Renderer/shims/NativeMethodsMixin.js',
'./node_modules/node_modules/react-native/Libraries/Renderer/shims/ReactNative.js',
'./node_modules/node_modules/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js',
'./node_modules/node_modules/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js',
@ -751,6 +742,7 @@ module.exports = [
'./node_modules/node_modules/react-native/Libraries/TurboModule/TurboModuleRegistry.js',
'./node_modules/node_modules/react-native/Libraries/UTFSequence.js',
'./node_modules/node_modules/react-native/Libraries/Utilities/BackHandler.android.js',
'./node_modules/node_modules/react-native/Libraries/Utilities/DeviceInfo.js',
'./node_modules/node_modules/react-native/Libraries/Utilities/Dimensions.js',
'./node_modules/node_modules/react-native/Libraries/Utilities/GlobalPerformanceLogger.js',
'./node_modules/node_modules/react-native/Libraries/Utilities/HMRClient.js',
@ -898,18 +890,16 @@ module.exports = [
'./node_modules/node_modules/semver/ranges/min-satisfying.js',
'./node_modules/node_modules/semver/ranges/min-version.js',
'./node_modules/node_modules/semver/ranges/outside.js',
'./node_modules/node_modules/semver/ranges/simplify.js',
'./node_modules/node_modules/semver/ranges/to-comparators.js',
'./node_modules/node_modules/semver/ranges/valid.js',
'./node_modules/node_modules/serialize-error/index.js',
'./node_modules/node_modules/shallow-equals/index.js',
'./node_modules/node_modules/simple-swizzle/index.js',
'./node_modules/node_modules/stacktrace-parser/dist/stack-trace-parser.cjs.js',
'./node_modules/node_modules/simple-swizzle/node_modules/is-arrayish/index.js',
'./node_modules/node_modules/symbol-observable/lib/index.js',
'./node_modules/node_modules/symbol-observable/lib/ponyfill.js',
'./node_modules/node_modules/url-parse/index.js',
'./node_modules/node_modules/util/support/isBufferBrowser.js',
'./node_modules/node_modules/util/support/types.js',
'./node_modules/node_modules/util/util.js',
'./node_modules/share_extension/android/actions/index.js',
'./node_modules/share_extension/android/index.js',
];

View file

@ -0,0 +1,39 @@
diff --git a/node_modules/@react-native-community/cookies/ios/RNCookieManagerIOS/RNCookieManagerIOS.m b/node_modules/@react-native-community/cookies/ios/RNCookieManagerIOS/RNCookieManagerIOS.m
index 9cdc74d..5477405 100644
--- a/node_modules/@react-native-community/cookies/ios/RNCookieManagerIOS/RNCookieManagerIOS.m
+++ b/node_modules/@react-native-community/cookies/ios/RNCookieManagerIOS/RNCookieManagerIOS.m
@@ -139,7 +139,8 @@ + (BOOL)requiresMainQueueSetup
[cookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *allCookies) {
NSMutableDictionary *cookies = [NSMutableDictionary dictionary];
for (NSHTTPCookie *cookie in allCookies) {
- if ([topLevelDomain containsString:cookie.domain]) {
+ NSString *domainWithDot = [NSString stringWithFormat:@".%@", cookie.domain];
+ if([cookie.domain containsString:topLevelDomain] || [domainWithDot containsString:topLevelDomain]) {
[cookies setObject:[self createCookieData:cookie] forKey:cookie.name];
}
}
@@ -185,6 +186,8 @@ + (BOOL)requiresMainQueueSetup
}
resolve(nil);
}
+
+ [self deleteBinaryCookiesAndWebsiteData];
}
RCT_EXPORT_METHOD(clearByName:(NSString *) name
@@ -244,4 +247,15 @@ -(NSDictionary *)createCookieData:(NSHTTPCookie *)cookie
return cookieData;
}
+-(void) deleteBinaryCookiesAndWebsiteData {
+ NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
+ NSString *cookiesPath = [libraryPath stringByAppendingString:@"/Cookies/Cookies.binarycookies"];
+ NSString *dataPath = [libraryPath stringByAppendingString:@"/WebKit/WebsiteData"];
+
+ NSError *error;
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ [fileManager removeItemAtPath:cookiesPath error:&error];
+ [fileManager removeItemAtPath:dataPath error:&error];
+}
+
@end

View file

@ -0,0 +1,13 @@
diff --git a/node_modules/moment-timezone/index.d.ts b/node_modules/moment-timezone/index.d.ts
index 8cb684d..3a1d563 100644
--- a/node_modules/moment-timezone/index.d.ts
+++ b/node_modules/moment-timezone/index.d.ts
@@ -66,6 +66,8 @@ declare module 'moment' {
/** Parse an offset for a timestamp constructed from Date.UTC in that zone. */
parse(timestamp: number): number;
+
+ utcOffset(timestamp: number): number;
}
/** Return a timezone by name or null if timezone by that name is not loaded. */

View file

@ -0,0 +1,28 @@
diff --git a/node_modules/react-native-button/Button.js b/node_modules/react-native-button/Button.js
index b248176..2ee35d5 100644
--- a/node_modules/react-native-button/Button.js
+++ b/node_modules/react-native-button/Button.js
@@ -71,7 +71,6 @@ export default class Button extends Component {
}
return (
- <View style={containerStyle}>
<TouchableNativeFeedback
{...touchableProps}
style={{flex: 1}}
@@ -79,11 +78,12 @@ export default class Button extends Component {
accessibilityLabel={this.props.accessibilityLabel}
accessibilityRole="button"
background={background}>
- <View style={{padding: padding}}>
- {this._renderGroupedChildren()}
+ <View style={containerStyle}>
+ <View style={{padding: padding}}>
+ {this._renderGroupedChildren()}
+ </View>
</View>
</TouchableNativeFeedback>
- </View>
);
}
}

View file

@ -0,0 +1,17 @@
diff --git a/node_modules/react-native-device-info/android/src/main/java/com/learnium/RNDeviceInfo/resolver/DeviceTypeResolver.java b/node_modules/react-native-device-info/android/src/main/java/com/learnium/RNDeviceInfo/resolver/DeviceTypeResolver.java
index a8e9b0c..2fac079 100644
--- a/node_modules/react-native-device-info/android/src/main/java/com/learnium/RNDeviceInfo/resolver/DeviceTypeResolver.java
+++ b/node_modules/react-native-device-info/android/src/main/java/com/learnium/RNDeviceInfo/resolver/DeviceTypeResolver.java
@@ -80,10 +80,10 @@ public class DeviceTypeResolver {
double heightInches = metrics.heightPixels / (double) metrics.ydpi;
double diagonalSizeInches = Math.sqrt(Math.pow(widthInches, 2) + Math.pow(heightInches, 2));
- if (diagonalSizeInches >= 3.0 && diagonalSizeInches <= 6.9) {
+ if (diagonalSizeInches >= 3.0 && diagonalSizeInches <= 7.9) {
// Devices in a sane range for phones are considered to be Handsets.
return DeviceType.HANDSET;
- } else if (diagonalSizeInches > 6.9 && diagonalSizeInches <= 18.0) {
+ } else if (diagonalSizeInches > 7.9 && diagonalSizeInches <= 18.0) {
// Devices larger than handset and in a sane range for tablets are tablets.
return DeviceType.TABLET;
} else {

View file

@ -1,5 +1,5 @@
diff --git a/node_modules/react-native-elements/src/searchbar/SearchBar-android.js b/node_modules/react-native-elements/src/searchbar/SearchBar-android.js
index eeaeb81..93f58de 100644
index f44866a..76406c2 100644
--- a/node_modules/react-native-elements/src/searchbar/SearchBar-android.js
+++ b/node_modules/react-native-elements/src/searchbar/SearchBar-android.js
@@ -78,6 +78,12 @@ class SearchBar extends Component {
@ -16,7 +16,7 @@ index eeaeb81..93f58de 100644
const {
clearIcon,
diff --git a/node_modules/react-native-elements/src/searchbar/SearchBar-ios.js b/node_modules/react-native-elements/src/searchbar/SearchBar-ios.js
index 41ef6be..dbf727b 100644
index 32a28d5..d43e9bf 100644
--- a/node_modules/react-native-elements/src/searchbar/SearchBar-ios.js
+++ b/node_modules/react-native-elements/src/searchbar/SearchBar-ios.js
@@ -41,6 +41,12 @@ class SearchBar extends Component {
@ -32,7 +32,7 @@ index 41ef6be..dbf727b 100644
focus = () => {
this.input.focus();
};
@@ -259,7 +265,6 @@ const styles = StyleSheet.create({
@@ -260,7 +266,6 @@ const styles = StyleSheet.create({
paddingBottom: 13,
paddingTop: 13,
flexDirection: 'row',
@ -40,7 +40,7 @@ index 41ef6be..dbf727b 100644
alignItems: 'center',
},
input: {
@@ -270,7 +275,7 @@ const styles = StyleSheet.create({
@@ -271,7 +276,7 @@ const styles = StyleSheet.create({
borderBottomWidth: 0,
backgroundColor: '#dcdce1',
borderRadius: 9,

View file

@ -1,27 +1,8 @@
diff --git a/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.h b/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.h
index 0d9600e..03bd962 100644
--- a/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.h
+++ b/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.h
@@ -11,4 +11,5 @@
#import <React/RCTBridgeModule.h>
@interface KeyboardTrackingViewManager : RCTViewManager
+
@end
diff --git a/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.m b/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.m
index 800bd35..c215a8d 100644
index 1333a10..86d3678 100644
--- a/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.m
+++ b/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.m
@@ -6,6 +6,8 @@
// Copyright © 2016 Wix.com All rights reserved.
//
+#import <WebKit/WebKit.h>
+
#import "KeyboardTrackingViewManager.h"
#import "ObservingInputAccessoryView.h"
#import "UIResponder+FirstResponder.h"
@@ -22,7 +24,7 @@
@@ -23,7 +23,7 @@
NSUInteger const kInputViewKey = 101010;
NSUInteger const kMaxDeferedInitializeAccessoryViews = 15;
NSInteger const kTrackingViewNotFoundErrorCode = 1;
@ -30,7 +11,7 @@ index 800bd35..c215a8d 100644
typedef NS_ENUM(NSUInteger, KeyboardTrackingScrollBehavior) {
KeyboardTrackingScrollBehaviorNone,
@@ -39,6 +41,7 @@ @interface KeyboardTrackingView : UIView
@@ -40,6 +40,7 @@ @interface KeyboardTrackingView : UIView
CGFloat _bottomViewHeight;
}
@ -38,21 +19,21 @@ index 800bd35..c215a8d 100644
@property (nonatomic, strong) UIScrollView *scrollViewToManage;
@property (nonatomic) BOOL scrollIsInverted;
@property (nonatomic) BOOL revealKeyboardInteractive;
@@ -51,6 +54,13 @@ @interface KeyboardTrackingView : UIView
@property (nonatomic) BOOL addBottomView;
@@ -53,6 +54,13 @@ @interface KeyboardTrackingView : UIView
@property (nonatomic) BOOL scrollToFocusedInput;
@property (nonatomic) BOOL allowHitsOutsideBounds;
+@property (nonatomic) BOOL normalList;
+@property (nonatomic) NSString* scrollViewNativeID;
+@property (nonatomic) CGFloat initialOffsetY;
+@property (nonatomic) BOOL initialOffsetIsSet;
+
+@property (nonatomic, strong) UIView *accessoriesContainer;
+@property (nonatomic) NSString* accessoriesContainerID;
+
@end
@@ -69,12 +79,17 @@ -(instancetype)init
@interface KeyboardTrackingView () <ObservingInputAccessoryViewDelegate, UIScrollViewDelegate>
@@ -70,12 +78,17 @@ -(instancetype)init
[self addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
_inputViewsMap = [NSMapTable weakToWeakObjectsMapTable];
_deferedInitializeAccessoryViewsCount = 0;
@ -60,7 +41,7 @@ index 800bd35..c215a8d 100644
_observingInputAccessoryView = [ObservingInputAccessoryView new];
_observingInputAccessoryView.delegate = self;
+ _initialOffsetY = 0;
+ _initialOffsetIsSet = NO;
+
@ -70,13 +51,7 @@ index 800bd35..c215a8d 100644
_bottomViewHeight = kBottomViewHeight;
@@ -128,12 +143,12 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return subview;
}
--(void)_swizzleWebViewInputAccessory:(UIWebView*)webview
+-(void)_swizzleWebViewInputAccessory:(WKWebView*)webview
{
@@ -134,7 +147,7 @@ -(void)_swizzleWebViewInputAccessory:(WKWebView*)webview
UIView* subview;
for (UIView* view in webview.scrollView.subviews)
{
@ -85,7 +60,7 @@ index 800bd35..c215a8d 100644
{
subview = view;
}
@@ -166,33 +181,32 @@ -(void)layoutSubviews
@@ -167,33 +180,32 @@ -(void)layoutSubviews
- (void)initializeAccessoryViewsAndHandleInsets
{
NSArray<UIView*>* allSubviews = [self getBreadthFirstSubviewsForView:[self getRootView]];
@ -96,27 +71,27 @@ index 800bd35..c215a8d 100644
+ if(subview.nativeID) {
+ NSLog(@"self.accessoriesContainerID %@ %@", self.accessoriesContainerID, subview.nativeID);
+ }
+
+
+ if (subview.nativeID && [subview.nativeID isEqualToString:self.accessoriesContainerID]) {
+ NSLog(@"SuperView ID: %@", subview.nativeID);
+ _accessoriesContainer = subview;
+ }
+
+
if(_manageScrollView)
{
if(_scrollViewToManage == nil)
{
- if(_requiresSameParentToManageScrollView && [subview isKindOfClass:[RCTScrollView class]] && subview.superview == self.superview)
+ if([subview isKindOfClass:[RCTScrollView class]])
{
- {
- _scrollViewToManage = ((RCTScrollView*)subview).scrollView;
- }
- else if(!_requiresSameParentToManageScrollView && [subview isKindOfClass:[UIScrollView class]])
- {
+ if([subview isKindOfClass:[RCTScrollView class]])
{
- _scrollViewToManage = (UIScrollView*)subview;
- }
+ RCTScrollView *scrollView = (RCTScrollView*)subview;
- if(_scrollViewToManage != nil)
- {
- _scrollIsInverted = CGAffineTransformEqualToTransform(_scrollViewToManage.superview.transform, CGAffineTransformMakeScale(1, -1));
@ -134,15 +109,7 @@ index 800bd35..c215a8d 100644
}
if ([subview isKindOfClass:NSClassFromString(@"RCTTextField")])
@@ -235,13 +249,13 @@ - (void)initializeAccessoryViewsAndHandleInsets
{
[self setupTextView:(UITextView*)subview];
}
- else if ([subview isKindOfClass:[UIWebView class]])
+ else if ([subview isKindOfClass:[WKWebView class]])
{
- [self _swizzleWebViewInputAccessory:(UIWebView*)subview];
+ [self _swizzleWebViewInputAccessory:(WKWebView*)subview];
@@ -242,7 +254,7 @@ - (void)initializeAccessoryViewsAndHandleInsets
}
}
@ -151,7 +118,7 @@ index 800bd35..c215a8d 100644
{
if(scrollView.scrollView == _scrollViewToManage)
{
@@ -266,6 +280,21 @@ - (void)initializeAccessoryViewsAndHandleInsets
@@ -267,6 +279,21 @@ - (void)initializeAccessoryViewsAndHandleInsets
[self addBottomViewIfNecessary];
}
@ -173,7 +140,7 @@ index 800bd35..c215a8d 100644
- (void)setupTextView:(UITextView*)textView
{
if (textView != nil)
@@ -342,7 +371,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
@@ -343,7 +370,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
- (void)observingInputAccessoryViewKeyboardWillDisappear:(ObservingInputAccessoryView *)observingInputAccessoryView
{
@ -182,7 +149,7 @@ index 800bd35..c215a8d 100644
[self updateBottomViewFrame];
}
@@ -387,32 +416,43 @@ - (void)_updateScrollViewInsets
@@ -388,32 +415,42 @@ - (void)_updateScrollViewInsets
{
if(self.scrollViewToManage != nil)
{
@ -190,7 +157,7 @@ index 800bd35..c215a8d 100644
+ self.initialOffsetY = self.scrollViewToManage.contentOffset.y;
+ _initialOffsetIsSet = YES;
+ }
+
+
+ if (_observingInputAccessoryView.keyboardState != KeyboardStateWillHide && _observingInputAccessoryView.keyboardState != KeyboardStateHidden) {
+ [self.scrollViewToManage setContentOffset:CGPointMake(self.scrollViewToManage.contentOffset.x, self.initialOffsetY) animated:NO];
+ }
@ -214,7 +181,6 @@ index 800bd35..c215a8d 100644
- insets.bottom = bottomInset;
+ insets.bottom = keyboardHeight;
}
+
self.scrollViewToManage.contentInset = insets;
if(self.scrollBehavior == KeyboardTrackingScrollBehaviorScrollToBottomInvertedOnly && _scrollIsInverted)
@ -231,10 +197,10 @@ index 800bd35..c215a8d 100644
}
}
else if(self.scrollBehavior == KeyboardTrackingScrollBehaviorFixedOffset && !self.isDraggingScrollView)
@@ -421,16 +461,16 @@ - (void)_updateScrollViewInsets
@@ -422,16 +459,15 @@ - (void)_updateScrollViewInsets
self.scrollViewToManage.contentOffset = CGPointMake(originalOffset.x, originalOffset.y + insetsDiff);
}
- insets = self.scrollViewToManage.contentInset;
- if(self.scrollIsInverted)
- {
@ -247,30 +213,24 @@ index 800bd35..c215a8d 100644
+ CGRect frame = CGRectMake(self.scrollViewToManage.frame.origin.x, positionY,
+ self.scrollViewToManage.frame.size.width, self.scrollViewToManage.frame.size.height);
+ self.scrollViewToManage.frame = frame;
+
+
+ if (self.accessoriesContainer) {
+ self.accessoriesContainer.bounds = CGRectMake(self.accessoriesContainer.bounds.origin.x, positionY,
+ self.accessoriesContainer.bounds.size.width, self.accessoriesContainer.bounds.size.height);
}
- self.scrollViewToManage.scrollIndicatorInsets = insets;
+
}
}
@@ -447,11 +487,9 @@ -(void)addBottomViewIfNecessary
@@ -448,7 +484,6 @@ -(void)addBottomViewIfNecessary
if (self.addBottomView && _bottomView == nil)
{
_bottomView = [UIView new];
- _bottomView.backgroundColor = [UIColor whiteColor];
[self addSubview:_bottomView];
[self updateBottomViewFrame];
- }
- else if (!self.addBottomView && _bottomView != nil)
+ } else if (!self.addBottomView && _bottomView != nil)
{
[_bottomView removeFromSuperview];
_bottomView = nil;
@@ -466,6 +504,12 @@ -(void)updateBottomViewFrame
}
@@ -467,6 +502,12 @@ -(void)updateBottomViewFrame
}
}
@ -283,16 +243,7 @@ index 800bd35..c215a8d 100644
#pragma mark - safe area
-(void)safeAreaInsetsDidChange
@@ -483,7 +527,7 @@ -(CGFloat)getBottomSafeArea
CGFloat bottomSafeArea = 0;
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3
if (@available(iOS 11.0, *)) {
- bottomSafeArea = self.superview ? self.superview.safeAreaInsets.bottom : self.safeAreaInsets.bottom;
+ bottomSafeArea = self.superview ? self.superview.safeAreaInsets.bottom : self.safeAreaInsets.bottom;
}
#endif
return bottomSafeArea;
@@ -509,7 +553,7 @@ -(void)updateTransformAndInsets
@@ -510,7 +551,7 @@ -(void)updateTransformAndInsets
CGFloat accessoryTranslation = MIN(-bottomSafeArea, -_observingInputAccessoryView.keyboardHeight);
if (_observingInputAccessoryView.keyboardHeight <= bottomSafeArea) {
@ -301,7 +252,7 @@ index 800bd35..c215a8d 100644
} else if (_observingInputAccessoryView.keyboardState != KeyboardStateWillHide) {
_bottomViewHeight = 0;
}
@@ -553,6 +597,14 @@ - (void) observingInputAccessoryViewKeyboardWillAppear:(ObservingInputAccessoryV
@@ -554,6 +595,14 @@ - (void) observingInputAccessoryViewKeyboardWillAppear:(ObservingInputAccessoryV
[self performScrollToFocusedInput];
}
@ -316,7 +267,7 @@ index 800bd35..c215a8d 100644
#pragma mark - UIScrollViewDelegate methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
@@ -581,6 +633,8 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
@@ -582,6 +631,8 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
self.isDraggingScrollView = YES;
@ -325,7 +276,7 @@ index 800bd35..c215a8d 100644
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
@@ -591,6 +645,15 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi
@@ -592,6 +643,15 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
self.isDraggingScrollView = NO;
@ -341,7 +292,7 @@ index 800bd35..c215a8d 100644
}
- (CGFloat)getKeyboardHeight
@@ -633,6 +696,12 @@ @implementation KeyboardTrackingViewManager
@@ -634,6 +694,12 @@ @implementation KeyboardTrackingViewManager
RCT_REMAP_VIEW_PROPERTY(addBottomView, addBottomView, BOOL)
RCT_REMAP_VIEW_PROPERTY(scrollToFocusedInput, scrollToFocusedInput, BOOL)
RCT_REMAP_VIEW_PROPERTY(allowHitsOutsideBounds, allowHitsOutsideBounds, BOOL)
@ -354,8 +305,8 @@ index 800bd35..c215a8d 100644
+ (BOOL)requiresMainQueueSetup
{
@@ -687,6 +756,20 @@ - (UIView *)view
}];
@@ -654,6 +720,20 @@ - (UIView *)view
return [[KeyboardTrackingView alloc] init];
}
+RCT_EXPORT_METHOD(resetScrollView:(nonnull NSNumber *)reactTag scrollViewNativeID:(NSString*)scrollViewNativeID) {
@ -372,9 +323,9 @@ index 800bd35..c215a8d 100644
+ }];
+}
+
#pragma mark - helper methods
-(void)rejectPromise:(RCTPromiseRejectBlock)reject withErrorMessage:(NSString*)errorMessage errorCode:(NSInteger)errorCode
RCT_EXPORT_METHOD(getNativeProps:(nonnull NSNumber *)reactTag resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:
diff --git a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.h b/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.h
index 9b242e8..b500db1 100644
--- a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.h
@ -388,21 +339,21 @@ index 9b242e8..b500db1 100644
@end
diff --git a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m b/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
index e472679..1e62c61 100644
index e472679..dbc5c5e 100644
--- a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
+++ b/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
@@ -130,6 +130,11 @@ - (void)_keyboardDidShowNotification:(NSNotification*)notification
_keyboardState = KeyboardStateShown;
[self invalidateIntrinsicContentSize];
+
@@ -123,6 +123,11 @@ - (void)_keyboardWillShowNotification:(NSNotification*)notification
{
[_delegate observingInputAccessoryViewKeyboardWillAppear:self keyboardDelta:_keyboardHeight - _previousKeyboardHeight];
}
+
+ if([_delegate respondsToSelector:@selector(observingInputAccessoryViewKeyboardDidAppear:)])
+ {
+ [_delegate observingInputAccessoryViewKeyboardDidAppear:self];
+ }
}
- (void)_keyboardWillHideNotification:(NSNotification*)notification
- (void)_keyboardDidShowNotification:(NSNotification*)notification
diff --git a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js b/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js
index af15edf..3ba0a3a 100644
--- a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js
@ -415,7 +366,7 @@ index af15edf..3ba0a3a 100644
scrollToStart() {}
}
diff --git a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.ios.js b/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.ios.js
index 5e2c207..e6099f3 100644
index 5e2c207..727017c 100644
--- a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.ios.js
+++ b/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.ios.js
@@ -25,6 +25,12 @@ export default class KeyboardTrackingView extends PureComponent {
@ -423,9 +374,9 @@ index 5e2c207..e6099f3 100644
}
+ resetScrollView(scrollViewNativeID) {
+ if (this.ref && KeyboardTrackingViewManager && KeyboardTrackingViewManager.resetScrollView) {
+ KeyboardTrackingViewManager.resetScrollView(ReactNative.findNodeHandle(this.ref), scrollViewNativeID);
+ }
+ if (this.ref && KeyboardTrackingViewManager && KeyboardTrackingViewManager.resetScrollView) {
+ KeyboardTrackingViewManager.resetScrollView(ReactNative.findNodeHandle(this.ref), scrollViewNativeID);
+ }
+ }
+
scrollToStart() {

View file

@ -0,0 +1,188 @@
diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
index 1995d87..33bd83c 100644
--- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
@@ -2,8 +2,12 @@ package com.reactnativecommunity.webview;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.AlertDialog;
import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -15,6 +19,7 @@ import android.os.Build;
import android.os.Environment;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
+import android.text.InputType;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
@@ -25,7 +30,9 @@ import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.GeolocationPermissions;
+import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
+import android.widget.LinearLayout;
import android.webkit.PermissionRequest;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
@@ -35,6 +42,7 @@ import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import android.widget.EditText;
import android.widget.FrameLayout;
import com.facebook.react.views.scroll.ScrollEvent;
@@ -720,6 +728,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected static class RNCWebViewClient extends WebViewClient {
+ protected Activity mCurrentActivity;
protected boolean mLastLoadFailed = false;
protected @Nullable
ReadableArray mUrlPrefixesForDefaultIntent;
@@ -729,6 +738,10 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
ignoreErrFailedForThisURL = url;
}
+ public void setCurrentActivity(Activity mCurrentActivity) {
+ this.mCurrentActivity = mCurrentActivity;
+ }
+
@Override
public void onPageFinished(WebView webView, String url) {
super.onPageFinished(webView, url);
@@ -810,6 +823,49 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
new TopLoadingErrorEvent(webView.getId(), eventData));
}
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view,
+ final HttpAuthHandler handler, String host, String realm)
+ {
+ if (this.mCurrentActivity != null) {
+ final EditText usernameInput = new EditText(this.mCurrentActivity);
+ usernameInput.setHint("Username");
+
+ final EditText passwordInput = new EditText(this.mCurrentActivity);
+ passwordInput.setHint("Password");
+ passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ LinearLayout layout = new LinearLayout(this.mCurrentActivity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(usernameInput);
+ layout.addView(passwordInput);
+
+ AlertDialog.Builder authDialog = new AlertDialog.Builder(this.mCurrentActivity)
+ .setTitle("Authentication Challenge")
+ .setMessage(host + " requires user name and password ")
+ .setView(layout)
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ handler.proceed(usernameInput.getText().toString(), passwordInput.getText().toString());
+ dialogInterface.dismiss();
+ }
+ })
+ .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ dialogInterface.dismiss();
+ handler.cancel();
+ }
+ });
+
+ if (view != null) {
+ authDialog.show();
+ }
+ } else {
+ handler.cancel();
+ }
+ }
+
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onReceivedHttpError(
@@ -1010,6 +1066,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected boolean sendContentSizeChangeEvents = false;
private OnScrollDispatchHelper mOnScrollDispatchHelper;
protected boolean hasScrollEvent = false;
+ protected ReactContext reactContext;
/**
* WebView must be created with an context of the current activity
@@ -1019,6 +1076,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
*/
public RNCWebView(ThemedReactContext reactContext) {
super(reactContext);
+ this.reactContext = reactContext;
}
public void setIgnoreErrFailedForThisURL(String url) {
@@ -1069,6 +1127,9 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
super.setWebViewClient(client);
if (client instanceof RNCWebViewClient) {
mRNCWebViewClient = (RNCWebViewClient) client;
+ if (this.reactContext != null && this.reactContext.getCurrentActivity() != null && mRNCWebViewClient != null) {
+ mRNCWebViewClient.setCurrentActivity(this.reactContext.getCurrentActivity());
+ }
}
}
diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m
index d2f9956..4b8d0fe 100644
--- a/node_modules/react-native-webview/apple/RNCWebView.m
+++ b/node_modules/react-native-webview/apple/RNCWebView.m
@@ -737,7 +737,44 @@ - (void) webView:(WKWebView *)webView
if (webView.URL != nil) {
host = webView.URL.host;
}
- if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
+
+ NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
+
+ if (authenticationMethod == NSURLAuthenticationMethodNTLM || authenticationMethod == NSURLAuthenticationMethodNegotiate) {
+ NSString *title = @"Authentication Challenge";
+ NSString *message = [NSString stringWithFormat:@"%@ requires user name and password", host];
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+ textField.placeholder = @"User";
+ }];
+
+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+ textField.placeholder = @"Password";
+ textField.secureTextEntry = YES;
+ }];
+
+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSString *userName = ((UITextField *)alertController.textFields[0]).text;
+ NSString *password = ((UITextField *)alertController.textFields[1]).text;
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:userName password:password persistence:NSURLCredentialPersistenceNone];
+
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
+ }]];
+
+ [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
+ completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
+ }]];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController;
+
+ while (rootVC.presentedViewController != nil) {
+ rootVC = rootVC.presentedViewController;
+ }
+ [rootVC presentViewController:alertController animated:YES completion:^{}];
+ });
+ return;
+ } else if (authenticationMethod == NSURLAuthenticationMethodClientCertificate) {
completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential);
return;
}

View file

@ -1,27 +1,24 @@
diff --git a/node_modules/react-native-youtube/RCTYouTubeStandalone.m b/node_modules/react-native-youtube/RCTYouTubeStandalone.m
index fabd291..1e29586 100644
index fabd291..45b322b 100644
--- a/node_modules/react-native-youtube/RCTYouTubeStandalone.m
+++ b/node_modules/react-native-youtube/RCTYouTubeStandalone.m
@@ -5,6 +5,18 @@
@@ -5,6 +5,15 @@
#endif
@import AVKit;
+@interface AVPlayerViewControllerRotation : AVPlayerViewController
+
+@end
+
+@implementation AVPlayerViewControllerRotation
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+ return UIInterfaceOrientationMaskAllButUpsideDown;
+}
+
+@end
+
@implementation RCTYouTubeStandalone {
RCTPromiseResolveBlock resolver;
RCTPromiseRejectBlock rejecter;
@@ -14,6 +26,7 @@ @implementation RCTYouTubeStandalone {
@@ -14,6 +23,7 @@ @implementation RCTYouTubeStandalone {
RCT_REMAP_METHOD(playVideo,
playVideoWithResolver:(NSString*)videoId
@ -29,7 +26,7 @@ index fabd291..1e29586 100644
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
@@ -22,10 +35,10 @@ @implementation RCTYouTubeStandalone {
@@ -22,10 +32,10 @@ @implementation RCTYouTubeStandalone {
#else
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
@ -42,7 +39,7 @@ index fabd291..1e29586 100644
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:videoId
completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error) {
@@ -38,10 +51,18 @@ @implementation RCTYouTubeStandalone {
@@ -38,10 +48,18 @@ @implementation RCTYouTubeStandalone {
streamURLs[@(XCDYouTubeVideoQualitySmall240)
];
@ -51,27 +48,27 @@ index fabd291..1e29586 100644
-
- resolve(@"YouTubeStandaloneIOS player launched successfully");
+ @try {
+ CMTime initialPlaybackTime = CMTimeMakeWithSeconds([startTime doubleValue], 1);
+ weakPlayerViewController.player = [AVPlayer playerWithURL:streamURL];
+ [weakPlayerViewController.player seekToTime:initialPlaybackTime completionHandler: ^(BOOL finished) {
+ [weakPlayerViewController.player play];
+ resolve(@"YouTubeStandaloneIOS player launched successfully");
+ }];
+ }
+ @catch (NSException *ex) {
+ reject(@"error", ex.reason, nil);
+ [root dismissViewControllerAnimated:YES completion:nil];
+ }
+ CMTime initialPlaybackTime = CMTimeMakeWithSeconds([startTime doubleValue], 1);
+ weakPlayerViewController.player = [AVPlayer playerWithURL:streamURL];
+ [weakPlayerViewController.player seekToTime:initialPlaybackTime completionHandler: ^(BOOL finished) {
+ [weakPlayerViewController.player play];
+ resolve(@"YouTubeStandaloneIOS player launched successfully");
+ }];
+ }
+ @catch (NSException *ex) {
+ reject(@"error", ex.reason, nil);
+ [root dismissViewControllerAnimated:YES completion:nil];
+ }
} else {
reject(@"error", error.localizedDescription, nil);
[root dismissViewControllerAnimated:YES completion:nil];
diff --git a/node_modules/react-native-youtube/YouTubeStandalone.ios.js b/node_modules/react-native-youtube/YouTubeStandalone.ios.js
index b5e1b3c..f7c9999 100644
index 0ee59c6..4a8294b 100644
--- a/node_modules/react-native-youtube/YouTubeStandalone.ios.js
+++ b/node_modules/react-native-youtube/YouTubeStandalone.ios.js
@@ -5,4 +5,4 @@ const { YouTubeStandalone } = NativeModules;
@@ -4,4 +4,4 @@ const { YouTubeStandalone } = NativeModules;
export const YouTubeStandaloneIOS = !YouTubeStandalone
? null
- : { playVideo: videoId => YouTubeStandalone.playVideo(videoId) };
- : { playVideo: (videoId) => YouTubeStandalone.playVideo(videoId) };
+ : { playVideo: (videoId, startTime) => YouTubeStandalone.playVideo(videoId, startTime) };

View file

@ -15,7 +15,7 @@ export function getTeamChannels(teamId) {
const channelsInTeam = getChannelsNameMapInTeam(state, teamId);
const redirectChannel = getChannelByName(channelsInTeam, getRedirectChannelNameForTeam(state, teamId));
return redirectChannel.id;
return redirectChannel?.id;
};
}

View file

@ -4,7 +4,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import {NavigationActions} from 'react-navigation';
import {CommonActions as NavigationActions} from '@react-navigation/native';
import {
ActivityIndicator,
SectionList,
@ -28,6 +28,7 @@ export default class ExtensionTeam extends PureComponent {
navigation: PropTypes.object.isRequired,
privateChannels: PropTypes.array,
publicChannels: PropTypes.array,
route: PropTypes.object.isRequired,
};
static defaultProps = {
@ -40,10 +41,6 @@ export default class ExtensionTeam extends PureComponent {
intl: intlShape,
};
static navigationOptions = ({navigation}) => ({
title: navigation.state.params.title,
});
state = {
sections: null,
};
@ -102,14 +99,14 @@ export default class ExtensionTeam extends PureComponent {
};
handleSelectChannel = async (channel) => {
const {state} = this.props.navigation;
const backAction = NavigationActions.back();
const {navigation, route} = this.props;
const backAction = NavigationActions.goBack();
if (state.params && state.params.onSelectChannel) {
state.params.onSelectChannel(channel.id);
if (route?.params?.onSelectChannel) {
route.params.onSelectChannel(channel.id);
}
this.props.navigation.dispatch(backAction);
navigation.dispatch(backAction);
};
handleSearch = (term) => {
@ -160,9 +157,8 @@ export default class ExtensionTeam extends PureComponent {
};
renderItem = ({item}) => {
const {navigation} = this.props;
const {params = {}} = navigation.state;
const {currentChannelId} = params;
const {route} = this.props;
const {currentChannelId} = route.params;
return (
<ExtensionChannelItem

View file

@ -2,8 +2,8 @@
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {NavigationActions} from 'react-navigation';
import TouchableItem from 'react-navigation-stack/lib/module/views/TouchableItem';
import {CommonActions as NavigationActions} from '@react-navigation/native';
import TouchableItem from '@react-navigation/stack/lib/module/views/TouchableItem';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
@ -32,7 +32,6 @@ import {MAX_FILE_COUNT} from 'app/constants/post_draft';
import {getCurrentServerUrl, getAppCredentials} from 'app/init/credentials';
import mattermostManaged from 'app/mattermost_managed';
import {getExtensionFromMime} from 'app/utils/file';
import {emptyFunction} from 'app/utils/general';
import {setCSRFFromCookie} from 'app/utils/security';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@ -64,12 +63,10 @@ const MAX_MESSAGE_LENGTH = 4000;
export default class ExtensionPost extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
getTeamChannels: PropTypes.func.isRequired,
}).isRequired,
channelId: PropTypes.string,
channels: PropTypes.object.isRequired,
currentUserId: PropTypes.string.isRequired,
getTeamChannels: PropTypes.func.isRequired,
maxFileSize: PropTypes.number.isRequired,
navigation: PropTypes.object.isRequired,
teamId: PropTypes.string.isRequired,
@ -79,57 +76,10 @@ export default class ExtensionPost extends PureComponent {
intl: intlShape,
};
static navigationOptions = ({navigation}) => {
const {params = {}} = navigation.state;
const title = params.title || '';
const headerLeft = (
<TouchableItem
accessibilityComponentType='button'
accessibilityTraits='button'
borderless={true}
delayPressIn={0}
pressColorAndroid='rgba(0, 0, 0, .32)'
onPress={params.close ? params.close : emptyFunction}
>
<View style={styles.left}>
<MaterialIcon
name='close'
style={styles.closeButton}
/>
</View>
</TouchableItem>
);
let headerRight = null;
if (params.post) {
headerRight = (
<TouchableItem
accessibilityComponentType='button'
accessibilityTraits='button'
borderless={true}
delayPressIn={0}
pressColorAndroid='rgba(0, 0, 0, .32)'
onPress={params.post}
>
<View style={styles.left}>
<PaperPlane
color={defaultTheme.sidebarHeaderTextColor}
height={20}
width={20}
/>
</View>
</TouchableItem>
);
}
return {headerLeft, headerRight, title};
};
constructor(props, context) {
super(props, context);
props.navigation.setParams({
props.navigation.setOptions({
title: context.intl.formatMessage({
id: 'mobile.extension.title',
defaultMessage: 'Share in Mattermost',
@ -147,8 +97,8 @@ export default class ExtensionPost extends PureComponent {
}
componentDidMount() {
this.props.navigation.setParams({
close: this.onClose,
this.props.navigation.setOptions({
headerLeft: this.leftHeader,
});
this.auth();
}
@ -191,6 +141,20 @@ export default class ExtensionPost extends PureComponent {
return this.initialize();
};
canPost = (error, text, extensionFiles, calculatedSize) => {
const {maxFileSize} = this.props;
const files = extensionFiles || this.state.files;
const totalSize = calculatedSize || this.state.totalSize;
const filesOK = files.length ? files.length <= MAX_FILE_COUNT : false;
const sizeOK = totalSize ? totalSize <= maxFileSize : false;
if (!error && ((filesOK && sizeOK) || text.length)) {
this.props.navigation.setOptions({headerRight: this.rightHeader});
} else {
this.props.navigation.setOptions({headerRight: null});
}
}
showNotSecuredAlert(vendor) {
const {formatMessage} = this.context.intl;
@ -259,7 +223,7 @@ export default class ExtensionPost extends PureComponent {
const {formatMessage} = this.context.intl;
const {navigation} = this.props;
const navigateAction = NavigationActions.navigate({
routeName: 'Channels',
name: 'Channels',
params: {
title: formatMessage({
id: 'mobile.routes.selectChannel',
@ -276,7 +240,7 @@ export default class ExtensionPost extends PureComponent {
const {formatMessage} = this.context.intl;
const {navigation} = this.props;
const navigateAction = NavigationActions.navigate({
routeName: 'Teams',
name: 'Teams',
params: {
title: formatMessage({
id: 'mobile.routes.selectTeam',
@ -314,6 +278,7 @@ export default class ExtensionPost extends PureComponent {
};
handleTextChange = (value) => {
this.canPost(null, value);
this.setState({value});
};
@ -336,15 +301,33 @@ export default class ExtensionPost extends PureComponent {
return this.setState({hasPermission: false});
};
leftHeader = () => (
<TouchableItem
accessibilityComponentType='button'
accessibilityTraits='button'
borderless={true}
delayPressIn={0}
pressColorAndroid='rgba(0, 0, 0, .32)'
onPress={this.onClose}
>
<View style={styles.left}>
<MaterialIcon
name='close'
style={styles.closeButton}
/>
</View>
</TouchableItem>
);
loadData = async (items) => {
const {actions, maxFileSize, teamId} = this.props;
const {getTeamChannels, teamId} = this.props;
if (this.token && this.url) {
const text = [];
const files = [];
let totalSize = 0;
let error;
actions.getTeamChannels(teamId);
getTeamChannels(teamId);
for (let i = 0; i < items.length; i++) {
const item = items[i];
@ -387,12 +370,7 @@ export default class ExtensionPost extends PureComponent {
}
const value = text.join('\n');
if (!error && files.length <= MAX_FILE_COUNT && totalSize <= maxFileSize) {
this.props.navigation.setParams({
post: this.onPost,
});
}
this.canPost(error, value, files, totalSize);
this.setState({error, files, value, hasPermission: true, totalSize});
}
@ -570,6 +548,25 @@ export default class ExtensionPost extends PureComponent {
});
};
rightHeader = () => (
<TouchableItem
accessibilityComponentType='button'
accessibilityTraits='button'
borderless={true}
delayPressIn={0}
pressColorAndroid='rgba(0, 0, 0, .32)'
onPress={this.onPost}
>
<View style={styles.left}>
<PaperPlane
color={defaultTheme.sidebarHeaderTextColor}
height={20}
width={20}
/>
</View>
</TouchableItem>
);
renderTeamButton = () => {
const {teamId} = this.state;

View file

@ -10,7 +10,7 @@ import ExtensionPost from './extension_post';
jest.spyOn(Alert, 'alert').mockReturnValue(true);
jest.spyOn(PermissionsAndroid, 'check').mockReturnValue(PermissionsAndroid.RESULTS.GRANTED);
jest.mock('react-navigation-stack/lib/module/views/TouchableItem', () => null);
jest.mock('@react-navigation/stack/lib/module/views/TouchableItem', () => null);
jest.mock('app/mattermost_managed', () => ({
getConfig: jest.fn().mockReturnValue(false),
@ -20,15 +20,16 @@ const MAX_MESSAGE_LENGTH = 4000;
describe('ExtensionPost', () => {
const baseProps = {
actions: {
getTeamChannels: jest.fn(),
},
channelId: 'channel-id',
channels: {},
currentUserId: 'current-user-id',
getTeamChannels: jest.fn(),
maxFileSize: 1024,
navigation: {
setParams: jest.fn(),
setOptions: jest.fn(),
},
route: {
params: {},
},
teamId: 'team-id',
};

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {getAllChannels, getCurrentChannel, getDefaultChannel} from '@mm-redux/selectors/entities/channels';
@ -18,7 +17,7 @@ function mapStateToProps(state) {
const config = getConfig(state);
let channel = getCurrentChannel(state);
if (channel && channel.delete_at !== 0) {
if (channel && (channel.delete_at !== 0)) {
channel = getDefaultChannel(state);
}
@ -31,12 +30,8 @@ function mapStateToProps(state) {
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getTeamChannels,
}, dispatch),
};
}
const mapDispatchToProps = ({
getTeamChannels,
});
export default connect(mapStateToProps, mapDispatchToProps)(ExtensionPost);

View file

@ -4,7 +4,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import {NavigationActions} from 'react-navigation';
import {CommonActions as NavigationActions} from '@react-navigation/native';
import {
ActivityIndicator,
FlatList,
@ -26,6 +26,7 @@ export default class ExtensionTeam extends PureComponent {
getTeamChannels: PropTypes.func.isRequired,
}).isRequired,
navigation: PropTypes.object.isRequired,
route: PropTypes.object.isRequired,
teamIds: PropTypes.array,
};
@ -37,26 +38,22 @@ export default class ExtensionTeam extends PureComponent {
intl: intlShape,
};
static navigationOptions = ({navigation}) => ({
title: navigation.state.params.title,
});
state = {
loading: false,
};
handleSelectTeam = async (teamId) => {
const {state} = this.props.navigation;
const backAction = NavigationActions.back();
const {actions, navigation, route} = this.props;
const backAction = NavigationActions.goBack();
if (state.params && state.params.onSelectTeam) {
if (route?.params?.onSelectTeam) {
this.setState({loading: true});
const channelId = await this.props.actions.getTeamChannels(teamId);
this.props.actions.extensionSelectTeamId(teamId);
state.params.onSelectTeam(teamId, channelId);
const channelId = await actions.getTeamChannels(teamId);
actions.extensionSelectTeamId(teamId);
route.params.onSelectTeam(teamId, channelId);
}
this.props.navigation.dispatch(backAction);
navigation.dispatch(backAction);
};
keyExtractor = (item) => item;
@ -70,8 +67,7 @@ export default class ExtensionTeam extends PureComponent {
};
renderItem = ({item}) => {
const {navigation} = this.props;
const {params} = navigation.state;
const {params} = this.props.route;
return (
<TeamItem

View file

@ -1,8 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {Preferences} from '@mm-redux/constants';
@ -11,32 +12,49 @@ import ExtensionPost from './extension_post';
import ExtensionTeams from './extension_teams';
const theme = Preferences.THEMES.default;
const Navigation = createStackNavigator({
Post: {
screen: ExtensionPost,
const Stack = createStackNavigator();
const defaultNavigationOptions = {
headerStyle: {
backgroundColor: theme.sidebarHeaderBg,
},
Teams: {
screen: ExtensionTeams,
headerTitleStyle: {
marginHorizontal: 0,
left: 0,
color: theme.sidebarHeaderTextColor,
},
Channels: {
screen: ExtensionChannels,
headerBackTitleStyle: {
color: theme.sidebarHeaderTextColor,
margin: 0,
},
}, {
defaultNavigationOptions: {
headerStyle: {
backgroundColor: theme.sidebarHeaderBg,
},
headerTitleStyle: {
marginHorizontal: 0,
left: 0,
color: theme.sidebarHeaderTextColor,
},
headerBackTitleStyle: {
color: theme.sidebarHeaderTextColor,
margin: 0,
},
headerTintColor: theme.sidebarHeaderTextColor,
},
});
headerTintColor: theme.sidebarHeaderTextColor,
};
export default createAppContainer(Navigation);
function RootStack() {
return (
<Stack.Navigator
initialRouteName='Post'
screenOptions={defaultNavigationOptions}
>
<Stack.Screen
name='Post'
component={ExtensionPost}
/>
<Stack.Screen
name='Teams'
component={ExtensionTeams}
/>
<Stack.Screen
name='Channels'
component={ExtensionChannels}
/>
</Stack.Navigator>
);
}
export default function ExtensionNavigation() {
return (
<NavigationContainer>
<RootStack/>
</NavigationContainer>
);
}

View file

@ -109,15 +109,6 @@ jest.doMock('react-native', () => {
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
jest.mock('../node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter');
jest.mock('react-native-cookies', () => ({
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
openURL: jest.fn(),
canOpenURL: jest.fn(),
getInitialURL: jest.fn(),
clearAll: jest.fn(),
}));
jest.mock('react-native-device-info', () => {
return {
getVersion: () => '0.0.0',
@ -125,12 +116,11 @@ jest.mock('react-native-device-info', () => {
getModel: () => 'iPhone X',
isTablet: () => false,
getApplicationName: () => 'Mattermost',
getDeviceLocale: () => 'en-US',
};
});
jest.mock('react-native-fast-image', () => {
const FastImage = require.requireActual('react-native-fast-image').default;
const FastImage = jest.requireActual('react-native-fast-image').default;
FastImage.preload = jest.fn();
return FastImage;
@ -162,8 +152,33 @@ jest.mock('rn-fetch-blob/fs', () => ({
mv: jest.fn(),
}));
jest.mock('react-native-localize', () => ({
getTimeZone: () => 'World/Somewhere',
getLocales: () => ([
{countryCode: 'GB', languageTag: 'en-GB', languageCode: 'en', isRTL: false},
{countryCode: 'US', languageTag: 'en-US', languageCode: 'en', isRTL: false},
{countryCode: 'FR', languageTag: 'fr-FR', languageCode: 'fr', isRTL: false},
]),
}));
jest.mock('@react-native-community/cookies', () => ({
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
openURL: jest.fn(),
canOpenURL: jest.fn(),
getInitialURL: jest.fn(),
clearAll: jest.fn(),
get: () => Promise.resolve(({
res: {
MMCSRF: {
value: 'the cookie',
},
},
})),
}));
jest.mock('react-native-navigation', () => {
const RNN = require.requireActual('react-native-navigation');
const RNN = jest.requireActual('react-native-navigation');
return {
...RNN,
Navigation: {