forked from Ivasoft/mattermost-mobile
MM-12879 Fix iOS photo/camera permission denied prompt (#2904)
* Update Github issues link * Update GH issue to permalink * Add missing comma * Fix ios not prompting alert after denied photo or camera permission * Rename permission var * Update text * Change to correct text * Update text for attachement button * Update text for image_preview * Fix test * Integrate react-native-android-open-settings for storage permission denied * Move react-native-android-open-settings * Change all default permission denied message * Revert "Merge remote-tracking branch 'upstream/master'" This reverts commit65187f8f98, reversing changes made todaca425676. * Revert "Revert "Merge remote-tracking branch 'upstream/master'"" This reverts commitc82fa628d5. * Add NSPhotoLibraryAddUsageDescription description * Fix bad import * Lazy load react-native-android-open-settings * Fix indent
This commit is contained in:
@@ -242,6 +242,7 @@ dependencies {
|
||||
implementation project(':react-native-gesture-handler')
|
||||
implementation project(':@react-native-community_async-storage')
|
||||
implementation project(':@react-native-community_netinfo')
|
||||
implementation project(':react-native-android-open-settings')
|
||||
implementation project(':react-native-haptic-feedback')
|
||||
|
||||
// For animated GIF support
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.mattermost.rnbeta;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
@@ -32,6 +31,7 @@ import com.reactnativedocumentpicker.DocumentPicker;
|
||||
import com.oblador.keychain.KeychainModule;
|
||||
import com.reactnativecommunity.asyncstorage.AsyncStorageModule;
|
||||
import com.reactnativecommunity.netinfo.NetInfoModule;
|
||||
import com.levelasquez.androidopensettings.AndroidOpenSettings;
|
||||
import com.mkuczera.RNReactNativeHapticFeedbackModule;
|
||||
|
||||
import com.reactnativecommunity.webview.RNCWebViewPackage;
|
||||
@@ -43,7 +43,6 @@ import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
|
||||
import com.reactnativenavigation.NavigationApplication;
|
||||
import com.reactnativenavigation.react.NavigationReactNativeHost;
|
||||
import com.reactnativenavigation.react.ReactGateway;
|
||||
import com.wix.reactnativenotifications.RNNotificationsPackage;
|
||||
import com.wix.reactnativenotifications.core.notification.INotificationsApplication;
|
||||
import com.wix.reactnativenotifications.core.notification.IPushNotification;
|
||||
import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
|
||||
@@ -152,6 +151,8 @@ public class MainApplication extends NavigationApplication implements INotificat
|
||||
return new AsyncStorageModule(reactContext);
|
||||
case NetInfoModule.NAME:
|
||||
return new NetInfoModule(reactContext);
|
||||
case "RNAndroidOpenSettings":
|
||||
return new AndroidOpenSettings(reactContext);
|
||||
case "RNReactNativeHapticFeedbackModule":
|
||||
return new RNReactNativeHapticFeedbackModule(reactContext);
|
||||
default:
|
||||
@@ -187,6 +188,7 @@ public class MainApplication extends NavigationApplication implements INotificat
|
||||
map.put("RNKeychainManager", new ReactModuleInfo("RNKeychainManager", "com.oblador.keychain.KeychainModule", false, false, true, false, false));
|
||||
map.put(AsyncStorageModule.NAME, new ReactModuleInfo(AsyncStorageModule.NAME, "com.reactnativecommunity.asyncstorage.AsyncStorageModule", false, false, false, false, false));
|
||||
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));
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
rootProject.name = 'Mattermost'
|
||||
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-haptic-feedback'
|
||||
project(':react-native-haptic-feedback').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-haptic-feedback/android')
|
||||
include ':react-native-gesture-handler'
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import AndroidOpenSettings from 'react-native-android-open-settings';
|
||||
|
||||
import Icon from 'react-native-vector-icons/Ionicons';
|
||||
import {DocumentPicker} from 'react-native-document-picker';
|
||||
@@ -67,12 +69,93 @@ export default class AttachmentButton extends PureComponent {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
getPermissionDeniedMessage = (source, mediaType = '') => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const applicationName = DeviceInfo.getApplicationName();
|
||||
switch (source) {
|
||||
case 'camera': {
|
||||
if (mediaType === 'video') {
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.camera_video_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your camera',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.camera_video_permission_denied_description',
|
||||
defaultMessage: 'Take videos and upload them to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your camera.',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.camera_photo_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your camera',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.camera_photo_permission_denied_description',
|
||||
defaultMessage: 'Take photos and upload them to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your camera.',
|
||||
}),
|
||||
};
|
||||
}
|
||||
case 'storage':
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.storage_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your files',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.storage_permission_denied_description',
|
||||
defaultMessage: 'Upload files to your Mattermost instance. Open Settings to grant Mattermost Read and Write access to files on this device.',
|
||||
}),
|
||||
};
|
||||
case 'video':
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your videos',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_description',
|
||||
defaultMessage: 'Upload videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your video library.',
|
||||
}),
|
||||
};
|
||||
case 'photo':
|
||||
default: {
|
||||
if (Platform.OS === 'android') {
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your photos',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_description',
|
||||
defaultMessage: 'Upload photos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo library.',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: formatMessage({
|
||||
id: 'mobile.ios.photos_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your photos',
|
||||
}, {applicationName}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.ios.photos_permission_denied_description',
|
||||
defaultMessage: 'Upload photos and videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo and video library.',
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attachPhotoFromCamera = () => {
|
||||
return this.attachFileFromCamera('photo', 'camera');
|
||||
return this.attachFileFromCamera('camera', 'photo');
|
||||
};
|
||||
|
||||
attachFileFromCamera = async (mediaType, source) => {
|
||||
attachFileFromCamera = async (source, mediaType) => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {title, text} = this.getPermissionDeniedMessage('camera', mediaType);
|
||||
const options = {
|
||||
quality: 0.8,
|
||||
videoQuality: 'high',
|
||||
@@ -83,25 +166,19 @@ export default class AttachmentButton extends PureComponent {
|
||||
waitUntilSaved: true,
|
||||
},
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.camera_permission_denied_title',
|
||||
defaultMessage: 'Camera access is required',
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.camera_permission_denied_description',
|
||||
defaultMessage: 'To take photos and videos with your camera, please change your permission settings.',
|
||||
}),
|
||||
title,
|
||||
text,
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission',
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'}),
|
||||
okTitle: formatMessage({id: 'mobile.permission_denied_dismiss', defaultMessage: 'Don\'t Allow'}),
|
||||
},
|
||||
};
|
||||
|
||||
const hasPhotoPermission = await this.hasPhotoPermission(source);
|
||||
const hasCameraPermission = await this.hasPhotoPermission(source, mediaType);
|
||||
|
||||
if (hasPhotoPermission) {
|
||||
if (hasCameraPermission) {
|
||||
ImagePicker.launchCamera(options, (response) => {
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
@@ -112,25 +189,20 @@ export default class AttachmentButton extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
attachFileFromLibrary = () => {
|
||||
attachFileFromLibrary = async () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {title, text} = this.getPermissionDeniedMessage('photo');
|
||||
const options = {
|
||||
quality: 0.8,
|
||||
noData: true,
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_title',
|
||||
defaultMessage: 'Photo library access is required',
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_description',
|
||||
defaultMessage: 'To upload images from your library, please change your permission settings.',
|
||||
}),
|
||||
title,
|
||||
text,
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission',
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'}),
|
||||
okTitle: formatMessage({id: 'mobile.permission_denied_dismiss', defaultMessage: 'Don\'t Allow'}),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -138,39 +210,38 @@ export default class AttachmentButton extends PureComponent {
|
||||
options.mediaType = 'mixed';
|
||||
}
|
||||
|
||||
ImagePicker.launchImageLibrary(options, (response) => {
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
}
|
||||
const hasPhotoPermission = await this.hasPhotoPermission('photo');
|
||||
|
||||
this.uploadFiles([response]);
|
||||
});
|
||||
if (hasPhotoPermission) {
|
||||
ImagePicker.launchImageLibrary(options, (response) => {
|
||||
if (response.error || response.didCancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.uploadFiles([response]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
attachVideoFromCamera = () => {
|
||||
return this.attachFileFromCamera('video', 'camera');
|
||||
return this.attachFileFromCamera('camera', 'video');
|
||||
};
|
||||
|
||||
attachVideoFromLibraryAndroid = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {title, text} = this.getPermissionDeniedMessage('video');
|
||||
const options = {
|
||||
videoQuality: 'high',
|
||||
mediaType: 'video',
|
||||
noData: true,
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_title',
|
||||
defaultMessage: 'Video library access is required',
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_description',
|
||||
defaultMessage: 'To upload videos from your library, please change your permission settings.',
|
||||
}),
|
||||
title,
|
||||
text,
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission',
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'}),
|
||||
okTitle: formatMessage({id: 'mobile.permission_denied_dismiss', defaultMessage: 'Don\'t Allow'}),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -213,15 +284,16 @@ export default class AttachmentButton extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
hasPhotoPermission = async (source) => {
|
||||
hasPhotoPermission = async (source, mediaType = '') => {
|
||||
if (Platform.OS === 'ios') {
|
||||
const {formatMessage} = this.context.intl;
|
||||
let permissionRequest;
|
||||
const hasPermissionToStorage = await Permissions.check(source || 'photo');
|
||||
const targetSource = source || 'photo';
|
||||
const hasPermissionToStorage = await Permissions.check(targetSource);
|
||||
|
||||
switch (hasPermissionToStorage) {
|
||||
case PermissionTypes.UNDETERMINED:
|
||||
permissionRequest = await Permissions.request('photo');
|
||||
permissionRequest = await Permissions.request(targetSource);
|
||||
if (permissionRequest !== PermissionTypes.AUTHORIZED) {
|
||||
return false;
|
||||
}
|
||||
@@ -232,28 +304,24 @@ export default class AttachmentButton extends PureComponent {
|
||||
if (canOpenSettings) {
|
||||
grantOption = {
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set permission',
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
}
|
||||
|
||||
const {title, text} = this.getPermissionDeniedMessage(source, mediaType);
|
||||
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_title',
|
||||
defaultMessage: 'Photo library access is required',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_description',
|
||||
defaultMessage: 'To upload images from your library, please change your permission settings.',
|
||||
}),
|
||||
title,
|
||||
text,
|
||||
[
|
||||
grantOption,
|
||||
{
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.permission_denied_dismiss',
|
||||
defaultMessage: 'Dismiss',
|
||||
id: 'mobile.permission_denied_dismiss',
|
||||
defaultMessage: 'Don\'t Allow',
|
||||
}),
|
||||
},
|
||||
]
|
||||
@@ -280,35 +348,25 @@ export default class AttachmentButton extends PureComponent {
|
||||
}
|
||||
break;
|
||||
case PermissionTypes.DENIED: {
|
||||
const canOpenSettings = await Permissions.canOpenSettings();
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
grantOption = {
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set permission',
|
||||
}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
}
|
||||
const {title, text} = this.getPermissionDeniedMessage('storage');
|
||||
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.android.storage_permission_denied_title',
|
||||
defaultMessage: 'File Storage access is required',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.android.storage_permission_denied_description',
|
||||
defaultMessage: 'To upload images from your Android device, please change your permission settings.',
|
||||
}),
|
||||
title,
|
||||
text,
|
||||
[
|
||||
{
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.permission_denied_dismiss',
|
||||
defaultMessage: 'Dismiss',
|
||||
id: 'mobile.permission_denied_dismiss',
|
||||
defaultMessage: 'Don\'t Allow',
|
||||
}),
|
||||
},
|
||||
grantOption,
|
||||
{
|
||||
text: formatMessage({
|
||||
id: 'mobile.permission_denied_retry',
|
||||
defaultMessage: 'Settings',
|
||||
}),
|
||||
onPress: () => AndroidOpenSettings.appDetailsSettings(),
|
||||
},
|
||||
]
|
||||
);
|
||||
return false;
|
||||
|
||||
@@ -3,15 +3,25 @@
|
||||
|
||||
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 AttachmentButton from './attachment_button';
|
||||
import {PermissionTypes} from 'app/constants';
|
||||
|
||||
jest.mock('react-intl');
|
||||
|
||||
jest.mock('Platform', () => {
|
||||
const Platform = require.requireActual('Platform');
|
||||
Platform.OS = 'ios';
|
||||
return Platform;
|
||||
});
|
||||
|
||||
describe('AttachmentButton', () => {
|
||||
const formatMessage = jest.fn();
|
||||
const baseProps = {
|
||||
actions: {
|
||||
showModalOverCurrentContext: jest.fn(),
|
||||
@@ -73,4 +83,20 @@ describe('AttachmentButton', () => {
|
||||
expect(props.uploadFiles).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test('should show permission denied alert if permission is denied in iOS', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
jest.spyOn(Permissions, 'check').mockReturnValue(PermissionTypes.DENIED);
|
||||
jest.spyOn(Permissions, 'canOpenSettings').mockReturnValue(true);
|
||||
jest.spyOn(Alert, 'alert').mockReturnValue(true);
|
||||
|
||||
const wrapper = shallow(
|
||||
<AttachmentButton {...baseProps}/>,
|
||||
{context: {intl: {formatMessage}}},
|
||||
);
|
||||
|
||||
await wrapper.instance().hasPhotoPermission('camera');
|
||||
expect(Alert.alert).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -259,7 +259,7 @@ export default class EditProfile extends PureComponent {
|
||||
this.setState({profileImageRemove: true});
|
||||
this.emitCanUpdateAccount(true);
|
||||
this.props.actions.dismissModal();
|
||||
}
|
||||
};
|
||||
|
||||
uploadProfileImage = async () => {
|
||||
const {profileImage} = this.state;
|
||||
@@ -547,7 +547,7 @@ export default class EditProfile extends PureComponent {
|
||||
</ProfilePictureButton>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
|
||||
@@ -21,6 +21,7 @@ import LinearGradient from 'react-native-linear-gradient';
|
||||
import {intlShape} from 'react-intl';
|
||||
import Permissions from 'react-native-permissions';
|
||||
import Gallery from 'react-native-image-gallery';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
@@ -474,20 +475,24 @@ export default class ImagePreview extends PureComponent {
|
||||
let grantOption = null;
|
||||
if (canOpenSettings) {
|
||||
grantOption = {
|
||||
text: formatMessage({id: 'mobile.android.permission_denied_retry', defaultMessage: 'Set permission'}),
|
||||
text: formatMessage({id: 'mobile.permission_denied_retry', defaultMessage: 'Settings'}),
|
||||
onPress: () => Permissions.openSettings(),
|
||||
};
|
||||
}
|
||||
|
||||
const applicationName = DeviceInfo.getApplicationName();
|
||||
Alert.alert(
|
||||
formatMessage({id: 'mobile.android.photos_permission_denied_title', defaultMessage: 'Photo library access is required'}),
|
||||
formatMessage({
|
||||
id: 'mobile.ios.photos_permission_denied_description',
|
||||
id: 'mobile.photo_library_permission_denied_title',
|
||||
defaultMessage: '{applicationName} would like to access your photo library',
|
||||
}, {applicationName}),
|
||||
formatMessage({
|
||||
id: 'mobile.photo_library_permission_denied_description',
|
||||
defaultMessage: 'To save images and videos to your library, please change your permission settings.',
|
||||
}),
|
||||
[
|
||||
grantOption,
|
||||
{text: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'})},
|
||||
{text: formatMessage({id: 'mobile.permission_denied_dismiss', defaultMessage: 'Don\'t Allow'})},
|
||||
]
|
||||
);
|
||||
return;
|
||||
|
||||
@@ -138,16 +138,10 @@
|
||||
"mobile.advanced_settings.timezone": "Timezone",
|
||||
"mobile.advanced_settings.title": "Advanced Settings",
|
||||
"mobile.alert_dialog.alertCancel": "Cancel",
|
||||
"mobile.android.camera_permission_denied_description": "To take photos and videos with your camera, please change your permission settings.",
|
||||
"mobile.android.camera_permission_denied_title": "Camera access is required",
|
||||
"mobile.android.permission_denied_dismiss": "Dismiss",
|
||||
"mobile.android.permission_denied_retry": "Set permission",
|
||||
"mobile.android.photos_permission_denied_description": "To upload images from your library, please change your permission settings.",
|
||||
"mobile.android.photos_permission_denied_title": "Photo library access is required",
|
||||
"mobile.android.storage_permission_denied_description": "To upload images from your Android device, please change your permission settings.",
|
||||
"mobile.android.storage_permission_denied_title": "File Storage access is required",
|
||||
"mobile.android.videos_permission_denied_description": "To upload videos from your library, please change your permission settings.",
|
||||
"mobile.android.videos_permission_denied_title": "Video library access is required",
|
||||
"mobile.android.photos_permission_denied_description": "Upload photos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo library.",
|
||||
"mobile.android.photos_permission_denied_title": "{applicationName} would like to access your photos",
|
||||
"mobile.android.videos_permission_denied_description": "Upload videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your video library.",
|
||||
"mobile.android.videos_permission_denied_title": "{applicationName} would like to access your videos",
|
||||
"mobile.announcement_banner.title": "Announcement",
|
||||
"mobile.authentication_error.message": "Mattermost has encountered an error. Please re-authenticate to start a new session.",
|
||||
"mobile.authentication_error.title": "Authentication Error",
|
||||
@@ -155,6 +149,10 @@
|
||||
"mobile.calendar.dayNamesShort": "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
||||
"mobile.calendar.monthNames": "January,February,March,April,May,June,July,August,September,October,November,December",
|
||||
"mobile.calendar.monthNamesShort": "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
||||
"mobile.camera_photo_permission_denied_description": "Take photos and upload them to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your camera.",
|
||||
"mobile.camera_photo_permission_denied_title": "{applicationName} would like to access your camera",
|
||||
"mobile.camera_video_permission_denied_description": "Take videos and upload them to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your camera.",
|
||||
"mobile.camera_video_permission_denied_title": "{applicationName} would like to access your camera",
|
||||
"mobile.channel_drawer.search": "Jump to...",
|
||||
"mobile.channel_info.alertMessageDeleteChannel": "Are you sure you want to archive the {term} {name}?",
|
||||
"mobile.channel_info.alertMessageLeaveChannel": "Are you sure you want to leave the {term} {name}?",
|
||||
@@ -266,7 +264,8 @@
|
||||
"mobile.intro_messages.default_message": "This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.",
|
||||
"mobile.intro_messages.default_welcome": "Welcome to {name}!",
|
||||
"mobile.intro_messages.DM": "This is the start of your direct message history with {teammate}. Direct messages and files shared here are not shown to people outside this area.",
|
||||
"mobile.ios.photos_permission_denied_description": "To save images and videos to your library, please change your permission settings.",
|
||||
"mobile.ios.photos_permission_denied_description": "Upload photos and videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo and video library.",
|
||||
"mobile.ios.photos_permission_denied_title": "{applicationName} would like to access your photos",
|
||||
"mobile.join_channel.error": "We couldn't join the channel {displayName}. Please check your connection and try again.",
|
||||
"mobile.loading_channels": "Loading Channels...",
|
||||
"mobile.loading_members": "Loading Members...",
|
||||
@@ -342,6 +341,10 @@
|
||||
"mobile.open_dm.error": "We couldn't open a direct message with {displayName}. Please check your connection and try again.",
|
||||
"mobile.open_gm.error": "We couldn't open a group message with those users. Please check your connection and try again.",
|
||||
"mobile.open_unknown_channel.error": "Unable to join the channel. Please reset the cache and try again.",
|
||||
"mobile.permission_denied_dismiss": "Don't Allow",
|
||||
"mobile.permission_denied_retry": "Settings",
|
||||
"mobile.photo_library_permission_denied_description": "To save images and videos to your library, please change your permission settings.",
|
||||
"mobile.photo_library_permission_denied_title": "{applicationName} would like to access your photo library",
|
||||
"mobile.pinned_posts.empty_description": "Pin important items by holding down on any message and selecting \"Pin to Channel\".",
|
||||
"mobile.pinned_posts.empty_title": "No Pinned Posts",
|
||||
"mobile.post_info.add_reaction": "Add Reaction",
|
||||
@@ -440,6 +443,8 @@
|
||||
"mobile.share_extension.error_message": "An error has occurred while using the share extension.",
|
||||
"mobile.share_extension.error_title": "Extension Error",
|
||||
"mobile.share_extension.team": "Team",
|
||||
"mobile.storage_permission_denied_description": "Upload files to your Mattermost instance. Open Settings to grant Mattermost Read and Write access to files on this device.",
|
||||
"mobile.storage_permission_denied_title": "{applicationName} would like to access your files",
|
||||
"mobile.sidebar_settings.permanent": "Permanent Sidebar",
|
||||
"mobile.sidebar_settings.permanent_description": "Keep the sidebar open permanently",
|
||||
"mobile.suggestion.members": "Members",
|
||||
|
||||
@@ -71,7 +71,9 @@
|
||||
<key>NSMotionUsageDescription</key>
|
||||
<string>Share your route in your Mattermost instance</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Upload Photos and Videos to your Mattermost instance or save them to your device</string>
|
||||
<string>Upload Photos and Videos from your device to your Mattermost instance</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Save downloaded Photos and Videos from your Mattermost instance to your device</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>Send voice messages to your Mattermost instance</string>
|
||||
<key>UIAppFonts</key>
|
||||
|
||||
5
package-lock.json
generated
5
package-lock.json
generated
@@ -16454,6 +16454,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-android-open-settings": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-android-open-settings/-/react-native-android-open-settings-1.3.0.tgz",
|
||||
"integrity": "sha512-h4FTWRtTLRVNS7RK4Bg2gAXe8G5bFZL8Jtmfk2rG2a/N/wJR+v1rAY2BxRkC48lQTqwQCIAQRbWgLVkJ8XmaLQ=="
|
||||
},
|
||||
"react-native-animatable": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.2.tgz",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"react": "16.8.6",
|
||||
"react-intl": "2.8.0",
|
||||
"react-native": "0.59.9",
|
||||
"react-native-android-open-settings": "1.3.0",
|
||||
"react-native-animatable": "1.3.2",
|
||||
"react-native-button": "2.4.0",
|
||||
"react-native-calendars": "github:mattermost/react-native-calendars#4937ec5a3bf7e86f9f35fcd85eb4aa6133f45b58",
|
||||
|
||||
@@ -56,6 +56,7 @@ jest.mock('react-native-device-info', () => {
|
||||
getBuildNumber: () => '0',
|
||||
getModel: () => 'iPhone X',
|
||||
isTablet: () => false,
|
||||
getApplicationName: () => 'Mattermost',
|
||||
getDeviceLocale: () => 'en-US',
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user