parent
08e748bcae
commit
7c09334dc4
145 changed files with 4982 additions and 2415 deletions
|
|
@ -267,6 +267,7 @@ dependencies {
|
|||
implementation project(':@sentry_react-native')
|
||||
implementation project(':react-native-android-open-settings')
|
||||
implementation project(':react-native-haptic-feedback')
|
||||
implementation project(':react-native-permissions')
|
||||
|
||||
implementation project(':react-native-fast-image')
|
||||
// For animated GIF support
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import io.sentry.RNSentryModule;
|
|||
import com.dylanvann.fastimage.FastImageViewPackage;
|
||||
import com.levelasquez.androidopensettings.AndroidOpenSettings;
|
||||
import com.mkuczera.RNReactNativeHapticFeedbackModule;
|
||||
import com.reactnativecommunity.rnpermissions.RNPermissionsModule;
|
||||
|
||||
import com.reactnativecommunity.webview.RNCWebViewPackage;
|
||||
import com.brentvatne.react.ReactVideoPackage;
|
||||
|
|
@ -153,6 +154,8 @@ public class MainApplication extends NavigationApplication implements INotificat
|
|||
return new AndroidOpenSettings(reactContext);
|
||||
case "RNReactNativeHapticFeedbackModule":
|
||||
return new RNReactNativeHapticFeedbackModule(reactContext);
|
||||
case "RNPermissions":
|
||||
return new RNPermissionsModule(reactContext);
|
||||
default:
|
||||
throw new IllegalArgumentException("Could not find module " + name);
|
||||
}
|
||||
|
|
@ -187,6 +190,7 @@ public class MainApplication extends NavigationApplication implements INotificat
|
|||
map.put(NetInfoModule.NAME, new ReactModuleInfo(NetInfoModule.NAME, "com.reactnativecommunity.netinfo.NetInfoModule", false, false, false, false, false));
|
||||
map.put("RNAndroidOpenSettings", new ReactModuleInfo("RNAndroidOpenSettings", "com.levelasquez.androidopensettings.AndroidOpenSettings", false, false, false, false, false));
|
||||
map.put("RNReactNativeHapticFeedbackModule", new ReactModuleInfo("RNReactNativeHapticFeedback", "com.mkuczera.RNReactNativeHapticFeedbackModule", false, false, false, false, false));
|
||||
map.put("RNPermissions", new ReactModuleInfo("RNPermissions", "com.reactnativecommunity.rnpermissions.RNPermissionsModule", false, false, false, false, false));
|
||||
return map;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ include ':@sentry_react-native'
|
|||
project(':@sentry_react-native').projectDir = new File(rootProject.projectDir, '../node_modules/@sentry/react-native/android')
|
||||
include ':react-native-android-open-settings'
|
||||
project(':react-native-android-open-settings').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-open-settings/android')
|
||||
include ':react-native-permissions'
|
||||
project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
|
||||
include ':react-native-fast-image'
|
||||
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
|
||||
include ':react-native-haptic-feedback'
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('AnnouncementBanner', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<AnnouncementBanner {...baseProps}/>
|
||||
<AnnouncementBanner {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ describe('AtMention', () => {
|
|||
|
||||
test('should match snapshot, no highlight', () => {
|
||||
const wrapper = shallow(
|
||||
<AtMention {...baseProps}/>
|
||||
<AtMention {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -25,7 +25,7 @@ describe('AtMention', () => {
|
|||
|
||||
test('should match snapshot, with highlight', () => {
|
||||
const wrapper = shallow(
|
||||
<AtMention {...baseProps}/>
|
||||
<AtMention {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({user: {username: 'John.Smith'}});
|
||||
|
|
@ -34,7 +34,7 @@ describe('AtMention', () => {
|
|||
|
||||
test('should match snapshot, without highlight', () => {
|
||||
const wrapper = shallow(
|
||||
<AtMention {...baseProps}/>
|
||||
<AtMention {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({user: {username: 'Victor.Welch'}});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import Permissions from 'react-native-permissions';
|
|||
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
|
||||
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
import emmProvider from 'app/init/emm_provider';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
import {t} from 'app/utils/i18n';
|
||||
import {showModalOverCurrentContext} from 'app/actions/navigation';
|
||||
|
|
@ -178,6 +178,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
|
||||
if (hasCameraPermission) {
|
||||
ImagePicker.launchCamera(options, (response) => {
|
||||
emmProvider.inBackgroundSince = null;
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -208,10 +209,11 @@ export default class AttachmentButton extends PureComponent {
|
|||
options.mediaType = 'mixed';
|
||||
}
|
||||
|
||||
const hasPhotoPermission = await this.hasPhotoPermission('photo');
|
||||
const hasPhotoPermission = await this.hasPhotoPermission('photo', 'photo');
|
||||
|
||||
if (hasPhotoPermission) {
|
||||
ImagePicker.launchImageLibrary(options, (response) => {
|
||||
emmProvider.inBackgroundSince = null;
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -244,6 +246,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
};
|
||||
|
||||
ImagePicker.launchImageLibrary(options, (response) => {
|
||||
emmProvider.inBackgroundSince = null;
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -259,6 +262,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
if (hasPermission) {
|
||||
try {
|
||||
const res = await DocumentPicker.pick({type: [browseFileTypes]});
|
||||
emmProvider.inBackgroundSince = null;
|
||||
if (Platform.OS === 'android') {
|
||||
// For android we need to retrieve the realPath in case the file being imported is from the cloud
|
||||
const newUri = await ShareExtension.getFilePath(res.uri);
|
||||
|
|
@ -283,28 +287,21 @@ export default class AttachmentButton extends PureComponent {
|
|||
if (Platform.OS === 'ios') {
|
||||
const {formatMessage} = this.context.intl;
|
||||
let permissionRequest;
|
||||
const targetSource = source || 'photo';
|
||||
const targetSource = source === 'camera' ? Permissions.PERMISSIONS.IOS.CAMERA : Permissions.PERMISSIONS.IOS.PHOTO_LIBRARY;
|
||||
const hasPermissionToStorage = await Permissions.check(targetSource);
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
case Permissions.RESULTS.DENIED:
|
||||
permissionRequest = await Permissions.request(targetSource);
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
if (permissionRequest !== Permissions.RESULTS.GRANTED) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
const canOpenSettings = await Permissions.canOpenSettings();
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
grantOption = {
|
||||
text: formatMessage({
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
}
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const grantOption = {
|
||||
text: formatMessage({id: 'mobile.permission_denied_retry', defaultMessage: 'Settings'}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
|
||||
const {title, text} = this.getPermissionDeniedMessage(source, mediaType);
|
||||
|
||||
|
|
@ -319,7 +316,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
defaultMessage: 'Don\'t Allow',
|
||||
}),
|
||||
},
|
||||
]
|
||||
],
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -336,13 +333,13 @@ export default class AttachmentButton extends PureComponent {
|
|||
const hasPermissionToStorage = await Permissions.check('storage');
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
case Permissions.RESULTS.DENIED:
|
||||
permissionRequest = await Permissions.request('storage');
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
if (permissionRequest !== Permissions.RESULTS.GRANTED) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const {title, text} = this.getPermissionDeniedMessage('storage');
|
||||
|
||||
Alert.alert(
|
||||
|
|
@ -362,7 +359,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
}),
|
||||
onPress: () => AndroidOpenSettings.appDetailsSettings(),
|
||||
},
|
||||
]
|
||||
],
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
|
||||
import Permissions from 'react-native-permissions';
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
import {VALID_MIME_TYPES} from 'app/screens/edit_profile/edit_profile';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
|
||||
import AttachmentButton from './index';
|
||||
|
||||
|
|
@ -28,9 +28,7 @@ describe('AttachmentButton', () => {
|
|||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<AttachmentButton {...baseProps}/>
|
||||
);
|
||||
const wrapper = shallow(<AttachmentButton {...baseProps}/>);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -42,9 +40,7 @@ describe('AttachmentButton', () => {
|
|||
onShowUnsupportedMimeTypeWarning: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<AttachmentButton {...props}/>
|
||||
);
|
||||
const wrapper = shallow(<AttachmentButton {...props}/>);
|
||||
|
||||
const file = {
|
||||
type: 'image/gif',
|
||||
|
|
@ -63,9 +59,7 @@ describe('AttachmentButton', () => {
|
|||
onShowUnsupportedMimeTypeWarning: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<AttachmentButton {...props}/>
|
||||
);
|
||||
const wrapper = shallow(<AttachmentButton {...props}/>);
|
||||
|
||||
const file = {
|
||||
fileSize: 10,
|
||||
|
|
@ -79,11 +73,24 @@ describe('AttachmentButton', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should show permission denied alert if permission is denied in iOS', async () => {
|
||||
expect.assertions(1);
|
||||
test('should return permission false if permission is denied in iOS', async () => {
|
||||
jest.spyOn(Permissions, 'check').mockReturnValue(Permissions.RESULTS.DENIED);
|
||||
jest.spyOn(Permissions, 'request').mockReturnValue(Permissions.RESULTS.DENIED);
|
||||
|
||||
jest.spyOn(Permissions, 'check').mockReturnValue(PermissionTypes.DENIED);
|
||||
jest.spyOn(Permissions, 'canOpenSettings').mockReturnValue(true);
|
||||
const wrapper = shallow(
|
||||
<AttachmentButton {...baseProps}/>,
|
||||
{context: {intl: {formatMessage}}},
|
||||
);
|
||||
|
||||
const hasPhotoPermission = await wrapper.instance().hasPhotoPermission('camera');
|
||||
expect(Permissions.check).toHaveBeenCalled();
|
||||
expect(Permissions.request).toHaveBeenCalled();
|
||||
expect(Alert.alert).not.toHaveBeenCalled();
|
||||
expect(hasPhotoPermission).toBe(false);
|
||||
});
|
||||
|
||||
test('should show permission denied alert and return permission false if permission is blocked in iOS', async () => {
|
||||
jest.spyOn(Permissions, 'check').mockReturnValue(Permissions.RESULTS.BLOCKED);
|
||||
jest.spyOn(Alert, 'alert').mockReturnValue(true);
|
||||
|
||||
const wrapper = shallow(
|
||||
|
|
@ -91,7 +98,10 @@ describe('AttachmentButton', () => {
|
|||
{context: {intl: {formatMessage}}},
|
||||
);
|
||||
|
||||
await wrapper.instance().hasPhotoPermission('camera');
|
||||
expect(Alert.alert).toBeCalled();
|
||||
const hasPhotoPermission = await wrapper.instance().hasPhotoPermission('camera');
|
||||
expect(Permissions.check).toHaveBeenCalled();
|
||||
expect(Permissions.request).not.toHaveBeenCalled();
|
||||
expect(Alert.alert).toHaveBeenCalled();
|
||||
expect(hasPhotoPermission).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -24,7 +24,7 @@ const getEmojisByName = createSelector(
|
|||
}
|
||||
|
||||
return Array.from(emoticons);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const mobileCommandsSelector = createSelector(
|
|||
getAutocompleteCommandsList,
|
||||
(commands) => {
|
||||
return commands.filter((command) => !COMMANDS_TO_HIDE_ON_MOBILE.includes(command.trigger));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ describe('Badge', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<Badge {...baseProps}/>
|
||||
<Badge {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.instance().renderText()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function makeMapStateToProps() {
|
|||
(currentUserId, profilesInChannel) => {
|
||||
const currentChannelMembers = profilesInChannel || [];
|
||||
return currentChannelMembers.filter((m) => m.id !== currentUserId);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return function mapStateToProps(state, ownProps) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function makeGetChannelNamesMap() {
|
|||
}
|
||||
|
||||
return channelsNameMap;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ export default class ChannelLoader extends PureComponent {
|
|||
|
||||
stopLoadingAnimation = () => {
|
||||
Animated.timing(
|
||||
this.state.barsOpacity
|
||||
this.state.barsOpacity,
|
||||
).stop();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export default class ClientUpgradeListener extends PureComponent {
|
|||
intl.formatMessage({
|
||||
id: 'mobile.client_upgrade.download_error.message',
|
||||
defaultMessage: 'An error occurred while trying to open the download link.',
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('CustomList', () => {
|
|||
|
||||
test('should match snapshot with FlatList', () => {
|
||||
const wrapper = shallow(
|
||||
<CustomList {...baseProps}/>
|
||||
<CustomList {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('FlatList')).toHaveLength(1);
|
||||
|
|
@ -42,7 +42,7 @@ describe('CustomList', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<CustomList {...props}/>
|
||||
<CustomList {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('SectionList')).toHaveLength(1);
|
||||
|
|
@ -50,7 +50,7 @@ describe('CustomList', () => {
|
|||
|
||||
test('should match snapshot, renderSectionHeader', () => {
|
||||
const wrapper = shallow(
|
||||
<CustomList {...baseProps}/>
|
||||
<CustomList {...baseProps}/>,
|
||||
);
|
||||
const section = {
|
||||
id: 'section_id',
|
||||
|
|
@ -61,7 +61,7 @@ describe('CustomList', () => {
|
|||
test('should call props.renderItem on renderItem', () => {
|
||||
const props = {...baseProps};
|
||||
const wrapper = shallow(
|
||||
<CustomList {...props}/>
|
||||
<CustomList {...props}/>,
|
||||
);
|
||||
wrapper.instance().renderItem({item: {id: 'item_id', selected: true}, index: 0, section: null});
|
||||
expect(props.renderItem).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -69,7 +69,7 @@ describe('CustomList', () => {
|
|||
|
||||
test('should match snapshot, renderSeparator', () => {
|
||||
const wrapper = shallow(
|
||||
<CustomList {...baseProps}/>
|
||||
<CustomList {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.instance().renderSeparator()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -77,7 +77,7 @@ describe('CustomList', () => {
|
|||
test('should match snapshot, renderFooter', () => {
|
||||
const props = {...baseProps};
|
||||
const wrapper = shallow(
|
||||
<CustomList {...props}/>
|
||||
<CustomList {...props}/>,
|
||||
);
|
||||
|
||||
// should return null
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ describe('EditChannelInfo', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<EditChannelInfo {...baseProps}/>
|
||||
<EditChannelInfo {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -45,7 +45,7 @@ describe('EditChannelInfo', () => {
|
|||
|
||||
test('should have called onHeaderChangeText on text change from Autocomplete', () => {
|
||||
const wrapper = shallow(
|
||||
<EditChannelInfo {...baseProps}/>
|
||||
<EditChannelInfo {...baseProps}/>,
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
|
|
@ -67,7 +67,7 @@ describe('EditChannelInfo', () => {
|
|||
|
||||
test('should call scrollHeaderToTop', () => {
|
||||
const wrapper = shallow(
|
||||
<EditChannelInfo {...baseProps}/>
|
||||
<EditChannelInfo {...baseProps}/>,
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ const getEmojisBySection = createSelector(
|
|||
}
|
||||
|
||||
return emoticons;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const getEmojisByName = createSelector(
|
||||
|
|
@ -137,7 +137,7 @@ const getEmojisByName = createSelector(
|
|||
}
|
||||
|
||||
return Array.from(emoticons);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default class Fade extends PureComponent {
|
|||
toValue: prevProps.visible ? 0 : 1,
|
||||
duration: this.props.duration || FADE_DURATION,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('Fade', () => {
|
|||
{...props}
|
||||
>
|
||||
<Text>{dummyText}</Text>
|
||||
</Fade>
|
||||
</Fade>,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ describe('FileAttachment', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<FileAttachment {...baseProps}/>
|
||||
<FileAttachment {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ export default class FileAttachmentDocument extends PureComponent {
|
|||
id: 'mobile.server_upgrade.button',
|
||||
defaultMessage: 'OK',
|
||||
}),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
this.onDonePreviewingFile();
|
||||
RNFetchBlob.fs.unlink(path);
|
||||
|
|
@ -303,7 +303,7 @@ export default class FileAttachmentDocument extends PureComponent {
|
|||
id: 'mobile.server_upgrade.button',
|
||||
defaultMessage: 'OK',
|
||||
}),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -324,7 +324,7 @@ export default class FileAttachmentDocument extends PureComponent {
|
|||
id: 'mobile.server_upgrade.button',
|
||||
defaultMessage: 'OK',
|
||||
}),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('FormattedTime', () => {
|
|||
console.error = jest.fn();
|
||||
|
||||
let wrapper = renderWithIntl(
|
||||
<FormattedTime {...baseProps}/>
|
||||
<FormattedTime {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.baseElement).toMatchSnapshot();
|
||||
|
|
@ -33,7 +33,7 @@ describe('FormattedTime', () => {
|
|||
<FormattedTime
|
||||
{...baseProps}
|
||||
hour12={false}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getByText('19:02')).toBeTruthy();
|
||||
|
|
@ -81,7 +81,7 @@ describe('FormattedTime', () => {
|
|||
{...baseProps}
|
||||
timeZone='NZ-CHAT'
|
||||
hour12={false}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getByText('08:47')).toBeTruthy();
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export default class MarkdownCodeBlock extends React.PureComponent {
|
|||
},
|
||||
{
|
||||
language: languageDisplayName,
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
title = intl.formatMessage({
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ describe('MarkdownEmoji', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<MarkdownEmoji {...baseProps}/>
|
||||
<MarkdownEmoji {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe('MarkdownTable', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<MarkdownTable {...baseProps}/>
|
||||
<MarkdownTable {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -40,7 +40,7 @@ describe('MarkdownTable', () => {
|
|||
|
||||
test('should slice rows and columns', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<MarkdownTable {...baseProps}/>
|
||||
<MarkdownTable {...baseProps}/>,
|
||||
);
|
||||
|
||||
const {maxPreviewColumns} = wrapper.state();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default function ActionButtonText({message, style}) {
|
|||
literal={match[0]}
|
||||
emojiName={match[1]}
|
||||
textStyle={style}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
text = text.substring(match[0].length);
|
||||
continue;
|
||||
|
|
@ -48,7 +48,7 @@ export default function ActionButtonText({message, style}) {
|
|||
literal={match[0]}
|
||||
emojiName={emoticonName}
|
||||
textStyle={style}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
text = text.substring(match[0].length);
|
||||
continue;
|
||||
|
|
@ -65,7 +65,7 @@ export default function ActionButtonText({message, style}) {
|
|||
style={style}
|
||||
>
|
||||
{match[0]}
|
||||
</Text>
|
||||
</Text>,
|
||||
);
|
||||
text = text.substring(match[0].length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default class AttachmentActions extends PureComponent {
|
|||
options={action.options}
|
||||
postId={postId}
|
||||
disabled={action.disabled}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
break;
|
||||
case 'button':
|
||||
|
|
@ -55,7 +55,7 @@ export default class AttachmentActions extends PureComponent {
|
|||
name={action.name}
|
||||
postId={postId}
|
||||
disabled={action.disabled}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default class AttachmentFields extends PureComponent {
|
|||
style={style.field}
|
||||
>
|
||||
{fieldInfos}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
fieldInfos = [];
|
||||
rowPos = 0;
|
||||
|
|
@ -89,7 +89,7 @@ export default class AttachmentFields extends PureComponent {
|
|||
onPermalinkPress={onPermalinkPress}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
|
||||
rowPos += 1;
|
||||
|
|
@ -103,7 +103,7 @@ export default class AttachmentFields extends PureComponent {
|
|||
style={style.table}
|
||||
>
|
||||
{fieldInfos}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default class MessageAttachments extends PureComponent {
|
|||
postId={postId}
|
||||
theme={theme}
|
||||
textStyles={textStyles}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -175,14 +175,14 @@ export default class NetworkIndicator extends PureComponent {
|
|||
this.backgroundColor, {
|
||||
toValue: 1,
|
||||
duration: 100,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.top, {
|
||||
toValue: (this.getNavBarHeight() - HEIGHT),
|
||||
duration: 300,
|
||||
delay: 500,
|
||||
}
|
||||
},
|
||||
),
|
||||
]).start(() => {
|
||||
this.backgroundColor.setValue(0);
|
||||
|
|
@ -317,7 +317,7 @@ export default class NetworkIndicator extends PureComponent {
|
|||
}),
|
||||
onPress: actions.logout,
|
||||
}],
|
||||
{cancelable: false}
|
||||
{cancelable: false},
|
||||
);
|
||||
closeWebSocket(true);
|
||||
});
|
||||
|
|
@ -340,7 +340,7 @@ export default class NetworkIndicator extends PureComponent {
|
|||
this.top, {
|
||||
toValue: this.getNavBarHeight(),
|
||||
duration: 300,
|
||||
}
|
||||
},
|
||||
).start(() => {
|
||||
this.props.actions.setCurrentUserStatusOffline();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ describe('CustomTextInput', () => {
|
|||
const onPaste = jest.fn();
|
||||
const text = 'My Text';
|
||||
const component = shallow(
|
||||
<CustomTextInput onPaste={onPaste}>{text}</CustomTextInput>
|
||||
<CustomTextInput onPaste={onPaste}>{text}</CustomTextInput>,
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ describe('PasteableTextInput', () => {
|
|||
const onPaste = jest.fn();
|
||||
const text = 'My Text';
|
||||
const component = shallow(
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>,
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -23,7 +23,7 @@ describe('PasteableTextInput', () => {
|
|||
const event = {someData: 'data'};
|
||||
const text = 'My Text';
|
||||
shallow(
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>,
|
||||
);
|
||||
nativeEventEmitter.emit('onPaste', event);
|
||||
expect(onPaste).toHaveBeenCalledWith(null, event);
|
||||
|
|
@ -34,7 +34,7 @@ describe('PasteableTextInput', () => {
|
|||
const onPaste = jest.fn();
|
||||
const text = 'My Text';
|
||||
const component = shallow(
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>
|
||||
<PasteableTextInput onPaste={onPaste}>{text}</PasteableTextInput>,
|
||||
);
|
||||
|
||||
component.instance().subscription.remove = mockRemove;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export default class PostAddChannelMember extends React.PureComponent {
|
|||
{
|
||||
username: currentUser.username,
|
||||
addedUsername: usernames[index],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
actions.sendAddToChannelEphemeralPost(currentUser, usernames[index], message, post.channel_id, post.root_id);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ describe('PostAttachmentOpenGraph', () => {
|
|||
|
||||
test('should match snapshot, without image and description', () => {
|
||||
const wrapper = shallow(
|
||||
<PostAttachmentOpenGraph {...baseProps}/>
|
||||
<PostAttachmentOpenGraph {...baseProps}/>,
|
||||
);
|
||||
|
||||
// should return null
|
||||
|
|
@ -58,7 +58,7 @@ describe('PostAttachmentOpenGraph', () => {
|
|||
<PostAttachmentOpenGraph
|
||||
{...baseProps}
|
||||
openGraphData={newOpenGraphData}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -68,14 +68,14 @@ describe('PostAttachmentOpenGraph', () => {
|
|||
<PostAttachmentOpenGraph
|
||||
{...baseProps}
|
||||
openGraphData={{}}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match state and snapshot, on renderImage', () => {
|
||||
const wrapper = shallow(
|
||||
<PostAttachmentOpenGraph {...baseProps}/>
|
||||
<PostAttachmentOpenGraph {...baseProps}/>,
|
||||
);
|
||||
|
||||
// should return null
|
||||
|
|
@ -99,7 +99,7 @@ describe('PostAttachmentOpenGraph', () => {
|
|||
<PostAttachmentOpenGraph
|
||||
{...baseProps}
|
||||
openGraphData={openGraphData}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
// should return null
|
||||
|
|
@ -112,7 +112,7 @@ describe('PostAttachmentOpenGraph', () => {
|
|||
|
||||
test('should match result on getFilename', () => {
|
||||
const wrapper = shallow(
|
||||
<PostAttachmentOpenGraph {...baseProps}/>
|
||||
<PostAttachmentOpenGraph {...baseProps}/>,
|
||||
);
|
||||
|
||||
const testCases = [
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ describe('PostHeader', () => {
|
|||
|
||||
test('should match snapshot when just a base post', () => {
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...baseProps}/>
|
||||
<PostHeader {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#ReplyIcon').exists()).toEqual(false);
|
||||
|
|
@ -55,7 +55,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -67,7 +67,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -79,7 +79,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#ReplyIcon').exists()).toEqual(false);
|
||||
|
|
@ -92,7 +92,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#ReplyIcon').exists()).toEqual(false);
|
||||
|
|
@ -108,7 +108,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -123,7 +123,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -135,7 +135,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#ReplyIcon').exists()).toEqual(false);
|
||||
|
|
@ -150,7 +150,7 @@ describe('PostHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostHeader {...props}/>
|
||||
<PostHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe('PostPreHeader', () => {
|
|||
|
||||
test('should match snapshot when not flagged or pinned post', () => {
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...baseProps}/>
|
||||
<PostPreHeader {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.type()).toBeNull();
|
||||
|
|
@ -35,7 +35,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.type()).toBeNull();
|
||||
|
|
@ -49,7 +49,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.type()).toBeNull();
|
||||
|
|
@ -62,7 +62,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#flagIcon').exists()).toEqual(true);
|
||||
|
|
@ -77,7 +77,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#flagIcon').exists()).toEqual(false);
|
||||
|
|
@ -93,7 +93,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#flagIcon').exists()).toEqual(true);
|
||||
|
|
@ -110,7 +110,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#flagIcon').exists()).toEqual(true);
|
||||
|
|
@ -127,7 +127,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.find('#flagIcon').exists()).toEqual(false);
|
||||
|
|
@ -145,7 +145,7 @@ describe('PostPreHeader', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostPreHeader {...props}/>
|
||||
<PostPreHeader {...props}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
expect(wrapper.type()).toBeNull();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe('PostList', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<PostList {...baseProps}/>
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -49,7 +49,7 @@ describe('PostList', () => {
|
|||
test('setting permalink deep link', () => {
|
||||
const showModalOverCurrentContext = jest.spyOn(NavigationActions, 'showModalOverCurrentContext');
|
||||
const wrapper = shallow(
|
||||
<PostList {...baseProps}/>
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setProps({deepLinkURL: deepLinks.permalink});
|
||||
|
|
@ -61,7 +61,7 @@ describe('PostList', () => {
|
|||
|
||||
test('setting channel deep link', () => {
|
||||
const wrapper = shallow(
|
||||
<PostList {...baseProps}/>
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setProps({deepLinkURL: deepLinks.channel});
|
||||
|
|
@ -74,7 +74,7 @@ describe('PostList', () => {
|
|||
jest.spyOn(global, 'requestAnimationFrame').mockImplementation((cb) => cb());
|
||||
|
||||
const wrapper = shallow(
|
||||
<PostList {...baseProps}/>
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
const flatListScrollToIndex = jest.spyOn(instance, 'flatListScrollToIndex');
|
||||
|
|
@ -103,7 +103,7 @@ describe('PostList', () => {
|
|||
|
||||
test('should load more posts if available space on the screen', () => {
|
||||
const wrapper = shallow(
|
||||
<PostList {...baseProps}/>
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
instance.loadToFillContent = jest.fn();
|
||||
|
|
|
|||
|
|
@ -6,31 +6,26 @@ import {intlShape} from 'react-intl';
|
|||
import {
|
||||
Alert,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {ICON_SIZE} from 'app/constants/post_textbox';
|
||||
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
import Permissions from 'react-native-permissions';
|
||||
|
||||
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
|
||||
export default class AttachmentButton extends PureComponent {
|
||||
static propTypes = {
|
||||
validMimeTypes: PropTypes.array,
|
||||
fileCount: PropTypes.number,
|
||||
maxFileCount: PropTypes.number.isRequired,
|
||||
maxFileSize: PropTypes.number.isRequired,
|
||||
onShowFileMaxWarning: PropTypes.func,
|
||||
onShowFileSizeWarning: PropTypes.func,
|
||||
onShowUnsupportedMimeTypeWarning: PropTypes.func,
|
||||
theme: PropTypes.object.isRequired,
|
||||
uploadFiles: PropTypes.func.isRequired,
|
||||
buttonContainerStyle: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -102,7 +97,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
this.uploadFiles([response]);
|
||||
this.props.uploadFiles([response]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -115,13 +110,13 @@ export default class AttachmentButton extends PureComponent {
|
|||
const hasPermissionToStorage = await Permissions.check(targetSource);
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
case Permissions.RESULTS.UNAVAILABLE:
|
||||
permissionRequest = await Permissions.request(targetSource);
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
if (permissionRequest !== Permissions.RESULTS.AUTHORIZED) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const canOpenSettings = await Permissions.canOpenSettings();
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
|
|
@ -157,51 +152,20 @@ export default class AttachmentButton extends PureComponent {
|
|||
return true;
|
||||
};
|
||||
|
||||
uploadFiles = async (files) => {
|
||||
const file = files[0];
|
||||
if (!file.fileSize | !file.fileName) {
|
||||
const path = (file.path || file.uri).replace('file://', '');
|
||||
const fileInfo = await RNFetchBlob.fs.stat(path);
|
||||
file.fileSize = fileInfo.size;
|
||||
file.fileName = fileInfo.filename;
|
||||
}
|
||||
|
||||
if (!file.type) {
|
||||
file.type = lookupMimeType(file.fileName);
|
||||
}
|
||||
|
||||
const {validMimeTypes} = this.props;
|
||||
if (validMimeTypes.length && !validMimeTypes.includes(file.type)) {
|
||||
this.props.onShowUnsupportedMimeTypeWarning();
|
||||
} else if (file.fileSize > this.props.maxFileSize) {
|
||||
this.props.onShowFileSizeWarning(file.fileName);
|
||||
} else {
|
||||
this.props.uploadFiles(files);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
|
||||
const {theme, buttonContainerStyle} = this.props;
|
||||
return (
|
||||
<TouchableWithFeedback
|
||||
onPress={this.attachFileFromCamera}
|
||||
style={style.buttonContainer}
|
||||
style={buttonContainerStyle}
|
||||
type={'opacity'}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
color={theme.centerChannelColor}
|
||||
color={changeOpacity(theme.centerChannelColor, 0.64)}
|
||||
name='camera-outline'
|
||||
size={20}
|
||||
size={ICON_SIZE}
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const style = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
},
|
||||
});
|
||||
|
|
@ -7,20 +7,18 @@ import {
|
|||
Alert,
|
||||
NativeModules,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {ICON_SIZE} from 'app/constants/post_textbox';
|
||||
import AndroidOpenSettings from 'react-native-android-open-settings';
|
||||
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import DocumentPicker from 'react-native-document-picker';
|
||||
import Permissions from 'react-native-permissions';
|
||||
|
||||
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
|
||||
const ShareExtension = NativeModules.MattermostShare;
|
||||
|
||||
|
|
@ -28,15 +26,12 @@ export default class FileUploadButton extends PureComponent {
|
|||
static propTypes = {
|
||||
blurTextBox: PropTypes.func.isRequired,
|
||||
browseFileTypes: PropTypes.string,
|
||||
validMimeTypes: PropTypes.array,
|
||||
fileCount: PropTypes.number,
|
||||
maxFileCount: PropTypes.number.isRequired,
|
||||
maxFileSize: PropTypes.number.isRequired,
|
||||
onShowFileMaxWarning: PropTypes.func,
|
||||
onShowFileSizeWarning: PropTypes.func,
|
||||
onShowUnsupportedMimeTypeWarning: PropTypes.func,
|
||||
theme: PropTypes.object.isRequired,
|
||||
uploadFiles: PropTypes.func.isRequired,
|
||||
buttonContainerStyle: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -90,7 +85,7 @@ export default class FileUploadButton extends PureComponent {
|
|||
// Decode file uri to get the actual path
|
||||
res.uri = decodeURIComponent(res.uri);
|
||||
|
||||
this.uploadFiles([res]);
|
||||
this.props.uploadFiles([res]);
|
||||
} catch (error) {
|
||||
// Do nothing
|
||||
}
|
||||
|
|
@ -104,13 +99,13 @@ export default class FileUploadButton extends PureComponent {
|
|||
const hasPermissionToStorage = await Permissions.check('storage');
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
case Permissions.RESULTS.UNAVAILABLE:
|
||||
permissionRequest = await Permissions.request('storage');
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
if (permissionRequest !== Permissions.RESULTS.AUTHORIZED) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const {title, text} = this.getPermissionDeniedMessage();
|
||||
|
||||
Alert.alert(
|
||||
|
|
@ -130,7 +125,7 @@ export default class FileUploadButton extends PureComponent {
|
|||
}),
|
||||
onPress: () => AndroidOpenSettings.appDetailsSettings(),
|
||||
},
|
||||
]
|
||||
],
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -140,29 +135,6 @@ export default class FileUploadButton extends PureComponent {
|
|||
return true;
|
||||
};
|
||||
|
||||
uploadFiles = async (files) => {
|
||||
const file = files[0];
|
||||
if (!file.fileSize | !file.fileName) {
|
||||
const path = (file.path || file.uri).replace('file://', '');
|
||||
const fileInfo = await RNFetchBlob.fs.stat(path);
|
||||
file.fileSize = fileInfo.size;
|
||||
file.fileName = fileInfo.filename;
|
||||
}
|
||||
|
||||
if (!file.type) {
|
||||
file.type = lookupMimeType(file.fileName);
|
||||
}
|
||||
|
||||
const {validMimeTypes} = this.props;
|
||||
if (validMimeTypes.length && !validMimeTypes.includes(file.type)) {
|
||||
this.props.onShowUnsupportedMimeTypeWarning();
|
||||
} else if (file.fileSize > this.props.maxFileSize) {
|
||||
this.props.onShowFileSizeWarning(file.fileName);
|
||||
} else {
|
||||
this.props.uploadFiles(files);
|
||||
}
|
||||
};
|
||||
|
||||
handleButtonPress = () => {
|
||||
const {
|
||||
fileCount,
|
||||
|
|
@ -179,26 +151,19 @@ export default class FileUploadButton extends PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
const {theme, buttonContainerStyle} = this.props;
|
||||
return (
|
||||
<TouchableWithFeedback
|
||||
onPress={this.handleButtonPress}
|
||||
style={style.buttonContainer}
|
||||
style={buttonContainerStyle}
|
||||
type={'opacity'}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
color={theme.centerChannelColor}
|
||||
color={changeOpacity(theme.centerChannelColor, 0.64)}
|
||||
name='file-document-outline'
|
||||
size={20}
|
||||
size={ICON_SIZE}
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const style = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
},
|
||||
});
|
||||
|
|
@ -6,32 +6,27 @@ import {intlShape} from 'react-intl';
|
|||
import {
|
||||
Alert,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {ICON_SIZE} from 'app/constants/post_textbox';
|
||||
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
import Permissions from 'react-native-permissions';
|
||||
|
||||
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
|
||||
export default class ImageUploadButton extends PureComponent {
|
||||
static propTypes = {
|
||||
blurTextBox: PropTypes.func.isRequired,
|
||||
validMimeTypes: PropTypes.array,
|
||||
fileCount: PropTypes.number,
|
||||
maxFileCount: PropTypes.number.isRequired,
|
||||
maxFileSize: PropTypes.number.isRequired,
|
||||
onShowFileMaxWarning: PropTypes.func,
|
||||
onShowFileSizeWarning: PropTypes.func,
|
||||
onShowUnsupportedMimeTypeWarning: PropTypes.func,
|
||||
theme: PropTypes.object.isRequired,
|
||||
uploadFiles: PropTypes.func.isRequired,
|
||||
buttonContainerStyle: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -104,7 +99,7 @@ export default class ImageUploadButton extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
this.uploadFiles([response]);
|
||||
this.props.uploadFiles([response]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -117,13 +112,13 @@ export default class ImageUploadButton extends PureComponent {
|
|||
const hasPermissionToStorage = await Permissions.check(targetSource);
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
case Permissions.RESULTS.UNAVAILABLE:
|
||||
permissionRequest = await Permissions.request(targetSource);
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
if (permissionRequest !== Permissions.RESULTS.AUTHORIZED) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const canOpenSettings = await Permissions.canOpenSettings();
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
|
|
@ -159,29 +154,6 @@ export default class ImageUploadButton extends PureComponent {
|
|||
return true;
|
||||
};
|
||||
|
||||
uploadFiles = async (files) => {
|
||||
const file = files[0];
|
||||
if (!file.fileSize | !file.fileName) {
|
||||
const path = (file.path || file.uri).replace('file://', '');
|
||||
const fileInfo = await RNFetchBlob.fs.stat(path);
|
||||
file.fileSize = fileInfo.size;
|
||||
file.fileName = fileInfo.filename;
|
||||
}
|
||||
|
||||
if (!file.type) {
|
||||
file.type = lookupMimeType(file.fileName);
|
||||
}
|
||||
|
||||
const {validMimeTypes} = this.props;
|
||||
if (validMimeTypes.length && !validMimeTypes.includes(file.type)) {
|
||||
this.props.onShowUnsupportedMimeTypeWarning();
|
||||
} else if (file.fileSize > this.props.maxFileSize) {
|
||||
this.props.onShowFileSizeWarning(file.fileName);
|
||||
} else {
|
||||
this.props.uploadFiles(files);
|
||||
}
|
||||
};
|
||||
|
||||
handleButtonPress = () => {
|
||||
const {
|
||||
fileCount,
|
||||
|
|
@ -199,26 +171,19 @@ export default class ImageUploadButton extends PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
const {theme, buttonContainerStyle} = this.props;
|
||||
return (
|
||||
<TouchableWithFeedback
|
||||
onPress={this.handleButtonPress}
|
||||
style={style.buttonContainer}
|
||||
style={buttonContainerStyle}
|
||||
type={'opacity'}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
color={theme.centerChannelColor}
|
||||
color={changeOpacity(theme.centerChannelColor, 0.64)}
|
||||
name='image-outline'
|
||||
size={20}
|
||||
size={ICON_SIZE}
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const style = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
},
|
||||
});
|
||||
|
|
@ -344,7 +344,7 @@ describe('PostTextBox', () => {
|
|||
mockResolvedValue({data: 'success'});
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<PostTextbox {...props}/>
|
||||
<PostTextbox {...props}/>,
|
||||
);
|
||||
|
||||
const msg = '/fail preserve this text in the post draft';
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ describe('ProgressiveImage', () => {
|
|||
<ProgressiveImage
|
||||
{...baseProps}
|
||||
thumbnailUri={null}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
jest.spyOn(instance, 'setImage');
|
||||
|
|
@ -73,7 +73,7 @@ describe('ProgressiveImage', () => {
|
|||
<ProgressiveImage
|
||||
{...baseProps}
|
||||
imageUri={null}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
jest.spyOn(instance, 'setThumbnail');
|
||||
|
|
|
|||
|
|
@ -44,14 +44,14 @@ class RadioButton extends PureComponent {
|
|||
{
|
||||
toValue: 1,
|
||||
duration: 150,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
Animated.timing(
|
||||
this.state.opacityValue,
|
||||
{
|
||||
toValue: 0.1,
|
||||
duration: 100,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
};
|
||||
|
||||
|
|
@ -61,13 +61,13 @@ class RadioButton extends PureComponent {
|
|||
{
|
||||
toValue: 0.001,
|
||||
duration: 1500,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
Animated.timing(
|
||||
this.state.opacityValue,
|
||||
{
|
||||
toValue: 0,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -162,13 +162,13 @@ export default class Reactions extends PureComponent {
|
|||
case 'right':
|
||||
reactionElements.push(
|
||||
this.renderReactions(),
|
||||
addMoreReactions
|
||||
addMoreReactions,
|
||||
);
|
||||
break;
|
||||
case 'left':
|
||||
reactionElements.push(
|
||||
addMoreReactions,
|
||||
this.renderReactions()
|
||||
this.renderReactions(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ export default class SafeAreaIos extends PureComponent {
|
|||
if (this.mounted) {
|
||||
this.setState({statusBarHeight: statusBarFrameData.height});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
// not needed
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -91,7 +91,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = false;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(SafeArea.getSafeAreaInsetsForRootView).toHaveBeenCalled();
|
||||
|
|
@ -104,7 +104,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = true;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(SafeArea.getSafeAreaInsetsForRootView).toHaveBeenCalled();
|
||||
|
|
@ -117,7 +117,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = false;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(SafeArea.getSafeAreaInsetsForRootView).not.toHaveBeenCalled();
|
||||
|
|
@ -130,7 +130,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = false;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(TEST_INSETS_2.safeAreaInsets);
|
||||
|
|
@ -145,7 +145,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = true;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(TEST_INSETS_2.safeAreaInsets);
|
||||
|
|
@ -160,7 +160,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = false;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(TEST_INSETS_2.safeAreaInsets);
|
||||
|
|
@ -175,7 +175,7 @@ describe('SafeAreaIos', () => {
|
|||
mattermostManaged.hasSafeAreaInsets = true;
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(TEST_INSETS_2.safeAreaInsets);
|
||||
|
|
@ -188,7 +188,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
test('should set portrait safe area insets', () => {
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(PORTRAIT_INSETS.safeAreaInsets);
|
||||
|
|
@ -205,7 +205,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
test('should set portrait safe area insets from EphemeralStore', () => {
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
EphemeralStore.safeAreaInsets[PORTRAIT] = PORTRAIT_INSETS.safeAreaInsets;
|
||||
|
|
@ -221,7 +221,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
test('should set landscape safe area insets', () => {
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.state().safeAreaInsets).not.toEqual(LANDSCAPE_INSETS.safeAreaInsets);
|
||||
|
|
@ -238,7 +238,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
test('should set landscape safe area insets from EphemeralStore', () => {
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
|
||||
EphemeralStore.safeAreaInsets[LANDSCAPE] = LANDSCAPE_INSETS.safeAreaInsets;
|
||||
|
|
@ -258,7 +258,7 @@ describe('SafeAreaIos', () => {
|
|||
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
|
||||
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
|
||||
let wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
let instance = wrapper.instance();
|
||||
expect(addEventListener).toHaveBeenCalledWith('safeAreaInsetsForRootViewDidChange', instance.onSafeAreaInsetsForRootViewChange);
|
||||
|
|
@ -266,7 +266,7 @@ describe('SafeAreaIos', () => {
|
|||
|
||||
EphemeralStore.safeAreaInsets[PORTRAIT] = TEST_INSETS_1.safeAreaInsets;
|
||||
wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
instance = wrapper.instance();
|
||||
expect(addEventListener).toHaveBeenCalledWith('safeAreaInsetsForRootViewDidChange', instance.onSafeAreaInsetsForRootViewChange);
|
||||
|
|
@ -275,7 +275,7 @@ describe('SafeAreaIos', () => {
|
|||
EphemeralStore.safeAreaInsets[PORTRAIT] = TEST_INSETS_1.safeAreaInsets;
|
||||
EphemeralStore.safeAreaInsets[LANDSCAPE] = TEST_INSETS_1.safeAreaInsets;
|
||||
wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
instance = wrapper.instance();
|
||||
expect(addEventListener).not.toHaveBeenCalled();
|
||||
|
|
@ -285,7 +285,7 @@ describe('SafeAreaIos', () => {
|
|||
const removeEventListener = jest.spyOn(SafeArea, 'removeEventListener');
|
||||
|
||||
const wrapper = shallow(
|
||||
<SafeAreaIos {...baseProps}/>
|
||||
<SafeAreaIos {...baseProps}/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ export default class Search extends Component {
|
|||
toValue: (text.length > 0) ? 1 : 0,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
|
||||
if (this.props.onChangeText) {
|
||||
|
|
@ -228,7 +228,7 @@ export default class Search extends Component {
|
|||
toValue: 0,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
).start();
|
||||
this.focus();
|
||||
|
||||
|
|
@ -258,42 +258,42 @@ export default class Search extends Component {
|
|||
{
|
||||
toValue: this.contentWidth - 90,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.inputFocusAnimated,
|
||||
{
|
||||
toValue: this.state.leftComponentWidth,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.leftComponentAnimated,
|
||||
{
|
||||
toValue: this.contentWidth,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.btnCancelAnimated,
|
||||
{
|
||||
toValue: this.state.leftComponentWidth ? 15 - this.state.leftComponentWidth : 5,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.inputFocusPlaceholderAnimated,
|
||||
{
|
||||
toValue: this.props.placeholderExpandedMargin,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.iconSearchAnimated,
|
||||
{
|
||||
toValue: this.props.searchIconExpandedMargin,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.iconDeleteAnimated,
|
||||
|
|
@ -301,7 +301,7 @@ export default class Search extends Component {
|
|||
toValue: (this.props.value.length > 0) ? 1 : 0,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.shadowOpacityAnimated,
|
||||
|
|
@ -309,7 +309,7 @@ export default class Search extends Component {
|
|||
toValue: this.props.shadowOpacityExpanded,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
),
|
||||
]).start();
|
||||
this.shadowHeight = this.props.shadowOffsetHeightExpanded;
|
||||
|
|
@ -326,28 +326,28 @@ export default class Search extends Component {
|
|||
{
|
||||
toValue: this.contentWidth - this.state.leftComponentWidth - this.props.inputCollapsedMargin,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.inputFocusAnimated,
|
||||
{
|
||||
toValue: 0,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.leftComponentAnimated,
|
||||
{
|
||||
toValue: 0,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.btnCancelAnimated,
|
||||
{
|
||||
toValue: this.contentWidth,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
),
|
||||
((this.props.keyboardShouldPersist === false) ?
|
||||
Animated.timing(
|
||||
|
|
@ -355,7 +355,7 @@ export default class Search extends Component {
|
|||
{
|
||||
toValue: this.props.placeholderCollapsedMargin,
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
) : null),
|
||||
((this.props.keyboardShouldPersist === false || isForceAnim === true) ?
|
||||
Animated.timing(
|
||||
|
|
@ -363,7 +363,7 @@ export default class Search extends Component {
|
|||
{
|
||||
toValue: (this.props.searchIconCollapsedMargin + this.state.leftComponentWidth),
|
||||
duration: 200,
|
||||
}
|
||||
},
|
||||
) : null),
|
||||
Animated.timing(
|
||||
this.iconDeleteAnimated,
|
||||
|
|
@ -371,7 +371,7 @@ export default class Search extends Component {
|
|||
toValue: 0,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
),
|
||||
Animated.timing(
|
||||
this.shadowOpacityAnimated,
|
||||
|
|
@ -379,7 +379,7 @@ export default class Search extends Component {
|
|||
toValue: this.props.shadowOpacityCollapsed,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}
|
||||
},
|
||||
),
|
||||
]).start(({finished}) => this.props.onAnimationComplete(finished));
|
||||
this.shadowHeight = this.props.shadowOffsetHeightCollapsed;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe('SendButton', () => {
|
|||
<SendButton
|
||||
{...baseProps}
|
||||
{...props}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ describe('ShowMoreButton', () => {
|
|||
|
||||
test('should match, full snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<ShowMoreButton {...baseProps}/>
|
||||
<ShowMoreButton {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -28,7 +28,7 @@ describe('ShowMoreButton', () => {
|
|||
|
||||
test('should match, button snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<ShowMoreButton {...baseProps}/>
|
||||
<ShowMoreButton {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.instance().renderButton(true, {button: {}, sign: {}, text: {}})).toMatchSnapshot();
|
||||
|
|
@ -37,7 +37,7 @@ describe('ShowMoreButton', () => {
|
|||
|
||||
test('should LinearGradient exists', () => {
|
||||
const wrapper = shallow(
|
||||
<ShowMoreButton {...baseProps}/>
|
||||
<ShowMoreButton {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.find(LinearGradient).exists()).toBe(true);
|
||||
|
|
@ -51,7 +51,7 @@ describe('ShowMoreButton', () => {
|
|||
<ShowMoreButton
|
||||
{...baseProps}
|
||||
onPress={onPress}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
wrapper.find(TouchableWithFeedback).props().onPress();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const DEFAULT_SEARCH_ORDER = ['unreads', 'dms', 'channels', 'members', 'nonmembe
|
|||
|
||||
const pastDirectMessages = createSelector(
|
||||
getDirectShowPreferences,
|
||||
(directChannelsFromPreferences) => directChannelsFromPreferences.filter((d) => d.value === 'false').map((d) => d.name)
|
||||
(directChannelsFromPreferences) => directChannelsFromPreferences.filter((d) => d.value === 'false').map((d) => d.name),
|
||||
);
|
||||
|
||||
const getTeamProfiles = createSelector(
|
||||
|
|
@ -40,7 +40,7 @@ const getTeamProfiles = createSelector(
|
|||
|
||||
return memberProfiles;
|
||||
}, {});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Fill an object for each group channel with concatenated strings for username, email, fullname, and nickname
|
||||
|
|
@ -93,7 +93,7 @@ const getGroupChannelMemberDetails = createSelector(
|
|||
getUserIdsInChannels,
|
||||
getUsers,
|
||||
getGroupChannels,
|
||||
getGroupDetails
|
||||
getGroupDetails,
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ export default class ChannelSidebar extends Component {
|
|||
drawerOpened={this.state.drawerOpened}
|
||||
previewChannel={previewChannel}
|
||||
/>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe('MainSidebar', () => {
|
|||
|
||||
test('should match, full snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...baseProps}/>
|
||||
<MainSidebar {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -42,7 +42,7 @@ describe('MainSidebar', () => {
|
|||
|
||||
test('should not set the permanentSidebar state if not Tablet', () => {
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...baseProps}/>
|
||||
<MainSidebar {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.instance().handlePermanentSidebar();
|
||||
|
|
@ -51,7 +51,7 @@ describe('MainSidebar', () => {
|
|||
|
||||
test('should set the permanentSidebar state if Tablet', async () => {
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...baseProps}/>
|
||||
<MainSidebar {...baseProps}/>,
|
||||
);
|
||||
|
||||
DeviceTypes.IS_TABLET = true;
|
||||
|
|
@ -73,7 +73,7 @@ describe('MainSidebar', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...props}/>
|
||||
<MainSidebar {...props}/>,
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
|
|
@ -88,7 +88,7 @@ describe('MainSidebar', () => {
|
|||
Platform.OS = 'ios';
|
||||
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...baseProps}/>
|
||||
<MainSidebar {...baseProps}/>,
|
||||
);
|
||||
const drawer = wrapper.dive().childAt(1);
|
||||
const drawerStyle = drawer.props().style.reduce((acc, obj) => ({...acc, ...obj}));
|
||||
|
|
@ -99,7 +99,7 @@ describe('MainSidebar', () => {
|
|||
Platform.OS = 'android';
|
||||
|
||||
const wrapper = shallow(
|
||||
<MainSidebar {...baseProps}/>
|
||||
<MainSidebar {...baseProps}/>,
|
||||
);
|
||||
const drawer = wrapper.dive().childAt(1);
|
||||
const drawerStyle = drawer.props().style.reduce((acc, obj) => ({...acc, ...obj}));
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ export default class SettingsDrawer extends PureComponent {
|
|||
this.openModal(
|
||||
'EditProfile',
|
||||
formatMessage({id: 'mobile.routes.edit_profile', defaultMessage: 'Edit Profile'}),
|
||||
{currentUser, commandType}
|
||||
{currentUser, commandType},
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -207,7 +207,7 @@ export default class SettingsDrawer extends PureComponent {
|
|||
this.openModal(
|
||||
'UserProfile',
|
||||
formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'}),
|
||||
{userId, fromSettings: true}
|
||||
{userId, fromSettings: true},
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -111,13 +111,13 @@ export default class SlideUpPanel extends PureComponent {
|
|||
|
||||
this.reverseLastScrollY = Animated.multiply(
|
||||
new Animated.Value(-1),
|
||||
this.lastScrollY
|
||||
this.lastScrollY,
|
||||
);
|
||||
|
||||
this.translateYOffset = new Animated.Value(containerHeight);
|
||||
this.translateY = Animated.add(
|
||||
this.translateYOffset,
|
||||
Animated.add(this.dragY, this.reverseLastScrollY)
|
||||
Animated.add(this.dragY, this.reverseLastScrollY),
|
||||
).interpolate({
|
||||
inputRange: [marginFromTop, containerHeight],
|
||||
outputRange: [marginFromTop, containerHeight],
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ describe('SlideUpPanelIndicator', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<SlideUpPanelIndicator {...baseProps}/>
|
||||
<SlideUpPanelIndicator {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class ArchiveIcon extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 14 14'
|
||||
>
|
||||
<Path
|
||||
d='M8.5 6.5q0-0.203-0.148-0.352t-0.352-0.148h-2q-0.203 0-0.352 0.148t-0.148 0.352 0.148 0.352 0.352 0.148h2q0.203 0 0.352-0.148t0.148-0.352zM13 5v7.5q0 0.203-0.148 0.352t-0.352 0.148h-11q-0.203 0-0.352-0.148t-0.148-0.352v-7.5q0-0.203 0.148-0.352t0.352-0.148h11q0.203 0 0.352 0.148t0.148 0.352zM13.5 1.5v2q0 0.203-0.148 0.352t-0.352 0.148h-12q-0.203 0-0.352-0.148t-0.148-0.352v-2q0-0.203 0.148-0.352t0.352-0.148h12q0.203 0 0.352 0.148t0.148 0.352z'
|
||||
fill={color}
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Circle,
|
||||
G,
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class AwayAvatar extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 12 12'
|
||||
>
|
||||
<G transform='matrix(1,0,0,1,299,-391)'>
|
||||
<Circle
|
||||
cx='-294.5'
|
||||
cy='394'
|
||||
r='2.5'
|
||||
fill={color}
|
||||
/>
|
||||
<Path
|
||||
d='M-294.3,399.7C-294.3,399.3 -294.2,398.9 -294.1,398.5C-294.2,398.5 -294.3,398.5 -294.5,398.5C-297,398.5 -297,396.5 -297,396.5C-297,396.5 -298,396.6 -298.2,397C-298.6,397.6 -298.8,398.7 -298.9,399.5C-298.9,399.6 -299,400 -298.9,400.1C-298.7,401.4 -296.7,402.4 -294.5,402.5L-294.3,402.5C-294,402.5 -293.6,402.5 -293.3,402.4C-293.9,401.6 -294.3,400.7 -294.3,399.7Z'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
<Path
|
||||
d='M8.415,5C8.614,5 8.775,5.161 8.775,5.36L8.775,8.352L11.49,10.334C11.651,10.451 11.686,10.677 11.569,10.837L10.932,11.709C10.814,11.87 10.589,11.905 10.429,11.788L7.261,9.475C7.243,9.463 7.226,9.451 7.21,9.437L7.123,9.374C7.009,9.291 6.959,9.154 6.98,9.024C6.977,8.999 6.975,8.973 6.975,8.946L6.975,5.36C6.975,5.161 7.137,5 7.335,5L8.415,5Z'
|
||||
fill={color}
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class AwayIcon extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<Path
|
||||
d='M10,0C15.519,0 20,4.481 20,10C20,15.519 15.519,20 10,20C4.481,20 0,15.519 0,10C0,4.481 4.481,0 10,0ZM10.27,3C10.949,3 11.5,3.586 11.5,4.307L11.5,9.379L15.002,12.881C15.492,13.37 15.499,14.158 15.019,14.638L14.638,15.019C14.158,15.499 13.37,15.492 12.881,15.002L8.887,11.008C8.739,10.861 8.636,10.686 8.576,10.501C8.528,10.402 8.5,10.299 8.5,10.193L8.5,4.307C8.5,3.586 9.051,3 9.73,3L10.27,3Z'
|
||||
fill={color}
|
||||
fillRule='evenodd'
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Ellipse,
|
||||
G,
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class DndAvatar extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='-299 391 12 12'
|
||||
>
|
||||
<G>
|
||||
<Ellipse
|
||||
cx='-294.6'
|
||||
cy='394'
|
||||
rx='2.5'
|
||||
ry='2.5'
|
||||
fill={color}
|
||||
/>
|
||||
<Path
|
||||
d='M-293.8,399.4c0-0.4,0.1-0.7,0.2-1c-0.3,0.1-0.6,0.2-1,0.2c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0.7,0,1.4-0.1,2-0.3 C-293.3,401.5-293.8,400.5-293.8,399.4z'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
<Path
|
||||
d='M-287,400c0,0.1-0.1,0.1-0.1,0.1l-4.9,0c-0.1,0-0.1-0.1-0.1-0.1v-1.6c0-0.1,0.1-0.1,0.1-0.1l4.9,0c0.1,0,0.1,0.1,0.1,0.1 V400z'
|
||||
fill={color}
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
export default class DndIcon extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<Path
|
||||
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm5.25,8.5l-10.5,0c-0.414,0 -0.75,0.336 -0.75,0.75l0,1.5c0,0.414 0.336,0.75 0.75,0.75l10.5,0c0.414,0 0.75,-0.336 0.75,-0.75l0,-1.5c0,-0.414 -0.336,-0.75 -0.75,-0.75Z'
|
||||
fill={color}
|
||||
fillRule='evenodd'
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ArchiveIcon from './archive_icon';
|
||||
import AwayAvatar from './away_avatar';
|
||||
import AwayIcon from './away_icon';
|
||||
import DndAvatar from './dnd_avatar';
|
||||
import DndIcon from './dnd_icon';
|
||||
import OfflineAvatar from './offline_avatar';
|
||||
import OfflineIcon from './offline_icon';
|
||||
import OnlineAvatar from './online_avatar';
|
||||
import OnlineIcon from './online_icon';
|
||||
|
||||
export {
|
||||
ArchiveIcon,
|
||||
AwayAvatar,
|
||||
AwayIcon,
|
||||
DndAvatar,
|
||||
DndIcon,
|
||||
OfflineAvatar,
|
||||
OfflineIcon,
|
||||
OnlineAvatar,
|
||||
OnlineIcon,
|
||||
};
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Ellipse,
|
||||
G,
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class OfflineStatus extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='-299 391 12 12'
|
||||
>
|
||||
<G>
|
||||
<G>
|
||||
<Ellipse
|
||||
cx='-294.5'
|
||||
cy='394'
|
||||
rx='2.5'
|
||||
ry='2.5'
|
||||
fill={color}
|
||||
/>
|
||||
<Path
|
||||
d='M-294.3,399.7c0-0.4,0.1-0.8,0.2-1.2c-0.1,0-0.2,0-0.4,0c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4h0.1h0.1c0.3,0,0.7,0,1-0.1C-293.9,401.6-294.3,400.7-294.3,399.7z'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
</G>
|
||||
<G>
|
||||
<Path
|
||||
d='M-288.9,399.4l1.8-1.8c0.1-0.1,0.1-0.3,0-0.3l-0.7-0.7c-0.1-0.1-0.3-0.1-0.3,0l-1.8,1.8l-1.8-1.8c-0.1-0.1-0.3-0.1-0.3,0 l-0.7,0.7c-0.1,0.1-0.1,0.3,0,0.3l1.8,1.8l-1.8,1.8c-0.1,0.1-0.1,0.3,0,0.3l0.7,0.7c0.1,0.1,0.3,0.1,0.3,0l1.8-1.8l1.8,1.8 c0.1,0.1,0.3,0.1,0.3,0l0.7-0.7c0.1-0.1,0.1-0.3,0-0.3L-288.9,399.4z'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class OfflineIcon extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<Path
|
||||
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm0,2c4.415,0 8,3.585 8,8c0,4.415 -3.585,8 -8,8c-4.415,0 -8,-3.585 -8,-8c0,-4.415 3.585,-8 8,-8Z'
|
||||
fill={color}
|
||||
fillOpacity={0.5}
|
||||
fillRule='evenodd'
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Ellipse,
|
||||
G,
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class OnlineStatus extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='-243 245 12 12'
|
||||
>
|
||||
<G>
|
||||
<Path
|
||||
d='M-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5z'
|
||||
fill={color}
|
||||
/>
|
||||
<Ellipse
|
||||
cx='-238.5'
|
||||
cy='248'
|
||||
rx='2.5'
|
||||
ry='2.5'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
<Path
|
||||
d='M-238.9,253.8c0-0.4,0.1-0.9,0.2-1.3c-2.2-0.2-2.2-2-2.2-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5c0,0.1-0.1,0.5,0,0.6 c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0C-238.7,255.7-238.9,254.8-238.9,253.8z'
|
||||
fill={color}
|
||||
/>
|
||||
<G>
|
||||
<G>
|
||||
<Path
|
||||
d='M-232.3,250.1l1.3,1.3c0,0,0,0.1,0,0.1l-4.1,4.1c0,0,0,0-0.1,0c0,0,0,0,0,0l-2.7-2.7c0,0,0-0.1,0-0.1l1.2-1.2 c0,0,0.1,0,0.1,0l1.4,1.4l2.9-2.9C-232.4,250.1-232.3,250.1-232.3,250.1z'
|
||||
fill={color}
|
||||
/>
|
||||
</G>
|
||||
</G>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
import Svg, {
|
||||
Path,
|
||||
} from 'react-native-svg';
|
||||
|
||||
export default class OnlineIcon extends PureComponent {
|
||||
static propTypes = {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {color, height, width} = this.props;
|
||||
return (
|
||||
<View style={{height, width, alignItems: 'flex-start'}}>
|
||||
<Svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<Path
|
||||
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm6.19,7.18c0,0.208 -0.075,0.384 -0.224,0.53l-5.782,5.64l-1.087,1.059c-0.149,0.146 -0.33,0.218 -0.543,0.218c-0.213,0 -0.394,-0.072 -0.543,-0.218l-1.086,-1.059l-2.891,-2.82c-0.149,-0.146 -0.224,-0.322 -0.224,-0.53c0,-0.208 0.075,-0.384 0.224,-0.53l1.086,-1.059c0.149,-0.146 0.33,-0.218 0.543,-0.218c0.213,0 0.394,0.072 0.543,0.218l2.348,2.298l5.24,-5.118c0.149,-0.146 0.33,-0.218 0.543,-0.218c0.213,0 0.394,0.072 0.543,0.218l1.086,1.059c0.149,0.146 0.224,0.322 0.224,0.53Z'
|
||||
fill={color}
|
||||
fillRule='evenodd'
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ describe('UserStatus', () => {
|
|||
|
||||
test('should match snapshot, should default to offline status', () => {
|
||||
const wrapper = shallow(
|
||||
<UserStatus {...baseProps}/>
|
||||
<UserStatus {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -28,7 +28,7 @@ describe('UserStatus', () => {
|
|||
<UserStatus
|
||||
{...baseProps}
|
||||
status={General.AWAY}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -39,7 +39,7 @@ describe('UserStatus', () => {
|
|||
<UserStatus
|
||||
{...baseProps}
|
||||
status={General.DND}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -50,7 +50,7 @@ describe('UserStatus', () => {
|
|||
<UserStatus
|
||||
{...baseProps}
|
||||
status={General.ONLINE}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import icoMoonConfig from 'assets/mattermost-fonts.json';
|
|||
const Mattermost = createIconSetFromIcoMoon(
|
||||
icoMoonConfig,
|
||||
'Mattermost',
|
||||
'Mattermost-Regular.otf'
|
||||
'Mattermost-Regular.otf',
|
||||
);
|
||||
|
||||
export default class VectorIcon extends PureComponent {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe('components/widgets/settings/TextSetting', () => {
|
|||
theme={theme}
|
||||
onChange={onChange}
|
||||
isLandscape={false}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
wrapper.instance().handleChange(false);
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ export default class RadioSetting extends PureComponent {
|
|||
{this.renderCheckMark(value, style.checkMark)}
|
||||
</View>
|
||||
{this.renderRowSeparator(i, style.separator)}
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>,
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ describe('components/widgets/settings/RadioSetting', () => {
|
|||
default={'Administration'}
|
||||
onChange={onChange}
|
||||
theme={theme}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
wrapper.find(TouchableOpacity).at(1).props().onPress();
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ describe('components/widgets/settings/RadioSetting', () => {
|
|||
default={'Administration'}
|
||||
onChange={onChange}
|
||||
theme={theme}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -61,7 +61,7 @@ describe('components/widgets/settings/RadioSetting', () => {
|
|||
default={'invalid-option-value'}
|
||||
onChange={onChange}
|
||||
theme={theme}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.find(CheckMark)).toHaveLength(0);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ describe('components/widgets/settings/TextSetting', () => {
|
|||
value='some value'
|
||||
onChange={onChange}
|
||||
theme={theme}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
wrapper.instance().onChangeText('somenewvalue');
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import DeepLinkTypes from './deep_linking';
|
|||
import DeviceTypes from './device';
|
||||
import ListTypes from './list';
|
||||
import NavigationTypes from './navigation';
|
||||
import PermissionTypes from './permissions';
|
||||
import ViewTypes, {UpgradeTypes} from './view';
|
||||
|
||||
export {
|
||||
|
|
@ -13,7 +12,6 @@ export {
|
|||
DeviceTypes,
|
||||
ListTypes,
|
||||
NavigationTypes,
|
||||
PermissionTypes,
|
||||
UpgradeTypes,
|
||||
ViewTypes,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export default {
|
||||
AUTHORIZED: 'authorized',
|
||||
DENIED: 'denied',
|
||||
UNDETERMINED: 'undetermined',
|
||||
};
|
||||
|
|
@ -48,7 +48,7 @@ class EMMProvider {
|
|||
mattermostManaged.quitApp();
|
||||
},
|
||||
}],
|
||||
{cancelable: false}
|
||||
{cancelable: false},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class GlobalEventHandler {
|
|||
StatusBarManager.getHeight(
|
||||
(data) => {
|
||||
this.onStatusBarHeightChange(data.height);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ class GlobalEventHandler {
|
|||
StatusBarManager.getHeight(
|
||||
(data) => {
|
||||
this.onStatusBarHeightChange(data.height);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +239,7 @@ class GlobalEventHandler {
|
|||
text: translations[t('mobile.server_upgrade.button')],
|
||||
onPress: this.serverUpgradeNeeded,
|
||||
}],
|
||||
{cancelable: false}
|
||||
{cancelable: false},
|
||||
);
|
||||
} else if (state.entities.users && state.entities.users.currentUserId) {
|
||||
dispatch(setServerVersion(serverVersion));
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default {
|
|||
let granted;
|
||||
if (!hasPermission) {
|
||||
granted = await PermissionsAndroid.request(
|
||||
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE
|
||||
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ describe('Reducers.channel', () => {
|
|||
lastChannelViewTime: {},
|
||||
keepChannelIdAsUnread: null,
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
expect(nextState).toEqual(initialState);
|
||||
|
|
@ -66,7 +66,7 @@ describe('Reducers.channel', () => {
|
|||
type: ViewTypes.INCREASE_POST_VISIBILITY,
|
||||
data: channelId,
|
||||
amount,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
expect(nextState).toEqual({
|
||||
|
|
@ -101,7 +101,7 @@ describe('Reducers.channel', () => {
|
|||
type: ViewTypes.INCREASE_POST_VISIBILITY,
|
||||
data: channelId,
|
||||
amount,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
expect(nextState).toEqual({
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ describe('ChannelDrawerButton', () => {
|
|||
|
||||
test('should match, full snapshot', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelDrawerButton {...baseProps}/>
|
||||
<ChannelDrawerButton {...baseProps}/>,
|
||||
);
|
||||
|
||||
// no badge to show
|
||||
|
|
@ -70,7 +70,7 @@ describe('ChannelDrawerButton', () => {
|
|||
};
|
||||
|
||||
shallowWithIntl(
|
||||
<ChannelDrawerButton {...props}/>
|
||||
<ChannelDrawerButton {...props}/>,
|
||||
);
|
||||
expect(setApplicationIconBadgeNumber).not.toBeCalled();
|
||||
NotificationsIOS.getBadgesCount((count) => expect(count).toBe(0));
|
||||
|
|
@ -84,7 +84,7 @@ describe('ChannelDrawerButton', () => {
|
|||
};
|
||||
|
||||
shallowWithIntl(
|
||||
<ChannelDrawerButton {...props}/>
|
||||
<ChannelDrawerButton {...props}/>,
|
||||
);
|
||||
expect(setApplicationIconBadgeNumber).toHaveBeenCalledTimes(1);
|
||||
NotificationsIOS.getBadgesCount((count) => expect(count).toBe(1));
|
||||
|
|
@ -98,7 +98,7 @@ describe('ChannelDrawerButton', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelDrawerButton {...props}/>
|
||||
<ChannelDrawerButton {...props}/>,
|
||||
);
|
||||
NotificationsIOS.getBadgesCount((count) => expect(count).toBe(0));
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ describe('ChannelDrawerButton', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelDrawerButton {...props}/>
|
||||
<ChannelDrawerButton {...props}/>,
|
||||
);
|
||||
wrapper.setProps({badgeCount: 2});
|
||||
expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(2);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('ChannelNavBar', () => {
|
|||
|
||||
test('should match, full snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelNavBar {...baseProps}/>
|
||||
<ChannelNavBar {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -31,7 +31,7 @@ describe('ChannelNavBar', () => {
|
|||
|
||||
test('should not set the permanentSidebar state if not Tablet', () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelNavBar {...baseProps}/>
|
||||
<ChannelNavBar {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.instance().handlePermanentSidebar();
|
||||
|
|
@ -40,7 +40,7 @@ describe('ChannelNavBar', () => {
|
|||
|
||||
test('should set the permanentSidebar state if Tablet', async () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelNavBar {...baseProps}/>
|
||||
<ChannelNavBar {...baseProps}/>,
|
||||
);
|
||||
|
||||
DeviceTypes.IS_TABLET = true;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ describe('ChannelTitle', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelTitle {...baseProps}/>
|
||||
<ChannelTitle {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ export default class ChannelPostList extends PureComponent {
|
|||
this.isLoadingMoreTop = true;
|
||||
actions.increasePostVisibility(
|
||||
channelId,
|
||||
this.state.visiblePostIds[this.state.visiblePostIds.length - 1]
|
||||
this.state.visiblePostIds[this.state.visiblePostIds.length - 1],
|
||||
).then((hasMore) => {
|
||||
this.isLoadingMoreTop = !hasMore;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('ChannelPostList', () => {
|
|||
|
||||
test('should call increasePostVisibilityByOne', () => {
|
||||
shallow(
|
||||
<ChannelPostList {...baseProps}/>
|
||||
<ChannelPostList {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(baseProps.actions.increasePostVisibilityByOne).toHaveBeenCalledTimes(0);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
currentChannelId,
|
||||
currentChannelGroupConstrained,
|
||||
this.page + 1,
|
||||
General.PROFILE_CHUNK_SIZE
|
||||
General.PROFILE_CHUNK_SIZE,
|
||||
).then(this.onProfilesLoaded);
|
||||
});
|
||||
}
|
||||
|
|
@ -164,7 +164,7 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
formatMessage({
|
||||
id: 'mobile.channel_members.add_members_alert',
|
||||
defaultMessage: 'You must select at least one member to add to the channel.',
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
}, {
|
||||
text: formatMessage({id: 'mobile.terms_of_service.alert_retry', defaultMessage: 'Try Again'}),
|
||||
onPress: this.handleConfirmConvertToPrivate,
|
||||
}]
|
||||
}],
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
|
|
@ -272,7 +272,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
},
|
||||
{
|
||||
displayName: channel.display_name.trim(),
|
||||
}
|
||||
},
|
||||
);
|
||||
if (result.error.server_error_id === 'api.channel.delete_channel.deleted.app_error') {
|
||||
this.props.actions.getChannel(channel.id);
|
||||
|
|
@ -294,7 +294,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
{
|
||||
term: term.toLowerCase(),
|
||||
name: channel.display_name.trim(),
|
||||
}
|
||||
},
|
||||
),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
const {header} = this.props;
|
||||
this.handleLongPress(
|
||||
header,
|
||||
formatMessage({id: 'mobile.channel_info.copy_header', defaultMessage: 'Copy Header'})
|
||||
formatMessage({id: 'mobile.channel_info.copy_header', defaultMessage: 'Copy Header'}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
const {purpose} = this.props;
|
||||
this.handleLongPress(
|
||||
purpose,
|
||||
formatMessage({id: 'mobile.channel_info.copy_purpose', defaultMessage: 'Copy Purpose'})
|
||||
formatMessage({id: 'mobile.channel_info.copy_purpose', defaultMessage: 'Copy Purpose'}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ export default class ChannelMembers extends PureComponent {
|
|||
actions.getProfilesInChannel(
|
||||
currentChannelId,
|
||||
this.page + 1,
|
||||
General.PROFILE_CHUNK_SIZE
|
||||
General.PROFILE_CHUNK_SIZE,
|
||||
).then(this.loadedProfiles);
|
||||
});
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ export default class ChannelMembers extends PureComponent {
|
|||
formatMessage({
|
||||
id: 'mobile.routes.channel_members.action_message',
|
||||
defaultMessage: 'You must select at least one member to remove from the channel.',
|
||||
})
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ export default class ChannelMembers extends PureComponent {
|
|||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_list.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: () => this.removeMembers(membersToRemove),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export default class ClientUpgrade extends PureComponent {
|
|||
intl.formatMessage({
|
||||
id: 'mobile.client_upgrade.download_error.message',
|
||||
defaultMessage: 'An error occurred while trying to open the download link.',
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -212,12 +212,12 @@ export default class EditChannel extends PureComponent {
|
|||
} else if (displayName.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
|
||||
return {error: formatMessage(
|
||||
messages.display_name_maxLength,
|
||||
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH}
|
||||
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH},
|
||||
)};
|
||||
} else if (displayName.length < ViewTypes.MIN_CHANNELNAME_LENGTH) {
|
||||
return {error: formatMessage(
|
||||
messages.display_name_minLength,
|
||||
{minLength: ViewTypes.MIN_CHANNELNAME_LENGTH}
|
||||
{minLength: ViewTypes.MIN_CHANNELNAME_LENGTH},
|
||||
)};
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ export default class EditChannel extends PureComponent {
|
|||
} else if (channelURL.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
|
||||
return {error: formatMessage(
|
||||
messages.name_maxLength,
|
||||
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH}
|
||||
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH},
|
||||
)};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('ErrorTeamsList', () => {
|
|||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<ErrorTeamsList {...baseProps}/>
|
||||
<ErrorTeamsList {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
@ -52,7 +52,7 @@ describe('ErrorTeamsList', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<ErrorTeamsList {...newProps}/>
|
||||
<ErrorTeamsList {...newProps}/>,
|
||||
);
|
||||
|
||||
wrapper.find(FailedNetworkAction).props().onRetry();
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export default class Downloader extends PureComponent {
|
|||
defaultMessage: 'OK',
|
||||
}),
|
||||
onPress: () => this.downloadDidCancel(),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|||
|
||||
import FileAttachmentDocument from 'app/components/file_attachment_list/file_attachment_document';
|
||||
import FileAttachmentIcon from 'app/components/file_attachment_list/file_attachment_icon';
|
||||
import {DeviceTypes, NavigationTypes, PermissionTypes} from 'app/constants';
|
||||
import {DeviceTypes, NavigationTypes} from 'app/constants';
|
||||
import {getLocalFilePathFromFile, isDocument, isVideo} from 'app/utils/file';
|
||||
import {emptyFunction} from 'app/utils/general';
|
||||
import {calculateDimensions} from 'app/utils/images';
|
||||
|
|
@ -475,24 +475,21 @@ export default class ImagePreview extends PureComponent {
|
|||
const actions = [];
|
||||
let permissionRequest;
|
||||
|
||||
const hasPermissionToStorage = await Permissions.check('photo');
|
||||
const photo = Permissions.PERMISSIONS.IOS.PHOTO_LIBRARY;
|
||||
const hasPermissionToStorage = await Permissions.check(photo);
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
permissionRequest = await Permissions.request('photo');
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
case Permissions.RESULTS.DENIED:
|
||||
permissionRequest = await Permissions.request(photo);
|
||||
if (permissionRequest !== Permissions.RESULTS.GRANTED) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
const canOpenSettings = await Permissions.canOpenSettings();
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
grantOption = {
|
||||
text: formatMessage({id: 'mobile.permission_denied_retry', defaultMessage: 'Settings'}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
}
|
||||
case Permissions.RESULTS.BLOCKED: {
|
||||
const grantOption = {
|
||||
text: formatMessage({id: 'mobile.permission_denied_retry', defaultMessage: 'Settings'}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
|
||||
const applicationName = DeviceInfo.getApplicationName();
|
||||
Alert.alert(
|
||||
|
|
@ -507,7 +504,7 @@ export default class ImagePreview extends PureComponent {
|
|||
[
|
||||
grantOption,
|
||||
{text: formatMessage({id: 'mobile.permission_denied_dismiss', defaultMessage: 'Don\'t Allow'})},
|
||||
]
|
||||
],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -568,7 +565,7 @@ export default class ImagePreview extends PureComponent {
|
|||
id: 'mobile.server_upgrade.button',
|
||||
defaultMessage: 'OK',
|
||||
}),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import {TouchableOpacity} from 'react-native';
|
||||
|
||||
// import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
import * as NavigationActions from 'app/actions/navigation';
|
||||
import BottomSheet from 'app/utils/bottom_sheet';
|
||||
|
||||
// import BottomSheet from 'app/utils/bottom_sheet';
|
||||
|
||||
import ImagePreview from './image_preview';
|
||||
|
||||
|
|
@ -22,11 +22,12 @@ jest.mock('react-native-doc-viewer', () => {
|
|||
OpenFile: jest.fn(),
|
||||
};
|
||||
});
|
||||
jest.mock('react-native-permissions', () => {
|
||||
return {
|
||||
check: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
// jest.mock('react-native-permissions', () => {
|
||||
// return {
|
||||
// check: jest.fn(),
|
||||
// };
|
||||
// });
|
||||
|
||||
describe('ImagePreview', () => {
|
||||
const baseProps = {
|
||||
|
|
@ -116,110 +117,110 @@ describe('ImagePreview', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('should show bottom sheet when showDownloadOptionsIOS is called for existing video', async () => {
|
||||
BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
RNFetchBlob.fs.exists = jest.fn().mockReturnValue(true);
|
||||
const formatMessage = jest.fn(({defaultMessage}) => {
|
||||
return defaultMessage;
|
||||
});
|
||||
// test('should show bottom sheet when showDownloadOptionsIOS is called for existing video', async () => {
|
||||
// BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
// RNFetchBlob.fs.exists = jest.fn().mockReturnValue(true);
|
||||
// const formatMessage = jest.fn(({defaultMessage}) => {
|
||||
// return defaultMessage;
|
||||
// });
|
||||
|
||||
const index = 0;
|
||||
const files = [{
|
||||
caption: 'caption',
|
||||
data: {
|
||||
mime_type: 'video/mp4',
|
||||
},
|
||||
}];
|
||||
const props = {
|
||||
...baseProps,
|
||||
index,
|
||||
files,
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<ImagePreview
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: {formatMessage}}},
|
||||
);
|
||||
// const index = 0;
|
||||
// const files = [{
|
||||
// caption: 'caption',
|
||||
// data: {
|
||||
// mime_type: 'video/mp4',
|
||||
// },
|
||||
// }];
|
||||
// const props = {
|
||||
// ...baseProps,
|
||||
// index,
|
||||
// files,
|
||||
// };
|
||||
// const wrapper = shallow(
|
||||
// <ImagePreview
|
||||
// {...props}
|
||||
// />,
|
||||
// {context: {intl: {formatMessage}}},
|
||||
// );
|
||||
|
||||
const instance = wrapper.instance();
|
||||
await instance.showDownloadOptionsIOS();
|
||||
// const instance = wrapper.instance();
|
||||
// await instance.showDownloadOptionsIOS();
|
||||
|
||||
const expectedOptions = {
|
||||
options: ['Save Video', 'Cancel'],
|
||||
cancelButtonIndex: 1,
|
||||
anchor: null,
|
||||
title: files[index].caption,
|
||||
};
|
||||
expect(BottomSheet.showBottomSheetWithOptions).
|
||||
toHaveBeenCalledWith(expectedOptions, expect.any(Function));
|
||||
});
|
||||
// const expectedOptions = {
|
||||
// options: ['Save Video', 'Cancel'],
|
||||
// cancelButtonIndex: 1,
|
||||
// anchor: null,
|
||||
// title: files[index].caption,
|
||||
// };
|
||||
// expect(BottomSheet.showBottomSheetWithOptions).
|
||||
// toHaveBeenCalledWith(expectedOptions, expect.any(Function));
|
||||
// });
|
||||
|
||||
test('should not show bottom sheet when showDownloadOptionsIOS is called for non-existing video', async () => {
|
||||
BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
RNFetchBlob.fs.exists = jest.fn().mockReturnValue(false);
|
||||
// test('should not show bottom sheet when showDownloadOptionsIOS is called for non-existing video', async () => {
|
||||
// BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
// RNFetchBlob.fs.exists = jest.fn().mockReturnValue(false);
|
||||
|
||||
const index = 0;
|
||||
const files = [{
|
||||
caption: 'caption',
|
||||
data: {
|
||||
mime_type: 'video/mp4',
|
||||
},
|
||||
}];
|
||||
const props = {
|
||||
...baseProps,
|
||||
index,
|
||||
files,
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<ImagePreview
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
// const index = 0;
|
||||
// const files = [{
|
||||
// caption: 'caption',
|
||||
// data: {
|
||||
// mime_type: 'video/mp4',
|
||||
// },
|
||||
// }];
|
||||
// const props = {
|
||||
// ...baseProps,
|
||||
// index,
|
||||
// files,
|
||||
// };
|
||||
// const wrapper = shallow(
|
||||
// <ImagePreview
|
||||
// {...props}
|
||||
// />,
|
||||
// {context: {intl: {formatMessage: jest.fn()}}},
|
||||
// );
|
||||
|
||||
const instance = wrapper.instance();
|
||||
await instance.showDownloadOptionsIOS();
|
||||
// const instance = wrapper.instance();
|
||||
// await instance.showDownloadOptionsIOS();
|
||||
|
||||
expect(BottomSheet.showBottomSheetWithOptions).not.toHaveBeenCalled();
|
||||
});
|
||||
// expect(BottomSheet.showBottomSheetWithOptions).not.toHaveBeenCalled();
|
||||
// });
|
||||
|
||||
test('should show bottom sheet when showDownloadOptionsIOS is called for image', async () => {
|
||||
BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
RNFetchBlob.fs.exists = jest.fn().mockReturnValue(true);
|
||||
const formatMessage = jest.fn(({defaultMessage}) => {
|
||||
return defaultMessage;
|
||||
});
|
||||
// test('should show bottom sheet when showDownloadOptionsIOS is called for image', async () => {
|
||||
// BottomSheet.showBottomSheetWithOptions = jest.fn();
|
||||
// RNFetchBlob.fs.exists = jest.fn().mockReturnValue(true);
|
||||
// const formatMessage = jest.fn(({defaultMessage}) => {
|
||||
// return defaultMessage;
|
||||
// });
|
||||
|
||||
const index = 0;
|
||||
const files = [{
|
||||
caption: 'caption',
|
||||
data: {
|
||||
mime_type: 'image/jpeg',
|
||||
},
|
||||
}];
|
||||
const props = {
|
||||
...baseProps,
|
||||
index,
|
||||
files,
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<ImagePreview
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: {formatMessage}}},
|
||||
);
|
||||
// const index = 0;
|
||||
// const files = [{
|
||||
// caption: 'caption',
|
||||
// data: {
|
||||
// mime_type: 'image/jpeg',
|
||||
// },
|
||||
// }];
|
||||
// const props = {
|
||||
// ...baseProps,
|
||||
// index,
|
||||
// files,
|
||||
// };
|
||||
// const wrapper = shallow(
|
||||
// <ImagePreview
|
||||
// {...props}
|
||||
// />,
|
||||
// {context: {intl: {formatMessage}}},
|
||||
// );
|
||||
|
||||
const instance = wrapper.instance();
|
||||
await instance.showDownloadOptionsIOS();
|
||||
// const instance = wrapper.instance();
|
||||
// await instance.showDownloadOptionsIOS();
|
||||
|
||||
const expectedOptions = {
|
||||
options: ['Save Image', 'Cancel'],
|
||||
cancelButtonIndex: 1,
|
||||
anchor: null,
|
||||
title: files[index].caption,
|
||||
};
|
||||
expect(BottomSheet.showBottomSheetWithOptions).
|
||||
toHaveBeenCalledWith(expectedOptions, expect.any(Function));
|
||||
});
|
||||
// const expectedOptions = {
|
||||
// options: ['Save Image', 'Cancel'],
|
||||
// cancelButtonIndex: 1,
|
||||
// anchor: null,
|
||||
// title: files[index].caption,
|
||||
// };
|
||||
// expect(BottomSheet.showBottomSheetWithOptions).
|
||||
// toHaveBeenCalledWith(expectedOptions, expect.any(Function));
|
||||
// });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ export default class VideoPreview extends PureComponent {
|
|||
id: 'mobile.server_upgrade.button',
|
||||
defaultMessage: 'OK',
|
||||
}),
|
||||
}]
|
||||
}],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('DialogElement', () => {
|
|||
{...baseDialogProps}
|
||||
theme={theme}
|
||||
subtype='password'
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find({secureTextEntry: true}).exists()).toBe(true);
|
||||
expect(wrapper.find({multiline: false}).exists()).toBe(true);
|
||||
|
|
@ -35,7 +35,7 @@ describe('DialogElement', () => {
|
|||
{...baseDialogProps}
|
||||
theme={theme}
|
||||
subtype='email'
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find({secureTextEntry: false}).exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -54,7 +54,7 @@ describe('DialogElement', () => {
|
|||
type='radio'
|
||||
options={radioOptions}
|
||||
value={radioOptions[1].value}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find(RadioSetting).find({options: radioOptions, default: radioOptions[1].value}).exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -68,7 +68,7 @@ describe('DialogElement', () => {
|
|||
theme={theme}
|
||||
type='bool'
|
||||
value={false}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find(BoolSetting).find({value: false}).exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -80,7 +80,7 @@ describe('DialogElement', () => {
|
|||
theme={theme}
|
||||
type='bool'
|
||||
value={true}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find(BoolSetting).find({value: true}).exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -92,7 +92,7 @@ describe('DialogElement', () => {
|
|||
theme={theme}
|
||||
type='bool'
|
||||
value={null}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find(BoolSetting).find({value: false}).exists()).toBe(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ describe('DialogIntroductionText', () => {
|
|||
const wrapper = shallow(
|
||||
<DialogIntroductionText
|
||||
{...baseProps}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
@ -31,7 +31,7 @@ describe('DialogIntroductionText', () => {
|
|||
const wrapper = shallow(
|
||||
<DialogIntroductionText
|
||||
{...baseProps}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ describe('InteractiveDialog', () => {
|
|||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialog {...props}/>
|
||||
<InteractiveDialog {...props}/>,
|
||||
);
|
||||
wrapper.instance().scrollView = {current: {scrollTo: jest.fn()}};
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ describe('InteractiveDialog', () => {
|
|||
|
||||
test('should show no error when submit does not return an error', async () => {
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialog {...baseProps}/>
|
||||
<InteractiveDialog {...baseProps}/>,
|
||||
);
|
||||
wrapper.instance().scrollView = {current: {scrollTo: jest.fn()}};
|
||||
|
||||
|
|
@ -214,9 +214,7 @@ describe('InteractiveDialog', () => {
|
|||
element.default = testCase.default;
|
||||
}
|
||||
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialog {...props}/>
|
||||
);
|
||||
const wrapper = shallow(<InteractiveDialog {...props}/>);
|
||||
wrapper.instance().scrollView = {current: {scrollTo: jest.fn()}};
|
||||
|
||||
expect(wrapper.find(DialogElement).at(1).props().value).toBe(testCase.expectedChecked);
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ LongPost {
|
|||
"useCallback": [Function],
|
||||
"useContext": [Function],
|
||||
"useDebugValue": [Function],
|
||||
"useDeferredValue": [Function],
|
||||
"useEffect": [Function],
|
||||
"useImperativeHandle": [Function],
|
||||
"useLayoutEffect": [Function],
|
||||
|
|
@ -141,6 +142,7 @@ LongPost {
|
|||
"useRef": [Function],
|
||||
"useResponder": [Function],
|
||||
"useState": [Function],
|
||||
"useTransition": [Function],
|
||||
},
|
||||
"_element": <LongPost
|
||||
actions={
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ const joinablePublicChannels = createSelector(
|
|||
return channels.filter((c) => {
|
||||
return (!myMembers[c.id] && c.type === General.OPEN_CHANNEL && c.delete_at === 0);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const teamArchivedChannels = createSelector(
|
||||
getChannelsInCurrentTeam,
|
||||
(channels) => {
|
||||
return channels.filter((c) => c.delete_at !== 0);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ export default class MoreChannels extends PureComponent {
|
|||
},
|
||||
{
|
||||
displayName: channel ? channel.display_name : '',
|
||||
}
|
||||
},
|
||||
);
|
||||
this.setHeaderButtons(true);
|
||||
this.setState({adding: false});
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
},
|
||||
{
|
||||
displayName,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
{
|
||||
id: t('mobile.open_gm.error'),
|
||||
defaultMessage: "We couldn't open a group message with those users. Please check your connection and try again.",
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue