Compare commits

...

6 Commits

Author SHA1 Message Date
Mattermost Build
d965ef9e1e Bump app build number to 398 (#6236) (#6237)
(cherry picked from commit d5856f7b06)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-05-05 15:02:16 -04:00
Mattermost Build
b13ed0f409 MM-43904 - Fix: Calls batch actions (#6229) (#6232)
* fix batch actions

* tests

(cherry picked from commit 67c65156a7)

Co-authored-by: Christopher Poile <cpoile@gmail.com>
2022-05-05 14:13:18 -04:00
Mattermost Build
a046e70ba8 Bump app build number to 396 (#6218) (#6219)
(cherry picked from commit cd34873c23)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-05-03 18:32:32 -04:00
Mattermost Build
20d106b609 MM-43904 - Fix: Calls: "Access to route for non-existent plugin" error log (#6210) (#6212)
* add isCallsPluginEnabled; refactor Calls.PluginId

* revert Podfile.lock changes

(cherry picked from commit 912287fbe0)

Co-authored-by: Christopher Poile <cpoile@gmail.com>
2022-05-03 15:10:46 -04:00
Mattermost Build
b476fc00ff Bump version 1.52.0 build 394 (#6201) (#6202)
* Bump app version number to  1.52.0

* Bump app build number to  394

(cherry picked from commit c1e3c878e3)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-04-29 18:28:04 -04:00
Mattermost Build
80357fa57b Update NOTICE.txt (#6198) (#6199)
(cherry picked from commit fe5bd60cec)

Co-authored-by: Amy Blais <29708087+amyblais@users.noreply.github.com>
2022-04-29 10:18:55 -04:00
26 changed files with 206 additions and 60 deletions

View File

@@ -2273,6 +2273,42 @@ SOFTWARE.
---
## react-native-math-view
This product contains 'react-native-math-view' by Shachar.
A react native view used to easily display and handle math. The library doesn't use WebView.
* HOMEPAGE:
* https://github.com/ShaMan123/react-native-math-view
* LICENSE: MIT
MIT License
Copyright (c) 2018 ShaMan123
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
© 2022 GitHub, Inc.
---
## react-native-mmkv-storage
This product contains 'react-native-mmkv-storage' by Ammar Ahmed.

View File

@@ -131,8 +131,8 @@ android {
applicationId "com.mattermost.rnbeta"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 392
versionName "1.51.1"
versionCode 398
versionName "1.52.0"
multiDexEnabled = true
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -7,6 +7,7 @@
import {RNFetchBlobFetchRepsonse} from 'rn-fetch-blob';
import urlParse from 'url-parse';
import Calls from '@constants/calls';
import {Options} from '@mm-redux/types/client4';
import * as ClientConstants from './constants';
@@ -286,12 +287,16 @@ export default class ClientBase {
return `${this.getUserThreadsRoute(userId, teamId)}/${threadId}`;
}
getPluginsRoute() {
return `${this.getBaseRoute()}/plugins`;
}
getAppsProxyRoute() {
return `${this.url}/plugins/com.mattermost.apps`;
}
getCallsRoute() {
return `${this.url}/plugins/com.mattermost.calls`;
return `${this.url}/plugins/${Calls.PluginId}`;
}
// Client Helpers

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import ClientPlugins, {ClientPluginsMix} from '@client/rest/plugins';
import ClientCalls, {ClientCallsMix} from '@mmproducts/calls/client/rest';
import mix from '@utils/mix';
@@ -36,7 +37,8 @@ interface Client extends ClientBase,
ClientTeamsMix,
ClientTosMix,
ClientUsersMix,
ClientCallsMix
ClientCallsMix,
ClientPluginsMix
{}
class Client extends mix(ClientBase).with(
@@ -55,6 +57,7 @@ class Client extends mix(ClientBase).with(
ClientTos,
ClientUsers,
ClientCalls,
ClientPlugins,
) {}
const Client4 = new Client();

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ClientPluginManifest} from '@mm-redux/types/plugins';
export interface ClientPluginsMix {
getPluginsManifests: () => Promise<ClientPluginManifest[]>;
}
const ClientPlugins = (superclass: any) => class extends superclass {
getPluginsManifests = async () => {
return this.doFetch(
`${this.getPluginsRoute()}/webapp`,
{method: 'get'},
);
};
};
export default ClientPlugins;

View File

@@ -10,4 +10,6 @@ const RequiredServer = {
PATCH_VERSION: 0,
};
export default {RequiredServer, RefreshConfigMillis};
const PluginId = 'com.mattermost.calls';
export default {RequiredServer, RefreshConfigMillis, PluginId};

View File

@@ -1,5 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Calls from '@constants/calls';
const WebsocketEvents = {
POSTED: 'posted',
POST_EDITED: 'post_edited',
@@ -53,18 +56,18 @@ const WebsocketEvents = {
SIDEBAR_CATEGORY_UPDATED: 'sidebar_category_updated',
SIDEBAR_CATEGORY_DELETED: 'sidebar_category_deleted',
SIDEBAR_CATEGORY_ORDER_UPDATED: 'sidebar_category_order_updated',
CALLS_CHANNEL_ENABLED: 'custom_com.mattermost.calls_channel_enable_voice',
CALLS_CHANNEL_DISABLED: 'custom_com.mattermost.calls_channel_disable_voice',
CALLS_USER_CONNECTED: 'custom_com.mattermost.calls_user_connected',
CALLS_USER_DISCONNECTED: 'custom_com.mattermost.calls_user_disconnected',
CALLS_USER_MUTED: 'custom_com.mattermost.calls_user_muted',
CALLS_USER_UNMUTED: 'custom_com.mattermost.calls_user_unmuted',
CALLS_USER_VOICE_ON: 'custom_com.mattermost.calls_user_voice_on',
CALLS_USER_VOICE_OFF: 'custom_com.mattermost.calls_user_voice_off',
CALLS_CALL_START: 'custom_com.mattermost.calls_call_start',
CALLS_SCREEN_ON: 'custom_com.mattermost.calls_user_screen_on',
CALLS_SCREEN_OFF: 'custom_com.mattermost.calls_user_screen_off',
CALLS_USER_RAISE_HAND: 'custom_com.mattermost.calls_user_raise_hand',
CALLS_USER_UNRAISE_HAND: 'custom_com.mattermost.calls_user_unraise_hand',
CALLS_CHANNEL_ENABLED: `custom_${Calls.PluginId}_channel_enable_voice`,
CALLS_CHANNEL_DISABLED: `custom_${Calls.PluginId}_channel_disable_voice`,
CALLS_USER_CONNECTED: `custom_${Calls.PluginId}_user_connected`,
CALLS_USER_DISCONNECTED: `custom_${Calls.PluginId}_user_disconnected`,
CALLS_USER_MUTED: `custom_${Calls.PluginId}_user_muted`,
CALLS_USER_UNMUTED: `custom_${Calls.PluginId}_user_unmuted`,
CALLS_USER_VOICE_ON: `custom_${Calls.PluginId}_user_voice_on`,
CALLS_USER_VOICE_OFF: `custom_${Calls.PluginId}_user_voice_off`,
CALLS_CALL_START: `custom_${Calls.PluginId}_call_start`,
CALLS_SCREEN_ON: `custom_${Calls.PluginId}_user_screen_on`,
CALLS_SCREEN_OFF: `custom_${Calls.PluginId}_user_screen_off`,
CALLS_USER_RAISE_HAND: `custom_${Calls.PluginId}_user_raise_hand`,
CALLS_USER_UNRAISE_HAND: `custom_${Calls.PluginId}_user_unraise_hand`,
};
export default WebsocketEvents;

View File

@@ -11,7 +11,12 @@ import {getCurrentChannel} from '@mm-redux/selectors/entities/channels';
import {getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin} from '@mm-redux/utils/user_utils';
import {loadConfig} from '@mmproducts/calls/store/actions/calls';
import {getConfig, isCallsExplicitlyDisabled, isCallsExplicitlyEnabled} from '@mmproducts/calls/store/selectors/calls';
import {
getConfig,
isCallsExplicitlyDisabled,
isCallsExplicitlyEnabled,
isCallsPluginEnabled,
} from '@mmproducts/calls/store/selectors/calls';
// Check if calls is enabled. If it is, then run fn; if it isn't, show an alert and set
// msgPostfix to ' (Not Available)'.
@@ -45,12 +50,15 @@ export const useCallsChannelSettings = () => {
const dispatch = useDispatch();
const config = useSelector(getConfig);
const currentChannel = useSelector(getCurrentChannel);
const pluginEnabled = useSelector(isCallsPluginEnabled);
const explicitlyDisabled = useSelector(isCallsExplicitlyDisabled);
const explicitlyEnabled = useSelector(isCallsExplicitlyEnabled);
const roles = useSelector(getCurrentUserRoles);
useEffect(() => {
dispatch(loadConfig());
if (pluginEnabled) {
dispatch(loadConfig());
}
}, []);
const isDirectMessage = currentChannel.type === General.DM_CHANNEL;
@@ -58,9 +66,11 @@ export const useCallsChannelSettings = () => {
const isAdmin = checkIsAdmin(roles);
const isChannelAdmin = isAdmin || checkIsChannelAdmin(roles);
const enabled = (explicitlyEnabled || (!explicitlyDisabled && config.DefaultEnabled));
const enabled = pluginEnabled && (explicitlyEnabled || (!explicitlyDisabled && config.DefaultEnabled));
let canEnableDisable;
if (config.AllowEnableCalls) {
if (!pluginEnabled) {
canEnableDisable = false;
} else if (config.AllowEnableCalls) {
canEnableDisable = isDirectMessage || isGroupMessage || isChannelAdmin;
} else {
canEnableDisable = isAdmin;

View File

@@ -24,4 +24,5 @@ export default keyMirror({
SET_SCREENSHARE_URL: null,
SET_SPEAKERPHONE: null,
RECEIVED_CONFIG: null,
RECEIVED_PLUGIN_ENABLED: null,
});

View File

@@ -39,6 +39,12 @@ jest.mock('@client/rest', () => ({
DefaultEnabled: true,
last_retrieved_at: 1234,
})),
getPluginsManifests: jest.fn(() => (
[
{id: 'playbooks'},
{id: 'com.mattermost.calls'},
]
)),
enableChannelCalls: jest.fn(() => null),
disableChannelCalls: jest.fn(() => null),
},
@@ -135,14 +141,14 @@ describe('Actions.Calls', () => {
});
it('loadCalls', async () => {
await store.dispatch(await store.dispatch(CallsActions.loadCalls()));
await store.dispatch(CallsActions.loadCalls());
expect(Client4.getCalls).toBeCalledWith();
assert.equal(store.getState().entities.calls.calls['channel-1'].channelId, 'channel-1');
assert.equal(store.getState().entities.calls.enabled['channel-1'], true);
});
it('loadConfig', async () => {
await store.dispatch(await store.dispatch(CallsActions.loadConfig()));
await store.dispatch(CallsActions.loadConfig());
expect(Client4.getCallsConfig).toBeCalledWith();
assert.equal(store.getState().entities.calls.config.DefaultEnabled, true);
assert.equal(store.getState().entities.calls.config.AllowEnableCalls, true);
@@ -150,6 +156,7 @@ describe('Actions.Calls', () => {
it('batchLoadConfig', async () => {
await store.dispatch(CallsActions.batchLoadCalls());
expect(Client4.getPluginsManifests).toBeCalledWith();
expect(Client4.getCallsConfig).toBeCalledWith();
expect(Client4.getCalls).toBeCalledWith();

View File

@@ -3,12 +3,19 @@
import {intlShape} from 'react-intl';
import InCallManager from 'react-native-incall-manager';
import {batch} from 'react-redux';
import {Client4} from '@client/rest';
import Calls from '@constants/calls';
import {logError} from '@mm-redux/actions/errors';
import {forceLogoutIfNecessary} from '@mm-redux/actions/helpers';
import {GenericAction, ActionFunc, DispatchFunc, GetStateFunc, batchActions} from '@mm-redux/types/actions';
import {
GenericAction,
ActionFunc,
DispatchFunc,
GetStateFunc,
ActionResult,
} from '@mm-redux/types/actions';
import {Dictionary} from '@mm-redux/types/utilities';
import {newClient} from '@mmproducts/calls/connection';
import CallsTypes from '@mmproducts/calls/store/action_types/calls';
@@ -19,7 +26,7 @@ import {hasMicrophonePermission} from '@utils/permission';
export let ws: any = null;
export function loadConfig(force = false): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc): Promise<GenericAction> => {
return async (dispatch: DispatchFunc, getState: GetStateFunc): Promise<ActionResult> => {
if (!force) {
if ((Date.now() - getConfig(getState()).last_retrieved_at) < Calls.RefreshConfigMillis) {
return {} as GenericAction;
@@ -34,28 +41,27 @@ export function loadConfig(force = false): ActionFunc {
dispatch(logError(error));
// Reset the config to the default (off) since it looks like Calls is not enabled.
return {
dispatch({
type: CallsTypes.RECEIVED_CONFIG,
data: {...DefaultServerConfig, last_retrieved_at: Date.now()},
};
});
}
return {
type: CallsTypes.RECEIVED_CONFIG,
data: {...data, last_retrieved_at: Date.now()},
};
data = {...data, last_retrieved_at: Date.now()};
dispatch({type: CallsTypes.RECEIVED_CONFIG, data});
return {data};
};
}
export function loadCalls(): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc): Promise<GenericAction> => {
return async (dispatch: DispatchFunc, getState: GetStateFunc): Promise<ActionResult> => {
let resp = [];
try {
resp = await Client4.getCalls();
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {} as GenericAction;
return {};
}
const callsResults: Dictionary<Call> = {};
@@ -86,21 +92,46 @@ export function loadCalls(): ActionFunc {
enabled: enabledChannels,
};
return {type: CallsTypes.RECEIVED_CALLS, data};
dispatch({type: CallsTypes.RECEIVED_CALLS, data});
return {data};
};
}
export function batchLoadCalls(forceConfig = false): ActionFunc {
return async (dispatch: DispatchFunc) => {
const promises = [dispatch(loadConfig(forceConfig)), dispatch(loadCalls())];
Promise.all(promises).then((actions: Array<Awaited<GenericAction>>) => {
dispatch(batchActions(actions, 'BATCH_LOAD_CALLS'));
const res = await dispatch(checkIsCallsPluginEnabled());
if (!res.data) {
// Calls is not enabled.
return {};
}
batch(() => {
dispatch(loadConfig(forceConfig));
dispatch(loadCalls());
});
return {};
};
}
export function checkIsCallsPluginEnabled(): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
let data;
try {
data = await Client4.getPluginsManifests();
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {} as GenericAction;
}
const enabled = data.findIndex((m) => m.id === Calls.PluginId) !== -1;
dispatch({type: CallsTypes.RECEIVED_PLUGIN_ENABLED, data: enabled});
return {data: enabled};
};
}
export function enableChannelCalls(channelId: string): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
try {
@@ -135,6 +166,10 @@ export function disableChannelCalls(channelId: string): ActionFunc {
export function joinCall(channelId: string, intl: typeof intlShape): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
// Edge case: calls was disabled when app loaded, and then enabled, but app hasn't
// reconnected its websocket since then (i.e., hasn't called batchLoadCalls yet)
dispatch(checkIsCallsPluginEnabled());
const hasPermission = await hasMicrophonePermission(intl);
if (!hasPermission) {
return {error: 'no permissions to microphone, unable to start call'};

View File

@@ -216,6 +216,16 @@ function speakerphoneOn(state = false, action: GenericAction) {
}
}
function pluginEnabled(state = false, action: GenericAction) {
switch (action.type) {
case CallsTypes.RECEIVED_PLUGIN_ENABLED: {
return action.data;
}
default:
return state;
}
}
export default combineReducers({
calls,
enabled,
@@ -223,4 +233,5 @@ export default combineReducers({
screenShareURL,
speakerphoneOn,
config,
pluginEnabled,
});

View File

@@ -61,3 +61,7 @@ export function isSupportedServer(state: GlobalState) {
return false;
}
export function isCallsPluginEnabled(state: GlobalState) {
return state.entities.calls.pluginEnabled;
}

View File

@@ -11,6 +11,7 @@ export type CallsState = {
screenShareURL: string;
speakerphoneOn: boolean;
config: ServerConfig;
pluginEnabled: boolean;
}
export type Call = {

View File

@@ -2,13 +2,14 @@
// See LICENSE.txt for license information.
import {EventEmitter} from 'events';
import Calls from '@constants/calls';
import {encode} from '@msgpack/msgpack/dist';
export default class WebSocketClient extends EventEmitter {
private ws: WebSocket | null;
private seqNo = 0;
private connID = '';
private eventPrefix = 'custom_com.mattermost.calls';
private eventPrefix = `custom_${Calls.PluginId}`;
constructor(connURL: string) {
super();

View File

@@ -64,7 +64,7 @@ export default class ChannelAndroid extends ChannelBase {
}
render() {
const {theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
const {theme, viewingGlobalThreads, isCallsEnabled} = this.props;
let component;
if (viewingGlobalThreads) {
@@ -106,11 +106,12 @@ export default class ChannelAndroid extends ChannelBase {
{component}
<NetworkIndicator/>
<AnnouncementBanner/>
{isSupportedServerCalls &&
{isCallsEnabled &&
<FloatingCallContainer>
<JoinCall/>
<CurrentCall/>
</FloatingCallContainer>}
</FloatingCallContainer>
}
</>
);

View File

@@ -57,7 +57,7 @@ export default class ChannelIOS extends ChannelBase {
};
render() {
const {currentChannelId, theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
const {currentChannelId, theme, viewingGlobalThreads, isCallsEnabled} = this.props;
let component;
let renderDraftArea = false;
@@ -85,11 +85,12 @@ export default class ChannelIOS extends ChannelBase {
<>
<AnnouncementBanner/>
<NetworkIndicator/>
{isSupportedServerCalls &&
{isCallsEnabled &&
<FloatingCallContainer>
<JoinCall/>
<CurrentCall/>
</FloatingCallContainer>}
</FloatingCallContainer>
}
</>
);
const header = (

View File

@@ -40,6 +40,7 @@ export default class ChannelBase extends PureComponent {
viewingGlobalThreads: PropTypes.bool,
collapsedThreadsEnabled: PropTypes.bool.isRequired,
isSupportedServerCalls: PropTypes.bool.isRequired,
isCallsEnabled: PropTypes.bool.isRequired,
selectedPost: PropTypes.shape({
id: PropTypes.string.isRequired,
channel_id: PropTypes.string.isRequired,

View File

@@ -18,7 +18,10 @@ import {getCurrentUserId, getCurrentUserRoles, shouldShowTermsOfService} from '@
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
import {isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
import {batchLoadCalls} from '@mmproducts/calls/store/actions/calls';
import {isSupportedServer as isSupportedServerForCalls} from '@mmproducts/calls/store/selectors/calls';
import {
isCallsPluginEnabled,
isSupportedServer as isSupportedServerForCalls,
} from '@mmproducts/calls/store/selectors/calls';
import {getViewingGlobalThreads} from '@selectors/threads';
import Channel from './channel';
@@ -44,6 +47,7 @@ function mapStateToProps(state) {
const currentChannelId = currentTeam?.delete_at === 0 ? getCurrentChannelId(state) : '';
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(state);
const isSupportedServerCalls = isSupportedServerForCalls(state);
const isCallsEnabled = isCallsPluginEnabled(state);
return {
currentChannelId,
@@ -58,6 +62,7 @@ function mapStateToProps(state) {
theme: getTheme(state),
viewingGlobalThreads: collapsedThreadsEnabled && getViewingGlobalThreads(state),
isSupportedServerCalls,
isCallsEnabled,
};
}

View File

@@ -8,8 +8,8 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.579.0)
aws-sdk-core (3.130.1)
aws-partitions (1.581.0)
aws-sdk-core (3.130.2)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
@@ -17,7 +17,7 @@ GEM
aws-sdk-kms (1.56.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.113.0)
aws-sdk-s3 (1.113.2)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@@ -36,7 +36,7 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.2.3)
excon (0.92.2)
excon (0.92.3)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)

View File

@@ -911,7 +911,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 392;
CURRENT_PROJECT_VERSION = 398;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
@@ -953,7 +953,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 392;
CURRENT_PROJECT_VERSION = 398;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;

View File

@@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.51.1</string>
<string>1.52.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@@ -37,7 +37,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>392</string>
<string>398</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View File

@@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.51.1</string>
<string>1.52.0</string>
<key>CFBundleVersion</key>
<string>392</string>
<string>398</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>

View File

@@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.51.1</string>
<string>1.52.0</string>
<key>CFBundleVersion</key>
<string>392</string>
<string>398</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "mattermost-mobile",
"version": "1.51.1",
"version": "1.52.0",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@@ -1,6 +1,6 @@
{
"name": "mattermost-mobile",
"version": "1.51.1",
"version": "1.52.0",
"description": "Mattermost Mobile with React Native",
"repository": "git@github.com:mattermost/mattermost-mobile.git",
"author": "Mattermost, Inc.",