forked from Ivasoft/mattermost-mobile
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bd742bc50 | ||
|
|
b98812f84f | ||
|
|
71f96fc1cf | ||
|
|
33f18db34d | ||
|
|
82e6aac37f | ||
|
|
38009051bb | ||
|
|
955cf47921 | ||
|
|
54530f28a2 | ||
|
|
18e2da6e3b | ||
|
|
6b69b9fa40 | ||
|
|
78602977f9 | ||
|
|
85b07cd8b3 | ||
|
|
c56cd566d2 | ||
|
|
9f85a0a33e | ||
|
|
954868f572 | ||
|
|
e3ffb037e5 | ||
|
|
ca78c027a0 | ||
|
|
dd28c38196 | ||
|
|
e7a2f4d6b1 | ||
|
|
6fc8884ef3 | ||
|
|
89d159a659 | ||
|
|
a33f26e827 | ||
|
|
8f9a660433 | ||
|
|
749f8a50b3 | ||
|
|
f338279444 | ||
|
|
8ad2456d5e | ||
|
|
442ce13171 | ||
|
|
611a2c2c3c | ||
|
|
2fdb9ce35e | ||
|
|
31a5d46ee0 | ||
|
|
fe0450e4c7 | ||
|
|
cd724ce3c4 | ||
|
|
587514d868 | ||
|
|
2a1258fd8c | ||
|
|
2f25548f47 | ||
|
|
07c9556dfe | ||
|
|
be488178be | ||
|
|
8e013a7ede | ||
|
|
e64e427001 | ||
|
|
1734202326 | ||
|
|
81e328864e | ||
|
|
46788fa8f6 | ||
|
|
c84b05217b | ||
|
|
630a3db2a6 | ||
|
|
a565c96fcf | ||
|
|
dddfcbc362 | ||
|
|
a75c4d0a02 | ||
|
|
978c2cdda5 | ||
|
|
b1245f72c9 |
@@ -87,7 +87,7 @@ if (System.getenv("SENTRY_ENABLED") == "true") {
|
||||
flavorAware: false
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native-sentry/sentry.gradle"
|
||||
//apply from: "../../node_modules/react-native-sentry/sentry.gradle"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,16 +114,16 @@ android {
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
pickFirst 'lib/x86_64/libjsc.so'
|
||||
pickFirst 'lib/arm64-v8a/libjsc.so'
|
||||
pickFirst '**/libjsc.so'
|
||||
pickFirst '**/libc++_shared.so'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mattermost.rnbeta"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 198
|
||||
versionName "1.20.0"
|
||||
versionCode 208
|
||||
versionName "1.21.0"
|
||||
multiDexEnabled = true
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
|
||||
@@ -193,9 +193,6 @@ repositories {
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.name == 'android-jsc') {
|
||||
details.useTarget group: details.requested.group, name: 'android-jsc-intl', version: 'r241213'
|
||||
}
|
||||
if (details.requested.name == 'play-services-base') {
|
||||
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
|
||||
}
|
||||
@@ -213,6 +210,9 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Make sure to put android-jsc at the top
|
||||
implementation "org.webkit:android-jsc-intl:r241213"
|
||||
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 0
|
||||
"status": 2
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
@@ -57,7 +57,7 @@
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 0
|
||||
"status": 2
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
@@ -88,7 +88,7 @@
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 0
|
||||
"status": 2
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name="com.reactnativenavigation.controllers.NavigationActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:resizeableActivity="true"/>
|
||||
<activity
|
||||
android:name="com.mattermost.share.ShareActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
|
||||
@@ -57,7 +57,6 @@ public class InitializationModule extends ReactContextBaseJavaModule {
|
||||
*
|
||||
* Miscellaneous:
|
||||
* MattermostManaged.Config
|
||||
* replyFromPushNotification
|
||||
*/
|
||||
|
||||
MainApplication app = (MainApplication) mApplication;
|
||||
@@ -138,8 +137,6 @@ public class InitializationModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
constants.put("managedConfig", config[0]);
|
||||
constants.put("replyFromPushNotification", app.replyFromPushNotification);
|
||||
app.replyFromPushNotification = false;
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ import android.util.Log;
|
||||
public class MainApplication extends NavigationApplication implements INotificationsApplication, INotificationsDrawerApplication {
|
||||
public NotificationsLifecycleFacade notificationsLifecycleFacade;
|
||||
public Boolean sharedExtensionIsOpened = false;
|
||||
public Boolean replyFromPushNotification = false;
|
||||
|
||||
public long APP_START_TIME;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
public class MattermostManagedModule extends ReactContextBaseJavaModule {
|
||||
private static MattermostManagedModule instance;
|
||||
@@ -73,6 +74,19 @@ public class MattermostManagedModule extends ReactContextBaseJavaModule {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void isRunningInSplitView(final Promise promise) {
|
||||
WritableMap result = Arguments.createMap();
|
||||
Activity current = getCurrentActivity();
|
||||
if (current != null) {
|
||||
result.putBoolean("isSplitView", current.isInMultiWindowMode());
|
||||
} else {
|
||||
result.putBoolean("isSplitView", false);
|
||||
}
|
||||
|
||||
promise.resolve(result);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void quitApp() {
|
||||
getCurrentActivity().finish();
|
||||
|
||||
@@ -36,13 +36,17 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
final CharSequence message = getReplyMessage(intent);
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
|
||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
final ReactApplicationContext reactApplicationContext = new ReactApplicationContext(context);
|
||||
final int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1);
|
||||
final CharSequence message = getReplyMessage(intent);
|
||||
final KeychainModule keychainModule = new KeychainModule(reactApplicationContext);
|
||||
|
||||
keychainModule.getGenericPasswordForOptions(null, new ResolvePromise() {
|
||||
@@ -75,7 +79,11 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
protected void replyToMessage(final String serverUrl, final String token, final int notificationId, final CharSequence message) {
|
||||
final String channelId = bundle.getString("channel_id");
|
||||
final String rootId = bundle.getString("post_id");
|
||||
final String postId = bundle.getString("post_id");
|
||||
String rootId = bundle.getString("root_id");
|
||||
if (android.text.TextUtils.isEmpty(rootId)) {
|
||||
rootId = postId;
|
||||
}
|
||||
|
||||
if (token == null || serverUrl == null) {
|
||||
onReplyFailed(notificationManager, notificationId, channelId);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<!-- Trust preinstalled CAs -->
|
||||
<certificates src="system" />
|
||||
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
buildToolsVersion = "28.0.3"
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 26
|
||||
targetSdkVersion = 28
|
||||
supportLibVersion = "28.0.0"
|
||||
}
|
||||
repositories {
|
||||
|
||||
@@ -30,7 +30,7 @@ export function executeCommand(message, channelId, rootId) {
|
||||
|
||||
const {data, error} = await dispatch(executeCommandService(msg, args));
|
||||
|
||||
if (data.trigger_id) {
|
||||
if (data?.trigger_id) { //eslint-disable-line camelcase
|
||||
dispatch({type: IntegrationTypes.RECEIVED_DIALOG_TRIGGER_ID, data: data.trigger_id});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,13 @@ import {getSessions} from 'mattermost-redux/actions/users';
|
||||
import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {ViewTypes} from 'app/constants';
|
||||
import {app} from 'app/mattermost';
|
||||
import PushNotifications from 'app/push_notifications';
|
||||
import {getDeviceTimezone, isTimezoneEnabled} from 'app/utils/timezone';
|
||||
import {getDeviceTimezone} from 'app/utils/timezone';
|
||||
import {setCSRFFromCookie} from 'app/utils/security';
|
||||
|
||||
export function handleLoginIdChanged(loginId) {
|
||||
|
||||
@@ -198,10 +198,11 @@ export default class App {
|
||||
const username = `${deviceToken}, ${currentUserId}`;
|
||||
const password = `${token},${url}`;
|
||||
|
||||
this.token = token;
|
||||
this.url = url;
|
||||
|
||||
if (this.waitForRehydration) {
|
||||
this.waitForRehydration = false;
|
||||
this.token = token;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
// Only save to keychain if the url and token are set
|
||||
|
||||
@@ -29,11 +29,8 @@ export default class FormattedTime extends React.PureComponent {
|
||||
} = this.props;
|
||||
|
||||
if (timeZone) {
|
||||
return intl.formatDate(moment.tz(value, timeZone).toDate(), {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12,
|
||||
});
|
||||
const format = hour12 ? 'hh:mm A' : 'HH:mm';
|
||||
return moment.tz(value, timeZone).format(format);
|
||||
}
|
||||
|
||||
// If no timezone is defined fallback to the previous implementation
|
||||
|
||||
@@ -89,6 +89,7 @@ export default class PostAttachmentOpenGraph extends PureComponent {
|
||||
|
||||
const bestImage = getNearestPoint(bestDimensions, data.images, 'width', 'height');
|
||||
const imageUrl = bestImage.secure_url || bestImage.url;
|
||||
|
||||
let ogImage;
|
||||
if (imagesMetadata && imagesMetadata[imageUrl]) {
|
||||
ogImage = imagesMetadata[imageUrl];
|
||||
@@ -98,6 +99,12 @@ export default class PostAttachmentOpenGraph extends PureComponent {
|
||||
ogImage = data.images.find((i) => i.url === imageUrl || i.secure_url === imageUrl);
|
||||
}
|
||||
|
||||
// Fallback when the ogImage does not have dimensions but there is a metaImage defined
|
||||
const metaImages = imagesMetadata ? Object.values(imagesMetadata) : null;
|
||||
if ((!ogImage?.width || !ogImage?.height) && metaImages?.length) {
|
||||
ogImage = metaImages[0];
|
||||
}
|
||||
|
||||
let dimensions = bestDimensions;
|
||||
if (ogImage?.width && ogImage?.height) {
|
||||
dimensions = calculateDimensions(ogImage.height, ogImage.width, this.getViewPostWidth());
|
||||
@@ -139,9 +146,16 @@ export default class PostAttachmentOpenGraph extends PureComponent {
|
||||
ogImage = openGraphData.images.find((i) => i.url === openGraphImageUrl || i.secure_url === openGraphImageUrl);
|
||||
}
|
||||
|
||||
// Fallback when the ogImage does not have dimensions but there is a metaImage defined
|
||||
const metaImages = imagesMetadata ? Object.values(imagesMetadata) : null;
|
||||
if ((!ogImage?.width || !ogImage?.height) && metaImages?.length) {
|
||||
ogImage = metaImages[0];
|
||||
}
|
||||
|
||||
if (ogImage?.width && ogImage?.height) {
|
||||
this.setImageSize(imageUrl, ogImage.width, ogImage.height);
|
||||
} else {
|
||||
// if we get to this point there can be a scroll pop
|
||||
Image.getSize(imageUrl, (width, height) => {
|
||||
this.setImageSize(imageUrl, width, height);
|
||||
}, () => null);
|
||||
|
||||
@@ -10,6 +10,7 @@ import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general
|
||||
import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
|
||||
import {makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {memoizeResult} from 'mattermost-redux/utils/helpers';
|
||||
|
||||
import {
|
||||
@@ -30,10 +31,12 @@ const POST_TIMEOUT = 20000;
|
||||
|
||||
function makeMapStateToProps() {
|
||||
const memoizeHasEmojisOnly = memoizeResult((message, customEmojis) => hasEmojisOnly(message, customEmojis));
|
||||
const getReactionsForPost = makeGetReactionsForPost();
|
||||
|
||||
return (state, ownProps) => {
|
||||
const post = ownProps.post;
|
||||
const channel = getChannel(state, post.channel_id) || {};
|
||||
const reactions = getReactionsForPost(state, post.id);
|
||||
|
||||
let isFailed = post.failed;
|
||||
let isPending = post.id === post.pending_post_id;
|
||||
@@ -83,7 +86,7 @@ function makeMapStateToProps() {
|
||||
fileIds: post.file_ids,
|
||||
hasBeenDeleted: post.state === Posts.POST_DELETED,
|
||||
hasBeenEdited: isEdited(post),
|
||||
hasReactions: post.has_reactions,
|
||||
hasReactions: (reactions && Object.keys(reactions).length > 0) || Boolean(post.has_reactions),
|
||||
isFailed,
|
||||
isPending,
|
||||
isPostAddChannelMember,
|
||||
|
||||
@@ -179,11 +179,12 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
||||
};
|
||||
|
||||
generateStaticEmbed = (isYouTube, isImage) => {
|
||||
if (isYouTube || isImage) {
|
||||
const {isReplyPost, link, metadata, navigator, openGraphData, showLinkPreviews, theme} = this.props;
|
||||
|
||||
if (isYouTube || (isImage && !openGraphData)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {isReplyPost, link, metadata, navigator, openGraphData, showLinkPreviews, theme} = this.props;
|
||||
const attachments = this.getMessageAttachment();
|
||||
if (attachments) {
|
||||
return attachments;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {connect} from 'react-redux';
|
||||
import {Preferences} from 'mattermost-redux/constants';
|
||||
import {makeGetCommentCountForPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {getBool, getTeammateNameDisplaySetting, getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
import {getUser, getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
import {isPostPendingOrFailed, isSystemMessage} from 'mattermost-redux/utils/post_utils';
|
||||
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
|
||||
@@ -13,7 +14,6 @@ import {displayUsername} from 'mattermost-redux/utils/user_utils';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {fromAutoResponder} from 'app/utils/general';
|
||||
import {isTimezoneEnabled} from 'app/utils/timezone';
|
||||
|
||||
import PostHeader from './post_header';
|
||||
|
||||
|
||||
@@ -5,10 +5,9 @@ import {connect} from 'react-redux';
|
||||
|
||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
|
||||
|
||||
import {isTimezoneEnabled} from 'app/utils/timezone';
|
||||
|
||||
import DateHeader from './date_header';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
||||
@@ -281,7 +281,9 @@ export default class PostList extends PureComponent {
|
||||
|
||||
scrollToBottom = () => {
|
||||
setTimeout(() => {
|
||||
this.flatListRef.current.scrollToOffset({offset: 0, animated: true});
|
||||
if (this.flatListRef && this.flatListRef.current) {
|
||||
this.flatListRef.current.scrollToOffset({offset: 0, animated: true});
|
||||
}
|
||||
}, 250);
|
||||
};
|
||||
|
||||
@@ -290,13 +292,16 @@ export default class PostList extends PureComponent {
|
||||
width > 0 &&
|
||||
height > 0 &&
|
||||
this.props.initialIndex > 0 &&
|
||||
!this.hasDoneInitialScroll
|
||||
!this.hasDoneInitialScroll &&
|
||||
this.flatListRef?.current
|
||||
) {
|
||||
this.flatListRef.current.scrollToIndex({
|
||||
animated: false,
|
||||
index: this.props.initialIndex,
|
||||
viewOffset: 50,
|
||||
viewPosition: 0.5,
|
||||
requestAnimationFrame(() => {
|
||||
this.flatListRef.current.scrollToIndex({
|
||||
animated: false,
|
||||
index: this.props.initialIndex,
|
||||
viewOffset: 0,
|
||||
viewPosition: 1, // 0 is at bottom
|
||||
});
|
||||
});
|
||||
this.hasDoneInitialScroll = true;
|
||||
}
|
||||
|
||||
@@ -81,14 +81,12 @@ exports[`ChannelItem should match snapshot 1`] = `
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -196,14 +194,12 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -311,14 +307,12 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -426,14 +420,12 @@ exports[`ChannelItem should match snapshot for deactivated user and is currentCh
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -530,14 +522,12 @@ exports[`ChannelItem should match snapshot for deactivated user and is searchRes
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -640,14 +630,12 @@ exports[`ChannelItem should match snapshot with draft 1`] = `
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
@@ -746,14 +734,12 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.4)",
|
||||
"flex": 1,
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"height": "100%",
|
||||
"lineHeight": 44,
|
||||
"paddingRight": 10,
|
||||
"textAlignVertical": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
|
||||
@@ -242,10 +242,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
paddingRight: 10,
|
||||
height: '100%',
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
lineHeight: 44,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
textActive: {
|
||||
color: theme.sidebarTextActiveColor,
|
||||
|
||||
@@ -44,6 +44,7 @@ class FilteredList extends Component {
|
||||
teammateNameDisplay: PropTypes.string,
|
||||
onSelectChannel: PropTypes.func.isRequired,
|
||||
otherChannels: PropTypes.array,
|
||||
archivedChannels: PropTypes.array,
|
||||
profiles: PropTypes.object,
|
||||
teamProfiles: PropTypes.object,
|
||||
searchOrder: PropTypes.array.isRequired,
|
||||
@@ -176,6 +177,11 @@ class FilteredList extends Component {
|
||||
id: t('mobile.channel_list.not_member'),
|
||||
defaultMessage: 'NOT A MEMBER',
|
||||
},
|
||||
archived: {
|
||||
builder: this.buildArchivedForSearch,
|
||||
id: t('mobile.channel_list.archived'),
|
||||
defaultMessage: 'ARCHIVED',
|
||||
},
|
||||
});
|
||||
|
||||
buildUnreadChannelsForSearch = (props, term) => {
|
||||
@@ -294,6 +300,19 @@ class FilteredList extends Component {
|
||||
sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
}
|
||||
|
||||
buildArchivedForSearch = (props, term) => {
|
||||
const {currentChannel, archivedChannels} = props;
|
||||
|
||||
return this.filterChannels(archivedChannels.reduce((acc, channel) => {
|
||||
// when there is no search text, display an archived channel only if we are in it at the moment.
|
||||
if (term || channel.id === currentChannel.id) {
|
||||
acc.push({...channel});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []), term);
|
||||
}
|
||||
|
||||
buildOtherMembersForSearch = (props, term) => {
|
||||
const {otherChannels} = props;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
getChannelsWithUnreadSection,
|
||||
getCurrentChannel,
|
||||
getGroupChannels,
|
||||
getArchivedChannels,
|
||||
getOtherChannels,
|
||||
} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
@@ -24,7 +25,7 @@ import Config from 'assets/config';
|
||||
|
||||
import FilteredList from './filtered_list';
|
||||
|
||||
const DEFAULT_SEARCH_ORDER = ['unreads', 'dms', 'channels', 'members', 'nonmembers'];
|
||||
const DEFAULT_SEARCH_ORDER = ['unreads', 'dms', 'channels', 'members', 'nonmembers', 'archived'];
|
||||
|
||||
const pastDirectMessages = createSelector(
|
||||
getDirectShowPreferences,
|
||||
@@ -112,7 +113,8 @@ function mapStateToProps(state) {
|
||||
currentChannel: getCurrentChannel(state),
|
||||
currentTeam: getCurrentTeam(state),
|
||||
currentUserId,
|
||||
otherChannels: getOtherChannels(state),
|
||||
otherChannels: getOtherChannels(state, false),
|
||||
archivedChannels: getArchivedChannels(state),
|
||||
groupChannelMemberDetails: getGroupChannelMemberDetails(state),
|
||||
profiles,
|
||||
teamProfiles,
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
BackHandler,
|
||||
Dimensions,
|
||||
Keyboard,
|
||||
StyleSheet,
|
||||
View,
|
||||
@@ -17,6 +18,7 @@ import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
import SafeAreaView from 'app/components/safe_area_view';
|
||||
import DrawerLayout, {TABLET_WIDTH} from 'app/components/sidebars/drawer_layout';
|
||||
import {DeviceTypes} from 'app/constants';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import tracker from 'app/utils/time_tracker';
|
||||
import {t} from 'app/utils/i18n';
|
||||
|
||||
@@ -69,15 +71,19 @@ export default class ChannelSidebar extends Component {
|
||||
openDrawerOffset,
|
||||
drawerOpened: false,
|
||||
searching: false,
|
||||
isSplitView: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
this.props.actions.getTeams();
|
||||
this.handleDimensions();
|
||||
EventEmitter.on('close_channel_drawer', this.closeChannelDrawer);
|
||||
EventEmitter.on('renderDrawer', this.handleShowDrawerContent);
|
||||
EventEmitter.on(WebsocketEvents.CHANNEL_UPDATED, this.handleUpdateTitle);
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
|
||||
Dimensions.addEventListener('change', this.handleDimensions);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@@ -97,7 +103,7 @@ export default class ChannelSidebar extends Component {
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const {currentTeamId, deviceWidth, isLandscape, teamsCount} = this.props;
|
||||
const {openDrawerOffset, show, searching} = this.state;
|
||||
const {openDrawerOffset, isSplitView, show, searching} = this.state;
|
||||
|
||||
if (nextState.openDrawerOffset !== openDrawerOffset || nextState.show !== show || nextState.searching !== searching) {
|
||||
return true;
|
||||
@@ -105,14 +111,17 @@ export default class ChannelSidebar extends Component {
|
||||
|
||||
return nextProps.currentTeamId !== currentTeamId ||
|
||||
nextProps.isLandscape !== isLandscape || nextProps.deviceWidth !== deviceWidth ||
|
||||
nextProps.teamsCount !== teamsCount;
|
||||
nextProps.teamsCount !== teamsCount ||
|
||||
nextState.isSplitView !== isSplitView;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
EventEmitter.off('close_channel_drawer', this.closeChannelDrawer);
|
||||
EventEmitter.off(WebsocketEvents.CHANNEL_UPDATED, this.handleUpdateTitle);
|
||||
EventEmitter.off('renderDrawer', this.handleShowDrawerContent);
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleAndroidBack);
|
||||
Dimensions.addEventListener('change', this.handleDimensions);
|
||||
}
|
||||
|
||||
handleAndroidBack = () => {
|
||||
@@ -124,6 +133,15 @@ export default class ChannelSidebar extends Component {
|
||||
return false;
|
||||
};
|
||||
|
||||
handleDimensions = () => {
|
||||
if (DeviceTypes.IS_TABLET && this.mounted) {
|
||||
mattermostManaged.isRunningInSplitView().then((result) => {
|
||||
const isSplitView = Boolean(result.isSplitView);
|
||||
this.setState({isSplitView});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleShowDrawerContent = () => {
|
||||
this.setState({show: true});
|
||||
};
|
||||
@@ -380,6 +398,7 @@ export default class ChannelSidebar extends Component {
|
||||
render() {
|
||||
const {children, deviceWidth} = this.props;
|
||||
const {openDrawerOffset} = this.state;
|
||||
const isTablet = DeviceTypes.IS_TABLET && !this.state.isSplitView;
|
||||
const drawerWidth = DeviceTypes.IS_TABLET ? TABLET_WIDTH : (deviceWidth - openDrawerOffset);
|
||||
|
||||
return (
|
||||
@@ -390,7 +409,7 @@ export default class ChannelSidebar extends Component {
|
||||
onDrawerOpen={this.handleDrawerOpen}
|
||||
drawerWidth={drawerWidth}
|
||||
useNativeAnimations={true}
|
||||
isTablet={DeviceTypes.IS_TABLET}
|
||||
isTablet={isTablet}
|
||||
>
|
||||
{children}
|
||||
</DrawerLayout>
|
||||
|
||||
@@ -405,7 +405,7 @@ const launchSelectServer = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const launchChannel = () => {
|
||||
const launchChannel = (skipMetrics = false) => {
|
||||
Navigation.startSingleScreenApp({
|
||||
screen: {
|
||||
screen: 'Channel',
|
||||
@@ -416,6 +416,9 @@ const launchChannel = () => {
|
||||
screenBackgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
passProps: {
|
||||
skipMetrics,
|
||||
},
|
||||
appStyle: {
|
||||
orientation: 'auto',
|
||||
},
|
||||
@@ -508,19 +511,23 @@ const launchEntry = () => {
|
||||
|
||||
configurePushNotifications();
|
||||
const startedSharedExtension = Platform.OS === 'android' && MattermostShare.isOpened;
|
||||
const fromPushNotification = Platform.OS === 'android' && Initialization.replyFromPushNotification;
|
||||
|
||||
if (startedSharedExtension || fromPushNotification) {
|
||||
if (startedSharedExtension) {
|
||||
// Hold on launching Entry screen
|
||||
app.setAppStarted(true);
|
||||
|
||||
// Listen for when the user opens the app
|
||||
new NativeEventsReceiver().appLaunched(() => {
|
||||
app.setAppStarted(false);
|
||||
launchEntry();
|
||||
});
|
||||
}
|
||||
|
||||
if (!app.appStarted) {
|
||||
launchEntry();
|
||||
}
|
||||
|
||||
new NativeEventsReceiver().appLaunched(() => {
|
||||
if (startedSharedExtension) {
|
||||
app.setAppStarted(false);
|
||||
launchEntry();
|
||||
} else if (app.token && app.url) {
|
||||
launchChannel(true);
|
||||
} else {
|
||||
launchSelectServer();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ export default {
|
||||
},
|
||||
authenticate: LocalAuth.auth,
|
||||
blurAppScreen: MattermostManaged.blurAppScreen,
|
||||
isRunningInSplitView: MattermostManaged.isRunningInSplitView,
|
||||
getConfig: async () => {
|
||||
try {
|
||||
cachedConfig = await MattermostManaged.getConfig();
|
||||
|
||||
@@ -52,6 +52,7 @@ export default {
|
||||
return cachedConfig;
|
||||
},
|
||||
hasSafeAreaInsets: MattermostManaged.hasSafeAreaInsets,
|
||||
isRunningInSplitView: MattermostManaged.isRunningInSplitView,
|
||||
isDeviceSecure: async () => {
|
||||
try {
|
||||
return await LocalAuth.isDeviceSecure();
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {AppRegistry, AppState, NativeModules} from 'react-native';
|
||||
import {AppState, NativeModules} from 'react-native';
|
||||
import {NotificationsAndroid, PendingNotifications} from 'react-native-notifications';
|
||||
import Notification from 'react-native-notifications/notification.android';
|
||||
|
||||
import {emptyFunction} from 'app/utils/general';
|
||||
|
||||
const {NotificationPreferences} = NativeModules;
|
||||
|
||||
@@ -37,23 +34,6 @@ class PushNotification {
|
||||
this.handleNotification(data, true);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerHeadlessTask('notificationReplied', () => async (deviceNotification) => {
|
||||
const notification = new Notification(deviceNotification);
|
||||
const data = notification.getData();
|
||||
const completed = emptyFunction;
|
||||
|
||||
if (this.onReply) {
|
||||
this.onReply(data, data.text, parseInt(data.badge, 10) - parseInt(data.msg_count, 10), completed);
|
||||
} else {
|
||||
this.deviceNotification = {
|
||||
data,
|
||||
text: data.text,
|
||||
badge: parseInt(data.badge, 10) - parseInt(data.msg_count, 10),
|
||||
completed, // used to identify that the notification belongs to a reply
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleNotification = (data, userInteraction) => {
|
||||
|
||||
@@ -266,7 +266,11 @@ function postVisibility(state = {}, action) {
|
||||
}
|
||||
case ViewTypes.INCREASE_POST_VISIBILITY: {
|
||||
const nextState = {...state};
|
||||
nextState[action.data] += action.amount;
|
||||
if (nextState[action.data]) {
|
||||
nextState[action.data] += action.amount;
|
||||
} else {
|
||||
nextState[action.data] = action.amount;
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
case ViewTypes.RECEIVED_FOCUSED_POST: {
|
||||
|
||||
112
app/reducers/views/channel.test.js
Normal file
112
app/reducers/views/channel.test.js
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import channelReducer from './channel';
|
||||
import {ViewTypes} from 'app/constants';
|
||||
|
||||
describe('Reducers.channel', () => {
|
||||
const initialState = {
|
||||
displayName: '',
|
||||
drafts: {},
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
postCountInChannel: {},
|
||||
postVisibility: {},
|
||||
loadingPosts: {},
|
||||
lastGetPosts: {},
|
||||
retryFailed: false,
|
||||
loadMorePostsVisible: true,
|
||||
lastChannelViewTime: {},
|
||||
keepChannelIdAsUnread: null,
|
||||
};
|
||||
|
||||
test('Initial state', () => {
|
||||
const nextState = channelReducer(
|
||||
{
|
||||
displayName: '',
|
||||
drafts: {},
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
postCountInChannel: {},
|
||||
postVisibility: {},
|
||||
loadingPosts: {},
|
||||
lastGetPosts: {},
|
||||
retryFailed: false,
|
||||
loadMorePostsVisible: true,
|
||||
lastChannelViewTime: {},
|
||||
keepChannelIdAsUnread: null,
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
expect(nextState).toEqual(initialState);
|
||||
});
|
||||
|
||||
test('should set the postVisibility amount for a channel', () => {
|
||||
const channelId = 'channel_id';
|
||||
const amount = 15;
|
||||
const nextState = channelReducer(
|
||||
{
|
||||
displayName: '',
|
||||
drafts: {},
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
postCountInChannel: {},
|
||||
postVisibility: {},
|
||||
loadingPosts: {},
|
||||
lastGetPosts: {},
|
||||
retryFailed: false,
|
||||
loadMorePostsVisible: true,
|
||||
lastChannelViewTime: {},
|
||||
keepChannelIdAsUnread: null,
|
||||
},
|
||||
{
|
||||
type: ViewTypes.INCREASE_POST_VISIBILITY,
|
||||
data: channelId,
|
||||
amount,
|
||||
}
|
||||
);
|
||||
|
||||
expect(nextState).toEqual({
|
||||
...initialState,
|
||||
postVisibility: {
|
||||
[channelId]: amount,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('should increase the postVisibility amount for a channel', () => {
|
||||
const channelId = 'channel_id';
|
||||
const amount = 15;
|
||||
const nextState = channelReducer(
|
||||
{
|
||||
displayName: '',
|
||||
drafts: {},
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
postCountInChannel: {},
|
||||
postVisibility: {
|
||||
[channelId]: amount,
|
||||
},
|
||||
loadingPosts: {},
|
||||
lastGetPosts: {},
|
||||
retryFailed: false,
|
||||
loadMorePostsVisible: true,
|
||||
lastChannelViewTime: {},
|
||||
keepChannelIdAsUnread: null,
|
||||
},
|
||||
{
|
||||
type: ViewTypes.INCREASE_POST_VISIBILITY,
|
||||
data: channelId,
|
||||
amount,
|
||||
}
|
||||
);
|
||||
|
||||
expect(nextState).toEqual({
|
||||
...initialState,
|
||||
postVisibility: {
|
||||
[channelId]: 2 * amount,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -48,6 +48,7 @@ export default class ChannelBase extends PureComponent {
|
||||
theme: PropTypes.object.isRequired,
|
||||
showTermsOfService: PropTypes.bool,
|
||||
disableTermsModal: PropTypes.bool,
|
||||
skipMetrics: PropTypes.bool,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
@@ -88,7 +89,7 @@ export default class ChannelBase extends PureComponent {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (tracker.initialLoad) {
|
||||
if (tracker.initialLoad && !this.props.skipMetrics) {
|
||||
this.props.actions.recordLoadTime('Start time', 'initialLoad');
|
||||
}
|
||||
|
||||
@@ -98,7 +99,9 @@ export default class ChannelBase extends PureComponent {
|
||||
|
||||
EventEmitter.emit('renderDrawer');
|
||||
|
||||
telemetry.end(['start:channel_screen']);
|
||||
if (!this.props.skipMetrics) {
|
||||
telemetry.end(['start:channel_screen']);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Platform, View} from 'react-native';
|
||||
import {Dimensions, Platform, View} from 'react-native';
|
||||
|
||||
import {DeviceTypes, ViewTypes} from 'app/constants';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import ChannelDrawerButton from './channel_drawer_button';
|
||||
@@ -31,6 +32,30 @@ export default class ChannelNavBar extends PureComponent {
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
isSplitView: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
this.handleDimensions();
|
||||
Dimensions.addEventListener('change', this.handleDimensions);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
Dimensions.removeEventListener('change', this.handleDimensions);
|
||||
}
|
||||
|
||||
handleDimensions = () => {
|
||||
if (DeviceTypes.IS_TABLET && this.mounted) {
|
||||
mattermostManaged.isRunningInSplitView().then((result) => {
|
||||
const isSplitView = Boolean(result.isSplitView);
|
||||
this.setState({isSplitView});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {isLandscape, navigator, onPress, theme} = this.props;
|
||||
const {openChannelDrawer, openSettingsDrawer} = this.props;
|
||||
@@ -60,7 +85,7 @@ export default class ChannelNavBar extends PureComponent {
|
||||
}
|
||||
|
||||
let drawerButtonVisible = false;
|
||||
if (!DeviceTypes.IS_TABLET) {
|
||||
if (!DeviceTypes.IS_TABLET || this.state.isSplitView) {
|
||||
drawerButtonVisible = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelMembers should match snapshot 1`] = `
|
||||
<ForwardRef(forwardConnectRef)>
|
||||
<Connect(StatusBar) />
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"marginVertical": 5,
|
||||
}
|
||||
}
|
||||
>
|
||||
<SearchBarIos
|
||||
autoCapitalize="none"
|
||||
backgroundColor="transparent"
|
||||
blurOnSubmit={true}
|
||||
cancelTitle="Cancel"
|
||||
inputHeight={33}
|
||||
inputStyle={
|
||||
Object {
|
||||
"backgroundColor": "rgba(61,60,64,0.2)",
|
||||
"color": "#3d3c40",
|
||||
"fontSize": 15,
|
||||
}
|
||||
}
|
||||
leftComponent={null}
|
||||
onBlur={[Function]}
|
||||
onCancelButtonPress={[Function]}
|
||||
onChangeText={[Function]}
|
||||
onFocus={[Function]}
|
||||
onSearchButtonPress={[Function]}
|
||||
onSelectionChange={[Function]}
|
||||
placeholder="Search"
|
||||
placeholderTextColor="rgba(61,60,64,0.5)"
|
||||
searchIconCollapsedMargin={10}
|
||||
searchIconExpandedMargin={10}
|
||||
tintColorDelete="rgba(61,60,64,0.5)"
|
||||
tintColorSearch="rgba(61,60,64,0.5)"
|
||||
titleCancelColor="#3d3c40"
|
||||
value=""
|
||||
/>
|
||||
</View>
|
||||
<CustomList
|
||||
data={Array []}
|
||||
extraData={Object {}}
|
||||
listType="section"
|
||||
loading={false}
|
||||
loadingComponent={null}
|
||||
noResults={null}
|
||||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ForwardRef(forwardConnectRef)>
|
||||
`;
|
||||
@@ -225,20 +225,34 @@ export default class ChannelMembers extends PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
renderItem = (props) => {
|
||||
// The list will re-render when the selection changes because it's passed into the list as extraData
|
||||
const selected = this.state.selectedIds[props.id];
|
||||
const enabled = props.id !== this.props.currentUserId;
|
||||
|
||||
renderItem = (props, selectProps) => {
|
||||
return (
|
||||
<UserListRow
|
||||
key={props.id}
|
||||
{...props}
|
||||
selectable={true}
|
||||
selected={selected}
|
||||
enabled={enabled}
|
||||
{...selectProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderSelectableItem = (props) => {
|
||||
// The list will re-render when the selection changes because selectedIds is passed into the list as extraData
|
||||
const selectProps = {
|
||||
selectable: true,
|
||||
selected: this.state.selectedIds[props.id],
|
||||
enabled: props.id !== this.props.currentUserId,
|
||||
};
|
||||
|
||||
return this.renderItem(props, selectProps);
|
||||
}
|
||||
|
||||
renderUnselectableItem = (props) => {
|
||||
const selectProps = {
|
||||
selectable: false,
|
||||
enabled: false,
|
||||
};
|
||||
|
||||
return this.renderItem(props, selectProps);
|
||||
};
|
||||
|
||||
renderLoading = () => {
|
||||
@@ -292,7 +306,7 @@ export default class ChannelMembers extends PureComponent {
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {theme} = this.props;
|
||||
const {theme, canManageUsers} = this.props;
|
||||
const {
|
||||
removing,
|
||||
loading,
|
||||
@@ -374,7 +388,7 @@ export default class ChannelMembers extends PureComponent {
|
||||
noResults={this.renderNoResults()}
|
||||
onLoadMore={this.getProfiles}
|
||||
onRowPress={this.handleSelectProfile}
|
||||
renderItem={this.renderItem}
|
||||
renderItem={canManageUsers ? this.renderSelectableItem : this.renderUnselectableItem}
|
||||
theme={theme}
|
||||
/>
|
||||
</KeyboardLayout>
|
||||
|
||||
60
app/screens/channel_members/channel_members.test.js
Normal file
60
app/screens/channel_members/channel_members.test.js
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import CustomList from 'app/components/custom_list';
|
||||
import ChannelMembers from './channel_members';
|
||||
|
||||
describe('ChannelMembers', () => {
|
||||
const navigator = {
|
||||
setOnNavigatorEvent: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
theme: Preferences.THEMES.default,
|
||||
currentUserId: 'current-user-id',
|
||||
currentChannelId: 'current-channel-id',
|
||||
canManageUsers: false,
|
||||
actions: {
|
||||
getProfilesInChannel: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
handleRemoveChannelMembers: jest.fn(),
|
||||
searchProfiles: jest.fn(),
|
||||
},
|
||||
navigator,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelMembers {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should use renderUnselectableItem when canManagerUsers is false', () => {
|
||||
const props = {...baseProps, canManageUsers: false};
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelMembers {...props}/>,
|
||||
);
|
||||
|
||||
const renderItem = wrapper.find(CustomList).props().renderItem;
|
||||
expect(renderItem).toEqual(wrapper.instance().renderUnselectableItem);
|
||||
});
|
||||
|
||||
test('should use renderSelectableItem when canManagerUsers is true', () => {
|
||||
const props = {...baseProps, canManageUsers: true};
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelMembers {...props}/>,
|
||||
);
|
||||
|
||||
const renderItem = wrapper.find(CustomList).props().renderItem;
|
||||
expect(renderItem).toEqual(wrapper.instance().renderSelectableItem);
|
||||
});
|
||||
});
|
||||
@@ -88,9 +88,12 @@ export default class EditProfile extends PureComponent {
|
||||
removeProfileImage: PropTypes.func.isRequired,
|
||||
updateUser: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
config: PropTypes.object.isRequired,
|
||||
currentUser: PropTypes.object.isRequired,
|
||||
firstNameDisabled: PropTypes.bool.isRequired,
|
||||
lastNameDisabled: PropTypes.bool.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
nicknameDisabled: PropTypes.bool.isRequired,
|
||||
positionDisabled: PropTypes.bool.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
@@ -318,16 +321,12 @@ export default class EditProfile extends PureComponent {
|
||||
|
||||
renderFirstNameSettings = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {config, currentUser, theme} = this.props;
|
||||
const {firstNameDisabled, theme} = this.props;
|
||||
const {firstName} = this.state;
|
||||
|
||||
const {auth_service: service} = currentUser;
|
||||
const disabled = (service === 'ldap' && config.LdapFristNameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlFirstNameAttributeSet === 'true');
|
||||
|
||||
return (
|
||||
<TextSetting
|
||||
disabled={disabled}
|
||||
disabled={firstNameDisabled}
|
||||
id='firstName'
|
||||
label={holders.firstName}
|
||||
disabledText={formatMessage({
|
||||
@@ -343,17 +342,13 @@ export default class EditProfile extends PureComponent {
|
||||
|
||||
renderLastNameSettings = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {config, currentUser, theme} = this.props;
|
||||
const {lastNameDisabled, theme} = this.props;
|
||||
const {lastName} = this.state;
|
||||
|
||||
const {auth_service: service} = currentUser;
|
||||
const disabled = (service === 'ldap' && config.LdapLastNameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlLastNameAttributeSet === 'true');
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TextSetting
|
||||
disabled={disabled}
|
||||
disabled={lastNameDisabled}
|
||||
id='lastName'
|
||||
label={holders.lastName}
|
||||
disabledText={formatMessage({
|
||||
@@ -455,16 +450,12 @@ export default class EditProfile extends PureComponent {
|
||||
|
||||
renderNicknameSettings = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {config, currentUser, theme} = this.props;
|
||||
const {nicknameDisabled, theme} = this.props;
|
||||
const {nickname} = this.state;
|
||||
|
||||
const {auth_service: service} = currentUser;
|
||||
const disabled = (service === 'ldap' && config.LdapNicknameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlNicknameAttributeSet === 'true');
|
||||
|
||||
return (
|
||||
<TextSetting
|
||||
disabled={disabled}
|
||||
disabled={nicknameDisabled}
|
||||
id='nickname'
|
||||
label={holders.nickname}
|
||||
disabledText={formatMessage({
|
||||
@@ -481,15 +472,12 @@ export default class EditProfile extends PureComponent {
|
||||
|
||||
renderPositionSettings = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {config, currentUser, theme} = this.props;
|
||||
const {positionDisabled, theme} = this.props;
|
||||
const {position} = this.state;
|
||||
|
||||
const {auth_service: service} = currentUser;
|
||||
const disabled = (service === 'ldap' || service === 'saml') && config.PositionAttribute === 'true';
|
||||
|
||||
return (
|
||||
<TextSetting
|
||||
disabled={disabled}
|
||||
disabled={positionDisabled}
|
||||
id='position'
|
||||
label={holders.position}
|
||||
disabledText={formatMessage({
|
||||
|
||||
@@ -32,9 +32,10 @@ describe('edit_profile', () => {
|
||||
|
||||
const baseProps = {
|
||||
actions,
|
||||
config: {
|
||||
ShowEmailAddress: true,
|
||||
},
|
||||
firstNameDisabled: true,
|
||||
lastNameDisabled: true,
|
||||
nicknameDisabled: true,
|
||||
positionDisabled: true,
|
||||
theme: Preferences.THEMES.default,
|
||||
navigator,
|
||||
currentUser: {
|
||||
|
||||
@@ -6,14 +6,39 @@ import {bindActionCreators} from 'redux';
|
||||
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
|
||||
|
||||
import {setProfileImageUri, removeProfileImage, updateUser} from 'app/actions/views/edit_profile';
|
||||
|
||||
import EditProfile from './edit_profile';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const config = getConfig(state);
|
||||
const {serverVersion} = state.entities.general;
|
||||
const {auth_service: service} = ownProps.currentUser;
|
||||
|
||||
const firstNameDisabled = (service === 'ldap' && config.LdapFirstNameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlFirstNameAttributeSet === 'true');
|
||||
|
||||
const lastNameDisabled = (service === 'ldap' && config.LdapLastNameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlLastNameAttributeSet === 'true');
|
||||
|
||||
const nicknameDisabled = (service === 'ldap' && config.LdapNicknameAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlNicknameAttributeSet === 'true');
|
||||
|
||||
let positionDisabled = false;
|
||||
if (isMinimumServerVersion(serverVersion, 5, 12)) {
|
||||
positionDisabled = (service === 'ldap' && config.LdapPositionAttributeSet === 'true') ||
|
||||
(service === 'saml' && config.SamlPositionAttributeSet === 'true');
|
||||
} else {
|
||||
positionDisabled = (service === 'ldap' || service === 'saml') && config.PositionAttribute === 'true';
|
||||
}
|
||||
|
||||
return {
|
||||
config: getConfig(state),
|
||||
firstNameDisabled,
|
||||
lastNameDisabled,
|
||||
nicknameDisabled,
|
||||
positionDisabled,
|
||||
theme: getTheme(state),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ import {connect} from 'react-redux';
|
||||
import {setDeviceToken} from 'mattermost-redux/actions/general';
|
||||
import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
import {getDeviceTimezone, isTimezoneEnabled} from 'app/utils/timezone';
|
||||
import {getDeviceTimezone} from 'app/utils/timezone';
|
||||
|
||||
const lazyLoadEntry = () => {
|
||||
return require('./entry').default;
|
||||
|
||||
@@ -6,7 +6,7 @@ import {connect} from 'react-redux';
|
||||
|
||||
import {selectPost} from 'mattermost-redux/actions/posts';
|
||||
import {makeGetChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {getPost, makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {loadThreadIfNecessary} from 'app/actions/views/channel';
|
||||
@@ -15,14 +15,16 @@ import LongPost from './long_post';
|
||||
|
||||
function makeMapStateToProps() {
|
||||
const getChannel = makeGetChannel();
|
||||
const getReactionsForPost = makeGetReactionsForPost();
|
||||
|
||||
return function mapStateToProps(state, ownProps) {
|
||||
const post = getPost(state, ownProps.postId);
|
||||
const channel = post ? getChannel(state, {id: post.channel_id}) : null;
|
||||
const reactions = getReactionsForPost(state, post.id);
|
||||
|
||||
return {
|
||||
channelName: channel ? channel.display_name : '',
|
||||
hasReactions: post ? post.has_reactions : false,
|
||||
hasReactions: (reactions && Object.keys(reactions).length > 0) || Boolean(post.has_reactions),
|
||||
inThreadView: Boolean(state.entities.posts.selectedPostId),
|
||||
fileIds: post ? post.file_ids : false,
|
||||
theme: getTheme(state),
|
||||
|
||||
@@ -429,6 +429,7 @@ export default class PostOptions extends PureComponent {
|
||||
marginFromTop={marginFromTop > 0 ? marginFromTop : 0}
|
||||
onRequestClose={this.close}
|
||||
initialPosition={initialPosition}
|
||||
key={marginFromTop}
|
||||
>
|
||||
{options}
|
||||
</SlideUpPanel>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {clearSearch, removeSearchTerms, searchPostsWithParams, getMorePostsForSe
|
||||
import {getCurrentChannelId, filterPostIds} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
|
||||
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
|
||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
@@ -17,7 +18,7 @@ import {loadChannelsByTeamName, loadThreadIfNecessary} from 'app/actions/views/c
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
import {makePreparePostIdsForSearchPosts} from 'app/selectors/post_list';
|
||||
import {handleSearchDraftChanged} from 'app/actions/views/search';
|
||||
import {getDeviceUtcOffset, getUtcOffsetForTimeZone, isTimezoneEnabled} from 'app/utils/timezone';
|
||||
import {getDeviceUtcOffset, getUtcOffsetForTimeZone} from 'app/utils/timezone';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import Search from './search';
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
|
||||
import {isTimezoneEnabled} from 'app/utils/timezone';
|
||||
import {isThemeSwitchingEnabled} from 'app/utils/theme';
|
||||
|
||||
import DisplaySettings from './display_settings';
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {updateMe} from 'mattermost-redux/actions/users';
|
||||
|
||||
import NotificationSettingsMobile from './notification_settings_mobile';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const config = getConfig(state);
|
||||
const theme = getTheme(state);
|
||||
const updateMeRequest = state.requests.users.updateMe;
|
||||
const currentUser = getCurrentUser(state);
|
||||
|
||||
return {
|
||||
config: getConfig(state),
|
||||
theme: getTheme(state),
|
||||
config,
|
||||
theme,
|
||||
updateMeRequest,
|
||||
currentUser,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(NotificationSettingsMobile);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
updateMe,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(NotificationSettingsMobile);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import React from 'react';
|
||||
import {injectIntl} from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
Modal,
|
||||
Platform,
|
||||
ScrollView,
|
||||
@@ -12,6 +13,11 @@ import {
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
import deepEqual from 'deep-equal';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {RequestStatus} from 'mattermost-redux/constants';
|
||||
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import RadioButtonGroup from 'app/components/radio_button';
|
||||
import NotificationPreferences from 'app/notification_preferences';
|
||||
@@ -19,10 +25,20 @@ import PushNotifications from 'app/push_notifications';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import SectionItem from 'app/screens/settings/section_item';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {getNotificationProps} from 'app/utils/notify_props';
|
||||
|
||||
import NotificationSettingsMobileBase from './notification_settings_mobile_base';
|
||||
|
||||
class NotificationSettingsMobileAndroid extends NotificationSettingsMobileBase {
|
||||
static propTypes = {
|
||||
...NotificationSettingsMobileBase.propTypes,
|
||||
updateMeRequest: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
currentUser: {},
|
||||
}
|
||||
|
||||
cancelMobilePushModal = () => {
|
||||
this.setState({
|
||||
newPush: this.state.push,
|
||||
@@ -354,6 +370,24 @@ class NotificationSettingsMobileAndroid extends NotificationSettingsMobileBase {
|
||||
);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
super.componentWillReceiveProps(nextProps);
|
||||
|
||||
const {updateMeRequest, intl} = nextProps;
|
||||
if (this.props.updateMeRequest !== updateMeRequest && updateMeRequest.status === RequestStatus.FAILURE) {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.notification_settings.save_failed_title',
|
||||
defaultMessage: 'Connection issue',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.notification_settings.save_failed_description',
|
||||
defaultMessage: 'The notification settings failed to save due to a connection issue, please try again.',
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderMobilePushSection() {
|
||||
const {config, theme} = this.props;
|
||||
|
||||
@@ -583,12 +617,49 @@ class NotificationSettingsMobileAndroid extends NotificationSettingsMobileBase {
|
||||
|
||||
saveMobilePushModal = () => {
|
||||
this.setState({showMobilePushModal: false});
|
||||
this.setMobilePush(this.state.newPush);
|
||||
this.setMobilePush(this.state.newPush, this.saveNotificationProps);
|
||||
};
|
||||
|
||||
saveMobilePushStatusModal = () => {
|
||||
this.setState({showMobilePushStatusModal: false});
|
||||
this.setMobilePushStatus(this.state.newPushStatus);
|
||||
this.setMobilePushStatus(this.state.newPushStatus, this.saveNotificationProps);
|
||||
};
|
||||
|
||||
saveNotificationProps = () => {
|
||||
const {
|
||||
channel,
|
||||
comments,
|
||||
desktop,
|
||||
email,
|
||||
first_name: firstName,
|
||||
mention_keys: mentionKeys,
|
||||
push,
|
||||
push_status: pushStatus,
|
||||
} = this.state;
|
||||
|
||||
const {currentUser} = this.props;
|
||||
|
||||
const notifyProps = {
|
||||
channel,
|
||||
comments,
|
||||
desktop,
|
||||
email,
|
||||
first_name: firstName,
|
||||
mention_keys: mentionKeys,
|
||||
push,
|
||||
push_status: pushStatus,
|
||||
user_id: currentUser.id,
|
||||
};
|
||||
|
||||
const {user_id: userId} = notifyProps;
|
||||
const previousProps = {
|
||||
...getNotificationProps(currentUser),
|
||||
user_id: userId,
|
||||
};
|
||||
|
||||
if (!deepEqual(previousProps, notifyProps)) {
|
||||
this.props.actions.updateMe({notify_props: notifyProps});
|
||||
}
|
||||
};
|
||||
|
||||
saveMobileSoundsModal = () => {
|
||||
|
||||
@@ -11,6 +11,9 @@ import {setNavigatorStyles} from 'app/utils/theme';
|
||||
|
||||
export default class NotificationSettingsMobileBase extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
updateMe: PropTypes.func.isRequired,
|
||||
}),
|
||||
config: PropTypes.object.isRequired,
|
||||
currentUser: PropTypes.object.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
@@ -89,12 +92,12 @@ export default class NotificationSettingsMobileBase extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
setMobilePush = (push) => {
|
||||
this.setState({push});
|
||||
setMobilePush = (push, callback) => {
|
||||
this.setState({push}, callback);
|
||||
};
|
||||
|
||||
setMobilePushStatus = (value) => {
|
||||
this.setState({push_status: value});
|
||||
setMobilePushStatus = (value, callback) => {
|
||||
this.setState({push_status: value}, callback);
|
||||
};
|
||||
|
||||
saveUserNotifyProps = () => {
|
||||
|
||||
@@ -40,7 +40,7 @@ export default makeStyleSheetFromTheme((theme) => {
|
||||
color: theme.centerChannelColor,
|
||||
flex: 1,
|
||||
fontSize: 17,
|
||||
lineHeight: 43,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
arrowContainer: {
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -7,14 +7,13 @@ import {connect} from 'react-redux';
|
||||
import {setChannelDisplayName} from 'app/actions/views/channel';
|
||||
import {makeDirectChannel} from 'app/actions/views/more_dms';
|
||||
|
||||
import {getTeammateNameDisplaySetting, getTheme, getBool} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getTeammateNameDisplaySetting, getTheme, getBool} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
import {loadBot} from 'mattermost-redux/actions/bots';
|
||||
import {getBotAccounts} from 'mattermost-redux/selectors/entities/bots';
|
||||
|
||||
import {isTimezoneEnabled} from 'app/utils/timezone';
|
||||
|
||||
import UserProfile from './user_profile';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
|
||||
@@ -17,7 +17,3 @@ export function getUtcOffsetForTimeZone(timezone) {
|
||||
return moment.tz(timezone).utcOffset();
|
||||
}
|
||||
|
||||
export function isTimezoneEnabled(state) {
|
||||
const {config} = state.entities.general;
|
||||
return config.ExperimentalTimezone === 'true';
|
||||
}
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Erwähnungen in Antworten",
|
||||
"mobile.account_notifications.threads_start": "Diskussionen die ich starte",
|
||||
"mobile.account_notifications.threads_start_participate": "Diskussionen die ich starte oder an denen ich teilnehme",
|
||||
"mobile.account.settings.cancel": "Abbrechen",
|
||||
"mobile.account.settings.save": "Speichern",
|
||||
"mobile.action_menu.select": "Wählen Sie eine Option",
|
||||
"mobile.advanced_settings.clockDisplay": "Uhrzeit-Format",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Öffentlicher Kanal",
|
||||
"mobile.channel_list.alertNo": "Nein",
|
||||
"mobile.channel_list.alertYes": "Ja",
|
||||
"mobile.channel_list.archived": "ARCHIVIERT",
|
||||
"mobile.channel_list.channels": "KANÄLE",
|
||||
"mobile.channel_list.closeDM": "Direktnachricht schließen",
|
||||
"mobile.channel_list.closeGM": "Gruppennachricht schließen",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Mentions in threads",
|
||||
"mobile.account_notifications.threads_start": "Threads that I start",
|
||||
"mobile.account_notifications.threads_start_participate": "Threads that I start or participate in",
|
||||
"mobile.account.settings.cancel": "Cancel",
|
||||
"mobile.account.settings.save": "Save",
|
||||
"mobile.action_menu.select": "Select an option",
|
||||
"mobile.advanced_settings.clockDisplay": "Clock display",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Public Channel",
|
||||
"mobile.channel_list.alertNo": "No",
|
||||
"mobile.channel_list.alertYes": "Yes",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "CHANNELS",
|
||||
"mobile.channel_list.closeDM": "Close Direct Message",
|
||||
"mobile.channel_list.closeGM": "Close Group Message",
|
||||
@@ -401,6 +401,7 @@
|
||||
"mobile.routes.thread": "{channelName} Thread",
|
||||
"mobile.routes.thread_dm": "Direct Message Thread",
|
||||
"mobile.routes.user_profile": "Profile",
|
||||
"mobile.routes.user_profile.edit": "Edit",
|
||||
"mobile.routes.user_profile.local_time": "LOCAL TIME",
|
||||
"mobile.routes.user_profile.send_message": "Send Message",
|
||||
"mobile.search.after_modifier_description": "to find posts after a specific date",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Menciones en hilos",
|
||||
"mobile.account_notifications.threads_start": "Hilos que yo comience",
|
||||
"mobile.account_notifications.threads_start_participate": "Hilos que yo comience o participe",
|
||||
"mobile.account.settings.cancel": "Cancelar",
|
||||
"mobile.account.settings.save": "Guardar",
|
||||
"mobile.action_menu.select": "Selecciona una opción",
|
||||
"mobile.advanced_settings.clockDisplay": "Visualización de la hora",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Canal Público",
|
||||
"mobile.channel_list.alertNo": "No",
|
||||
"mobile.channel_list.alertYes": "Sí",
|
||||
"mobile.channel_list.archived": "ARCHIVADO",
|
||||
"mobile.channel_list.channels": "CANALES",
|
||||
"mobile.channel_list.closeDM": "Cerrar Mensaje Directo",
|
||||
"mobile.channel_list.closeGM": "Cerrar Mensaje de Grupo",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Mentions dans les fils de discussion",
|
||||
"mobile.account_notifications.threads_start": "Fils de discussion que je démarre",
|
||||
"mobile.account_notifications.threads_start_participate": "Fils de discussion que je démarre ou auxquels je participe",
|
||||
"mobile.account.settings.cancel": "Annuler",
|
||||
"mobile.account.settings.save": "Enregistrer",
|
||||
"mobile.action_menu.select": "Sélectionnez une option",
|
||||
"mobile.advanced_settings.clockDisplay": "Affichage de l'horloge",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Canal public",
|
||||
"mobile.channel_list.alertNo": "Non",
|
||||
"mobile.channel_list.alertYes": "Oui",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "CANAUX",
|
||||
"mobile.channel_list.closeDM": "Fermer le message personnel",
|
||||
"mobile.channel_list.closeGM": "Fermer le groupe de message",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Citazioni nelle discussioni",
|
||||
"mobile.account_notifications.threads_start": "Discussioni avviate da me",
|
||||
"mobile.account_notifications.threads_start_participate": "Discussioni alle quali ho partecipato",
|
||||
"mobile.account.settings.cancel": "Annulla",
|
||||
"mobile.account.settings.save": "Salva",
|
||||
"mobile.action_menu.select": "Seleziona un'opzione",
|
||||
"mobile.advanced_settings.clockDisplay": "Visualizza orologio",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Canale Pubblico",
|
||||
"mobile.channel_list.alertNo": "No",
|
||||
"mobile.channel_list.alertYes": "Si",
|
||||
"mobile.channel_list.archived": "ARCHIVIATO",
|
||||
"mobile.channel_list.channels": "CANALI",
|
||||
"mobile.channel_list.closeDM": "Chudi Messaggio Diretto",
|
||||
"mobile.channel_list.closeGM": "Chiudi Messaggio di Gruppo",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "スレッド内のあなたについての投稿",
|
||||
"mobile.account_notifications.threads_start": "自分で開始したスレッド",
|
||||
"mobile.account_notifications.threads_start_participate": "開始もしくは参加したスレッド",
|
||||
"mobile.account.settings.cancel": "キャンセル",
|
||||
"mobile.account.settings.save": "保存する",
|
||||
"mobile.action_menu.select": "オプションを選択してください",
|
||||
"mobile.advanced_settings.clockDisplay": "時刻表示",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "公開チャンネル",
|
||||
"mobile.channel_list.alertNo": "いいえ",
|
||||
"mobile.channel_list.alertYes": "はい",
|
||||
"mobile.channel_list.archived": "アーカイブ",
|
||||
"mobile.channel_list.channels": "チャンネル",
|
||||
"mobile.channel_list.closeDM": "ダイレクトメッセージを閉じる",
|
||||
"mobile.channel_list.closeGM": "グループメッセージを閉じる",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Mentions in threads",
|
||||
"mobile.account_notifications.threads_start": "등록한 모든 스레드의 답변에 대해 알림",
|
||||
"mobile.account_notifications.threads_start_participate": "등록하거나 답변했던 모든 스레드의 답변에 대해 알림",
|
||||
"mobile.account.settings.cancel": "취소",
|
||||
"mobile.account.settings.save": "저장",
|
||||
"mobile.action_menu.select": "Select an option",
|
||||
"mobile.advanced_settings.clockDisplay": "시간 표시",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "공개 채널",
|
||||
"mobile.channel_list.alertNo": "아니요",
|
||||
"mobile.channel_list.alertYes": "네",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "CHANNELS",
|
||||
"mobile.channel_list.closeDM": "Close Direct Message",
|
||||
"mobile.channel_list.closeGM": "Close Group Message",
|
||||
@@ -206,19 +206,19 @@
|
||||
"mobile.display_settings.theme": "테마",
|
||||
"mobile.document_preview.failed_description": "문서를 여는 중에 에러가 발생했습니다. {fileType} 뷰어를 설치한 후에 다시 시도해 주십시오.\n",
|
||||
"mobile.document_preview.failed_title": "Open Document failed",
|
||||
"mobile.downloader.android_complete": "Download complete",
|
||||
"mobile.downloader.android_failed": "Download failed",
|
||||
"mobile.downloader.android_permission": "We need access to the downloads folder to save files.",
|
||||
"mobile.downloader.android_started": "Download started",
|
||||
"mobile.downloader.android_success": "download successful",
|
||||
"mobile.downloader.complete": "Download complete",
|
||||
"mobile.downloader.disabled_description": "File downloads are disabled on this server. Please contact your System Admin for more details.\n",
|
||||
"mobile.downloader.disabled_title": "Download disabled",
|
||||
"mobile.downloader.android_complete": "다운로드 완료",
|
||||
"mobile.downloader.android_failed": "다운로드 실패",
|
||||
"mobile.downloader.android_permission": "파일 저장을 위해 다운로드 폴더 접근 권한이 필요합니다.",
|
||||
"mobile.downloader.android_started": "다운로드 시작",
|
||||
"mobile.downloader.android_success": "다운로드 성공",
|
||||
"mobile.downloader.complete": "다운로드 완료",
|
||||
"mobile.downloader.disabled_description": "이 서버에 파일을 다운로드할 수 없습니다. 자세한 사항은 시스템 관리자에게 문의하세요.\n",
|
||||
"mobile.downloader.disabled_title": "다운로드 실패",
|
||||
"mobile.downloader.downloading": "다운로드중...",
|
||||
"mobile.downloader.failed_description": "파일을 다운로드 하는 중 오류가 발생했습니다. 인터넷 연결 상태를 확인하고 다시 시도해 주세요.\n",
|
||||
"mobile.downloader.failed_title": "Download failed",
|
||||
"mobile.downloader.image_saved": "Image Saved",
|
||||
"mobile.downloader.video_saved": "Video Saved",
|
||||
"mobile.downloader.failed_title": "다운로드 실패",
|
||||
"mobile.downloader.image_saved": "이미지 저장 완료",
|
||||
"mobile.downloader.video_saved": "비디오 저장 완료",
|
||||
"mobile.drawer.teamsTitle": "서비스 약관",
|
||||
"mobile.edit_channel": "저장",
|
||||
"mobile.edit_post.title": "Editing Message",
|
||||
@@ -379,7 +379,7 @@
|
||||
"mobile.reset_status.title_ooo": "Disable \"Out Of Office\"?",
|
||||
"mobile.retry_message": "메세지를 새로 고침 하는데 실패하였습니다. 당겨 올려서 다시 시도해 보세요.",
|
||||
"mobile.routes.channel_members.action": "팀에서 제거하기",
|
||||
"mobile.routes.channel_members.action_message": "You must select at least one member to remove from the channel.",
|
||||
"mobile.routes.channel_members.action_message": "채널에 추가할 최소 한명의 멤버를 선택해야합니다.",
|
||||
"mobile.routes.channel_members.action_message_confirm": "Are you sure you want to remove the selected members from the channel?",
|
||||
"mobile.routes.channelInfo": "Info",
|
||||
"mobile.routes.channelInfo.createdBy": "Created by {creator} on ",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Mentions in threads",
|
||||
"mobile.account_notifications.threads_start": "Threads that I start",
|
||||
"mobile.account_notifications.threads_start_participate": "Threads that I start or participate in",
|
||||
"mobile.account.settings.cancel": "Annuleren",
|
||||
"mobile.account.settings.save": "Opslaan",
|
||||
"mobile.action_menu.select": "Select an option",
|
||||
"mobile.advanced_settings.clockDisplay": "Klok weergave",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Publieke kanalen",
|
||||
"mobile.channel_list.alertNo": "Nee",
|
||||
"mobile.channel_list.alertYes": "Ja",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "CHANNELS",
|
||||
"mobile.channel_list.closeDM": "Close Direct Message",
|
||||
"mobile.channel_list.closeGM": "Close Group Message",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Wzmianki w wątkach",
|
||||
"mobile.account_notifications.threads_start": "Wątki, które rozpocząłem",
|
||||
"mobile.account_notifications.threads_start_participate": "Wątki, które rozpocząłem lub w których uczestniczę",
|
||||
"mobile.account.settings.cancel": "Anuluj",
|
||||
"mobile.account.settings.save": "Zapisz",
|
||||
"mobile.action_menu.select": "Wybierz opcję",
|
||||
"mobile.advanced_settings.clockDisplay": "Wyświetlanie czasu",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Kanał publiczny",
|
||||
"mobile.channel_list.alertNo": "Nie",
|
||||
"mobile.channel_list.alertYes": "Tak",
|
||||
"mobile.channel_list.archived": "ZARCHIWIZOWANY",
|
||||
"mobile.channel_list.channels": "KANAŁY",
|
||||
"mobile.channel_list.closeDM": "Zamknij Wiadomość Bezpośrednią",
|
||||
"mobile.channel_list.closeGM": "Zamknij Wiadomość Grupową",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Menções em tópicos",
|
||||
"mobile.account_notifications.threads_start": "Tópicos que eu iniciei",
|
||||
"mobile.account_notifications.threads_start_participate": "Tópicos que eu iniciei ou participo",
|
||||
"mobile.account.settings.cancel": "Cancelar",
|
||||
"mobile.account.settings.save": "Salvar",
|
||||
"mobile.action_menu.select": "Selecione uma opção",
|
||||
"mobile.advanced_settings.clockDisplay": "Exibição do relógio",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Canal Público",
|
||||
"mobile.channel_list.alertNo": "Não",
|
||||
"mobile.channel_list.alertYes": "Sim",
|
||||
"mobile.channel_list.archived": "ARQUIVADO",
|
||||
"mobile.channel_list.channels": "CANAIS",
|
||||
"mobile.channel_list.closeDM": "Fechar Mensagem Direta",
|
||||
"mobile.channel_list.closeGM": "Fechar Mensagem em Grupo",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Menționează în fire",
|
||||
"mobile.account_notifications.threads_start": "Subiecte pe care le încep",
|
||||
"mobile.account_notifications.threads_start_participate": "Threads la care încep sau particip",
|
||||
"mobile.account.settings.cancel": "Anulare",
|
||||
"mobile.account.settings.save": "Salvați",
|
||||
"mobile.action_menu.select": "Selecteaza o optiune",
|
||||
"mobile.advanced_settings.clockDisplay": "Afișaj ceas",
|
||||
@@ -166,7 +165,8 @@
|
||||
"mobile.channel_info.publicChannel": "Canalul public",
|
||||
"mobile.channel_list.alertNo": "Nu",
|
||||
"mobile.channel_list.alertYes": "Da",
|
||||
"mobile.channel_list.channels": "Canale",
|
||||
"mobile.channel_list.archived": "ARHIVAT",
|
||||
"mobile.channel_list.channels": "CANALE",
|
||||
"mobile.channel_list.closeDM": "Închideți mesajul direct",
|
||||
"mobile.channel_list.closeGM": "Închideți Mesajul grupului",
|
||||
"mobile.channel_list.members": "Membri",
|
||||
@@ -479,7 +479,7 @@
|
||||
"post_info.auto_responder": "RASPUNS AUTOMAT",
|
||||
"post_info.bot": "BOT",
|
||||
"post_info.del": "Șterge",
|
||||
"post_info.edit": "Editează",
|
||||
"post_info.edit": "Editați",
|
||||
"post_info.message.show_less": "Afișați mai puține",
|
||||
"post_info.message.show_more": "Detalii",
|
||||
"post_info.system": "Sistem",
|
||||
|
||||
@@ -80,10 +80,10 @@
|
||||
"integrations.add": "Добавить",
|
||||
"intro_messages.anyMember": " Любой участник может зайти и читать этот канал.",
|
||||
"intro_messages.beginning": "Начало {name}",
|
||||
"intro_messages.creator": "{name} - {type}, созданный {creator} {date}",
|
||||
"intro_messages.creatorPrivate": "{name} - {type}, созданный {creator} {date}",
|
||||
"intro_messages.creator": "Канал: {name}, создан {creator} {date}",
|
||||
"intro_messages.creatorPrivate": "Приватный канал: {name}, созданный {creator} {date}",
|
||||
"intro_messages.group_message": "Начало истории групповых сообщений с участниками. Размещённые здесь сообщения и файлы не видны за пределами этой области.",
|
||||
"intro_messages.noCreator": "{name} - {type}, созданный {date}",
|
||||
"intro_messages.noCreator": "Канал: {name}, созданный {date}",
|
||||
"intro_messages.onlyInvited": " Только приглашенные пользователи могут видеть этот приватный канал.",
|
||||
"last_users_message.added_to_channel.type": " **добавлены на канал**. Кем: {actor}.",
|
||||
"last_users_message.added_to_team.type": "были **добавлены в команду** пользователем {actor}.",
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Если меня упомянули",
|
||||
"mobile.account_notifications.threads_start": "Если я начал эту ветку",
|
||||
"mobile.account_notifications.threads_start_participate": "Если я начал эту ветку или участвовал в ней",
|
||||
"mobile.account.settings.cancel": "Отмена",
|
||||
"mobile.account.settings.save": "Сохранить",
|
||||
"mobile.action_menu.select": "Выберите опцию",
|
||||
"mobile.advanced_settings.clockDisplay": "Отображение времени",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Публичные каналы",
|
||||
"mobile.channel_list.alertNo": "Нет",
|
||||
"mobile.channel_list.alertYes": "Да",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "КАНАЛЫ",
|
||||
"mobile.channel_list.closeDM": "Закрыть личные сообщения",
|
||||
"mobile.channel_list.closeGM": "Закрыть сообщения группы",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Konulardaki anmalar",
|
||||
"mobile.account_notifications.threads_start": "Başlattığım konular",
|
||||
"mobile.account_notifications.threads_start_participate": "Başlattığım ya da katıldığım konular",
|
||||
"mobile.account.settings.cancel": "İptal",
|
||||
"mobile.account.settings.save": "Kaydet",
|
||||
"mobile.action_menu.select": "Bir seçenek seçin",
|
||||
"mobile.advanced_settings.clockDisplay": "Saat görünümü",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Herkese Açık Kanal",
|
||||
"mobile.channel_list.alertNo": "Hayır",
|
||||
"mobile.channel_list.alertYes": "Evet",
|
||||
"mobile.channel_list.archived": "ARŞİVLENMİŞ",
|
||||
"mobile.channel_list.channels": "KANALLAR",
|
||||
"mobile.channel_list.closeDM": "Doğrudan İletiyi Kapat",
|
||||
"mobile.channel_list.closeGM": "Grup İletisini Kapat",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "Згадки в тредах",
|
||||
"mobile.account_notifications.threads_start": "Гілки розпочаті мною",
|
||||
"mobile.account_notifications.threads_start_participate": "Якщо я почав цю гілку або приймав участь в ній",
|
||||
"mobile.account.settings.cancel": "Відміна",
|
||||
"mobile.account.settings.save": "Зберегти ",
|
||||
"mobile.action_menu.select": "Виберіть параметр",
|
||||
"mobile.advanced_settings.clockDisplay": "Дисплей годинника",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "Публічний канал",
|
||||
"mobile.channel_list.alertNo": "Ні ",
|
||||
"mobile.channel_list.alertYes": "Так ",
|
||||
"mobile.channel_list.archived": "ARCHIVED",
|
||||
"mobile.channel_list.channels": "КАНАЛИ",
|
||||
"mobile.channel_list.closeDM": "Закрити пряме повідомлення",
|
||||
"mobile.channel_list.closeGM": "Закрити групове повідомлення",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "串中的提及",
|
||||
"mobile.account_notifications.threads_start": "我创建的串",
|
||||
"mobile.account_notifications.threads_start_participate": "我创建的或参与的串",
|
||||
"mobile.account.settings.cancel": "取消",
|
||||
"mobile.account.settings.save": "保存",
|
||||
"mobile.action_menu.select": "选择选项",
|
||||
"mobile.advanced_settings.clockDisplay": "时钟显示",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "公共频道",
|
||||
"mobile.channel_list.alertNo": "否",
|
||||
"mobile.channel_list.alertYes": "是",
|
||||
"mobile.channel_list.archived": "归档",
|
||||
"mobile.channel_list.channels": "频道",
|
||||
"mobile.channel_list.closeDM": "关闭私信",
|
||||
"mobile.channel_list.closeGM": "关闭组消息",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"mobile.account_notifications.threads_mentions": "被提及的討論串",
|
||||
"mobile.account_notifications.threads_start": "我開啟的討論串",
|
||||
"mobile.account_notifications.threads_start_participate": "我開啟或參與的討論串",
|
||||
"mobile.account.settings.cancel": "取消",
|
||||
"mobile.account.settings.save": "儲存",
|
||||
"mobile.action_menu.select": "選擇選項",
|
||||
"mobile.advanced_settings.clockDisplay": "顯示時間",
|
||||
@@ -166,6 +165,7 @@
|
||||
"mobile.channel_info.publicChannel": "公開頻道",
|
||||
"mobile.channel_list.alertNo": "否",
|
||||
"mobile.channel_list.alertYes": "是",
|
||||
"mobile.channel_list.archived": "已封存",
|
||||
"mobile.channel_list.channels": "頻道",
|
||||
"mobile.channel_list.closeDM": "關閉直接傳訊",
|
||||
"mobile.channel_list.closeGM": "關閉群組訊息",
|
||||
|
||||
@@ -30,9 +30,9 @@ GEM
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.4.1)
|
||||
domain_name (0.5.20180417)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.2)
|
||||
dotenv (2.7.4)
|
||||
emoji_regex (1.0.1)
|
||||
excon (0.64.0)
|
||||
faraday (0.15.4)
|
||||
@@ -43,7 +43,7 @@ GEM
|
||||
faraday_middleware (0.13.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.5)
|
||||
fastlane (2.125.2)
|
||||
fastlane (2.127.1)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
@@ -96,7 +96,7 @@ GEM
|
||||
signet (~> 0.9)
|
||||
google-cloud-core (1.3.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-env (1.1.0)
|
||||
google-cloud-env (1.2.0)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-storage (1.16.0)
|
||||
digest-crc (~> 0.4)
|
||||
@@ -163,7 +163,7 @@ GEM
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.9.0)
|
||||
xcodeproj (1.11.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
@@ -187,4 +187,4 @@ DEPENDENCIES
|
||||
nokogiri
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.1
|
||||
2.0.2
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
7F581D35221ED5C60099E66B /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F581D34221ED5C60099E66B /* NotificationService.swift */; };
|
||||
7F581D39221ED5C60099E66B /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7F581D32221ED5C60099E66B /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
7F581F78221EEA7C0099E66B /* libUploadAttachments.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FABE04522137F2A00D0F595 /* libUploadAttachments.a */; };
|
||||
7F5BA34722B99B7B005B05D3 /* Mattermost+RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */; };
|
||||
7F5CA9A0208FE3B9004F91CE /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F5CA991208FE38F004F91CE /* libRNDocumentPicker.a */; };
|
||||
7F642DF02093533300F3165E /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F642DED2093530B00F3165E /* libRNDeviceInfo.a */; };
|
||||
7F72F2EE2211220500F98FFF /* GenericPreview.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7F72F2ED2211220500F98FFF /* GenericPreview.xib */; };
|
||||
@@ -819,6 +820,8 @@
|
||||
7F581D34221ED5C60099E66B /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||
7F581D36221ED5C60099E66B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
7F581F77221EEA5A0099E66B /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = "<group>"; };
|
||||
7F5BA34522B99B7B005B05D3 /* Mattermost+RCTUITextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Mattermost+RCTUITextView.h"; path = "Mattermost/Mattermost+RCTUITextView.h"; sourceTree = "<group>"; };
|
||||
7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "Mattermost+RCTUITextView.m"; path = "Mattermost/Mattermost+RCTUITextView.m"; sourceTree = "<group>"; };
|
||||
7F5CA956208FE38F004F91CE /* RNDocumentPicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNDocumentPicker.xcodeproj; path = "../node_modules/react-native-document-picker/ios/RNDocumentPicker.xcodeproj"; sourceTree = "<group>"; };
|
||||
7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = "<group>"; };
|
||||
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = "<group>"; };
|
||||
@@ -1112,6 +1115,8 @@
|
||||
7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */,
|
||||
7F151D40221B069200FAD8F3 /* 0155-keys.png */,
|
||||
7F292AA51E8ABB1100A450A3 /* splash.png */,
|
||||
7F5BA34522B99B7B005B05D3 /* Mattermost+RCTUITextView.h */,
|
||||
7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */,
|
||||
);
|
||||
name = Mattermost;
|
||||
sourceTree = "<group>";
|
||||
@@ -2618,6 +2623,7 @@
|
||||
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */,
|
||||
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */,
|
||||
7F240ACD220D460300637665 /* MattermostBucketModule.m in Sources */,
|
||||
7F5BA34722B99B7B005B05D3 /* Mattermost+RCTUITextView.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2762,7 +2768,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 198;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2822,7 +2828,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 198;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
ENABLE_BITCODE = NO;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.20.0</string>
|
||||
<string>1.21.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -34,7 +34,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>198</string>
|
||||
<string>208</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
17
ios/Mattermost/Mattermost+RCTUITextView.h
Normal file
17
ios/Mattermost/Mattermost+RCTUITextView.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Mattermost+RCTUITextView.h
|
||||
// Mattermost
|
||||
//
|
||||
// Created by Elias Nahum on 6/18/19.
|
||||
// Copyright © 2019 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface Mattermost_RCTUITextView : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
36
ios/Mattermost/Mattermost+RCTUITextView.m
Normal file
36
ios/Mattermost/Mattermost+RCTUITextView.m
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Mattermost+RCTUITextView.m
|
||||
// Mattermost
|
||||
//
|
||||
// Created by Elias Nahum on 6/18/19.
|
||||
// Copyright © 2019 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Mattermost+RCTUITextView.h"
|
||||
#import "RCTUITextView.h"
|
||||
|
||||
@implementation Mattermost_RCTUITextView
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUITextView (DisableCopyPaste)
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
NSDictionary *response = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"com.apple.configuration.managed"];
|
||||
if(response) {
|
||||
NSString *copyPasteProtection = response[@"copyAndPasteProtection"];
|
||||
BOOL prevent = action == @selector(paste:) ||
|
||||
action == @selector(copy:) ||
|
||||
action == @selector(cut:) ||
|
||||
action == @selector(_share:);
|
||||
|
||||
if ([copyPasteProtection isEqual: @"true"] && prevent) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,7 +6,6 @@
|
||||
// See License.txt for license information.
|
||||
//
|
||||
|
||||
#import "RCTUITextView.h"
|
||||
#import "MattermostManaged.h"
|
||||
#import <UploadAttachments/Constants.h>
|
||||
|
||||
@@ -152,31 +151,19 @@ RCT_EXPORT_METHOD(getConfig:(RCTPromiseResolveBlock)resolve
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(isRunningInSplitView:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
BOOL isRunningInFullScreen = CGRectEqualToRect(
|
||||
[UIApplication sharedApplication].delegate.window.frame,
|
||||
[UIApplication sharedApplication].delegate.window.screen.bounds);
|
||||
resolve(@{
|
||||
@"isSplitView": @(!isRunningInFullScreen)
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(quitApp)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUITextView (DisableCopyPaste)
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
NSDictionary *response = [[NSUserDefaults standardUserDefaults] dictionaryForKey:configurationKey];
|
||||
if(response) {
|
||||
NSString *copyPasteProtection = response[@"copyAndPasteProtection"];
|
||||
BOOL prevent = action == @selector(paste:) ||
|
||||
action == @selector(copy:) ||
|
||||
action == @selector(cut:) ||
|
||||
action == @selector(_share:);
|
||||
|
||||
if ([copyPasteProtection isEqual: @"true"] && prevent) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.20.0</string>
|
||||
<string>1.21.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>198</string>
|
||||
<string>208</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.20.0</string>
|
||||
<string>1.21.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>198</string>
|
||||
<string>208</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.20.0</string>
|
||||
<string>1.21.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>198</string>
|
||||
<string>208</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
@@ -32,8 +32,13 @@
|
||||
if(![fileManager fileExistsAtPath:filePath]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = [NSData dataWithContentsOfFile:filePath];
|
||||
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
|
||||
if (data != nil) {
|
||||
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(void)removeFile:(NSString *)fileName {
|
||||
|
||||
@@ -126,28 +126,30 @@ import os.log
|
||||
|
||||
public func notificationReceipt(notificationId: Any?, receivedAt: Int, type: Any?) {
|
||||
let store = StoreManager.shared() as StoreManager
|
||||
let _ = store.getEntities(true)
|
||||
let serverURL = store.getServerUrl()
|
||||
let sessionToken = store.getToken()
|
||||
let urlString = "\(serverURL!)/api/v4/notifications/ack"
|
||||
|
||||
if (notificationId != nil) {
|
||||
let jsonObject: [String: Any] = [
|
||||
"id": notificationId as Any,
|
||||
"received_at": receivedAt,
|
||||
"platform": "ios",
|
||||
"type": type as Any
|
||||
]
|
||||
let entities = store.getEntities(true)
|
||||
if (entities != nil) {
|
||||
let serverURL = store.getServerUrl()
|
||||
let sessionToken = store.getToken()
|
||||
let urlString = "\(serverURL!)/api/v4/notifications/ack"
|
||||
|
||||
if !JSONSerialization.isValidJSONObject(jsonObject) {return}
|
||||
|
||||
guard let url = URL(string: urlString) else {return}
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("Bearer \(sessionToken!)", forHTTPHeaderField: "Authorization")
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
|
||||
URLSession(configuration: .ephemeral).dataTask(with: request).resume()
|
||||
if (notificationId != nil) {
|
||||
let jsonObject: [String: Any] = [
|
||||
"id": notificationId as Any,
|
||||
"received_at": receivedAt,
|
||||
"platform": "ios",
|
||||
"type": type as Any
|
||||
]
|
||||
|
||||
if !JSONSerialization.isValidJSONObject(jsonObject) {return}
|
||||
|
||||
guard let url = URL(string: urlString) else {return}
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("Bearer \(sessionToken!)", forHTTPHeaderField: "Authorization")
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
|
||||
URLSession(configuration: .ephemeral).dataTask(with: request).resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,8 @@ RCT_EXPORT_METHOD(
|
||||
[cookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *allCookies) {
|
||||
NSMutableDictionary *cookies = [NSMutableDictionary dictionary];
|
||||
for(NSHTTPCookie *currentCookie in allCookies) {
|
||||
if([currentCookie.domain containsString:topLevelDomain]) {
|
||||
NSString *domainWithDot = [NSString stringWithFormat:@".%@", currentCookie.domain];
|
||||
if([currentCookie.domain containsString:topLevelDomain] || [domainWithDot containsString:topLevelDomain]) {
|
||||
[cookies setObject:currentCookie.value forKey:currentCookie.name];
|
||||
}
|
||||
}
|
||||
|
||||
187
package-lock.json
generated
187
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mattermost-mobile",
|
||||
"version": "1.20.0",
|
||||
"version": "1.21.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -7664,25 +7664,25 @@
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"optional": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7692,13 +7692,13 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7708,37 +7708,37 @@
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"optional": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7747,25 +7747,25 @@
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"optional": true
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"optional": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7774,13 +7774,13 @@
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"optional": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7796,7 +7796,7 @@
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7810,13 +7810,13 @@
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"optional": true
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7825,7 +7825,7 @@
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7834,7 +7834,7 @@
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7844,19 +7844,19 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7865,13 +7865,13 @@
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"optional": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7880,13 +7880,13 @@
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7896,7 +7896,7 @@
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7905,7 +7905,7 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7914,13 +7914,13 @@
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"optional": true
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7931,7 +7931,7 @@
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7949,7 +7949,7 @@
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7959,13 +7959,13 @@
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
|
||||
"optional": true
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7975,7 +7975,7 @@
|
||||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -7987,19 +7987,19 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"optional": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8008,19 +8008,19 @@
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"optional": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"optional": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8030,19 +8030,19 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"optional": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8054,7 +8054,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"optional": true
|
||||
}
|
||||
@@ -8062,7 +8062,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8077,7 +8077,7 @@
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8086,43 +8086,43 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"optional": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"optional": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"optional": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"optional": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8133,7 +8133,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8142,7 +8142,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8151,13 +8151,13 @@
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8172,13 +8172,13 @@
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"optional": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -8187,13 +8187,13 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"optional": true
|
||||
}
|
||||
@@ -12579,9 +12579,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"jsc-android": {
|
||||
"version": "241213.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-241213.1.0.tgz",
|
||||
"integrity": "sha512-AH8NYyMNLNhcUEF97QbMxPNLNW+oiSBlvm1rsMNzgJ1d5TQzdh/AOJGsxeeESp3m9YIWGLCgUvGTVoVLs0p68A=="
|
||||
"version": "241213.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-241213.2.0.tgz",
|
||||
"integrity": "sha512-nfddejB9jxFSG+Uewf+zwATFi8F2CZEEgoHLoOj13egiBDoC7zMoxK1c5/Ycf3AGmGuwCgjpn3LWe0f4tKYbjw=="
|
||||
},
|
||||
"jsdom": {
|
||||
"version": "11.12.0",
|
||||
@@ -13155,8 +13155,8 @@
|
||||
"integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A=="
|
||||
},
|
||||
"mattermost-redux": {
|
||||
"version": "github:mattermost/mattermost-redux#80407bc07f477eaeb93be4045a686b6bf977697f",
|
||||
"from": "github:mattermost/mattermost-redux#80407bc07f477eaeb93be4045a686b6bf977697f",
|
||||
"version": "github:mattermost/mattermost-redux#7f38003e06057d8099949f757d6fbbb6170925e7",
|
||||
"from": "github:mattermost/mattermost-redux#7f38003e06057d8099949f757d6fbbb6170925e7",
|
||||
"requires": {
|
||||
"deep-equal": "1.0.1",
|
||||
"eslint-plugin-header": "3.0.0",
|
||||
@@ -13165,6 +13165,7 @@
|
||||
"harmony-reflect": "1.6.1",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"mime-db": "1.40.0",
|
||||
"moment-timezone": "0.5.25",
|
||||
"redux": "4.0.1",
|
||||
"redux-action-buffer": "1.2.0",
|
||||
"redux-batched-actions": "0.4.1",
|
||||
@@ -14180,7 +14181,7 @@
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -14192,7 +14193,7 @@
|
||||
},
|
||||
"cliui": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14221,7 +14222,7 @@
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14236,13 +14237,13 @@
|
||||
},
|
||||
"invert-kv": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
|
||||
"dev": true
|
||||
},
|
||||
"lcid": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14251,7 +14252,7 @@
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14278,7 +14279,7 @@
|
||||
},
|
||||
"os-locale": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14298,7 +14299,7 @@
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14319,7 +14320,7 @@
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
},
|
||||
@@ -14353,7 +14354,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14362,13 +14363,13 @@
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
@@ -15474,8 +15475,8 @@
|
||||
}
|
||||
},
|
||||
"react-native-device-info": {
|
||||
"version": "github:mattermost/react-native-device-info#5be3656f4e0ca5c3544618e5df3e9a498f183483",
|
||||
"from": "github:mattermost/react-native-device-info#5be3656f4e0ca5c3544618e5df3e9a498f183483"
|
||||
"version": "github:mattermost/react-native-device-info#66d730b4f675038867ca389be7374714c2db63b2",
|
||||
"from": "github:mattermost/react-native-device-info#66d730b4f675038867ca389be7374714c2db63b2"
|
||||
},
|
||||
"react-native-doc-viewer": {
|
||||
"version": "2.7.8",
|
||||
@@ -15556,8 +15557,8 @@
|
||||
}
|
||||
},
|
||||
"react-native-notifications": {
|
||||
"version": "github:mattermost/react-native-notifications#721fcb41b3c265a5eec208a1df181d4ffcafa477",
|
||||
"from": "github:mattermost/react-native-notifications#721fcb41b3c265a5eec208a1df181d4ffcafa477",
|
||||
"version": "github:mattermost/react-native-notifications#1b7ec8513606b42237ab4674de9dacb4d1935e38",
|
||||
"from": "github:mattermost/react-native-notifications#1b7ec8513606b42237ab4674de9dacb4d1935e38",
|
||||
"requires": {
|
||||
"core-js": "^1.0.0",
|
||||
"uuid": "^2.0.3"
|
||||
@@ -15567,11 +15568,6 @@
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
|
||||
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
|
||||
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18647,6 +18643,11 @@
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
|
||||
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mattermost-mobile",
|
||||
"version": "1.20.0",
|
||||
"version": "1.21.0",
|
||||
"description": "Mattermost Mobile with React Native",
|
||||
"repository": "git@github.com:mattermost/mattermost-mobile.git",
|
||||
"author": "Mattermost, Inc.",
|
||||
@@ -18,8 +18,8 @@
|
||||
"fuse.js": "3.4.4",
|
||||
"intl": "1.2.5",
|
||||
"jail-monkey": "2.2.0",
|
||||
"jsc-android": "241213.1.0",
|
||||
"mattermost-redux": "github:mattermost/mattermost-redux#80407bc07f477eaeb93be4045a686b6bf977697f",
|
||||
"jsc-android": "241213.2.0",
|
||||
"mattermost-redux": "github:mattermost/mattermost-redux#7f38003e06057d8099949f757d6fbbb6170925e7",
|
||||
"mime-db": "1.40.0",
|
||||
"moment-timezone": "0.5.25",
|
||||
"prop-types": "15.7.2",
|
||||
@@ -32,7 +32,7 @@
|
||||
"react-native-calendars": "github:mattermost/react-native-calendars#4937ec5a3bf7e86f9f35fcd85eb4aa6133f45b58",
|
||||
"react-native-circular-progress": "1.1.0",
|
||||
"react-native-cookies": "github:joeferraro/react-native-cookies#f11374745deba9f18f7b8a9bb4b0b2573026f522",
|
||||
"react-native-device-info": "github:mattermost/react-native-device-info#5be3656f4e0ca5c3544618e5df3e9a498f183483",
|
||||
"react-native-device-info": "github:mattermost/react-native-device-info#66d730b4f675038867ca389be7374714c2db63b2",
|
||||
"react-native-doc-viewer": "2.7.8",
|
||||
"react-native-document-picker": "2.3.0",
|
||||
"react-native-exception-handler": "2.10.7",
|
||||
@@ -45,7 +45,7 @@
|
||||
"react-native-linear-gradient": "2.5.4",
|
||||
"react-native-local-auth": "github:mattermost/react-native-local-auth#cc9ce2f468fbf7b431dfad3191a31aaa9227a6ab",
|
||||
"react-native-navigation": "github:migbot/react-native-navigation#03c623c373f818827a463ca0fe90f86f56e71b2f",
|
||||
"react-native-notifications": "github:mattermost/react-native-notifications#721fcb41b3c265a5eec208a1df181d4ffcafa477",
|
||||
"react-native-notifications": "github:mattermost/react-native-notifications#1b7ec8513606b42237ab4674de9dacb4d1935e38",
|
||||
"react-native-passcode-status": "1.1.1",
|
||||
"react-native-permissions": "1.1.1",
|
||||
"react-native-safe-area": "0.5.1",
|
||||
|
||||
@@ -21,7 +21,9 @@ import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||
import Video from 'react-native-video';
|
||||
import LocalAuth from 'react-native-local-auth';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import {getGenericPassword} from 'react-native-keychain';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
import {Preferences} from 'mattermost-redux/constants';
|
||||
import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
|
||||
@@ -29,8 +31,10 @@ import Loading from 'app/components/loading';
|
||||
import PaperPlane from 'app/components/paper_plane';
|
||||
import {MAX_FILE_COUNT} from 'app/constants/post_textbox';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import avoidNativeBridge from 'app/utils/avoid_native_bridge';
|
||||
import {getExtensionFromMime} from 'app/utils/file';
|
||||
import {emptyFunction} from 'app/utils/general';
|
||||
import {setCSRFFromCookie} from 'app/utils/security';
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
@@ -45,6 +49,7 @@ import {
|
||||
import ChannelButton from './channel_button';
|
||||
import TeamButton from './team_button';
|
||||
|
||||
const {Initialization} = NativeModules;
|
||||
const defaultTheme = Preferences.THEMES.default;
|
||||
const extensionSvg = {
|
||||
csv: ExcelSvg,
|
||||
@@ -70,8 +75,6 @@ export default class ExtensionPost extends PureComponent {
|
||||
maxFileSize: PropTypes.number.isRequired,
|
||||
navigation: PropTypes.object.isRequired,
|
||||
teamId: PropTypes.string.isRequired,
|
||||
token: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
@@ -227,6 +230,43 @@ export default class ExtensionPost extends PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
getAppCredentials = async () => {
|
||||
try {
|
||||
const credentials = await avoidNativeBridge(
|
||||
() => {
|
||||
return Initialization.credentialsExist;
|
||||
},
|
||||
() => {
|
||||
return Initialization.credentials;
|
||||
},
|
||||
() => {
|
||||
return getGenericPassword();
|
||||
}
|
||||
);
|
||||
|
||||
if (credentials) {
|
||||
const passwordParsed = credentials.password.split(',');
|
||||
|
||||
// password == token, url
|
||||
if (passwordParsed.length === 2) {
|
||||
const [token, url] = passwordParsed;
|
||||
|
||||
if (url && url !== 'undefined' && token && token !== 'undefined') {
|
||||
this.token = token;
|
||||
this.url = url;
|
||||
Client4.setUrl(url);
|
||||
Client4.setToken(token);
|
||||
await setCSRFFromCookie(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
getInputRef = (ref) => {
|
||||
this.input = ref;
|
||||
};
|
||||
@@ -294,6 +334,8 @@ export default class ExtensionPost extends PureComponent {
|
||||
};
|
||||
|
||||
initialize = async () => {
|
||||
await this.getAppCredentials();
|
||||
|
||||
const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
|
||||
let granted;
|
||||
if (!hasPermission) {
|
||||
@@ -311,8 +353,8 @@ export default class ExtensionPost extends PureComponent {
|
||||
};
|
||||
|
||||
loadData = async (items) => {
|
||||
const {actions, maxFileSize, teamId, token, url} = this.props;
|
||||
if (token && url) {
|
||||
const {actions, maxFileSize, teamId} = this.props;
|
||||
if (this.token && this.url) {
|
||||
const text = [];
|
||||
const files = [];
|
||||
let totalSize = 0;
|
||||
@@ -379,14 +421,14 @@ export default class ExtensionPost extends PureComponent {
|
||||
|
||||
onPost = () => {
|
||||
const {channelId, files, value} = this.state;
|
||||
const {currentUserId, token, url} = this.props;
|
||||
const {currentUserId} = this.props;
|
||||
|
||||
const data = {
|
||||
channelId,
|
||||
currentUserId,
|
||||
files,
|
||||
token,
|
||||
url,
|
||||
token: this.token,
|
||||
url: this.url,
|
||||
value,
|
||||
};
|
||||
|
||||
@@ -542,7 +584,7 @@ export default class ExtensionPost extends PureComponent {
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {maxFileSize, token, url} = this.props;
|
||||
const {maxFileSize} = this.props;
|
||||
const {error, hasPermission, files, totalSize, loaded} = this.state;
|
||||
|
||||
if (!loaded) {
|
||||
@@ -555,7 +597,7 @@ export default class ExtensionPost extends PureComponent {
|
||||
return this.renderErrorMessage(error);
|
||||
}
|
||||
|
||||
if (token && url) {
|
||||
if (this.token && this.url) {
|
||||
if (hasPermission === false) {
|
||||
const storage = formatMessage({
|
||||
id: 'mobile.extension.permission',
|
||||
|
||||
@@ -16,8 +16,7 @@ import ExtensionPost from './extension_post';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const config = getConfig(state);
|
||||
const {credentials} = state.entities.general;
|
||||
const {token, url} = credentials;
|
||||
|
||||
let channel = getCurrentChannel(state);
|
||||
if (channel && channel.delete_at !== 0) {
|
||||
channel = getDefaultChannel(state);
|
||||
@@ -29,8 +28,6 @@ function mapStateToProps(state) {
|
||||
currentUserId: getCurrentUserId(state),
|
||||
maxFileSize: getAllowedServerMaxFileSize(config),
|
||||
teamId: getCurrentTeamId(state),
|
||||
token,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import React, {PureComponent} from 'react';
|
||||
import {Provider} from 'react-redux';
|
||||
import {IntlProvider} from 'react-intl';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {getTranslations} from 'app/i18n';
|
||||
import {getCurrentLocale} from 'app/selectors/i18n';
|
||||
import {store} from 'app/mattermost';
|
||||
@@ -42,8 +40,6 @@ export default class ShareApp extends PureComponent {
|
||||
this.unsubscribeFromStore();
|
||||
}
|
||||
|
||||
this.setCredentialsForClient();
|
||||
|
||||
dispatch(extensionSelectTeamId(currentTeamId));
|
||||
|
||||
if (this.mounted) {
|
||||
@@ -52,16 +48,6 @@ export default class ShareApp extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
setCredentialsForClient() {
|
||||
const state = store.getState();
|
||||
const {credentials} = state.entities.general;
|
||||
|
||||
if (credentials.token && credentials.url) {
|
||||
Client4.setToken(credentials.token);
|
||||
Client4.setUrl(credentials.url);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.init) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user