Merge branch 'main' into MM-53857

This commit is contained in:
Caleb Roseland 2023-09-29 16:03:31 -05:00
commit ce82213a33
88 changed files with 3865 additions and 2829 deletions

View file

@ -7,7 +7,7 @@ runs:
- name: ci/setup-node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
with:
node-version: "${{ env.NODE_VERSION }}"
node-version-file: ".nvmrc"
cache: "npm"
cache-dependency-path: package-lock.json

View file

@ -1 +1 @@
18.7.0
18.17

1
.npmrc
View file

@ -1 +1,2 @@
save-exact=true
engine-strict=true

2
.nvmrc
View file

@ -1 +1 @@
18.7.0
18.17

View file

@ -4,20 +4,6 @@
"output" : "moderate"
},
"requirements": {
"Node": [
{
"rule": "cli",
"binary": "node",
"semver": ">=16.0.0",
"error": "install node using nvm https://github.com/nvm-sh/nvm#installing-and-updating"
},
{
"rule": "cli",
"binary": "npm",
"semver": ">=7.24.0 <9.0.0",
"error": "install npm 8.5.5 `npm i -g npm@8.5.5"
}
],
"Android": [
{
"rule": "cli",

View file

@ -596,42 +596,6 @@ Stack navigator component for iOS and Android with animated transitions and gest
---
## @rudderstack/rudder-sdk-react-native
This product contains '@rudderstack/rudder-sdk-react-native' by RudderStack.
Rudder React Native SDK
* HOMEPAGE:
* https://github.com/rudderlabs/rudder-sdk-reactnative#readme
* LICENSE: Apache-2.0
MIT License
Copyright (c) 2021 RudderStack
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.
---
## @sentry/react-native

View file

@ -110,8 +110,8 @@ android {
applicationId "com.mattermost.rnbeta"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 485
versionName "2.8.0"
versionCode 487
versionName "2.9.0"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}

View file

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {getActiveServerUrl} from '@app/init/credentials';
import {Tutorial} from '@constants';
import {GLOBAL_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
import {getActiveServerUrl} from '@init/credentials';
import {logError} from '@utils/log';
export const storeGlobal = async (id: string, value: unknown, prepareRecordsOnly = false) => {

View file

@ -35,7 +35,7 @@ const CopyChannelLinkOption = ({channelName, teamName, showAsLabel, testID}: Pro
<SlideUpPanelItem
onPress={onCopyLink}
text={intl.formatMessage({id: 'channel_info.copy_link', defaultMessage: 'Copy Link'})}
icon='link-variant'
leftIcon='link-variant'
testID={testID}
/>
);

View file

@ -45,7 +45,7 @@ const InfoBox = ({channelId, containerStyle, showAsLabel = false, testID}: Props
if (showAsLabel) {
return (
<SlideUpPanelItem
icon='information-outline'
leftIcon='information-outline'
onPress={onViewInfo}
testID={testID}
text={intl.formatMessage({id: 'channel_header.info', defaultMessage: 'View info'})}

View file

@ -174,7 +174,7 @@ const LeaveChannelLabel = ({canLeave, channelId, displayName, isOptionItem, type
return (
<SlideUpPanelItem
destructive={true}
icon={icon}
leftIcon={icon}
onPress={onLeave}
text={leaveText}
testID={testID}

View file

@ -167,7 +167,7 @@ const AtMention = ({
style={style.bottomSheet}
>
<SlideUpPanelItem
icon='content-copy'
leftIcon='content-copy'
onPress={() => {
dismissBottomSheet();
let username = mentionName;
@ -182,7 +182,7 @@ const AtMention = ({
/>
<SlideUpPanelItem
destructive={true}
icon='cancel'
leftIcon='cancel'
onPress={() => {
dismissBottomSheet();
}}

View file

@ -123,7 +123,7 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
style={style.bottomSheet}
>
<SlideUpPanelItem
icon='content-copy'
leftIcon='content-copy'
onPress={() => {
dismissBottomSheet();
Clipboard.setString(content);
@ -133,7 +133,7 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
/>
<SlideUpPanelItem
destructive={true}
icon='cancel'
leftIcon='cancel'
onPress={() => {
dismissBottomSheet();
}}

View file

@ -157,7 +157,7 @@ const MarkdownImage = ({
style={style.bottomSheet}
>
<SlideUpPanelItem
icon='content-copy'
leftIcon='content-copy'
onPress={() => {
dismissBottomSheet();
Clipboard.setString(linkDestination || source);
@ -167,7 +167,7 @@ const MarkdownImage = ({
/>
<SlideUpPanelItem
destructive={true}
icon='cancel'
leftIcon='cancel'
onPress={() => {
dismissBottomSheet();
}}

View file

@ -139,7 +139,7 @@ const LatexCodeBlock = ({content, theme}: Props) => {
style={styles.bottomSheet}
>
<SlideUpPanelItem
icon='content-copy'
leftIcon='content-copy'
onPress={() => {
dismissBottomSheet();
Clipboard.setString(content);
@ -149,7 +149,7 @@ const LatexCodeBlock = ({content, theme}: Props) => {
/>
<SlideUpPanelItem
destructive={true}
icon='cancel'
leftIcon='cancel'
onPress={dismissBottomSheet}
testID='at_mention.bottom_sheet.cancel'
text={intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'})}

View file

@ -116,7 +116,7 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU
style={style.bottomSheet}
>
<SlideUpPanelItem
icon='content-copy'
leftIcon='content-copy'
onPress={() => {
dismissBottomSheet();
Clipboard.setString(href);
@ -126,7 +126,7 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU
/>
<SlideUpPanelItem
destructive={true}
icon='cancel'
leftIcon='cancel'
onPress={() => {
dismissBottomSheet();
}}

View file

@ -66,13 +66,13 @@ const CameraType = ({onPress}: Props) => {
/>
}
<SlideUpPanelItem
icon='camera-outline'
leftIcon='camera-outline'
onPress={onPhoto}
testID='camera_type.photo'
text={intl.formatMessage({id: 'camera_type.photo.option', defaultMessage: 'Capture Photo'})}
/>
<SlideUpPanelItem
icon='video-outline'
leftIcon='video-outline'
onPress={onVideo}
testID='camera_type.video'
text={intl.formatMessage({id: 'camera_type.video.option', defaultMessage: 'Record Video'})}

View file

@ -44,7 +44,7 @@ const Failed = ({post, theme}: FailedProps) => {
style={styles.bottomSheet}
>
<SlideUpPanelItem
icon='send-outline'
leftIcon='send-outline'
onPress={() => {
dismissBottomSheet();
retryFailedPost(serverUrl, post);
@ -54,7 +54,7 @@ const Failed = ({post, theme}: FailedProps) => {
/>
<SlideUpPanelItem
destructive={true}
icon='close-circle-outline'
leftIcon='close-circle-outline'
onPress={() => {
dismissBottomSheet();
removePost(serverUrl, post);

View file

@ -14,10 +14,12 @@ import {isValidUrl} from '@utils/url';
type SlideUpPanelProps = {
destructive?: boolean;
icon?: string | Source;
rightIcon?: boolean;
imageStyles?: StyleProp<ImageStyle>;
iconStyles?: StyleProp<TextStyle>;
leftIcon?: string | Source;
leftImageStyles?: StyleProp<ImageStyle>;
leftIconStyles?: StyleProp<TextStyle>;
rightIcon?: string | Source;
rightImageStyles?: StyleProp<ImageStyle>;
rightIconStyles?: StyleProp<TextStyle>;
onPress: () => void;
textStyles?: TextStyle;
testID?: string;
@ -65,13 +67,55 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
};
});
const SlideUpPanelItem = ({destructive, icon, imageStyles, onPress, testID, text, textStyles, iconStyles, rightIcon = false}: SlideUpPanelProps) => {
const SlideUpPanelItem = ({
destructive = false,
leftIcon,
leftImageStyles,
leftIconStyles,
rightIcon,
rightImageStyles,
rightIconStyles,
onPress,
testID,
text,
textStyles,
}: SlideUpPanelProps) => {
const theme = useTheme();
const style = getStyleSheet(theme);
const {image: leftImage, iconStyle: leftIconStyle} = useImageAndStyle(leftIcon, leftImageStyles, leftIconStyles, destructive);
const {image: rightImage, iconStyle: rightIconStyle} = useImageAndStyle(rightIcon, rightImageStyles, rightIconStyles, destructive);
const handleOnPress = useCallback(preventDoubleTap(onPress, 500), []);
return (
<TouchableHighlight
onPress={handleOnPress}
style={style.container}
testID={testID}
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
>
<View style={style.row}>
{Boolean(leftImage) &&
<View style={leftIconStyle}>{leftImage}</View>
}
<View style={style.textContainer}>
<Text style={[style.text, destructive && style.destructive, textStyles]}>{text}</Text>
</View>
{Boolean(rightImage) &&
<View style={rightIconStyle}>{rightImage}</View>
}
</View>
</TouchableHighlight>
);
};
const useImageAndStyle = (icon: string | Source | undefined, imageStyles: StyleProp<ImageStyle>, iconStyles: StyleProp<TextStyle>, destructive: boolean) => {
const theme = useTheme();
const style = getStyleSheet(theme);
let image;
let iconStyle: StyleProp<ViewStyle> = [style.iconContainer];
let iconStyle: Array<StyleProp<ViewStyle>> = [style.iconContainer];
if (icon) {
if (typeof icon === 'object') {
if (icon.uri && isValidUrl(icon.uri)) {
@ -101,26 +145,7 @@ const SlideUpPanelItem = ({destructive, icon, imageStyles, onPress, testID, text
}
}
return (
<TouchableHighlight
onPress={handleOnPress}
style={style.container}
testID={testID}
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
>
<View style={style.row}>
{Boolean(image) && !rightIcon &&
<View style={iconStyle}>{image}</View>
}
<View style={style.textContainer}>
<Text style={[style.text, destructive && style.destructive, textStyles]}>{text}</Text>
</View>
{Boolean(image) && rightIcon &&
<View style={iconStyle}>{image}</View>
}
</View>
</TouchableHighlight>
);
return {image, iconStyle};
};
export default SlideUpPanelItem;

View file

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export const ALL = 'all';
export const DEFAULT = 'default';
export const MENTION = 'mention';
export const NONE = 'none';
export const ALL = 'all' as const;
export const DEFAULT = 'default' as const;
export const MENTION = 'mention' as const;
export const NONE = 'none' as const;
export default {
ALL,

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export const CATEGORIES_TO_KEEP: Record<string, string> = {
export const CATEGORIES_TO_KEEP = {
ADVANCED_SETTINGS: 'advanced_settings',
CHANNEL_APPROXIMATE_VIEW_TIME: 'channel_approximate_view_time',
CHANNEL_OPEN_TIME: 'channel_open_time',
@ -14,15 +14,21 @@ export const CATEGORIES_TO_KEEP: Record<string, string> = {
SIDEBAR_SETTINGS: 'sidebar_settings',
TEAMS_ORDER: 'teams_order',
THEME: 'theme',
SYSTEM_NOTICE: 'system_notice',
};
const CATEGORIES: Record<string, string> = {
const CATEGORIES = {
...CATEGORIES_TO_KEEP,
FAVORITE_CHANNEL: 'favorite_channel',
};
const NOTICES = {
GM_AS_DM: 'GMasDM',
};
const Preferences = {
CATEGORIES,
NOTICES,
COLLAPSED_REPLY_THREADS: 'collapsed_reply_threads',
COLLAPSED_REPLY_THREADS_OFF: 'off',
COLLAPSED_REPLY_THREADS_ON: 'on',

View file

@ -0,0 +1,4 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export const GM_AS_DM_VERSION = [9, 1, 0];

View file

@ -37,14 +37,16 @@ const UserHandler = <TBase extends Constructor<ServerDataOperatorBase>>(supercla
*/
handlePreferences = async ({preferences, prepareRecordsOnly = true, sync = false}: HandlePreferencesArgs): Promise<PreferenceModel[]> => {
const records: PreferenceModel[] = [];
const filtered = filterPreferences(preferences);
if (!filtered?.length) {
if (!preferences?.length) {
logWarning(
'An empty or undefined "preferences" array has been passed to the handlePreferences method',
);
return records;
}
const filtered = filterPreferences(preferences);
// WE NEED TO SYNC THE PREFS FROM WHAT WE GOT AND WHAT WE HAVE
const deleteValues: PreferenceModel[] = [];
const stored = await this.database.get(PREFERENCE).query().fetch() as PreferenceModel[];

View file

@ -53,8 +53,8 @@ export function getSidebarPreferenceAsBool(preferences: Preference[], name: stri
return getPreferenceAsBool(preferences, Preferences.CATEGORIES.SIDEBAR_SETTINGS, name, defaultValue);
}
export function filterPreferences(preferences?: PreferenceType[]) {
if (!preferences?.length) {
export function filterPreferences(preferences: PreferenceType[]) {
if (!preferences.length) {
return preferences;
}

View file

@ -74,7 +74,7 @@ const launchApp = async (props: LaunchProps) => {
let serverUrl: string | undefined;
switch (props?.launchType) {
case Launch.DeepLink:
if (props.extra?.type !== DeepLink.Invalid) {
if (props.extra && props.extra.type !== DeepLink.Invalid) {
const extra = props.extra as DeepLinkWithData;
const existingServer = DatabaseManager.searchUrl(extra.data!.serverUrl);
serverUrl = existingServer;

View file

@ -25,7 +25,8 @@ export class Analytics {
async init(config: ClientConfig) {
if (LocalConfig.RudderApiKey) {
this.analytics = require('@rudderstack/rudder-sdk-react-native').default;
// Rudder stack has been temporarily removed
// this.analytics = require('@rudderstack/rudder-sdk-react-native').default;
}
if (this.analytics) {

View file

@ -17,7 +17,8 @@ import {queryTeamDefaultChannel} from '@queries/servers/channel';
import {getCommonSystemValues} from '@queries/servers/system';
import {getTeamChannelHistory} from '@queries/servers/team';
import {setScreensOrientation} from '@screens/navigation';
import {handleDeepLink} from '@utils/deep_link';
import {alertInvalidDeepLink, handleDeepLink} from '@utils/deep_link';
import {getIntlShape} from '@utils/general';
type LinkingCallbackArg = {url: string};
@ -50,13 +51,16 @@ class GlobalEventHandler {
}
};
onDeepLink = (event: LinkingCallbackArg) => {
onDeepLink = async (event: LinkingCallbackArg) => {
if (event.url?.startsWith(Sso.REDIRECT_URL_SCHEME) || event.url?.startsWith(Sso.REDIRECT_URL_SCHEME_DEV)) {
return;
}
if (event.url) {
handleDeepLink(event.url);
const {error} = await handleDeepLink(event.url);
if (error) {
alertInvalidDeepLink(getIntlShape(DEFAULT_LOCALE));
}
}
};

View file

@ -14,7 +14,7 @@ import {Device} from '@constants';
import {useTheme} from '@context/theme';
import {bottomSheet, dismissBottomSheet} from '@screens/navigation';
import {bottomSheetSnapPoint} from '@utils/helpers';
import {typography} from '@utils/typography';
import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
pressableStyle: StyleProp<ViewStyle>;
@ -23,13 +23,16 @@ type Props = {
currentCall: CurrentCall;
}
const style = {
bold: typography('Body', 200, 'SemiBold'),
};
const getStyleFromTheme = makeStyleSheetFromTheme((theme: Theme) => ({
checkIcon: {
color: theme.buttonBg,
},
}));
export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, currentCall}: Props) => {
const intl = useIntl();
const theme = useTheme();
const style = getStyleFromTheme(theme);
const {bottom} = useSafeAreaInsets();
const isTablet = Device.IS_TABLET; // not `useIsTablet` because even if we're in splitView, we're still using a tablet.
const color = theme.awayIndicator;
@ -38,10 +41,14 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
const tabletLabel = intl.formatMessage({id: 'mobile.calls_tablet', defaultMessage: 'Tablet'});
const speakerLabel = intl.formatMessage({id: 'mobile.calls_speaker', defaultMessage: 'SpeakerPhone'});
const bluetoothLabel = intl.formatMessage({id: 'mobile.calls_bluetooth', defaultMessage: 'Bluetooth'});
const headsetLabel = intl.formatMessage({id: 'mobile.calls_headset', defaultMessage: 'Headset'});
const deviceSelector = useCallback(async () => {
const currentDevice = audioDeviceInfo.selectedAudioDevice;
const available = audioDeviceInfo.availableAudioDeviceList;
let available = audioDeviceInfo.availableAudioDeviceList;
if (available.includes(AudioDevice.WiredHeadset)) {
available = available.filter((d) => d !== AudioDevice.Earpiece);
}
const selectDevice = (device: AudioDevice) => {
setPreferredAudioRoute(device);
dismissBottomSheet();
@ -52,34 +59,47 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
<View>
{available.includes(AudioDevice.Earpiece) && isTablet &&
<SlideUpPanelItem
icon={'tablet'}
leftIcon={'tablet'}
onPress={() => selectDevice(AudioDevice.Earpiece)}
text={tabletLabel}
textStyles={currentDevice === AudioDevice.Earpiece ? {...style.bold, color} : {}}
rightIcon={currentDevice === AudioDevice.Earpiece ? 'check' : undefined}
rightIconStyles={currentDevice === AudioDevice.Earpiece ? style.checkIcon : {}}
/>
}
{available.includes(AudioDevice.Earpiece) && !isTablet &&
<SlideUpPanelItem
icon={'cellphone'}
leftIcon={'cellphone'}
onPress={() => selectDevice(AudioDevice.Earpiece)}
text={phoneLabel}
textStyles={currentDevice === AudioDevice.Earpiece ? {...style.bold, color} : {}}
rightIcon={currentDevice === AudioDevice.Earpiece ? 'check' : undefined}
rightIconStyles={currentDevice === AudioDevice.Earpiece ? style.checkIcon : {}}
/>
}
{available.includes(AudioDevice.Speakerphone) &&
<SlideUpPanelItem
icon={'volume-high'}
leftIcon={'volume-high'}
onPress={() => selectDevice(AudioDevice.Speakerphone)}
text={speakerLabel}
textStyles={currentDevice === AudioDevice.Speakerphone ? {...style.bold, color} : {}}
rightIcon={currentDevice === AudioDevice.Speakerphone ? 'check' : undefined}
rightIconStyles={currentDevice === AudioDevice.Speakerphone ? style.checkIcon : {}}
/>
}
{available.includes(AudioDevice.Bluetooth) &&
<SlideUpPanelItem
icon={'bluetooth'}
leftIcon={'bluetooth'}
onPress={() => selectDevice(AudioDevice.Bluetooth)}
text={bluetoothLabel}
textStyles={currentDevice === AudioDevice.Bluetooth ? {...style.bold, color} : {}}
rightIcon={currentDevice === AudioDevice.Bluetooth ? 'check' : undefined}
rightIconStyles={currentDevice === AudioDevice.Bluetooth ? style.checkIcon : {}}
/>
}
{available.includes(AudioDevice.WiredHeadset) &&
<SlideUpPanelItem
leftIcon={'headphones'}
onPress={() => selectDevice(AudioDevice.WiredHeadset)}
text={headsetLabel}
rightIcon={currentDevice === AudioDevice.WiredHeadset ? 'check' : undefined}
rightIconStyles={currentDevice === AudioDevice.WiredHeadset ? style.checkIcon : {}}
/>
}
</View>
@ -89,7 +109,7 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
await bottomSheet({
closeButtonId: 'close-other-actions',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(audioDeviceInfo.availableAudioDeviceList.length + 1, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(available.length + 1, ITEM_HEIGHT, bottom)],
title: intl.formatMessage({id: 'mobile.calls_audio_device', defaultMessage: 'Select audio device'}),
theme,
});
@ -106,6 +126,10 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
icon = 'bluetooth';
label = bluetoothLabel;
break;
case AudioDevice.WiredHeadset:
icon = 'headphones';
label = headsetLabel;
break;
}
return (

View file

@ -3,7 +3,7 @@
import {RTCMonitor, RTCPeer} from '@mattermost/calls/lib';
import {deflate} from 'pako';
import {DeviceEventEmitter, type EmitterSubscription, Platform} from 'react-native';
import {DeviceEventEmitter, type EmitterSubscription, NativeEventEmitter, NativeModules, Platform} from 'react-native';
import InCallManager from 'react-native-incall-manager';
import {mediaDevices, MediaStream, MediaStreamTrack, RTCPeerConnection} from 'react-native-webrtc';
@ -24,6 +24,8 @@ import type {EmojiData} from '@mattermost/calls/lib/types';
const peerConnectTimeout = 5000;
const rtcMonitorInterval = 4000;
const InCallManagerEmitter = new NativeEventEmitter(NativeModules.InCallManager);
export async function newConnection(
serverUrl: string,
channelID: string,
@ -40,6 +42,7 @@ export async function newConnection(
let isClosed = false;
let onCallEnd: EmitterSubscription | null = null;
let audioDeviceChanged: EmitterSubscription | null = null;
let wiredHeadsetEvent: EmitterSubscription | null = null;
const streams: MediaStream[] = [];
let rtcMonitor: RTCMonitor | null = null;
const logger = {
@ -106,6 +109,7 @@ export async function newConnection(
peer = null;
InCallManager.stop();
audioDeviceChanged?.remove();
wiredHeadsetEvent?.remove();
if (closeCb) {
closeCb();
@ -224,29 +228,50 @@ export async function newConnection(
let btInitialized = false;
let speakerInitialized = false;
audioDeviceChanged = DeviceEventEmitter.addListener('onAudioDeviceChanged', (data: AudioDeviceInfoRaw) => {
const info: AudioDeviceInfo = {
availableAudioDeviceList: JSON.parse(data.availableAudioDeviceList),
selectedAudioDevice: data.selectedAudioDevice,
};
setAudioDeviceInfo(info);
if (Platform.OS === 'android') {
audioDeviceChanged = DeviceEventEmitter.addListener('onAudioDeviceChanged', (data: AudioDeviceInfoRaw) => {
const info: AudioDeviceInfo = {
availableAudioDeviceList: JSON.parse(data.availableAudioDeviceList),
selectedAudioDevice: data.selectedAudioDevice,
};
setAudioDeviceInfo(info);
logDebug('AudioDeviceChanged. info:', info);
// Auto switch to bluetooth the first time we connect to bluetooth, but not after.
if (!btInitialized) {
if (info.availableAudioDeviceList.includes(AudioDevice.Bluetooth)) {
setPreferredAudioRoute(AudioDevice.Bluetooth);
btInitialized = true;
} else if (!speakerInitialized) {
// If we don't have bluetooth available, default to speakerphone on.
setPreferredAudioRoute(AudioDevice.Speakerphone);
speakerInitialized = true;
// Auto switch to bluetooth the first time we connect to bluetooth, but not after.
if (!btInitialized) {
if (info.availableAudioDeviceList.includes(AudioDevice.Bluetooth)) {
setPreferredAudioRoute(AudioDevice.Bluetooth);
btInitialized = true;
} else if (!speakerInitialized) {
// If we don't have bluetooth available, default to speakerphone on.
setPreferredAudioRoute(AudioDevice.Speakerphone);
speakerInitialized = true;
}
}
}
});
});
}
// We default to speakerphone (Android is handled above in the onAudioDeviceChanged handler above).
// We default to speakerphone, but not if the WiredHeadset is plugged in.
if (Platform.OS === 'ios') {
setSpeakerphoneOn(true);
wiredHeadsetEvent = InCallManagerEmitter.addListener('WiredHeadset', (data) => {
// Log for customer debugging. For the moment we're not changing output labels because of incall-manager iOS
// limitations with how it reports Bluetooth -- namely that it doesn't, so we don't know when Bluetooth is
// overriding the earpiece and/or headset.
logDebug('WiredHeadset plugged in. Data:', data);
// iOS switches to the headset when we connect it, so turn off speakerphone to keep UI in sync.
if (data.isPlugged) {
setSpeakerphoneOn(false);
}
});
// If headset is plugged in when the call starts, use it.
const report = await InCallManager.getIsWiredHeadsetPluggedIn();
if (report.isWiredHeadsetPluggedIn) {
setSpeakerphoneOn(false);
} else {
setSpeakerphoneOn(true);
}
}
peer = new RTCPeer({

View file

@ -477,7 +477,7 @@ const CallScreen = ({
{
showStartRecording &&
<SlideUpPanelItem
icon={'record-circle-outline'}
leftIcon={'record-circle-outline'}
onPress={startRecording}
text={recordOptionTitle}
/>
@ -485,14 +485,14 @@ const CallScreen = ({
{
showStopRecording &&
<SlideUpPanelItem
icon={'record-square-outline'}
leftIcon={'record-square-outline'}
onPress={stopRecording}
text={stopRecordingOptionTitle}
textStyles={style.denimDND}
/>
}
<SlideUpPanelItem
icon='message-text-outline'
leftIcon='message-text-outline'
onPress={switchToThread}
text={callThreadOptionTitle}
/>
@ -764,7 +764,6 @@ const CallScreen = ({
iconStyle={[
style.buttonIcon,
isLandscape && style.buttonIconLandscape,
style.speakerphoneIcon,
currentCall.speakerphoneOn && style.buttonOn,
]}
buttonTextStyle={style.buttonText}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {GM_AS_DM_VERSION} from '@constants/versions';
import {isMinimumServerVersion} from '@utils/helpers';
import {observeConfigValue} from './system';
import type {Database} from '@nozbe/watermelondb';
export const observeHasGMasDMFeature = (database: Database) => {
return observeConfigValue(database, 'Version').pipe(
switchMap((v) => of$(isMinimumServerVersion(v, ...GM_AS_DM_VERSION))),
);
};

View file

@ -42,11 +42,6 @@ export default function DropdownSlideup({
const style = getStyleFromTheme(theme);
const isTablet = useIsTablet();
const commonProps = {
rightIcon: true,
iconStyles: style.checkIcon,
};
const handlePublicPress = useCallback(() => {
dismissBottomSheet();
onPress(PUBLIC);
@ -73,16 +68,16 @@ export default function DropdownSlideup({
onPress={handlePublicPress}
testID='browse_channels.dropdown_slideup_item.public_channels'
text={intl.formatMessage({id: 'browse_channels.publicChannels', defaultMessage: 'Public Channels'})}
icon={selected === PUBLIC ? 'check' : undefined}
{...commonProps}
rightIcon={selected === PUBLIC ? 'check' : undefined}
rightIconStyles={style.checkIcon}
/>
{canShowArchivedChannels && (
<SlideUpPanelItem
onPress={handleArchivedPress}
testID='browse_channels.dropdown_slideup_item.archived_channels'
text={intl.formatMessage({id: 'browse_channels.archivedChannels', defaultMessage: 'Archived Channels'})}
icon={selected === ARCHIVED ? 'check' : undefined}
{...commonProps}
rightIcon={selected === ARCHIVED ? 'check' : undefined}
rightIconStyles={style.checkIcon}
/>
)}
{sharedChannelsEnabled && (
@ -90,8 +85,8 @@ export default function DropdownSlideup({
onPress={handleSharedPress}
testID='browse_channels.dropdown_slideup_item.shared_channels'
text={intl.formatMessage({id: 'browse_channels.sharedChannels', defaultMessage: 'Shared Channels'})}
icon={selected === SHARED ? 'check' : undefined}
{...commonProps}
rightIcon={selected === SHARED ? 'check' : undefined}
rightIconStyles={style.checkIcon}
/>
)}
</BottomSheetContent>

View file

@ -24,7 +24,9 @@ import EphemeralStore from '@store/ephemeral_store';
import ChannelPostList from './channel_post_list';
import ChannelHeader from './header';
import useGMasDMNotice from './use_gm_as_dm_notice';
import type PreferenceModel from '@typings/database/models/servers/preference';
import type {AvailableScreens} from '@typings/screens/navigation';
import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view';
@ -36,6 +38,10 @@ type ChannelProps = {
isCallsEnabledInChannel: boolean;
showIncomingCalls: boolean;
isTabletView?: boolean;
dismissedGMasDMNotice: PreferenceModel[];
currentUserId: string;
channelType: ChannelType;
hasGMasDMFeature: boolean;
};
const edges: Edge[] = ['left', 'right'];
@ -55,7 +61,12 @@ const Channel = ({
isCallsEnabledInChannel,
showIncomingCalls,
isTabletView,
dismissedGMasDMNotice,
channelType,
currentUserId,
hasGMasDMFeature,
}: ChannelProps) => {
useGMasDMNotice(currentUserId, channelType, dismissedGMasDMNotice, hasGMasDMFeature);
const isTablet = useIsTablet();
const insets = useSafeAreaInsets();
const [shouldRenderPosts, setShouldRenderPosts] = useState(false);

View file

@ -27,6 +27,7 @@ type Props = {
isBot: boolean;
members?: ChannelMembershipModel[];
theme: Theme;
hasGMasDMFeature: boolean;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
@ -52,6 +53,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
textAlign: 'center',
...typography('Body', 200, 'Regular'),
},
boldText: {
...typography('Body', 200, 'SemiBold'),
},
profilesContainer: {
justifyContent: 'center',
alignItems: 'center',
@ -67,7 +71,14 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
},
}));
const DirectChannel = ({channel, currentUserId, isBot, members, theme}: Props) => {
const DirectChannel = ({
channel,
currentUserId,
isBot,
members,
theme,
hasGMasDMFeature,
}: Props) => {
const serverUrl = useServerUrl();
const styles = getStyleSheet(theme);
@ -89,11 +100,23 @@ const DirectChannel = ({channel, currentUserId, isBot, members, theme}: Props) =
/>
);
}
if (!hasGMasDMFeature) {
return (
<FormattedText
defaultMessage={'This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.'}
id='intro.group_message.after_gm_as_dm'
style={styles.message}
/>
);
}
return (
<FormattedText
defaultMessage={'This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.'}
defaultMessage={'This is the start of your conversation with this group. You\'ll be notified for <b>all activity</b> in this group message.'}
id='intro.group_message'
style={styles.message}
values={{
b: (chunk: string) => <Text style={styles.boldText}>{chunk}</Text>,
}}
/>
);
}, [channel.displayName, theme]);

View file

@ -8,6 +8,7 @@ import {switchMap} from 'rxjs/operators';
import {General} from '@constants';
import {observeChannelMembers} from '@queries/servers/channel';
import {observeHasGMasDMFeature} from '@queries/servers/features';
import {observeCurrentUserId} from '@queries/servers/system';
import {observeUser} from '@queries/servers/user';
import {getUserIdFromChannelName} from '@utils/user';
@ -23,6 +24,7 @@ const observeIsBot = (user: UserModel | undefined) => of$(Boolean(user?.isBot));
const enhanced = withObservables([], ({channel, database}: {channel: ChannelModel} & WithDatabaseArgs) => {
const currentUserId = observeCurrentUserId(database);
const members = observeChannelMembers(database, channel.id);
const hasGMasDMFeature = observeHasGMasDMFeature(database);
let isBot = of$(false);
if (channel.type === General.DM_CHANNEL) {
@ -40,6 +42,7 @@ const enhanced = withObservables([], ({channel, database}: {channel: ChannelMode
currentUserId,
isBot,
members,
hasGMasDMFeature,
};
});

View file

@ -12,8 +12,12 @@ import {
observeCurrentCall,
observeIncomingCalls,
} from '@calls/state';
import {Preferences} from '@constants';
import {withServerUrl} from '@context/server';
import {observeCurrentChannelId} from '@queries/servers/system';
import {observeCurrentChannel} from '@queries/servers/channel';
import {observeHasGMasDMFeature} from '@queries/servers/features';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeCurrentChannelId, observeCurrentUserId} from '@queries/servers/system';
import Channel from './channel';
@ -56,12 +60,21 @@ const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => {
distinctUntilChanged(),
);
const dismissedGMasDMNotice = queryPreferencesByCategoryAndName(database, Preferences.CATEGORIES.SYSTEM_NOTICE, Preferences.NOTICES.GM_AS_DM).observe();
const channelType = observeCurrentChannel(database).pipe(switchMap((c) => of$(c?.type)));
const currentUserId = observeCurrentUserId(database);
const hasGMasDMFeature = observeHasGMasDMFeature(database);
return {
channelId,
showJoinCallBanner,
isInACall,
showIncomingCalls,
isCallsEnabledInChannel: observeIsCallsEnabledInChannel(database, serverUrl, channelId),
dismissedGMasDMNotice,
channelType,
currentUserId,
hasGMasDMFeature,
};
});

View file

@ -0,0 +1,65 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {useEffect} from 'react';
import {useIntl} from 'react-intl';
import {Alert} from 'react-native';
import {savePreference} from '@actions/remote/preference';
import {Preferences} from '@constants';
import {useServerUrl} from '@context/server';
import {getPreferenceAsBool} from '@helpers/api/preference';
import EphemeralStore from '@store/ephemeral_store';
import type PreferenceModel from '@typings/database/models/servers/preference';
const useGMasDMNotice = (userId: string, channelType: ChannelType, dismissedGMasDMNotice: PreferenceModel[], hasGMasDMFeature: boolean) => {
const intl = useIntl();
const serverUrl = useServerUrl();
useEffect(() => {
if (!hasGMasDMFeature) {
return;
}
const preferenceValue = getPreferenceAsBool(dismissedGMasDMNotice, Preferences.CATEGORIES.SYSTEM_NOTICE, Preferences.NOTICES.GM_AS_DM);
if (preferenceValue) {
return;
}
if (channelType !== 'G') {
return;
}
if (EphemeralStore.noticeShown.has(Preferences.NOTICES.GM_AS_DM)) {
return;
}
const onRemindMeLaterPress = () => {
EphemeralStore.noticeShown.add(Preferences.NOTICES.GM_AS_DM);
};
const onHideAndForget = () => {
EphemeralStore.noticeShown.add(Preferences.NOTICES.GM_AS_DM);
savePreference(serverUrl, [{category: Preferences.CATEGORIES.SYSTEM_NOTICE, name: Preferences.NOTICES.GM_AS_DM, value: 'true', user_id: userId}]);
};
// Show the GM as DM notice if needed
Alert.alert(
intl.formatMessage({id: 'system_notice.title.gm_as_dm', defaultMessage: 'Updates to Group Messages'}),
intl.formatMessage({id: 'system_noticy.body.gm_as_dm', defaultMessage: 'You will now be notified for all activity in your group messages along with a notification badge for every new message.\n\nYou can configure this in notification preferences for each group message.'}),
[
{
text: intl.formatMessage({id: 'system_notice.remind_me', defaultMessage: 'Remind Me Later'}),
onPress: onRemindMeLaterPress,
},
{
text: intl.formatMessage({id: 'system_notice.dont_show', defaultMessage: 'Don\'t Show Again'}),
onPress: onHideAndForget,
},
],
);
}, []);
};
export default useGMasDMNotice;

View file

@ -6,7 +6,9 @@ import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {NotificationLevel} from '@constants';
import {observeChannel, observeChannelSettings} from '@queries/servers/channel';
import {observeHasGMasDMFeature} from '@queries/servers/features';
import {observeCurrentUser} from '@queries/servers/user';
import {getNotificationProps} from '@utils/user';
@ -19,17 +21,22 @@ type Props = WithDatabaseArgs & {
}
const enhanced = withObservables(['channelId'], ({channelId, database}: Props) => {
const displayName = observeChannel(database, channelId).pipe(switchMap((c) => of$(c?.displayName)));
const channel = observeChannel(database, channelId);
const channelType = channel.pipe(switchMap((c) => of$(c?.type)));
const displayName = channel.pipe(switchMap((c) => of$(c?.displayName)));
const settings = observeChannelSettings(database, channelId);
const userNotifyLevel = observeCurrentUser(database).pipe(switchMap((u) => of$(getNotificationProps(u).push)));
const notifyLevel = settings.pipe(
switchMap((s) => of$(s?.notifyProps.push)),
switchMap((s) => of$(s?.notifyProps.push || NotificationLevel.DEFAULT)),
);
const hasGMasDMFeature = observeHasGMasDMFeature(database);
return {
displayName,
notifyLevel,
userNotifyLevel,
channelType,
hasGMasDMFeature,
};
});

View file

@ -10,6 +10,7 @@ import {NotificationLevel, Screens} from '@constants';
import {useTheme} from '@context/theme';
import {t} from '@i18n';
import {goToScreen} from '@screens/navigation';
import {isTypeDMorGM} from '@utils/channel';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity} from '@utils/theme';
@ -20,6 +21,8 @@ type Props = {
displayName: string;
notifyLevel: NotificationLevel;
userNotifyLevel: NotificationLevel;
channelType: ChannelType;
hasGMasDMFeature: boolean;
}
const notificationLevel = (notifyLevel: NotificationLevel) => {
@ -50,7 +53,14 @@ const notificationLevel = (notifyLevel: NotificationLevel) => {
return {id, defaultMessage};
};
const NotificationPreference = ({channelId, displayName, notifyLevel, userNotifyLevel}: Props) => {
const NotificationPreference = ({
channelId,
displayName,
notifyLevel,
userNotifyLevel,
channelType,
hasGMasDMFeature,
}: Props) => {
const {formatMessage} = useIntl();
const theme = useTheme();
const title = formatMessage({id: 'channel_info.mobile_notifications', defaultMessage: 'Mobile Notifications'});
@ -74,13 +84,19 @@ const NotificationPreference = ({channelId, displayName, notifyLevel, userNotify
});
const notificationLevelToText = () => {
if (notifyLevel === NotificationLevel.DEFAULT) {
const userLevel = notificationLevel(userNotifyLevel);
return formatMessage(userLevel);
let notifyLevelToUse = notifyLevel;
if (notifyLevelToUse === NotificationLevel.DEFAULT) {
notifyLevelToUse = userNotifyLevel;
}
const channelLevel = notificationLevel(notifyLevel);
return formatMessage(channelLevel);
if (hasGMasDMFeature) {
if (notifyLevel === NotificationLevel.DEFAULT && notifyLevelToUse === NotificationLevel.MENTION && isTypeDMorGM(channelType)) {
notifyLevelToUse = NotificationLevel.ALL;
}
}
const messageDescriptor = notificationLevel(notifyLevelToUse);
return formatMessage(messageDescriptor);
};
return (

View file

@ -7,10 +7,12 @@ import {useSharedValue} from 'react-native-reanimated';
import {updateChannelNotifyProps} from '@actions/remote/channel';
import SettingsContainer from '@components/settings/container';
import {NotificationLevel} from '@constants';
import {useServerUrl} from '@context/server';
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
import useDidUpdate from '@hooks/did_update';
import useBackNavigation from '@hooks/navigate_back';
import {isTypeDMorGM} from '@utils/channel';
import {popTopScreen} from '../navigation';
@ -28,16 +30,29 @@ type Props = {
defaultThreadReplies: 'all' | 'mention';
isCRTEnabled: boolean;
isMuted: boolean;
notifyLevel?: NotificationLevel;
notifyLevel: NotificationLevel;
notifyThreadReplies?: 'all' | 'mention';
channelType: ChannelType;
hasGMasDMFeature: boolean;
}
const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, defaultThreadReplies, isCRTEnabled, isMuted, notifyLevel, notifyThreadReplies}: Props) => {
const ChannelNotificationPreferences = ({
channelId,
componentId,
defaultLevel,
defaultThreadReplies,
isCRTEnabled,
isMuted,
notifyLevel,
notifyThreadReplies,
channelType,
hasGMasDMFeature,
}: Props) => {
const serverUrl = useServerUrl();
const defaultNotificationReplies = defaultThreadReplies === 'all';
const diffNotificationLevel = notifyLevel !== 'default' && notifyLevel !== defaultLevel;
const diffNotificationLevel = notifyLevel !== NotificationLevel.DEFAULT && notifyLevel !== defaultLevel;
const notifyTitleTop = useSharedValue((isMuted ? MUTED_BANNER_HEIGHT : 0) + BLOCK_TITLE_HEIGHT);
const [notifyAbout, setNotifyAbout] = useState<NotificationLevel>((notifyLevel === undefined || notifyLevel === 'default') ? defaultLevel : notifyLevel);
const [notifyAbout, setNotifyAbout] = useState<NotificationLevel>(notifyLevel === NotificationLevel.DEFAULT ? defaultLevel : notifyLevel);
const [threadReplies, setThreadReplies] = useState<boolean>((notifyThreadReplies || defaultThreadReplies) === 'all');
const [resetDefaultVisible, setResetDefaultVisible] = useState(diffNotificationLevel || defaultNotificationReplies !== threadReplies);
@ -64,8 +79,13 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
const save = useCallback(() => {
const pushThreads = threadReplies ? 'all' : 'mention';
if (notifyLevel !== notifyAbout || (isCRTEnabled && pushThreads !== notifyThreadReplies)) {
const props: Partial<ChannelNotifyProps> = {push: notifyAbout};
let notifyAboutToUse = notifyAbout;
if (notifyAbout === defaultLevel) {
notifyAboutToUse = NotificationLevel.DEFAULT;
}
if (notifyLevel !== notifyAboutToUse || (isCRTEnabled && pushThreads !== notifyThreadReplies)) {
const props: Partial<ChannelNotifyProps> = {push: notifyAboutToUse};
if (isCRTEnabled) {
props.push_threads = pushThreads;
}
@ -73,11 +93,15 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
updateChannelNotifyProps(serverUrl, channelId, props);
}
popTopScreen(componentId);
}, [channelId, componentId, isCRTEnabled, notifyAbout, notifyLevel, notifyThreadReplies, serverUrl, threadReplies]);
}, [defaultLevel, channelId, componentId, isCRTEnabled, notifyAbout, notifyLevel, notifyThreadReplies, serverUrl, threadReplies]);
useBackNavigation(save);
useAndroidHardwareBackHandler(componentId, save);
const showThreadReplies = isCRTEnabled && (
!hasGMasDMFeature ||
!isTypeDMorGM(channelType)
);
return (
<SettingsContainer testID='push_notification_settings'>
{isMuted && <MutedBanner channelId={channelId}/>}
@ -94,7 +118,7 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
notifyTitleTop={notifyTitleTop}
onPress={onNotificationLevel}
/>
{isCRTEnabled &&
{showThreadReplies &&
<ThreadReplies
isSelected={threadReplies}
onPress={onSetThreadReplies}

View file

@ -4,11 +4,14 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {switchMap, combineLatestWith} from 'rxjs/operators';
import {observeChannelSettings, observeIsMutedSetting} from '@queries/servers/channel';
import {NotificationLevel} from '@constants';
import {observeChannel, observeChannelSettings, observeIsMutedSetting} from '@queries/servers/channel';
import {observeHasGMasDMFeature} from '@queries/servers/features';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {observeCurrentUser} from '@queries/servers/user';
import {isTypeDMorGM} from '@utils/channel';
import {getNotificationProps} from '@utils/user';
import ChannelNotificationPreferences from './channel_notification_preferences';
@ -24,9 +27,11 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
const isCRTEnabled = observeIsCRTEnabled(database);
const isMuted = observeIsMutedSetting(database, channelId);
const notifyProps = observeCurrentUser(database).pipe(switchMap((u) => of$(getNotificationProps(u))));
const channelType = observeChannel(database, channelId).pipe(switchMap((c) => of$(c?.type)));
const hasGMasDMFeature = observeHasGMasDMFeature(database);
const notifyLevel = settings.pipe(
switchMap((s) => of$(s?.notifyProps.push)),
switchMap((s) => of$(s?.notifyProps.push || NotificationLevel.DEFAULT)),
);
const notifyThreadReplies = settings.pipe(
@ -35,7 +40,21 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
const defaultLevel = notifyProps.pipe(
switchMap((n) => of$(n?.push)),
combineLatestWith(hasGMasDMFeature, channelType),
switchMap(([v, hasFeature, cType]) => {
const shouldShowwithGMasDMBehavior = hasFeature && isTypeDMorGM(cType);
let defaultLevelToUse = v;
if (shouldShowwithGMasDMBehavior) {
if (v === NotificationLevel.MENTION) {
defaultLevelToUse = NotificationLevel.ALL;
}
}
return of$(defaultLevelToUse);
}),
);
const defaultThreadReplies = notifyProps.pipe(
switchMap((n) => of$(n?.push_threads)),
);
@ -47,6 +66,8 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
notifyThreadReplies,
defaultLevel,
defaultThreadReplies,
channelType,
hasGMasDMFeature,
};
});

View file

@ -40,7 +40,7 @@ const NOTIFY_OPTIONS: Record<string, NotifPrefOptions> = {
value: NotificationLevel.ALL,
},
[NotificationLevel.MENTION]: {
defaultMessage: 'Mentions, direct messages only',
defaultMessage: 'Mentions only',
id: t('channel_notification_preferences.notification.mention'),
testID: 'channel_notification_preferences.notification.mention',
value: NotificationLevel.MENTION,
@ -53,7 +53,13 @@ const NOTIFY_OPTIONS: Record<string, NotifPrefOptions> = {
},
};
const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPress}: Props) => {
const NotifyAbout = ({
defaultLevel,
isMuted,
notifyLevel,
notifyTitleTop,
onPress,
}: Props) => {
const {formatMessage} = useIntl();
const onLayout = useCallback((e: LayoutChangeEvent) => {
const {y} = e.nativeEvent.layout;
@ -61,6 +67,11 @@ const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPres
notifyTitleTop.value = y > 0 ? y + 10 : BLOCK_TITLE_HEIGHT;
}, []);
let notifyLevelToUse = notifyLevel;
if (notifyLevel === NotificationLevel.DEFAULT) {
notifyLevelToUse = defaultLevel;
}
return (
<SettingBlock
headerText={NOTIFY_ABOUT}
@ -77,7 +88,7 @@ const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPres
<SettingOption
action={onPress}
label={label}
selected={notifyLevel === key}
selected={notifyLevelToUse === key}
testID={testID}
type='select'
value={value}

View file

@ -36,7 +36,8 @@ const NOTIFY_OPTIONS_THREAD: Record<string, NotifPrefOptions> = {
const NotifyAbout = ({isSelected, notifyLevel, onPress}: Props) => {
const {formatMessage} = useIntl();
if ([NotificationLevel.NONE, NotificationLevel.ALL].includes(notifyLevel)) {
const hiddenStates: NotificationLevel[] = [NotificationLevel.NONE, NotificationLevel.ALL];
if (hiddenStates.includes(notifyLevel)) {
return null;
}

View file

@ -71,7 +71,7 @@ const PanelItem = ({pickerAction, pictureUtils, onRemoveProfileImage}: PanelItem
return (
<SlideUpPanelItem
icon={item.icon}
leftIcon={item.icon}
onPress={item.onPress}
testID={item.testID}
text={intl.formatMessage(item.text)}

View file

@ -78,8 +78,8 @@ const UserStatus = ({currentUser}: Props) => {
</View>
)}
<SlideUpPanelItem
icon='check-circle'
iconStyles={{color: theme.onlineIndicator}}
leftIcon='check-circle'
leftIconStyles={{color: theme.onlineIndicator}}
onPress={() => setUserStatus(ONLINE)}
testID='user_status.online.option'
text={intl.formatMessage({
@ -89,8 +89,8 @@ const UserStatus = ({currentUser}: Props) => {
textStyles={styles.label}
/>
<SlideUpPanelItem
icon='clock'
iconStyles={{color: theme.awayIndicator}}
leftIcon='clock'
leftIconStyles={{color: theme.awayIndicator}}
onPress={() => setUserStatus(AWAY)}
testID='user_status.away.option'
text={intl.formatMessage({
@ -100,8 +100,8 @@ const UserStatus = ({currentUser}: Props) => {
textStyles={styles.label}
/>
<SlideUpPanelItem
icon='minus-circle'
iconStyles={{color: theme.dndIndicator}}
leftIcon='minus-circle'
leftIconStyles={{color: theme.dndIndicator}}
onPress={() => setUserStatus(DND)}
testID='user_status.dnd.option'
text={intl.formatMessage({
@ -111,8 +111,8 @@ const UserStatus = ({currentUser}: Props) => {
textStyles={styles.label}
/>
<SlideUpPanelItem
icon='circle-outline'
iconStyles={{color: changeOpacity('#B8B8B8', 0.64)}}
leftIcon='circle-outline'
leftIconStyles={{color: changeOpacity('#B8B8B8', 0.64)}}
onPress={() => setUserStatus(OFFLINE)}
testID='user_status.offline.option'
text={intl.formatMessage({

View file

@ -17,7 +17,7 @@ import {useAppState} from '@hooks/device';
import {getAllServers} from '@queries/app/servers';
import {findChannels, popToRoot} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {handleDeepLink} from '@utils/deep_link';
import {alertInvalidDeepLink, handleDeepLink} from '@utils/deep_link';
import {logError} from '@utils/log';
import {alertChannelArchived, alertChannelRemove, alertTeamRemove} from '@utils/navigation';
import {notificationError} from '@utils/notification';
@ -121,9 +121,18 @@ export default function HomeScreen(props: HomeProps) {
useEffect(() => {
if (props.launchType === 'deeplink') {
if (props.launchError) {
alertInvalidDeepLink(intl);
return;
}
const deepLink = props.extra as DeepLinkWithData;
if (deepLink?.url) {
handleDeepLink(deepLink.url);
handleDeepLink(deepLink.url).then((result) => {
if (result.error) {
alertInvalidDeepLink(intl);
}
});
}
}
}, []);

View file

@ -143,7 +143,7 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
const result: LoginActionResponse = await login(serverUrl, {loginId, password, mfaToken: token, config, license, serverDisplayName});
setIsLoading(false);
if (result?.error && result.failed) {
setError(getErrorMessage(error, intl));
setError(getErrorMessage(result.error, intl));
return;
}
goToHome(result.error);
@ -191,7 +191,7 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
bounces={false}
contentContainerStyle={styles.innerContainer}
enableAutomaticScroll={Platform.OS === 'android'}
enableOnAndroid={true}
enableOnAndroid={false}
enableResetScrollToCoords={true}
extraScrollHeight={0}
keyboardDismissMode='on-drag'

View file

@ -73,19 +73,24 @@ const NotificationPush = ({componentId, currentUser, isCRTEnabled, sendPushNotif
sendPushNotifications={sendPushNotifications}
setMobilePushPref={setPushSend}
/>
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
{isCRTEnabled && pushSend === 'mention' && (
<MobilePushThread
pushThread={pushThread}
onMobilePushThreadChanged={onMobilePushThreadChanged}
/>
<>
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
<MobilePushThread
pushThread={pushThread}
onMobilePushThreadChanged={onMobilePushThreadChanged}
/>
</>
)}
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
{sendPushNotifications && pushSend !== 'none' && (
<MobilePushStatus
pushStatus={pushStatus}
setMobilePushStatus={setPushStatus}
/>
<>
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
<MobilePushStatus
pushStatus={pushStatus}
setMobilePushStatus={setPushStatus}
/>
</>
)}
</SettingContainer>
);

View file

@ -55,7 +55,7 @@ const MobileSendPush = ({sendPushNotifications, pushStatus, setMobilePushPref}:
<SettingSeparator/>
<SettingOption
action={setMobilePushPref}
label={intl.formatMessage({id: 'notification_settings.pushNotification.mentions_only', defaultMessage: 'Mentions, direct messages only (default)'})}
label={intl.formatMessage({id: 'notification_settings.pushNotification.mentions_only', defaultMessage: 'Only for mentions, direct messages and group messages (default)'})}
selected={pushStatus === 'mention'}
testID='push_notification_settings.mentions_only.option'
type='select'

View file

@ -14,6 +14,8 @@ class EphemeralStore {
creatingChannel = false;
creatingDMorGMTeammates: string[] = [];
noticeShown = new Set<string>();
private pushProxyVerification: {[serverUrl: string]: string | undefined} = {};
private canJoinOtherTeams: {[serverUrl: string]: BehaviorSubject<boolean>} = {};

View file

@ -10,14 +10,14 @@ import {fetchUsersByUsernames} from '@actions/remote/user';
import {DeepLink, Launch, Screens} from '@constants';
import {getDefaultThemeByAppearance} from '@context/theme';
import DatabaseManager from '@database/manager';
import {DEFAULT_LOCALE, getTranslations} from '@i18n';
import {DEFAULT_LOCALE, getTranslations, t} from '@i18n';
import WebsocketManager from '@managers/websocket_manager';
import {getActiveServerUrl} from '@queries/app/servers';
import {getCurrentUser, queryUsersByUsername} from '@queries/servers/user';
import {dismissAllModalsAndPopToRoot} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import NavigationStore from '@store/navigation_store';
import {errorBadChannel, errorUnkownUser} from '@utils/draft';
import {alertErrorWithFallback, errorBadChannel, errorUnkownUser} from '@utils/draft';
import {logError} from '@utils/log';
import {escapeRegex} from '@utils/markdown';
import {addNewServer} from '@utils/server';
@ -115,31 +115,39 @@ export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape,
}
export function parseDeepLink(deepLinkUrl: string): DeepLinkWithData {
const url = removeProtocol(deepLinkUrl);
try {
const url = removeProtocol(decodeURIComponent(deepLinkUrl));
let match = new RegExp('(.*)\\/([^\\/]+)\\/channels\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], channelName: match[3]}};
}
if (url.includes('../') || url.includes('/..')) {
return {type: DeepLink.Invalid, url: deepLinkUrl};
}
match = new RegExp('(.*)\\/([^\\/]+)\\/pl\\/(\\w+)').exec(url);
if (match) {
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], postId: match[3]}};
}
let match = new RegExp('(.*)\\/([^\\/]+)\\/channels\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], channelName: match[3]}};
}
match = new RegExp('(.*)\\/([^\\/]+)\\/messages\\/@(\\S+)').exec(url);
if (match) {
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], userName: match[3]}};
}
match = new RegExp('(.*)\\/([^\\/]+)\\/pl\\/(\\w+)').exec(url);
if (match) {
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], postId: match[3]}};
}
match = new RegExp('(.*)\\/([^\\/]+)\\/messages\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], channelId: match[3]}};
}
match = new RegExp('(.*)\\/([^\\/]+)\\/messages\\/@(\\S+)').exec(url);
if (match) {
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], userName: match[3]}};
}
match = new RegExp('(.*)\\/plugins\\/([^\\/]+)\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.Plugin, url: deepLinkUrl, data: {serverUrl: match[1], id: match[2], teamName: ''}};
match = new RegExp('(.*)\\/([^\\/]+)\\/messages\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl: match[1], teamName: match[2], channelId: match[3]}};
}
match = new RegExp('(.*)\\/plugins\\/([^\\/]+)\\/(\\S+)').exec(url);
if (match) {
return {type: DeepLink.Plugin, url: deepLinkUrl, data: {serverUrl: match[1], id: match[2], teamName: ''}};
}
} catch {
// do nothing just return invalid deeplink
}
return {type: DeepLink.Invalid, url: deepLinkUrl};
@ -201,3 +209,12 @@ export const getLaunchPropsFromDeepLink = (deepLinkUrl: string, coldStart = fals
return launchProps;
};
export function alertInvalidDeepLink(intl: IntlShape) {
const message = {
id: t('mobile.deep_link.invalid'),
defaultMessage: 'This link you are trying to open is invalid.',
};
return alertErrorWithFallback(intl, {}, message);
}

View file

@ -1,13 +1,23 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {createIntl} from 'react-intl';
import DeviceInfo from 'react-native-device-info';
import ReactNativeHapticFeedback, {HapticFeedbackTypes} from 'react-native-haptic-feedback';
import {getTranslations} from '@i18n';
type SortByCreatAt = (Session | Channel | Team | Post) & {
create_at: number;
}
export function getIntlShape(locale = 'en') {
return createIntl({
locale,
messages: getTranslations(locale),
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function emptyFunction(..._args: any[]) {
// do nothing

View file

@ -17,7 +17,7 @@ const ShareModule: NativeShareExtension|undefined = Platform.select({android: Na
// versions, and a non-equal minor version will ignore dot version.
// currentVersion is a string, e.g '4.6.0'
// minMajorVersion, minMinorVersion, minDotVersion are integers
export const isMinimumServerVersion = (currentVersion: string, minMajorVersion = 0, minMinorVersion = 0, minDotVersion = 0): boolean => {
export const isMinimumServerVersion = (currentVersion = '', minMajorVersion = 0, minMinorVersion = 0, minDotVersion = 0): boolean => {
if (!currentVersion || typeof currentVersion !== 'string') {
return false;
}

View file

@ -3,7 +3,7 @@
import {Alert} from 'react-native';
import {getIntlShape} from '@test/intl-test-helper';
import {getIntlShape} from '@utils/general';
import {unsupportedServer} from '.';

View file

@ -1067,5 +1067,13 @@
"settings.about.server.version": "Server Version: {version} (Build {buildNumber}",
"settings.about.server.version.title": "Server-Version:",
"settings.about.server.version.noBuild": "Server Version: {version}",
"snack.bar.info.copied": "Info in die Zwischenablage kopiert"
"snack.bar.info.copied": "Info in die Zwischenablage kopiert",
"mobile.calls_join_button": "Teilnehmen",
"mobile.calls_incoming_dm": "<b>{name}</b> lädt dich zu einem Anruf ein",
"mobile.calls_incoming_gm": "<b>{name}</b> lädt dich zu einem Anruf mit <b>{num, plural, one {einem anderen} other {# anderen}}</b> ein",
"server.invalid.certificate.title": "Ungültiges SSL-Zertifikat",
"server.invalid.certificate.description": "Das Zertifikat für diesen Server ist ungültig.\nMöglicherweise stellen Sie eine Verbindung zu einem Server her, der vorgibt, \"{hostname}\" zu sein, wodurch Ihre vertraulichen Daten gefährdet werden könnten.",
"markdown.max_nodes.error": "Diese Nachricht ist zu lang, um auf einem mobilen Gerät vollständig angezeigt zu werden. Bitte sehen Sie sie sich auf dem Desktop an oder kontaktieren Sie einen Administrator, um dieses Limit zu erhöhen.",
"mobile.deep_link.invalid": "Der Link, den du zu öffnen versuchst, ist ungültig.",
"mobile.calls_headset": "Kopfhörer"
}

View file

@ -179,7 +179,7 @@
"channel_notification_preferences.muted_content": "You can change the notification settings, but you will not receive notifications until the channel is unmuted.",
"channel_notification_preferences.muted_title": "This channel is muted",
"channel_notification_preferences.notification.all": "All new messages",
"channel_notification_preferences.notification.mention": "Mentions, direct messages only",
"channel_notification_preferences.notification.mention": "Mentions only",
"channel_notification_preferences.notification.none": "Nothing",
"channel_notification_preferences.notification.thread_replies": "Notify me about replies to threads Im following in this channel",
"channel_notification_preferences.notify_about": "Notify me about...",
@ -341,6 +341,7 @@
"intro.created_by": "created by {creator} on {date}.",
"intro.direct_message": "This is the start of your conversation with {teammate}. Messages and files shared here are not shown to anyone else.",
"intro.group_message": "This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.",
"intro.group_message.after_gm_as_dm": "This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.",
"intro.private_channel": "Private Channel",
"intro.public_channel": "Public Channel",
"intro.townsquare": "Welcome to {name}. Everyone automatically becomes a member of this channel when they join the team.",
@ -435,6 +436,7 @@
"mobile.calls_ended_at": "Ended at",
"mobile.calls_error_message": "Error: {error}",
"mobile.calls_error_title": "Error",
"mobile.calls_headset": "Headset",
"mobile.calls_host": "host",
"mobile.calls_host_rec": "You are recording this meeting. Consider letting everyone know that this meeting is being recorded.",
"mobile.calls_host_rec_error": "Please try to record again. You can also contact your system admin for troubleshooting help.",
@ -521,6 +523,7 @@
"mobile.custom_status.clear_after": "Clear After",
"mobile.custom_status.clear_after.title": "Clear Custom Status After",
"mobile.custom_status.modal_confirm": "Done",
"mobile.deep_link.invalid": "This link you are trying to open is invalid.",
"mobile.diagnostic_id.empty": "A DiagnosticId value is missing for this server. Contact your system admin to review this value and restart the server.",
"mobile.direct_message.error": "We couldn't open a DM with {displayName}.",
"mobile.display_settings.clockDisplay": "Clock Display",
@ -763,7 +766,7 @@
"notification_settings.push_threads.replies": "Thread replies",
"notification_settings.pushNotification.all_new_messages": "All new messages",
"notification_settings.pushNotification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.",
"notification_settings.pushNotification.mentions_only": "Mentions, direct messages only (default)",
"notification_settings.pushNotification.mentions_only": "Only for mentions, direct messages and group messages (default)",
"notification_settings.pushNotification.nothing": "Nothing",
"notification_settings.send_notification.about": "Notify me about...",
"notification_settings.threads_mentions": "Mentions in threads",
@ -1014,6 +1017,10 @@
"suggestion.search.direct": "Direct Messages",
"suggestion.search.private": "Private Channels",
"suggestion.search.public": "Public Channels",
"system_notice.dont_show": "Don't Show Again",
"system_notice.remind_me": "Remind Me Later",
"system_notice.title.gm_as_dm": "Updates to Group Messages",
"system_noticy.body.gm_as_dm": "You will now be notified for all activity in your group messages along with a notification badge for every new message.\n\nYou can configure this in notification preferences for each group message.",
"team_list.no_other_teams.description": "To join another team, ask a Team Admin for an invitation, or create your own team.",
"team_list.no_other_teams.title": "No additional teams to join",
"terms_of_service.acceptButton": "Accept",

View file

@ -1066,5 +1066,12 @@
"settings.about.database.title": "Database:",
"settings.about.server.version": "Server Version: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Server Version: {version}",
"settings.about.server.version.title": "Server Version:"
"settings.about.server.version.title": "Server Version:",
"snack.bar.info.copied": "Info copied to clipboard",
"mobile.calls_incoming_dm": "<b>{name}</b> is inviting you to a call",
"mobile.calls_incoming_gm": "<b>{name}</b> is inviting you to a call with <b>{num, plural, one {# other} other {# others}}</b>",
"mobile.calls_join_button": "Join",
"server.invalid.certificate.description": "The certificate for this server is invalid.\nYou might be connecting to a server that is pretending to be \"{hostname}\" which could put your confidential information at risk.",
"server.invalid.certificate.title": "Invalid SSL certificate",
"markdown.max_nodes.error": "This message is too long to by shown fully on a mobile device. Please view it on desktop or contact an admin to increase this limit."
}

View file

@ -5,7 +5,7 @@
"about.enterpriseEditionSt": "Communication moderne derrière votre pare-feu.",
"about.hash": "Hash de version :",
"about.hashee": "Hash de version EE :",
"about.teamEditionLearn": "Rejoignez la communauté Mattermost sur ",
"about.teamEditionLearn": "Rejoignez la communauté Mattermost sur",
"about.teamEditionSt": "Toute la communication de votre équipe en un seul endroit, consultable instantanément et accessible de partout.",
"about.teamEditiont0": "Édition Team",
"about.teamEditiont1": "Édition Entreprise",
@ -953,14 +953,14 @@
"mobile.manage_members.change_role.error": "",
"mobile.manage_members.cancel": "",
"mobile.manage_members.admin": "",
"channel_info.archive_description.cannot_view_archived": "",
"channel_info.archive_description.can_view_archived": "",
"channel_info.archive_description.cannot_view_archived": "Cela archivera le canal de l'équipe et le supprimera de l'interface utilisateur. Les canaux archivés peuvent être désarchivés en cas de besoin.\n\nÊtes-vous sûr de vouloir archiver le site {term} {name} ?",
"channel_info.archive_description.can_view_archived": "Cette opération permet d'archiver le canal de l'équipe. Le contenu du canal reste accessible aux membres du canal.\n\nÊtes-vous sûr de vouloir archiver le site {term} {name} ?",
"mobile.display_settings.crt": "",
"invite.summary.report.sent": "",
"invite.summary.done": "",
"display_settings.crt.on": "",
"display_settings.crt.off": "",
"display_settings.crt": "",
"display_settings.crt.on": "Activé",
"display_settings.crt.off": "Désactivé",
"display_settings.crt": "Fils de discussion repliables",
"mobile.managed.jailbreak_no_reason": "",
"mobile.managed.jailbreak_no_debug_info": "",
"invite.title.summary": "",
@ -978,11 +978,11 @@
"invite.sendInvitationsTo": "",
"invite.send_invite": "",
"invite.send_error": "",
"invite.searchPlaceholder": "",
"invite.search.no_results": "",
"invite.search.email_invite": "",
"invite.members.user_is_guest": "",
"invite.members.already_member": "",
"invite.searchPlaceholder": "Tapez un nom ou une adresse électronique…",
"invite.search.no_results": "Personne n'a trouvé de correspondance",
"invite.search.email_invite": "Inviter",
"invite.members.user_is_guest": "Contactez votre administrateur pour faire de cet utilisateur invité un membre à part entière",
"invite.members.already_member": "Cet utilisateur est déjà un membre d'équipe",
"mobile.calls_start_call_exists": "",
"mobile.calls_not_connected": "",
"channel_notification_preferences.notification.thread_replies": "M'avertir des réponses aux fils de discussion que je suis sur cette chaîne",
@ -990,5 +990,19 @@
"channel_notification_preferences.notification.all": "Tous les nouveaux messages",
"channel_notification_preferences.muted_title": "Ce canal est en sourdine",
"channel_notification_preferences.muted_content": "Vous pouvez modifier les paramètres de notification, mais vous ne recevrez pas de notifications tant que le canal n'aura pas été désactivé.",
"post_priority.picker.cancel": "Annuler"
"post_priority.picker.cancel": "Annuler",
"channel_files.empty.paragraph": "Les fichiers publiés sur cette chaîne s'afficheront ici.",
"channel_files.empty.title": "Aucun fichier ici",
"channel_files.noFiles.paragraph": "Ce canal ne contient aucun fichier avec les filtres appliqués",
"channel_files.noFiles.title": "Aucun fichier trouver",
"channel_add_members.add_members.button": "Ajouter des membres",
"channel_notification_preferences.notification.none": "Rien",
"channel_notification_preferences.unmute_content": "Rétablir le son du canal",
"channel_notification_preferences.reset_default": "Rétablissement des valeurs par défaut",
"channel_notification_preferences.thread_replies": "Réponses aux fils de discussion",
"intro.add_members": "Ajouter Membres",
"channel_info.add_members": "Ajouter des membres",
"channel_notification_preferences.notify_about": "Notifiez moi à propos...",
"channel_notification_preferences.default": "(par défaut)",
"channel_info.channel_files": "Fichiers"
}

View file

@ -151,7 +151,7 @@
"friendly_date.hoursAgo": "{count} {count, plural, one {時間} other {時間}} 前",
"friendly_date.minsAgo": "{count} {count, plural, one {分} other {分}} 前",
"friendly_date.monthsAgo": "{count} {count, plural, one {ヶ月} other {ヶ月}} 前",
"friendly_date.now": "今すぐ",
"friendly_date.now": "今",
"friendly_date.yearsAgo": "{count} {count, plural, one {年} other {年}} 前",
"friendly_date.yesterday": "昨日",
"gallery.footer.channel_name": "{channelName}に共有されました",
@ -1067,5 +1067,12 @@
"settings.about.database.title": "データベース:",
"settings.about.server.version": "サーバーのバージョン: {version} (Build {buildNumber})",
"settings.about.server.version.noBuild": "サーバーのバージョン: {version}",
"settings.about.server.version.title": "サーバーのバージョン:"
"settings.about.server.version.title": "サーバーのバージョン:",
"mobile.calls_incoming_dm": "<b>{name}</b>があなたを通話に招待しています",
"mobile.calls_incoming_gm": "<b>{name}</b>があなたを<b>{num, plural, one {# 人} other {# 人}}</b>との通話に招待しています",
"mobile.calls_join_button": "参加",
"server.invalid.certificate.title": "無効なSSL証明書",
"server.invalid.certificate.description": "このサーバーの証明書は無効です。\n\"{hostname}\" を装ったサーバーに接続しようとしている可能性があり、機密情報が危険にさらされる可能性があります。",
"mobile.deep_link.invalid": "あなたが開こうとしているこのリンクは無効です。",
"markdown.max_nodes.error": "このメッセージは長すぎるため、モバイルデバイスでは完全に表示されません。デスクトップで表示するか、管理者に連絡して制限を増やしてください。"
}

View file

@ -454,7 +454,7 @@
"display_settings.tz.auto": "자동",
"display_settings.timezone": "표준시간대",
"display_settings.theme": "테마",
"display_settings.clockDisplay": "시 표시",
"display_settings.clockDisplay": "시 표시",
"display_settings.clock.standard": "12시간제",
"display_settings.clock.military": "24시간제",
"custom_status.suggestions.title": "제안",
@ -555,437 +555,524 @@
"display_settings.crt.off": "끄기",
"display_settings.crt": "축소된 응답 글타래",
"default_skin_tone": "기본 피부색",
"permalink.error.public_channel.title": "",
"password_send.reset": "",
"permalink.error.private_channel_and_team.title": "",
"unreads.empty.show_all": "",
"mobile.calls_request_message": "",
"notification_settings.mentions.sensitiveName": "",
"invite.members.user_is_guest": "",
"mobile.login_options.heading": "",
"mobile.ios.photos_permission_denied_description": "",
"mobile.calls_host_rec_error_title": "",
"mobile.no_results_with_term.files": "",
"mobile.calls_recording_stop_none_in_progress": "",
"mobile.login_options.gitlab": "",
"password_send.link.title": "",
"mobile.calls_start_call": "",
"user.tutorial.long_press": "",
"server.tutorial.swipe": "",
"mobile.calls_end_permission_title": "",
"mobile.open_dm.error": "",
"notification_settings.push_threads.following": "",
"mobile.calls_rec": "",
"settings.about": "",
"snack.bar.link.copied": "",
"invite.searchPlaceholder": "",
"smobile.search.recent_title": "",
"notification_settings.pushNotification.all_new_messages": "",
"team_list.no_other_teams.description": "",
"post_info.auto_responder": "",
"notification_settings.pushNotification.mentions_only": "",
"server_list.push_proxy_unknown": "",
"unreads.empty.title": "",
"thread.repliesCount": "",
"settings_display.clock.standard": "",
"notification.message_not_found": "",
"mobile.calls_see_logs": "",
"invite.members.already_member": "",
"mobile.calls_lasted": "",
"mobile.calls_lower_hand": "",
"post.reactions.title": "",
"notification_settings.threads_start_participate": "",
"notification_settings.auto_responder.to.enable": "",
"mobile.calls_leave_call": "",
"settings.about.copyright": "",
"mobile.calls_end_msg_channel": "",
"unsupported_server.message": "",
"mobile.login_options.select_option": "",
"saved_messages.empty.paragraph": "",
"mobile.calls_host_rec_title": "",
"mobile.calls_end_msg_channel_default": "",
"mobile.calls_recording_stop_no_permissions": "",
"notification_settings.mobile": "",
"mobile.calls_react": "",
"notification_settings.pushNotification.disabled_long": "",
"mobile.no_results_with_term.messages": "",
"notification_settings.send_notification.about": "",
"threads.end_of_list.subtitle": "",
"notification_settings.mentions.keywords_mention": "",
"settings.display": "",
"user_profile.custom_status": "",
"notification_settings.mentions.keywords": "",
"mobile.login_options.none": "",
"mobile.components.select_server_view.msg_description": "",
"settings.link.error.text": "",
"mobile.login_options.saml": "",
"public_link_copied": "",
"select_team.title": "",
"notification_settings.mobile.away": "",
"mobile.create_channel.title": "",
"server.remove.alert_description": "",
"settings.link.error.title": "",
"notification_settings.push_threads.replies": "",
"settings.about.server.version.value": "",
"mobile.login_options.separator_text": "",
"notification_settings.auto_responder.footer.message": "",
"snack.bar.remove.user": "",
"settings_display.crt.label": "",
"settings_display.crt.desc": "",
"onboaring.welcome_description": "",
"onboarding.calls_description": "",
"onboarding.calls": "",
"notification_settings.email.emailInfo": "",
"mobile.manage_members.section_title_members": "",
"mobile.manage_members.section_title_admins": "",
"mobile.manage_members.remove_member": "",
"mobile.manage_members.remove": "",
"mobile.manage_members.message": "",
"mobile.manage_members.member": "",
"mobile.manage_members.manage_member": "",
"mobile.manage_members.manage": "",
"mobile.custom_list.no_results": "",
"mobile.components.select_server_view.displayName": "",
"mobile.components.select_server_view.displayHelp": "",
"mobile.components.select_server_view.connecting": "",
"mobile.calls_recording_start_no_permissions": "",
"mobile.calls_recording_start_in_progress": "",
"mobile.calls_host_rec_error": "",
"mobile.manage_members.make_channel_member": "",
"mobile.manage_members.make_channel_admin": "",
"mobile.manage_members.done": "",
"mobile.manage_members.change_role.error": "",
"mobile.manage_members.cancel": "",
"mobile.manage_members.admin": "",
"share_extension.message": "",
"share_extension.max_resolution": "",
"share_extension.file_limit.single": "",
"onboarding.realtime_collaboration": "",
"onboarding.integrations_description": "",
"onboarding.integrations": "",
"mobile.calls_stop_recording": "",
"mobile.calls_record": "",
"invite.summary.try_again": "",
"invite.summary.some_not_sent": "",
"channel_info.archive_description.cannot_view_archived": "",
"channel_info.archive_description.can_view_archived": "",
"mobile.server_identifier.exists": "",
"mobile.managed.jailbreak_no_reason": "",
"mobile.display_settings.crt": "",
"mobile.calls_participant_rec_title": "",
"invite.title.summary": "",
"invite.title": "",
"invite.summary.smtp_failure": "",
"mobile.managed.jailbreak_no_debug_info": "",
"invite.summary.sent": "",
"invite.summary.report.sent": "",
"invite.summary.report.notSent": "",
"invite.summary.not_sent": "",
"invite.summary.member_invite": "",
"invite.summary.error": "",
"invite.summary.email_invite": "",
"invite.summary.done": "",
"invite.shareLink": "",
"invite.sendInvitationsTo": "",
"invite.send_invite": "",
"invite.send_error": "",
"invite.search.no_results": "",
"invite.search.email_invite": "",
"terms_of_service.alert_retry": "",
"share_feedback.button.no": "",
"settings.notice_mobile_link": "",
"notification_settings.pushNotification.nothing": "",
"notification_settings.email.send": "",
"notification_settings.email.immediately": "",
"mobile.screen.your_profile": "",
"mobile.calls_start_call_exists": "",
"mobile.calls_not_connected": "",
"notification_settings.email.everyHour": "",
"video.download_description": "",
"user.edit_profile.profile_photo.change_photo": "",
"user_status.title": "",
"user_status.online": "",
"user_status.offline": "",
"user_status.dnd": "",
"user_status.away": "",
"share_extension.server_label": "",
"share_extension.multiple_label": "",
"mobile.camera_type.title": "",
"video.failed_description": "",
"thread.loadingReplies": "",
"settings_display.timezone.automatically": "",
"mobile.login_options.openid": "",
"mobile.login_options.office365": "",
"mobile.calls_open_channel": "",
"mobile.create_direct_message.max_limit_reached": "",
"mobile.calls_request_title": "",
"mobile.calls_participant_limit_title_GA": "",
"mobile.calls_limit_msg_GA": "",
"mobile.create_direct_message.start": "",
"share_extension.servers_screen.title": "",
"share_extension.upload_disabled": "",
"share_extension.share_screen.title": "",
"share_extension.file_limit.multiple": "",
"share_extension.count_limit": "",
"share_extension.channel_label": "",
"share_extension.channel_error": "",
"post_info.bot": "",
"mobile.calls_viewing_screen": "",
"settings.advanced.delete_message.confirmation": "",
"settings.advanced.delete_data": "",
"server.remove.alert_title": "",
"team_list.no_other_teams.title": "",
"skintone_selector.tooltip.title": "",
"mobile.login_options.enter_credentials": "",
"skintone_selector.tooltip.description": "",
"server.logout.alert_description": "",
"mobile.create_post.read_only": "",
"mobile.calls_ended_at": "",
"notification_settings.threads_start": "",
"server.websocket.unreachable": "",
"notification_settings.auto_responder.message": "",
"mobile.channel_list.unreads": "",
"settings.about.powered_by": "",
"screens.channel_info": "",
"user.settings.general.field_handled_externally": "",
"mobile.oauth.something_wrong.okButton": "",
"notification_settings.mentions.keywordsLabel": "",
"mobile.login_options.google": "",
"pinned_messages.empty.paragraph": "",
"server_list.push_proxy_error": "",
"login_mfa.enterToken": "",
"settings.advanced.delete": "",
"settings.advanced.cancel": "",
"mobile.calls_host_rec_stopped_title": "",
"mobile.calls_host_rec_stopped": "",
"mobile.calls_host_rec": "",
"mobile.calls_dismiss": "",
"mobile.calls_participant_rec": "",
"mobile.calls_okay": "",
"terms_of_service.terms_declined.title": "",
"terms_of_service.decline": "",
"permalink.error.public_channel.title": "채널 가입",
"password_send.reset": "비밀번호 재설정",
"permalink.error.private_channel_and_team.title": "비공개 채널 및 팀 가입",
"unreads.empty.show_all": "모두 보기",
"mobile.calls_request_message": "통화는 현재 테스트 모드에서 실행 중이며 시스템 관리자만 시작할 수 있습니다. 시스템 관리자에게 직접 문의하여 도움을 받으세요",
"notification_settings.mentions.sensitiveName": "대소문자를 구분하는 이름",
"invite.members.user_is_guest": "이 게스트를 정식 구성원으로 만들려면 관리자에게 문의하세요",
"mobile.login_options.heading": "계정에 로그인",
"mobile.ios.photos_permission_denied_description": "사진과 동영상을 서버에 업로드하거나 디바이스에 저장합니다. 설정을 열어 {applicationName} 에 사진 및 동영상 라이브러리에 대한 읽기 및 쓰기 액세스 권한을 부여합니다.",
"mobile.calls_host_rec_error_title": "녹화에 문제가 발생했습니다",
"mobile.no_results_with_term.files": "일치하는 파일 없음 \"{term}\"",
"mobile.calls_recording_stop_none_in_progress": "녹화가 진행 중이 아닙니다.",
"mobile.login_options.gitlab": "GitLab",
"password_send.link.title": "재설정 링크 보내기",
"mobile.calls_start_call": "통화 시작",
"user.tutorial.long_press": "항목을 길게 누르면 사용자 프로필을 볼 수 있습니다",
"server.tutorial.swipe": "서버에서 왼쪽으로 스와이프하면 더 많은 작업을 볼 수 있습니다",
"mobile.calls_end_permission_title": "오류",
"mobile.open_dm.error": "{displayName} (으)로 다이렉트 메시지를 열 수 없습니다. 연결을 확인하고 다시 시도하십시오.",
"notification_settings.push_threads.following": "이 채널에서 팔로우 중인 스레드에 대해 답글 알림 받기",
"mobile.calls_rec": "녹화",
"settings.about": "{appTitle} 정보",
"snack.bar.link.copied": "링크가 클립보드에 복사되었습니다",
"invite.searchPlaceholder": "이름 또는 이메일 주소를 입력하세요…",
"smobile.search.recent_title": "{teamName} 의 최근 검색",
"notification_settings.pushNotification.all_new_messages": "모든 새 메시지",
"team_list.no_other_teams.description": "다른 팀에 참여하려면 팀 관리자에게 초대를 요청하거나 직접 팀을 만드세요.",
"post_info.auto_responder": "자동 회신",
"notification_settings.pushNotification.mentions_only": "멘션, 쪽지만",
"server_list.push_proxy_unknown": "이 서버의 구성으로 인해 이 서버에서 알림을 수신할 수 없습니다. 로그아웃했다가 다시 로그인하여 다시 시도하세요.",
"unreads.empty.title": "읽지 않은 메시지 없음",
"thread.repliesCount": "{repliesCount, number} {repliesCount, plural, one {reply} other {replies}}",
"settings_display.clock.standard": "12시간제로 표시",
"notification.message_not_found": "메시지를 찾을 수 없습니다",
"mobile.calls_see_logs": "서버 로그 보기",
"invite.members.already_member": "이 사람은 이미 구성원입니다",
"mobile.calls_lasted": "{duration}동안 지속됨",
"mobile.calls_lower_hand": "손 내리기",
"post.reactions.title": "반응",
"notification_settings.threads_start_participate": "내가 시작하였거나 참여했던 글타래의 댓글을 알림",
"notification_settings.auto_responder.to.enable": "자동 답글 사용 설정",
"mobile.calls_leave_call": "통화 종료",
"settings.about.copyright": "Copyright 2015-{currentYear} Mattermost, Inc. All rights reserved",
"mobile.calls_end_msg_channel": "{numParticipants}명이 참가하고 있는 {displayName}의 통화를 종료 하시겠습니까?",
"unsupported_server.message": "{serverDisplayName} 서버는 지원되지 않는 서버 버전으로 작동 중입니다. 호환성 문제로 인해 충돌이 발생하거나 앱의 핵심 기능이 중단되는 심각한 버그가 발생할 수 있습니다. 시스템 관리자에게 문의하여 Mattermost 서버를 업그레이드하세요.",
"mobile.login_options.select_option": "아래에서 로그인 옵션을 선택합니다.",
"saved_messages.empty.paragraph": "나중을 위해 저장하려는 메시지가 있으면, 메시지를 길게 누른 후 메뉴에서 저장을 선택하십시오. 저장된 메시지는 본인만 볼 수 있습니다.",
"mobile.calls_host_rec_title": "녹화 중입니다",
"mobile.calls_end_msg_channel_default": "정말 통화를 종료하시겠습니까?",
"mobile.calls_recording_stop_no_permissions": "녹음을 중지할 수 있는 권한이 없습니다. 통화 호스트에게 녹음을 중지해 달라고 요청하세요.",
"notification_settings.mobile": "푸시 알림",
"mobile.calls_react": "반응하기",
"notification_settings.pushNotification.disabled_long": "시스템 관리자가 모바일 장치에 대한 푸시 알림을 비활성화했습니다.",
"mobile.no_results_with_term.messages": "\"{term}\" 일치하는 항목이 없습니다",
"notification_settings.send_notification.about": "푸시 알림을 받을 대상...",
"threads.end_of_list.subtitle": "이전 대화를 찾고 있다면, 검색을 활용해 보세요",
"notification_settings.mentions.keywords_mention": "멘션 알림 키워드",
"settings.display": "화면",
"user_profile.custom_status": "사용자 정의 상태",
"notification_settings.mentions.keywords": "키워드",
"mobile.login_options.none": "아직 계정에 로그인할 수 없습니다. 하나 이상의 로그인 옵션을 구성해야 합니다. 시스템 관리자에게 도움을 요청하세요.",
"mobile.components.select_server_view.msg_description": "서버는 고유 URL을 사용하여 액세스하는 팀의 커뮤니케이션 허브입니다",
"settings.link.error.text": "링크를 열 수 없습니다.",
"mobile.login_options.saml": "SAML",
"public_link_copied": "클립보드에 링크 복사",
"select_team.title": "팀 선택",
"notification_settings.mobile.away": "오프라인이거나 자리비움",
"mobile.create_channel.title": "새 채널",
"server.remove.alert_description": "이렇게 하면 서버 목록에서 해당 서버가 제거됩니다. 모든 관련 데이터가 제거됩니다",
"settings.link.error.title": "오류",
"notification_settings.push_threads.replies": "글타래 댓글",
"settings.about.server.version.value": "{version} (Build {number})",
"mobile.login_options.separator_text": "또는 다음으로 로그인",
"notification_settings.auto_responder.footer.message": "부재중 또는 휴가 답장 등의 쪽지에 대한 응답으로 자동으로 전송되는 사용자 지정 메시지를 설정합니다. 이 설정을 사용 설정하면 상태가 부재중으로 변경되고 알림이 비활성화됩니다.",
"snack.bar.remove.user": "채널에서 멤버 1명이 삭제되었습니다",
"settings_display.crt.label": "축소된 응답 글타래",
"settings_display.crt.desc": "사용으로 설정하면 댓글 메시지는 채널에 표시되지 않으며 팔로우 중인 스레드에 대한 알림은 \"스레드\" 보기에서 확인할 수 있습니다.",
"onboaring.welcome_description": "Mattermost는 개발자 협업을 위한 오픈 소스 플랫폼입니다. 안전하고 유연하며 도구와 통합되어 있습니다.",
"onboarding.calls_description": "타이핑 속도가 느리면 탭 한 번으로 채널 기반 채팅에서 보안 음성 통화로 전환하세요.",
"onboarding.calls": "즉시 보안 음성 통화 시작",
"notification_settings.email.emailInfo": "오프라인 상태이거나 5분 이상 자리를 비우면 멘션 및 개인 메시지에 대한 전자우편 알림이 전송됩니다.",
"mobile.manage_members.section_title_members": "멤버",
"mobile.manage_members.section_title_admins": "채널 관리자",
"mobile.manage_members.remove_member": "채널에서 제거",
"mobile.manage_members.remove": "제거",
"mobile.manage_members.message": "채널에서 선택한 멤버를 삭제하시겠습니까?",
"mobile.manage_members.member": "멤버",
"mobile.manage_members.manage_member": "회원 관리",
"mobile.manage_members.manage": "관리",
"mobile.custom_list.no_results": "결과가 없습니다",
"mobile.components.select_server_view.displayName": "표시명",
"mobile.components.select_server_view.displayHelp": "서버의 표시 이름을 선택하세요",
"mobile.components.select_server_view.connecting": "연결중",
"mobile.calls_recording_start_no_permissions": "녹음을 시작할 수 있는 권한이 없습니다. 통화 호스트에게 녹음을 시작하도록 요청하세요.",
"mobile.calls_recording_start_in_progress": "녹화가 이미 진행 중입니다.",
"mobile.calls_host_rec_error": "녹화를 다시 시도하십시오. 시스템 관리자에게 문의하여 문제 해결에 도움을 받을 수도 있습니다.",
"mobile.manage_members.make_channel_member": "회원으로 만들기",
"mobile.manage_members.make_channel_admin": "채널 관리자로 만들기",
"mobile.manage_members.done": "완료",
"mobile.manage_members.change_role.error": "역할을 업데이트하는 동안 오류가 발생했습니다. 연결을 확인한 후 다시 시도하세요.",
"mobile.manage_members.cancel": "취소",
"mobile.manage_members.admin": "관리자",
"share_extension.message": "메시지 입력(선택 사항)",
"share_extension.max_resolution": "이미지가 최대 크기인 7680 x 4320 픽셀을 초과합니다",
"share_extension.file_limit.single": "파일 크기는 다음보다 작아야 합니다. {size}",
"onboarding.realtime_collaboration": "실시간 협업",
"onboarding.integrations_description": "공통 개발 프로세스에 맞춰 긴밀하게 통합된 제품 솔루션으로 채팅을 뛰어넘을 수 있습니다.",
"onboarding.integrations": "즐겨 사용하는 도구와 통합",
"mobile.calls_stop_recording": "녹화 중지",
"mobile.calls_record": "녹화",
"invite.summary.try_again": "다시 시도",
"invite.summary.some_not_sent": "{notSentCount, plural, one {An invitation was} other {Some invitations were}} 전송되지 않음",
"channel_info.archive_description.cannot_view_archived": "이렇게 하면 팀에서 채널을 보관하고 사용자 인터페이스에서 제거합니다. 보관된 채널은 다시 필요할 경우 보관 해제할 수 있습니다. \n \n {term} {name}을 보관하시겠습니까?",
"channel_info.archive_description.can_view_archived": "이렇게 하면 팀에서 채널을 보관합니다. 채널 구성원은 채널에 계속 접근할 수 있습니다.\n\n{term} {name} 채널을 보관하시겠어요?",
"mobile.server_identifier.exists": "이미 이 서버에 연결되어 있습니다.",
"mobile.managed.jailbreak_no_reason": "(사용 불가)",
"mobile.display_settings.crt": "축소된 응답 글타래",
"mobile.calls_participant_rec_title": "녹화가 진행 중입니다",
"invite.title.summary": "초대 요약",
"invite.title": "초대",
"invite.summary.smtp_failure": "시스템 콘솔에서 SMTP가 설정되지 않았습니다",
"mobile.managed.jailbreak_no_debug_info": "(사용 불가)",
"invite.summary.sent": "당신의 {sentCount, plural, one {invitation has} other {invitations have}}이(가) 전송되었습니다",
"invite.summary.report.sent": "{count}건 성공 {count, plural, one {invitation} other {invitations}}",
"invite.summary.report.notSent": "{count} {count, plural, one {invitation} other {invitations}} 전송되지 않음",
"invite.summary.not_sent": "{notSentCount, plural, one {Invitation wasnt} other {Invitations werent}} 보냄",
"invite.summary.member_invite": "{teamDisplayName}의 회원으로 초대되었습니다",
"invite.summary.error": "{invitationsCount, plural, one {Invitation} other {Invitations}} could not be sent successfully",
"invite.summary.email_invite": "초대 이메일이 발신되었습니다",
"invite.summary.done": "완료",
"invite.shareLink": "공유 링크",
"invite.sendInvitationsTo": "다음 주소로 초대 보내기…",
"invite.send_invite": "보내기",
"invite.send_error": "초대를 보내는 동안 문제가 발생했습니다. 네트워크 연결을 확인한 후 다시 시도하세요.",
"invite.search.no_results": "일치하는 항목을 찾지 못했습니다",
"invite.search.email_invite": "초대",
"terms_of_service.alert_retry": "다시 시도",
"share_feedback.button.no": "아니요, 괜찮습니다",
"settings.notice_mobile_link": "모바일 앱",
"notification_settings.pushNotification.nothing": "알림을 받지 않음",
"notification_settings.email.send": "이메일 알림 보내기",
"notification_settings.email.immediately": "즉시",
"mobile.screen.your_profile": "내 프로필",
"mobile.calls_start_call_exists": "채널에서 이미 통화가 진행 중입니다.",
"mobile.calls_not_connected": "현재 채널에서 통화에 연결되어 있지 않습니다.",
"notification_settings.email.everyHour": "매 시간마다",
"video.download_description": "이 영상을 재생하려면 다운로드해야 합니다.",
"user.edit_profile.profile_photo.change_photo": "프로필 사진 변경",
"user_status.title": "상태",
"user_status.online": "온라인",
"user_status.offline": "오프라인",
"user_status.dnd": "방해 금지",
"user_status.away": "자리비움",
"share_extension.server_label": "서버",
"share_extension.multiple_label": "{count, number} 첨부 파일",
"mobile.camera_type.title": "카메라 옵션",
"video.failed_description": "영상을 재생하는 동안 오류가 발생했습니다.",
"thread.loadingReplies": "댓글 불러오는 중...",
"settings_display.timezone.automatically": "자동으로 설정",
"mobile.login_options.openid": "ID 열기",
"mobile.login_options.office365": "Office 365",
"mobile.calls_open_channel": "채널 열기",
"mobile.create_direct_message.max_limit_reached": "그룹 메시지는 {maxCount} 명의 구성원으로 제한됩니다",
"mobile.calls_request_title": "통화는 현재 사용하도록 설정되어 있지 않습니다",
"mobile.calls_participant_limit_title_GA": "이 통화의 용량이 초과되었습니다",
"mobile.calls_limit_msg_GA": "Cloud Professional 또는 Cloud Enterprise로 업그레이드하여 {maxParticipants} 이상의 참가자와 그룹 통화를 사용하세요.",
"mobile.create_direct_message.start": "대화 시작",
"share_extension.servers_screen.title": "서버 선택",
"share_extension.upload_disabled": "선택한 서버에 대해 파일 업로드가 비활성화됩니다",
"share_extension.share_screen.title": "공유 대상 {applicationName}",
"share_extension.file_limit.multiple": "각 파일은 다음보다 작아야 합니다. {size}",
"share_extension.count_limit": "이 서버에서는 {count, number} {count, plural, one {file} other {files}}만 공유할 수 있습니다",
"share_extension.channel_label": "채널",
"share_extension.channel_error": "선택한 서버의 팀원이 아닙니다. 다른 서버를 선택하거나 매터모스트를 열어 팀에 참여하세요.",
"post_info.bot": "",
"mobile.calls_viewing_screen": "{name} 의 화면을 보고 있습니다",
"settings.advanced.delete_message.confirmation": "\n이 서버에 대해 앱을 통해 다운로드한 모든 파일이 삭제됩니다. 계속하려면 확인해주세요.\n",
"settings.advanced.delete_data": "로컬 파일 삭제",
"server.remove.alert_title": "{displayName} 를 삭제하시겠습니까?",
"team_list.no_other_teams.title": "더 이상 참여할 팀이 없습니다",
"skintone_selector.tooltip.title": "기본 피부 톤 선택",
"mobile.login_options.enter_credentials": "아래에 로그인 정보를 입력하세요.",
"skintone_selector.tooltip.description": "이제 이모티콘에 사용할 피부 톤을 선택할 수 있습니다.",
"server.logout.alert_description": "모든 관련 데이터가 제거됩니다",
"mobile.create_post.read_only": "이 채널은 읽기 전용입니다.",
"mobile.calls_ended_at": "종료",
"notification_settings.threads_start": "내가 시작한 글타래의 댓글을 알림",
"server.websocket.unreachable": "서버에 연결할 수 없습니다.",
"notification_settings.auto_responder.message": "메시지",
"mobile.channel_list.unreads": "읽지않음",
"settings.about.powered_by": "{site} is powered by Mattermost",
"screens.channel_info": "채널 정보",
"user.settings.general.field_handled_externally": "아래의 필드중 일부는 로그인 서비스 제공업체를 통해 처리됩니다. 해당 필드를 변경하려면 로그인 공급업체를 통해 변경해야 합니다.",
"mobile.oauth.something_wrong.okButton": "확인",
"notification_settings.mentions.keywordsLabel": "키워드는 대소문자를 구분하지 않습니다. 쉼표로 키워드를 구분합니다.",
"mobile.login_options.google": "Google",
"pinned_messages.empty.paragraph": "중요한 쪽지를 고정하려면 쪽지를 길게 누르고 채널에 고정을 선택합니다. 고정된 메시지는 이 채널의 모든 사용자에게 표시됩니다.",
"server_list.push_proxy_error": "이 서버의 구성으로 인해 이 서버에서 알림을 수신할 수 없습니다. 시스템 관리자에게 문의하세요.",
"login_mfa.enterToken": "인증을 완료하시려면 스마트폰 인증 앱에 표시된 토큰 정보를 입력해주세요.",
"settings.advanced.delete": "삭제",
"settings.advanced.cancel": "취소",
"mobile.calls_host_rec_stopped_title": "녹화가 중지되었습니다. 처리 중...",
"mobile.calls_host_rec_stopped": "처리가 완료되면 이 통화의 채팅 스레드에서 녹음 내용을 찾을 수 있습니다.",
"mobile.calls_host_rec": "이 회의를 녹음하는 중입니다. 모든 사람에게 이 회의가 녹음되고 있음을 알리는 것이 좋습니다.",
"mobile.calls_dismiss": "취소",
"mobile.calls_participant_rec": "호스트가 이 미팅을 녹화하기 시작했습니다. 미팅에 계속 참여하면 녹화되는 것에 동의하는 것입니다.",
"mobile.calls_okay": "확인",
"terms_of_service.terms_declined.title": "서비스 약관에 동의해야 합니다",
"terms_of_service.decline": "거절",
"terms_of_service.api_error": "요청을 처리할 수 없습니다. 이 문제가 계속되면 시스템 관리자에게 연락하세요.",
"onboarding.welcome": "",
"onboarding.realtime_collaboration_description": "",
"mobile.onboarding.sign_in_to_get_started": "",
"mobile.onboarding.sign_in": "",
"mobile.onboarding.next": "",
"user.edit_profile.email.auth_service": "",
"unsupported_server.title": "",
"terms_of_service.terms_declined.text": "",
"terms_of_service.terms_declined.ok": "",
"terms_of_service.alert_cancel": "",
"terms_of_service.acceptButton": "",
"share_feedback.subtitle": "",
"share_feedback.button.yes": "",
"settings.advanced_settings": "",
"settings.about.database.schema": "",
"settings_display.timezone.select": "",
"settings_display.timezone.off": "",
"settings_display.timezone.manual": "",
"settings_display.custom_theme": "",
"settings_display.clock.normal.desc": "",
"servers.edit": "",
"servers.default": "",
"server_upgrade.learn_more": "",
"server_upgrade.dismiss": "",
"server_upgrade.alert_description": "",
"plus_menu.open_direct_message.title": "",
"plus_menu.invite_people_to_team.title": "",
"pinned_messages.empty.title": "",
"onboarding.welcome": "환영합니다",
"onboarding.realtime_collaboration_description": "영구 채널, 다이렉트 메시징 및 파일 공유가 원활하게 작동하므로 어디서나 연결 상태를 유지할 수 있습니다.",
"mobile.onboarding.sign_in_to_get_started": "로그인하여 시작하기",
"mobile.onboarding.sign_in": "로그인",
"mobile.onboarding.next": "다음",
"user.edit_profile.email.auth_service": "로그인은 {service} 을 통해 이루어집니다. 이메일을 업데이트할 수 없습니다. 알림에 사용되는 이메일 주소는 {email} 입니다.",
"unsupported_server.title": "지원되지 않는 서버 버전",
"terms_of_service.terms_declined.text": "이 서버에 액세스하려면 서비스 약관에 동의해야 합니다. 자세한 내용은 시스템 관리자에게 문의하세요. 이제 로그아웃됩니다. 다시 로그인하여 서비스 약관에 동의하세요.",
"terms_of_service.terms_declined.ok": "확인",
"terms_of_service.alert_cancel": "취소",
"terms_of_service.acceptButton": "수락",
"share_feedback.subtitle": "더 나은 경험을 제공할 수 있도록 당신의 의견에 귀 기울이겠습니다.",
"share_feedback.button.yes": "",
"settings.advanced_settings": "고급 설정",
"settings.about.database.schema": "Database Schema Version: {version}",
"settings_display.timezone.select": "표준시간대 선택",
"settings_display.timezone.off": "사용 안함",
"settings_display.timezone.manual": "표준시간대 변경",
"settings_display.custom_theme": "커스텀 테마",
"settings_display.clock.normal.desc": "예: 4:00 PM",
"servers.edit": "편집",
"servers.default": "기본 서버",
"server_upgrade.learn_more": "더 알아보기",
"server_upgrade.dismiss": "취소",
"server_upgrade.alert_description": "서버( {serverDisplayName})에서 지원되지 않는 서버 버전을 실행 중입니다. 사용자는 앱의 핵심 기능을 손상시키는 충돌 또는 심각한 버그를 유발하는 호환성 문제에 노출됩니다. 서버 버전 {supportedServerVersion} 이상으로 업그레이드해야 합니다.",
"plus_menu.open_direct_message.title": "쪽지 열기",
"plus_menu.invite_people_to_team.title": "팀에 구성원 초대하기",
"pinned_messages.empty.title": "아직 고정된 메시지가 없습니다",
"permalink.show_dialog_warn.description": "채널 관리자가 명시적으로 추가하지 않고 {channel}에 가입하려고 합니다. 이 비공개 채널에 참여하시겠습니까?",
"password_send.generic_error": "",
"notification.not_team_member": "",
"notification.not_channel_member": "",
"notification_settings.mentions.sensitiveUsername": "",
"notification_settings.mentions.channelWide": "",
"notification_settings.email.crt.send": "",
"notification_settings.email": "",
"notification_settings.auto_responder.default_message": "",
"mobile.session_expired.title": "",
"mobile.request.invalid_request_method": "",
"mobile.post_info.save": "",
"mobile.participants.header": "",
"mobile.display_settings.timezone": "",
"mobile.components.select_server_view.msg_welcome": "",
"video.download": "",
"user.edit_profile.email.web_client": "",
"terms_of_service.title": "",
"terms_of_service.error.title": "",
"terms_of_service.error.retry": "",
"terms_of_service.error.logout": "",
"terms_of_service.error.description": "",
"settings.about.database": "",
"select_team.description": "",
"rate.title": "",
"permalink.error.public_channel_and_team.title": "",
"permalink.error.private_channel.button": "",
"permalink.error.private_channel_and_team.text": "",
"permalink.error.access.title": "",
"more_messages.text": "",
"mobile.write_storage_permission_denied_description": "",
"mobile.screen.settings": "",
"mobile.calls_end_permission_msg": "",
"thread.options.title": "",
"thread.noReplies": "",
"thread.header.thread_in": "",
"status_dropdown.set_ooo": "",
"snack.bar.unmute.channel": "",
"snack.bar.unfavorite.channel": "",
"share_feedback.title": "",
"servers.create_button": "",
"server.logout.alert_title": "",
"select_team.no_team.title": "",
"select_team.no_team.description": "",
"screen.search.results.file_options.download": "",
"screen.saved_messages.title": "",
"screen.saved_messages.subtitle": "",
"screen.mentions.title": "",
"rate.subtitle": "",
"rate.error.title": "",
"rate.error.text": "",
"rate.dont_ask_again": "",
"rate.button.yes": "",
"rate.button.needs_work": "",
"settings.about.licensed": "",
"screen.mentions.subtitle": "",
"saved_messages.empty.title": "",
"post_priority.picker.title": "",
"post_priority.picker.label.urgent": "",
"post_priority.picker.label.standard": "",
"post_priority.picker.label.important": "",
"post_priority.picker.beta": "",
"permalink.error.public_channel.button": "",
"mobile.oauth.switch_to_browser.title": "",
"mobile.integration_selector.loading_options": "",
"mobile.integration_selector.loading_channels": "",
"notification_settings.threads_mentions": "",
"screen.search.results.filter.images": "",
"permalink.error.access.text": "",
"password_send.return": "",
"notification_settings.mobile.offline": "",
"mobile.post_info.unsave": "",
"mobile.display_settings.clockDisplay": "",
"mobile.direct_message.error": "",
"mobile.custom_status.clear_after.title": "",
"mobile.calls_unmute": "",
"mobile.calls_not_available_msg": "",
"mobile.calls_mute": "",
"mobile.calls_mic_error": "",
"mobile.calls_limit_msg": "",
"mobile.session_expired": "",
"mobile.server_upgrade.description": "",
"mobile.server_link.unreachable_user.error": "",
"mobile.search.team.select": "",
"mobile.search.show_more": "",
"mobile.reset_status.alert_ok": "",
"mobile.calls_leave": "",
"mobile.post_pre_header.saved": "",
"mobile.post_pre_header.pinned_saved": "",
"mobile.oauth.switch_to_browser.error_title": "",
"mobile.oauth.switch_to_browser": "",
"user.settings.notifications.email_threads.description": "",
"mobile.oauth.failed_to_open_link_no_browser": "",
"mobile.no_results.spelling": "",
"mobile.no_results_with_term": "",
"mobile.login_options.cant_heading": "",
"mobile.leave_and_join_title": "",
"mobile.leave_and_join_message": "",
"mobile.leave_and_join_confirmation": "",
"mobile.join_channel.error": "",
"mobile.edit_post.error": "",
"mobile.edit_post.delete_title": "",
"mobile.edit_post.delete_question": "",
"mobile.components.select_server_view.msg_connect": "",
"mobile.channel_list.recent": "",
"mobile.camera_photo_permission_denied_description": "",
"mobile.calls_you": "",
"mobile.calls_speaker": "",
"mobile.calls_raise_hand": "",
"mobile.calls_ok": "",
"mobile.calls_not_available_title": "",
"mobile.calls_not_available_option": "",
"mobile.calls_noone_talking": "",
"mobile.calls_name_started_call": "",
"mobile.calls_more": "",
"mobile.calls_limit_reached": "",
"mobile.calls_join_call": "",
"mobile.calls_end_msg_dm": "",
"screen.search.results.filter.documents": "",
"screen.search.results.filter.code": "",
"permalink.error.public_channel_and_team.button": "",
"permalink.error.private_channel.title": "",
"permalink.error.private_channel.text": "",
"permalink.error.private_channel_and_team.button": "",
"permalink.error.okay": "",
"notification_settings.push_notification": "",
"notification_settings.ooo_auto_responder": "",
"notification_settings.mentions..keywordsDescription": "",
"notification_settings.mentions_replies": "",
"notification_settings.email.fifteenMinutes": "",
"notification_settings.email.emailHelp2": "",
"notification_settings.auto_responder": "",
"your.servers": "",
"screens.channel_edit_header": "",
"screens.channel_edit": "",
"screen.search.title": "",
"screen.search.results.filter.videos": "",
"screen.search.results.filter.title": "",
"screen.search.results.filter.spreadsheets": "",
"screen.search.results.filter.presentations": "",
"screen.search.results.filter.audio": "",
"screen.search.results.filter.all_file_types": "",
"screen.search.results.file_options.open_in_channel": "",
"screen.search.results.file_options.copy_link": "",
"screen.search.placeholder": "",
"screen.search.modifier.header": "",
"screen.search.header.messages": "",
"screen.search.header.files": "",
"post.options.title": "",
"post_priority.label.urgent": "",
"post_priority.label.important": "",
"post_info.guest": "",
"plus_menu.create_new_channel.title": "",
"plus_menu.browse_channels.title": "",
"permalink.error.public_channel.text": "",
"permalink.error.public_channel_and_team.text": "",
"permalink.error.cancel": "",
"notification_settings.mobile.trigger_push": "",
"notification_settings.mobile.online": "",
"notification_settings.mentions": "",
"notification_settings.mention.reply": "",
"notification_settings.email.never": "",
"notification_settings.email.crt.emailInfo": "",
"mobile.storage_permission_denied_description": "",
"mobile.server_url.deeplink.emm.denied": "",
"mobile.server_requires_client_certificate": "",
"mobile.server_ping_failed": "",
"mobile.server_name.exists": "",
"mobile.search.show_less": "",
"mobile.search.modifier.phrases": "",
"mobile.search.modifier.in": "",
"mobile.search.modifier.from": "",
"mobile.search.modifier.exclude": "",
"unreads.empty.paragraph": "",
"threads.end_of_list.title": "",
"thread.header.thread": "",
"snack.bar.undo": "",
"snack.bar.mute.channel": "",
"snack.bar.message.copied": "",
"snack.bar.favorited.channel": "",
"settings.save": "",
"settings.notifications": "",
"settings.notice_text": "",
"settings.notice_platform_link": "",
"settings_display.clock.mz.desc": "",
"settings_display.clock.mz": "",
"servers.remove": "",
"servers.logout": "",
"servers.login": "",
"search_bar.search.placeholder": "",
"screens.channel_info.gm": "",
"screens.channel_info.dm": "",
"password_send.generic_error": "비밀번호 재설정 링크를 보내드릴 수 없습니다. 시스템 관리자에게 문의하여 도움을 받으세요.",
"notification.not_team_member": "이 메시지는 귀하가 멤버가 아닌 팀에 속해 있습니다.",
"notification.not_channel_member": "이 메시지는 회원이 아닌 채널에서 보낸 메시지입니다.",
"notification_settings.mentions.sensitiveUsername": "대소문자를 구분하지 않는 사용자 명",
"notification_settings.mentions.channelWide": "채널 전체 멘션",
"notification_settings.email.crt.send": "글타래 응답 알림",
"notification_settings.email": "이메일 알림",
"notification_settings.auto_responder.default_message": "안녕하세요. 저는 지금 부재중이라서 메시지에 응답할 수 없습니다.",
"mobile.session_expired.title": "세션 만료",
"mobile.request.invalid_request_method": "잘못된 요청 방법",
"mobile.post_info.save": "저장",
"mobile.participants.header": "글타래 참가자",
"mobile.display_settings.timezone": "표준시간대",
"mobile.components.select_server_view.msg_welcome": "환영합니다",
"video.download": "영상 다운로드",
"user.edit_profile.email.web_client": "이메일은 웹 클라이언트 혹은 데스크톱 애플리케이션을 사용하여 변경해야 합니다.",
"terms_of_service.title": "서비스 약관",
"terms_of_service.error.title": "ToS를 받지 못했습니다.",
"terms_of_service.error.retry": "다시 시도",
"terms_of_service.error.logout": "로그아웃",
"terms_of_service.error.description": "서버에서 서비스 약관을 가져올 수 없습니다.",
"settings.about.database": "Database: {driverName}",
"select_team.description": "아직 팀에 가입하지 않으셨습니다. 아래에서 하나를 선택하여 시작하세요.",
"rate.title": "매터모스트를 즐기고 계신가요?",
"permalink.error.public_channel_and_team.title": "채널 및 팀 가입",
"permalink.error.private_channel.button": "채널 가입",
"permalink.error.private_channel_and_team.text": "보려는 메시지가 내가 소속되어 있지 않은 팀의 비공개 채널에 있습니다. 관리자로 액세스 권한이 있습니다. {channelName} ** 및 **{teamName}** 팀에 가입하여 해당 메시지를 보시겠습니까?",
"permalink.error.access.title": "메시지를 볼 수 없음",
"more_messages.text": "{count}건의 새 {count, plural, one {message} other {messages}}",
"mobile.write_storage_permission_denied_description": "장치에 파일을 저장합니다. 설정을 열어 이 장치의 파일에 {applicationName} 쓰기 권한을 부여합니다.",
"mobile.screen.settings": "설정",
"mobile.calls_end_permission_msg": "통화를 종료할 수 있는 권한이 없습니다. 통화를 건 사람에게 통화를 종료하도록 요청하세요.",
"thread.options.title": "글타래 동작",
"thread.noReplies": "아직 댓글이 없습니다",
"thread.header.thread_in": "{channelName} 채널에 있음",
"status_dropdown.set_ooo": "부재 중",
"snack.bar.unmute.channel": "이 채널의 음소거가 해제되었습니다",
"snack.bar.unfavorite.channel": "이 채널이 즐겨찾기에서 제거 되었습니다",
"share_feedback.title": "피드백을 공유해 주시겠어요?",
"servers.create_button": "서버 추가",
"server.logout.alert_title": "{displayName} 에서 로그아웃하시겠습니까?",
"select_team.no_team.title": "가입할 수 있는 팀이 없습니다",
"select_team.no_team.description": "팀에 참여하려면 팀 관리자에게 초대를 요청하거나 직접 팀을 만드세요. 이메일 받은 편지함에서 초대장을 확인할 수도 있습니다.",
"screen.search.results.file_options.download": "다운로드",
"screen.saved_messages.title": "저장된 메시지",
"screen.saved_messages.subtitle": "팔로우 업을 위해 저장한 모든 메시지",
"screen.mentions.title": "최근 멘션",
"rate.subtitle": "여러분의 의견을 알려주세요.",
"rate.error.title": "오류",
"rate.error.text": "검토 모달을 여는 동안 오류가 발생했습니다.",
"rate.dont_ask_again": "다시 묻지 않기",
"rate.button.yes": "마음에 들어요!",
"rate.button.needs_work": "작업 필요",
"settings.about.licensed": "Licensed to: {company}",
"screen.mentions.subtitle": "내가 멘션된 메시지",
"saved_messages.empty.title": "저장된 메시지가 없습니다",
"post_priority.picker.title": "메시지 우선순위",
"post_priority.picker.label.urgent": "긴급",
"post_priority.picker.label.standard": "표준",
"post_priority.picker.label.important": "중요",
"post_priority.picker.beta": "베타",
"permalink.error.public_channel.button": "채널 가입",
"mobile.oauth.switch_to_browser.title": "리디렉션...",
"mobile.integration_selector.loading_options": "옵션 로딩중...",
"mobile.integration_selector.loading_channels": "채널을 불러오는 중...",
"notification_settings.threads_mentions": "글타래 내의 멘션",
"screen.search.results.filter.images": "이미지",
"permalink.error.access.text": "보려는 메시지가 액세스 권한이 없거나 삭제된 채널에 있습니다.",
"password_send.return": "로그인으로 돌아가기",
"notification_settings.mobile.offline": "오프라인",
"mobile.post_info.unsave": "저장 취소",
"mobile.display_settings.clockDisplay": "시간 표시",
"mobile.direct_message.error": "{displayName}의 DM을 열 수 없습니다.",
"mobile.custom_status.clear_after.title": "사용자 지정 상태를 해제한 후",
"mobile.calls_unmute": "음소거 해제",
"mobile.calls_not_available_msg": "이 기능을 사용하려면 시스템 관리자에게 문의하세요.",
"mobile.calls_mute": "음소거",
"mobile.calls_mic_error": "이 통화에 참여하려면 설정을 열어서 마이크 접근 권한을 부여해주세요.",
"mobile.calls_limit_msg": "통화당 최대 참가자 수는 {maxParticipants} 입니다. 한도를 늘리려면 시스템 관리자에게 문의하세요.",
"mobile.session_expired": "알림을 계속 받으려면 로그인하세요. {siteName} 세션은 {daysCount, number} {daysCount, plural, one {day} other {days}}마다 만료되도록 구성되어 있습니다.",
"mobile.server_upgrade.description": "\n매터모스트 앱을 사용하려면 서버 업그레이드가 필요합니다. 자세한 내용은 시스템 관리자에게 문의하세요.\n",
"mobile.server_link.unreachable_user.error": "DM으로 리디렉션할 수 없습니다. 지정한 사용자를 알 수 없습니다.",
"mobile.search.team.select": "검색할 팀 선택",
"mobile.search.show_more": "더보기",
"mobile.reset_status.alert_ok": "확인",
"mobile.calls_leave": "나가기",
"mobile.post_pre_header.saved": "저장됨",
"mobile.post_pre_header.pinned_saved": "고정 및 저장",
"mobile.oauth.switch_to_browser.error_title": "로그인 오류",
"mobile.oauth.switch_to_browser": "로그인 제공업체로 리디렉션됩니다",
"user.settings.notifications.email_threads.description": "팔로우 중인 스레드에 대한 모든 회신에 대해 알림을 받음",
"mobile.oauth.failed_to_open_link_no_browser": "링크를 열지 못했습니다. 장치에 브라우저가 설치되어 있는지 확인하세요.",
"mobile.no_results.spelling": "오타를 확인하거나 또는 다른 단어로 검색해보세요.",
"mobile.no_results_with_term": "\"{term}\" 에 대한 검색 결과가 없습니다",
"mobile.login_options.cant_heading": "로그인 할 수 없습니다",
"mobile.leave_and_join_title": "다른 통화로 전환하시겠습니까?",
"mobile.leave_and_join_message": "이미 {leaveChannelName}채널 통화를 진행 중입니다. 현재 통화를 종료하고 {joinChannelName}통화에 참여하시겠습니까?",
"mobile.leave_and_join_confirmation": "나가기 및 참여하기",
"mobile.join_channel.error": "{displayName} 채널에 가입할 수 없습니다.",
"mobile.edit_post.error": "이 메시지를 편집하는 동안 문제가 발생했습니다. 다시 시도해 주세요.",
"mobile.edit_post.delete_title": "게시물 삭제 확인",
"mobile.edit_post.delete_question": "정말 게시물을 삭제하시겠습니까?",
"mobile.components.select_server_view.msg_connect": "서버에 접속하기",
"mobile.channel_list.recent": "최근",
"mobile.camera_photo_permission_denied_description": "사진을 찍어 서버에 업로드하거나 디바이스에 저장합니다. 설정을 열어 {applicationName} 에 카메라에 대한 읽기 및 쓰기 액세스 권한을 부여합니다.",
"mobile.calls_you": "(당신)",
"mobile.calls_speaker": "스피커",
"mobile.calls_raise_hand": "손 들기",
"mobile.calls_ok": "확인",
"mobile.calls_not_available_title": "통화가 활성화되지 않았습니다",
"mobile.calls_not_available_option": "(사용 불가)",
"mobile.calls_noone_talking": "아무도 말하지 않음",
"mobile.calls_name_started_call": "{name}가 통화를 시작했습니다",
"mobile.calls_more": "더 보기",
"mobile.calls_limit_reached": "참가자 제한에 도달했습니다",
"mobile.calls_join_call": "통화 참가하기",
"mobile.calls_end_msg_dm": "{displayName}의 전화를 종료하겠습니까?",
"screen.search.results.filter.documents": "문서",
"screen.search.results.filter.code": "코드",
"permalink.error.public_channel_and_team.button": "채널 및 팀 가입",
"permalink.error.private_channel.title": "비공개 채널에 가입",
"permalink.error.private_channel.text": "보려는 메시지가 초대받지 않은 비공개 채널에 있지만 관리자 권한으로 액세스할 수 있습니다. {channelName} **에 가입하시겠습니까?",
"permalink.error.private_channel_and_team.button": "채널 및 팀 가입",
"permalink.error.okay": "확인",
"notification_settings.push_notification": "푸시 알림",
"notification_settings.ooo_auto_responder": "자동 회신",
"notification_settings.mentions..keywordsDescription": "멘션 알림 키워드",
"notification_settings.mentions_replies": "멘션 및 응답",
"notification_settings.email.fifteenMinutes": "매 15분마다",
"notification_settings.email.emailHelp2": "시스템 관리자에 의해 이메일이 비활성화되었습니다. 활성화할 때까지 알림 이메일이 전송되지 않습니다.",
"notification_settings.auto_responder": "자동 회신",
"your.servers": "서버 선택",
"screens.channel_edit_header": "채널 헤더 변경",
"screens.channel_edit": "채널 편집",
"screen.search.title": "검색",
"screen.search.results.filter.videos": "동영상",
"screen.search.results.filter.title": "파일 유형별 필터링",
"screen.search.results.filter.spreadsheets": "스프레드시트",
"screen.search.results.filter.presentations": "프레젠테이션",
"screen.search.results.filter.audio": "오디오",
"screen.search.results.filter.all_file_types": "모든 파일 형식",
"screen.search.results.file_options.open_in_channel": "채널에서 열기",
"screen.search.results.file_options.copy_link": "링크 복사",
"screen.search.placeholder": "메시지 및 파일 검색",
"screen.search.modifier.header": "검색 옵션",
"screen.search.header.messages": "메시지",
"screen.search.header.files": "파일",
"post.options.title": "옵션",
"post_priority.label.urgent": "긴급",
"post_priority.label.important": "중요",
"post_info.guest": "게스트",
"plus_menu.create_new_channel.title": "채널 만들기",
"plus_menu.browse_channels.title": "채널 탐색",
"permalink.error.public_channel.text": "보려는 메시지가 내가 속해 있지 않은 채널에 있습니다. {channelName} **에 가입하여 보시겠습니까?",
"permalink.error.public_channel_and_team.text": "보려는 메시지가 내가 속해 있지 않은 채널과 내가 소속되지 않은 팀에 있습니다. {channelName} ** 및 **{teamName}** 팀에 가입하여 메시지를 보시겠습니까?",
"permalink.error.cancel": "취소",
"notification_settings.mobile.trigger_push": "아래의 상태일 때 푸시 알림 활성화...",
"notification_settings.mobile.online": "온라인, 오프라인, 자리비움",
"notification_settings.mentions": "멘션",
"notification_settings.mention.reply": "댓글에 대한 알림 설정",
"notification_settings.email.never": "알리지 않음",
"notification_settings.email.crt.emailInfo": "활성화하면, 지켜보는 중인 글타래의 모든 응답에 대해 전자우편 알림을 보냅니다",
"mobile.storage_permission_denied_description": "서버에 파일을 업로드합니다. 설정을 열어 {applicationName} 에 이 장치의 파일에 대한 읽기 및 쓰기 액세스 권한을 부여합니다.",
"mobile.server_url.deeplink.emm.denied": "이 앱은 EMM에 의해 제어되며 딥링크 서버 URL이 EMM 허용 서버와 일치하지 않습니다",
"mobile.server_requires_client_certificate": "서버는 인증을 위해 클라이언트 인증서가 필요합니다.",
"mobile.server_ping_failed": "서버에 연결할 수 없습니다.",
"mobile.server_name.exists": "다른 서버에 이 이름을 사용하고 있습니다.",
"mobile.search.show_less": "감추기",
"mobile.search.modifier.phrases": "문구가 포함된 메시지",
"mobile.search.modifier.in": "특정 채널",
"mobile.search.modifier.from": "특정 사용자",
"mobile.search.modifier.exclude": "검색어 제외",
"unreads.empty.paragraph": "모든 채널을 표시하려면 읽지 않음 필터를 해제하세요.",
"threads.end_of_list.title": "목록의 끝입니다!",
"thread.header.thread": "글타래",
"snack.bar.undo": "실행 취소",
"snack.bar.mute.channel": "이 채널이 음소거되었습니다",
"snack.bar.message.copied": "텍스트가 클립보드에 복사되었습니다",
"snack.bar.favorited.channel": "이 채널이 즐겨찾기에 추가되었습니다",
"settings.save": "저장",
"settings.notifications": "알림",
"settings.notice_text": "Mattermost is made possible by the open source software used in our {platform} and {mobile}.",
"settings.notice_platform_link": "서버",
"settings_display.clock.mz.desc": "예: 16:00",
"settings_display.clock.mz": "24시간제로 표시",
"servers.remove": "제거",
"servers.logout": "로그아웃",
"servers.login": "로그인",
"search_bar.search.placeholder": "표준시간대 검색",
"screens.channel_info.gm": "그룹 메시지 정보",
"screens.channel_info.dm": "쪽지 정보",
"post_priority.picker.cancel": "취소",
"post_priority.picker.apply": "적용",
"post_priority.button.acknowledge": "수신확인"
"post_priority.button.acknowledge": "수신확인",
"channel_files.empty.title": "아직 파일이 없습니다",
"channel_files.noFiles.title": "파일이 존재하지 않습니다",
"screen.channel_files.header.recent_files": "최근 파일",
"channel_add_members.add_members.button": "멤버 추가",
"channel_info.add_members": "멤버 추가",
"channel_notification_preferences.notification.all": "모든 새 메시지",
"channel_notification_preferences.notify_about": "푸시 알림을 받을 대상...",
"channel_notification_preferences.notification.mention": "멘션, 쪽지만",
"channel_notification_preferences.notification.none": "알림을 받지 않음",
"channel_files.empty.paragraph": "이 채널에 게시된 파일은 여기에 표시됩니다.",
"channel_files.noFiles.paragraph": "이 채널에는 필터가 적용된 파일이 포함되어 있지 않습니다",
"channel_notification_preferences.notification.thread_replies": "이 채널에서 팔로우 중인 스레드에 대해 답글 알림 받기",
"channel_info.channel_files": "파일",
"channel_notification_preferences.reset_default": "기본값으로 되돌리기",
"mobile.ios.plist.NSAppleMusicUsageDescription": "미디어 라이브러리에 액세스할 수 있도록 설정하면 미디어 라이브러리에 있는 파일을 {applicationName}의 메시지에 첨부할 수 있습니다.",
"mobile.ios.plist.NSCameraUsageDescription": "디바이스 카메라에 대한 액세스를 활성화하면 사진이나 동영상을 촬영하여 {applicationName}에 업로드할 수 있습니다.",
"mobile.ios.plist.NSBluetoothAlwaysUsageDescription": "Bluetooth에 대한 액세스를 활성화하면 장치와 클라이언트 간에 콘텐츠를 동기화할 수 있습니다.",
"mobile.ios.plist.NSMicrophoneUsageDescription": "디바이스의 마이크에 액세스할 수 있도록 설정하면 {applicationName} 에서 공유할 통화 또는 동영상에 대한 오디오를 캡처할 수 있습니다.",
"mobile.acknowledgements.header": "확인",
"mobile.ios.plist.NSSpeechRecognitionUsageDescription": "기기에서 사용자 데이터를 Apple에 전송하도록 설정하면 {applicationName} 으로 음성 메시지를 보낼 수 있습니다.",
"mobile.calls_audio_device": "오디오 장치 선택",
"mobile.calls_bluetooth": "블루투스",
"mobile.calls_phone": "전화",
"mobile.ios.plist.NSFaceIDUsageDescription": "Face ID에 대한 액세스를 활성화하면 권한이 없는 사용자가 장치에서 {applicationName} 에 액세스하는 것을 제한할 수 있습니다.",
"mobile.calls_thread": "글타래",
"mobile.calls_you_2": "당신",
"mobile.calls_tablet": "태블릿",
"intro.add_members": "멤버 추가",
"channel_notification_preferences.default": "(기본값)",
"channel_notification_preferences.muted_title": "이 채널은 음소거되어 있습니다",
"channel_notification_preferences.muted_content": "알림 설정을 변경할 수 있지만 채널의 음소거를 해제할 때까지 알림을 받지 못합니다.",
"channel_notification_preferences.thread_replies": "스레드 댓글",
"channel_notification_preferences.unmute_content": "채널 음소거 해제",
"mobile.calls_quality_warning": "불안정한 네트워크 상태로 인해 통화 품질이 저하될 수 있습니다.",
"mobile.diagnostic_id.empty": "이 서버에 진단 ID 값이 없습니다. 시스템 관리자에게 문의하여 이 값을 검토하고 서버를 다시 시작하세요.",
"mobile.calls_incoming_dm": "<b>{name}</b> 이(가) 통화로 초대합니다",
"mobile.calls_join_button": "참가",
"mobile.calls_name_is_talking_postfix": "말하고 있습니다...",
"mobile.channel_add_members.error": "오류가 발생하여 해당 사용자를 채널에 추가할 수 없습니다.",
"mobile.ios.plist.NSBluetoothPeripheralUsageDescription": "Bluetooth 액세스를 활성화하면 통화를 위해 오디오 주변 장치에 연결하고 장치와 클라이언트 간에 콘텐츠를 동기화할 수 있습니다.",
"mobile.ios.plist.NSLocationAlwaysUsageDescription": "위치 데이터에 대한 액세스를 활성화하면 {applicationName} 에서 공유하는 사진 및 동영상에 위치 메타데이터를 추가할 수 있습니다.",
"mobile.ios.plist.NSPhotoLibraryAddUsageDescription": "사진 보관함에 대한 쓰기 액세스를 활성화하면 {applicationName} 에서 다운로드한 사진과 동영상을 내 장치에 저장할 수 있습니다.",
"mobile.calls_raised_hand": "<bold>{name} {num, plural, =0 {} other {+# more }}</bold>가 손을 들었습니다",
"mobile.ios.plist.NSLocationWhenInUseUsageDescription": "위치 데이터에 대한 액세스를 활성화하면 {applicationName} 에서 공유하는 사진 및 동영상에 위치 메타데이터를 추가할 수 있습니다.",
"mobile.ios.plist.NSPhotoLibraryUsageDescription": "사진 보관함에 대한 읽기 액세스를 활성화하면 내 장치에서 {applicationName} 으로 사진과 동영상을 업로드할 수 있습니다.",
"invite.summary.back": "뒤로 가기",
"post_priority.picker.label.persistent_notifications.description": "수신자는 확인하거나 회신할 때까지 {interval, plural, one {1 분} other {{interval} 분}}마다 알림을 받습니다.",
"share_extension.channels_screen.title": "채널 선택",
"share_extension.error_screen.description": "{applicationName} 으로 콘텐츠를 공유하려고 할 때 오류가 발생했습니다.",
"share_extension.error_screen.label": "오류가 발생했습니다",
"share_extension.error_screen.reason": "이유: {reason}",
"persistent_notifications.confirm.send": "보내기",
"persistent_notifications.confirm.title": "지속적 알림 보내기",
"persistent_notifications.error.max_recipients.title": "수신자가 너무 많습니다",
"persistent_notifications.error.no_mentions.description": "메시지에 멘션한 받는 사람이 없습니다. 지속적인 알림을 보내려면 멘션을 추가해야 합니다.",
"post_priority.picker.label.persistent_notifications": "지속적 알림 보내기",
"post_priority.picker.label.request_ack": "수신확인 요청",
"requested_ack.title": "수신확인 요청",
"screen.channel_files.results.filter.title": "파일 유형별 필터링",
"persistent_notifications.error.special_mentions": "@channel, @all 또는 @here를 사용하여 영구 알림 수신자를 멘션할 수 없습니다.",
"notification.no_post": "메시지를 찾을 수 없습니다.",
"notification.no_connection": "서버에 연결할 수 없으며 알림에 대한 특정 메시지 정보를 검색할 수 없습니다.",
"snack.bar.info.copied": "정보가 클립보드에 복사되었습니다",
"persistent_notifications.confirm.cancel": "취소",
"persistent_notifications.confirm.description": "멘션된 수신자는 메시지를 확인하거나 답장할 때까지 매 {interval, plural, one {minute} other {{interval} minutes}}마다 알림을 받게 됩니다.",
"mobile.search.results": "{count}건의 검색 {count, plural, one {result} other {results}}",
"post_priority.picker.label.request_ack.description": "메시지와 함께 확인 버튼이 나타납니다",
"snack.bar.following.thread": "글타래 팔로우",
"snack.bar.unfollow.thread": "글타래 언팔로우",
"settings.about.app.version": "App Version: {version} (Build {number})",
"settings.about.app.version.title": "App Version:",
"settings.about.app.version.value": "{version} (Build {number})",
"settings.about.button.copyInfo": "정보 복사",
"settings.about.database.schema.title": "Database Schema Version:",
"settings.about.database.title": "Database:",
"settings.about.server.version": "Server Version: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Server Version: {version}",
"settings.about.server.version.title": "Server Version:",
"mobile.calls_incoming_gm": "<b>{name}</b> is inviting you to a call with <b>{num, plural, one {# other} other {# others}}</b>",
"persistent_notifications.error.max_recipients.description": "최대 {max} 수신자에게 영구 알림을 보낼 수 있습니다. 메시지에 언급된 {count} 수신자가 있습니다. 멘션한 사람을 변경해야만 보낼 수 있습니다.",
"persistent_notifications.error.no_mentions.title": "수신자는 @멘션되어야 합니다",
"persistent_notifications.error.okay": "확인",
"snack.bar.channel.members.added": "{numMembers, number} {numMembers, plural, one {member} other {members}} 추가됨",
"server.invalid.certificate.title": "잘못된 SSL 인증서",
"server.invalid.certificate.description": "이 서버의 인증서가 유효하지 않습니다.\n\"{hostname}\"인 것처럼 속이고 있는 서버에 연결하려 하므로 기밀 정보가 위험에 노출될 수 있습니다.",
"markdown.max_nodes.error": "이 메시지는 모바일 기기에서 표시하기에 너무 깁니다. 데스크톱에서 확인하거나 또는 이 한계를 늘리도록 관리자에게 연락하시기 바랍니다.",
"mobile.deep_link.invalid": "열려고 하는 링크가 잘못되었습니다."
}

View file

@ -1067,5 +1067,12 @@
"settings.about.server.version": "Serverversie: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Serverversie: {version}",
"settings.about.server.version.title": "Serverversie:",
"snack.bar.info.copied": "Info gekopieerd naar klembord"
"snack.bar.info.copied": "Info gekopieerd naar klembord",
"mobile.calls_incoming_dm": "<b>{name}</b> nodigt je uit voor een gesprek",
"mobile.calls_incoming_gm": "<b>{name}</b> nodigt je uit voor een gesprek met {num, plural, one {# other} other {# others}} <b></b>",
"mobile.calls_join_button": "Deelnemen",
"server.invalid.certificate.title": "Ongeldig SSL-certificaat",
"server.invalid.certificate.description": "Het certificaat voor deze server is ongeldig.\nMogelijks maak je verbinding met een server die zich voordoet als \"{hostname}\", waardoor je vertrouwelijke gegevens in gevaar kunnen komen.",
"mobile.deep_link.invalid": "De link die je probeert te openen is ongeldig.",
"markdown.max_nodes.error": "Dit bericht is te lang om volledig te worden weergegeven op een mobiel apparaat. Bekijk het op een desktop of neem contact op met een beheerder om deze limiet te verhogen."
}

View file

@ -1067,5 +1067,13 @@
"settings.about.server.version.title": "Wersja serwera:",
"settings.about.app.version": "Wersja Aplikacji: {version} (Build {number})",
"settings.about.server.version": "Wersja serwera: {version} (kompilacja {buildNumber}",
"snack.bar.info.copied": "Informacje skopiowane do schowka"
"snack.bar.info.copied": "Informacje skopiowane do schowka",
"mobile.calls_incoming_dm": "<b>{name}</b> zaprasza do rozmowy",
"mobile.calls_incoming_gm": "<b>{name}</b> zaprasza do rozmowy z {num, plural, one {# innym} other {# innymi}} <b></b>",
"mobile.calls_join_button": "Dołącz",
"server.invalid.certificate.title": "Nieprawidłowy certyfikat SSL",
"server.invalid.certificate.description": "Certyfikat tego serwera jest nieprawidłowy.\nMożliwe, że łączysz się z serwerem podszywającym się pod \"{hostname}\", co może narazić Twoje poufne informacje na ryzyko.",
"mobile.deep_link.invalid": "Link, który próbujesz otworzyć, jest nieprawidłowy.",
"markdown.max_nodes.error": "Ta wiadomość jest zbyt długa, aby wyświetlić ją w całości na urządzeniu mobilnym. Wyświetl ją na komputerze lub skontaktuj się z administratorem, aby zwiększyć limit.",
"mobile.calls_headset": "Zestaw słuchawkowy"
}

View file

@ -13,54 +13,54 @@
"api.channel.add_member.added": "{addedUsername} foi adicionado ao canal por {username}.",
"api.channel.guest_join_channel.post_and_forget": "{username} entrou no canal como convidado.",
"apps.error": "Erro: {error}",
"apps.error.command.field_missing": "Campos obrigatórios ausentes: `{fieldName}`.",
"apps.error.command.field_missing": "Faltam campos obrigatórios: `{fieldName}`.",
"apps.error.command.same_channel": "Canal repetido para o campo `{fieldName}`: `{option}`.",
"apps.error.command.same_option": "Opção repetida para o campo `{fieldName}`: `{option}`.",
"apps.error.command.same_user": "Usuário repetido para o campo `{fieldName}`: `{option}`.",
"apps.error.command.unknown_channel": "Canal desconhecido para o campo `{fieldName}`: `{option}`.",
"apps.error.command.unknown_option": "Opção desconhecida para o campo `{fieldName}`: `{option}`.",
"apps.error.command.unknown_user": "Usuário desconhecido para o campo `{fieldName}`: `{opção}`.",
"apps.error.command.unknown_user": "Usuário desconhecido para o campo `{fieldName}`: `{option}`.",
"apps.error.form.no_form": "`form` não está definido.",
"apps.error.form.no_lookup": "`procurar` não está definido.",
"apps.error.form.no_source": "`fonte` não está definida.",
"apps.error.form.no_submit": "`enviar ` não está definido",
"apps.error.form.refresh": "Ocorreu um erro ao buscar os campos selecionados. Entre em contato com o desenvolvedor do aplicativo. Detalhes: {details}",
"apps.error.form.refresh_no_refresh": "Atualização chamada no campo sem atualização.",
"apps.error.form.refresh_no_refresh": "Chamada de atualização em nenhum campo de atualização.",
"apps.error.form.submit.pretext": "Ocorreu um erro ao enviar o modal. Entre em contato com o desenvolvedor do aplicativo. Detalhes: {details}",
"apps.error.lookup.error_preparing_request": "Erro ao preparar solicitação de pesquisa: {errorMessage}",
"apps.error.lookup.error_preparing_request": "Erro ao preparar a solicitação de pesquisa: {errorMessage}",
"apps.error.malformed_binding": "Esta ligação não está formada corretamente. Entre em contato com o desenvolvedor do aplicativo.",
"apps.error.parser": "Erro de análise: {error}",
"apps.error.parser.execute_non_leaf": "Você deve selecionar um subcomando.",
"apps.error.parser.missing_binding": "Ligações de comando ausentes.",
"apps.error.parser.missing_field_value": "Falta o valor do campo.",
"apps.error.parser.missing_field_value": "O valor do campo está ausente.",
"apps.error.parser.missing_list_end": "Token de fechamento de lista esperado.",
"apps.error.parser.missing_quote": "Aspas duplas correspondentes são esperadas antes do final da entrada.",
"apps.error.parser.missing_quote": "Aspas duplas é esperada antes do final da entrada.",
"apps.error.parser.missing_source": "O formulário não tem envio nem fonte.",
"apps.error.parser.missing_submit": "Nenhuma chamada de envio em forma ou vinculação.",
"apps.error.parser.missing_tick": "Crase correspondente é esperada antes do final de entrada.",
"apps.error.parser.missing_tick": "Citação de marcação esperada antes do final da entrada.",
"apps.error.parser.multiple_equal": "Vários sinais `=` não são permitidos.",
"apps.error.parser.no_argument_pos_x": "Incapaz de identificar o argumento.",
"apps.error.parser.no_bindings": "Sem ligações de comando.",
"apps.error.parser.no_argument_pos_x": "Não foi possível identificar o argumento.",
"apps.error.parser.no_bindings": "Sem vinculações de comando.",
"apps.error.parser.no_form": "Nenhum formulário encontrado.",
"apps.error.parser.no_match": "`{command}`: Nenhum comando correspondente encontrado neste espaço de trabalho.",
"apps.error.parser.no_slash_start": "O comando deve começar com `/`.",
"apps.error.parser.no_slash_start": "O comando deve começar com um `/`.",
"apps.error.parser.unexpected_character": "Caracter inesperado.",
"apps.error.parser.unexpected_comma": "Vírgula inesperada.",
"apps.error.parser.unexpected_error": "Erro inesperado.",
"apps.error.parser.unexpected_flag": "O comando não aceita o sinalizador `{flagName}`.",
"apps.error.parser.unexpected_flag": "Comando não aceita sinalizador `{flagName}`.",
"apps.error.parser.unexpected_squared_bracket": "Abertura de lista inesperada.",
"apps.error.parser.unexpected_state": "Inacessível: Estado inesperado em matchBinding: `{state}`.",
"apps.error.parser.unexpected_state": "Inacessível: estado inesperado em matchBinding: `{state}`.",
"apps.error.parser.unexpected_whitespace": "Inacessível: espaço em branco inesperado.",
"apps.error.responses.navigate.no_url": "O tipo de resposta é `navigate`, mas nenhuma url foi incluído na resposta.",
"apps.error.responses.unexpected_error": "Recebeu um erro inesperado.",
"apps.error.responses.navigate.no_url": "O tipo de resposta é `navigate`, mas nenhuma URL foi incluída na resposta.",
"apps.error.responses.unexpected_error": "Recebido um erro inesperado.",
"apps.error.responses.unknown_field_error": "Recebeu um erro para um campo desconhecido. Nome do campo: `{field}`. Erro: `{error}`.",
"apps.error.responses.unknown_type": "O tipo de resposta do aplicativo não é compatível. Tipo de resposta: {type}.",
"apps.error.unknown": "Ocorreu um erro desconhecido.",
"apps.suggestion.dynamic.error": "Erro de seleção dinâmica",
"apps.suggestion.errors.parser_error": "Erro de análise",
"apps.suggestion.no_dynamic": "Nenhum dado foi retornado para sugestões dinâmicas",
"apps.suggestion.no_static": "Sem opções correspondentes.",
"apps.suggestion.no_suggestion": "Sem sugestões correspondentes.",
"apps.suggestion.no_static": "Nenhuma opção correspondente.",
"apps.suggestion.no_suggestion": "Nenhuma sugestão correspondente.",
"archivedChannelMessage": "Você está vendo um **canal arquivado**. Novas mensagens não podem ser publicadas.",
"camera_type.photo.option": "Capturar foto",
"camera_type.video.option": "Gravar Vídeo",
@ -398,7 +398,7 @@
"account.logout_from": "Desconectar de {serverName}",
"alert.channel_deleted.description": "O canal {displayName} foi arquivado.",
"screen.mentions.subtitle": "",
"login.forgot": "",
"login.forgot": "Esqueceu sua senha?",
"mobile.create_post.read_only": "",
"channel_info.error_close": "Fechar",
"notification_settings.pushNotification.disabled_long": "",
@ -462,7 +462,7 @@
"invite_people_to_team.message": "",
"find_channels.open_dm": "",
"post_info.bot": "",
"permalink.show_dialog_warn.description": "",
"permalink.show_dialog_warn.description": "Você está prestes a ingressar em {channel} sem ser explicitamente adicionado pelo administrador do canal. Tem certeza que deseja entrar neste canal privado?",
"mobile.request.invalid_request_method": "",
"saved_messages.empty.paragraph": "",
"unreads.empty.paragraph": "",
@ -928,7 +928,7 @@
"browse_channels.dropdownTitle": "Mostrar",
"browse_channels.archivedChannels": "Canais Arquivados",
"autocomplete_selector.unknown_channel": "Canal desconhecido",
"apps.error.responses.unexpected_type": "O tipo de resposta da aplicação não foi esperado. Tipo de resposta: {type}",
"apps.error.responses.unexpected_type": "O tipo de resposta do aplicativo não era esperado. Tipo de resposta: {type}",
"apps.error.responses.form.no_form": "O tipo de resposta é `form`, mas não foi incluído nenhum formulário na resposta.",
"apps.error.parser.empty_value": "Não são permitidos valores em branco.",
"mobile.oauth.switch_to_browser.title": "",
@ -1002,5 +1002,8 @@
"channel_notification_preferences.notify_about": "Avise-me sobre...",
"channel_files.noFiles.title": "Nenhum arquivo encontrado",
"channel_notification_preferences.muted_title": "Este canal está mudo",
"channel_notification_preferences.notification.mention": "Menções, apenas mensagens diretas"
"channel_notification_preferences.notification.mention": "Menções, apenas mensagens diretas",
"post_priority.picker.cancel": "Cancelar",
"post_priority.button.acknowledge": "Confirmação",
"post_priority.picker.apply": "Aplicar"
}

View file

@ -1067,5 +1067,12 @@
"settings.about.server.version": "Версия сервера: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Версия сервера: {version}",
"settings.about.server.version.title": "Версия сервера:",
"snack.bar.info.copied": "Информация скопирована в буфер обмена"
"snack.bar.info.copied": "Информация скопирована в буфер обмена",
"mobile.calls_incoming_dm": "<b>{name}</b> приглашает вас на звонок",
"mobile.calls_join_button": "Присоединиться",
"mobile.calls_incoming_gm": "<b>{name}</b> приглашает Вас на разговор с <b>{num, plural, one {# одним участником} few {# несколькими участниками} other {# несколькими участниками}}</b>",
"server.invalid.certificate.title": "Недействительный сертификат SSL",
"server.invalid.certificate.description": "Сертификат этого сервера недействителен.\nВозможно, вы подключаетесь к серверу, который выдает себя за \"{hostname}\", что может подвергнуть риску вашу конфиденциальную информацию.",
"mobile.deep_link.invalid": "Ссылка, которую вы пытаетесь открыть, недействительна.",
"markdown.max_nodes.error": "Это сообщение слишком длинное для полного отображения на мобильном устройстве. Пожалуйста, просмотрите его на настольном компьютере или свяжитесь с администратором, чтобы увеличить этот лимит."
}

View file

@ -1067,5 +1067,12 @@
"settings.about.server.version": "Serverversion: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Serverversion: {version}",
"settings.about.server.version.title": "Serverversion:",
"snack.bar.info.copied": "Kopierat till clipboard"
"snack.bar.info.copied": "Kopierat till clipboard",
"server.invalid.certificate.title": "Ogiltigt SSL-certifikat",
"server.invalid.certificate.description": "Servercertifikatet på servern är felaktigt.\nDet kan vara så att du ansluter till en server som låtsas vara \"{hostname}\" och din information skulle kunna riskera läcka till obehöriga.",
"mobile.calls_incoming_gm": "<b>{name}</b> bjuder in dig till ett samtal med <b>{num, plural, one {# annan} other {# andra}}</b>",
"mobile.calls_incoming_dm": "<b>{name}</b> bjuder in till ett samtal",
"mobile.deep_link.invalid": "Länken du försöker öppna är ogiltig.",
"markdown.max_nodes.error": "Meddelandet är för långt för att kunna visas på en mobil. Du kan se det i en dator eller kontakta en administratör för att utöka gränsen.",
"mobile.calls_join_button": "Anslut"
}

View file

@ -1066,5 +1066,13 @@
"settings.about.database.title": "Veri tabanı:",
"settings.about.server.version": "Sunucu sürümü: {version} (Yapım {buildNumber}",
"settings.about.server.version.noBuild": "Sunucu sürümü: {version}",
"settings.about.server.version.title": "Sunucu sürümü:"
"settings.about.server.version.title": "Sunucu sürümü:",
"snack.bar.info.copied": "Bilgiler panoya kopyalandı",
"mobile.calls_incoming_dm": "<b>{name}</b> sizi bir görüşmeye çağırıyor",
"mobile.calls_incoming_gm": "<b>{name}</b> sizi <b>{num, plural, one {kişinin} other {kişinin}}</b> olduğu bir görüşmeye çağırıyor",
"mobile.calls_join_button": "Katıl",
"server.invalid.certificate.description": "Bu sunucunun sertifikası geçersiz.\n\"{hostname}\" gibi davranan bir sunucuya bağlanıyor olabilirsiniz. Bu durumda gizli bilgilerinizi tehlikeye atabilir.",
"server.invalid.certificate.title": "SSL sertifikası geçersiz",
"markdown.max_nodes.error": "Bu ileti bir mobil aygıtta tam olarak görüntülenemeyecek kadar uzun. Lütfen iletiyi masaüstü uygulamasından görüntüleyin ya da bu sınırı artırmak için bir yönetici ile görüşün.",
"mobile.deep_link.invalid": "Açmaya çalıştığınız bağlantı geçersiz."
}

View file

@ -1,10 +1,10 @@
{
"about.date": "Ngày Xây Dựng:",
"about.enterpriseEditione1": "Phiên bản doanh nghiệp",
"about.date": "Ngày xây dựng:",
"about.enterpriseEditione1": "Phiên bản Doanh nghiệp",
"about.enterpriseEditionLearn": "Tìm hiểu thêm về phiên bản Doanh Nghiệp ở ",
"about.enterpriseEditionSt": "Hệ thống giao tiếp hiện đại được bảo vệ dưới tường lửa của bạn.",
"about.hash": "Mã băm của bản dựng:",
"about.teamEditiont0": "Phiên bản Nhóm",
"about.enterpriseEditionSt": "Giao tiếp hiện đại từ phía sau tường lửa của bạn.",
"about.hash": "Build Hash:",
"about.teamEditiont0": "Phiên bản Đội",
"apps.error.parser.missing_field_value": "Giá trị của trường bị thiếu.",
"apps.error.parser.missing_list_end": "Cần mã đóng danh sách.",
"apps.error.parser.missing_quote": "Đối sánh báo giá kép dự kiến trước khi kết thúc đầu vào.",
@ -18,7 +18,7 @@
"camera_type.photo.option": "Chụp ảnh",
"camera_type.video.option": "Quay video",
"center_panel.archived.closeChannel": "Đóng kênh",
"channel_header.directchannel.you": "{displayname} (you)",
"channel_header.directchannel.you": "{displayName} (bạn)",
"channel_info.header": "Tiêu đề:",
"channel_modal.nameEx": "Ví dụ: \"Bugs\", \"Marketing\", \"客户支持\"",
"channel_modal.optional": "(không bắt buộc)",
@ -42,7 +42,7 @@
"emoji_picker.custom": "Tuỳ chỉnh",
"emoji_picker.flags": "Cờ",
"emoji_picker.food-drink": "Đồ ăn thức uống",
"edit_post.editPost": "Chỉnh sửa bài ...",
"edit_post.editPost": "Chỉnh sửa bài đăng ...",
"friendly_date.yesterday": "Hôm qua",
"gallery.footer.channel_name": "Chia sẻ trong {channelName}",
"gallery.open_file": "Mở file",
@ -68,7 +68,7 @@
"mobile.post_info.unpin": "Bỏ ghim khỏi Kênh",
"mobile.post_pre_header.pinned": "Đã ghim",
"mobile.post_textbox.entire_channel_here.message": "Bằng cách sử dụng @here, bạn sắp gửi thông báo tới tối đa {totalMembers, number} {totalMembers,plural, one {người} other {người}}. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel_here.message.with_timezones": "Bằng cách sử dụng @here, bạn sắp gửi thông báo tới {totalMembers, number} {totalMembers,plult, one {người} other {người}} trong {timezones, number} {timezones,plural, one {múi giờ} other {múi giờ} }. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel_here.message.with_timezones": "Bằng cách sử dụng @here, bạn sắp gửi thông báo tới {totalMembers, number} {totalMembers,plural, one {người} other {người}} trong {timezones, number} {timezones,plural, one {múi giờ} other {múi giờ}}. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel.cancel": "Hủy",
"mobile.post_textbox.entire_channel.confirm": "Xác nhận",
"mobile.push_notification_reply.placeholder": "Viết câu trả lời...",
@ -86,7 +86,7 @@
"post_body.check_for_out_of_channel_mentions.message.multiple": "đã được đề cập nhưng họ không có trong kênh. Bạn có muốn ",
"post_body.check_for_out_of_channel_mentions.message.one": "đã được đề cập nhưng không có trong kênh. Bạn có muốn ",
"post_body.commentedOn": "Đã nhận xét về tin nhắn {name}{apostrophe}: ",
"post_body.deleted": "(tin nhắn đã xóa)",
"post_body.deleted": "(tin nhắn đã bị xóa)",
"post_info.auto_responder": "TRẢ LỜI TỰ ĐỘNG",
"post_info.bot": "BOT",
"post_info.guest": "KHÁCH",
@ -182,13 +182,13 @@
"last_users_message.added_to_team.type": "đã được {actor} **thêm vào nhóm**.",
"last_users_message.first": "{firstUser} và ",
"last_users_message.others": "{numOthers} khác ",
"last_users_message.joined_channel.type": "Bạn **joined the channel**.",
"last_users_message.joined_team.type": "Bạn **joined the channel**.",
"last_users_message.joined_channel.type": "** đã tham gia kênh **.",
"last_users_message.joined_team.type": "** đã tham gia nhóm **.",
"login.email": "Email",
"login.ldapUsername": "AD/LDAP Tên tài khoản",
"login.username": "Tên tài khoản",
"login.username": "Tên người dùng",
"msg_typing.isTyping": "{user} đang gõ...",
"password_send.link": "Nếu tài khoản tồn tại, một email đặt lại mật khẩu sẽ được gửi đến:",
"password_send.link": "Nếu tài khoản tồn tại, một email đặt lại mật khẩu sẽ được gửi tới:",
"password_send.description": "Để đặt lại mật khẩu của bạn, hãy nhập địa chỉ email bạn đã sử dụng để đăng ký",
"password_send.error": "Vui lòng nhập một địa chỉ email hợp lệ.",
"post_body.check_for_out_of_channel_mentions.link.and": " và ",
@ -212,18 +212,18 @@
"terms_of_service.api_error": "Không thể hoàn thành yêu cầu. Nếu sự cố này vẫn tiếp diễn, hãy liên hệ với Quản trị viên hệ thống của bạn.",
"user.settings.general.lastName": "Họ",
"user.settings.general.position": "Vị trí",
"user.settings.general.nickname": "Biệt danh",
"about.hashee": "Mã băm của bản dựng EE :",
"about.teamEditionLearn": "Tham gia Mattermost cộng đồng",
"about.teamEditionSt": "Tất cả các đội liên lạc ở một nơi, ngay lập tức tìm kiếm và có thể truy cập bất cứ nơi nào.",
"about.teamEditiont1": "Phiên bản doanh nghiệp",
"user.settings.general.nickname": "Biệt hiệu",
"about.hashee": "EE Build Hash:",
"about.teamEditionLearn": "Tham gia cộng đồng Mattermost",
"about.teamEditionSt": "Tất cả thông tin liên lạc trong đội của bạn ở một nơi, có thể tìm kiếm ngay lập tức và có thể truy cập ở mọi nơi.",
"about.teamEditiont1": "Phiên bản Doanh nghiệp",
"apps.error.form.no_submit": "`submit` không được định nghĩa",
"apps.error.form.refresh": "Đã xảy ra lỗi khi tìm nạp các trường đã chọn. Liên hệ với nhà phát triển ứng dụng. Thông tin chi tiết: {details}",
"apps.error.parser.empty_value": "giá trị không được rỗng",
"apps.error.parser.empty_value": "Giá trị không được rỗng.",
"apps.error.responses.form.no_form": "Loại phản hồi là `form`, nhưng không có form nào được đưa vào phản hồi.",
"apps.error.responses.unexpected_type": "Loại phản hồi của ứng dụng không được mong đợi. Loại phản hồi: {type}.",
"apps.error.responses.unexpected_type": "Loại phản hồi của ứng dụng không được mong đợi. Loại phản hồi: {type}",
"apps.error.responses.unknown_field_error": "Đã nhận được lỗi cho một trường không xác định. Tên trường: `{field}`. Lỗi: `{error}`.",
"channel_loader.someone": "Người nào",
"channel_loader.someone": "Ai đó",
"channel_modal.descriptionHelp": "Mô tả cách sử dụng kênh này.",
"channel_modal.header": "Tiêu đề",
"channel_modal.headerEx": "Ví dụ: \"[Link Title](http://example.com)\"",
@ -238,7 +238,7 @@
"custom_status.suggestions.recent_title": "GẦN ĐÂY",
"custom_status.suggestions.title": "ĐỀ XUẤT",
"edit_post.save": "Lưu",
"emoji_picker.recent": "Gần đây",
"emoji_picker.recent": "Được sử dụng gần đây",
"emoji_picker.travel-places": "Du lịch & Địa điểm",
"emoji_skin.dark_skin_tone": "màu da tối",
"emoji_skin.default": "tông màu da mặc định",
@ -262,14 +262,14 @@
"global_threads.options.mark_as_read": "Đánh đấu đã đọc",
"global_threads.options.open_in_channel": "Mở trong kênh",
"global_threads.options.title": "Thao tác trên chủ đề",
"last_users_message.left_channel.type": "Bạn **left the channel**.",
"last_users_message.left_team.type": "**left the team**.",
"last_users_message.removed_from_channel.type": "Bạn đã **removed from the channel**.",
"last_users_message.removed_from_team.type": "Bạn đã **removed from the channel**.",
"login_mfa.enterToken": "Để hoàn tất quá trình đăng nhập, vui lòng nhập token xác nhận từ điện thoại của bạn",
"last_users_message.left_channel.type": "** đã rời khỏi kênh **.",
"last_users_message.left_team.type": "** đã rời khỏi nhóm **.",
"last_users_message.removed_from_channel.type": "đã ** bị xóa khỏi kênh **.",
"last_users_message.removed_from_team.type": "đã ** bị xóa khỏi nhóm **.",
"login_mfa.enterToken": "Để hoàn tất quá trình đăng nhập, vui lòng nhập token xác nhận từ điện thoại của bạn.",
"login_mfa.token": "MFA Token",
"login_mfa.tokenReq": "Vui lòng nhập mã thông báo MFA",
"login.forgot": "Tôi quên mật khẩu của tôi",
"login.forgot": "Tôi quên mật khẩu của mình.",
"login.or": "hoặc",
"login.password": "Mật khẩu",
"login.signIn": "Đăng nhập",
@ -287,11 +287,11 @@
"mobile.channel_list.unreads": "Chưa đọc",
"mobile.commands.error_title": "Lỗi thực thi lệnh",
"mobile.components.select_server_view.connect": "Đã kết nối",
"mobile.components.select_server_view.connecting": "Đang kết nối...",
"mobile.components.select_server_view.connecting": "Đang kết nối",
"mobile.components.select_server_view.enterServerUrl": "Nhập URL máy chủ",
"mobile.components.select_server_view.proceed": "Tiếp tục",
"mobile.create_channel": "Tạo",
"mobile.create_post.read_only": "Kênh này chỉ có thể đọc",
"mobile.create_post.read_only": "Kênh này chỉ có thể đọc.",
"mobile.custom_list.no_results": "Không có kết quả",
"mobile.custom_status.choose_emoji": "Chọn một biểu tượng cảm xúc",
"mobile.custom_status.clear_after": "Xoá sau",
@ -316,7 +316,7 @@
"mobile.ios.photos_permission_denied_description": "Tải ảnh và video lên phiên bản Mattermost của bạn hoặc lưu chúng vào thiết bị của bạn. Mở Cài đặt để cấp quyền truy cập Đọc và ghi vào thư viện ảnh và video của bạn cho Mattermost.",
"mobile.ios.photos_permission_denied_title": "{applicationName} muốn truy cập ảnh của bạn",
"mobile.managed.exit": "Chỉnh sửa",
"mobile.managed.jailbreak": "Các thiết bị bẻ khóa không được {vendor} tin cậy.\n \nLý do {reason}\n\n\nThông tin gỡ lỗi: {debug}\n\nVui lòng thoát khỏi ứng dụng.",
"mobile.managed.jailbreak": "Các thiết bị bẻ khóa không được {vendor} tin cậy.\n\nLý do {reason}\n\n\n\nThông tin gỡ lỗi: {debug}\n\nVui lòng thoát khỏi ứng dụng.",
"mobile.managed.not_secured.android": "Thiết bị này phải được bảo mật bằng khóa màn hình để sử dụng Mattermost.",
"mobile.managed.not_secured.ios": "Thiết bị này phải được bảo mật bằng mật mã để sử dụng Mattermost.\n\nChuyển đến Cài đặt > Face ID & Mật mã.",
"mobile.managed.not_secured.ios.touchId": "Thiết bị này phải được bảo mật bằng mật mã để sử dụng Mattermost.\n\nChuyển đến Cài đặt > Face ID & Mật mã.",
@ -334,12 +334,12 @@
"mobile.oauth.failed_to_open_link": "Liên kết không mở được. Vui lòng thử lại.",
"mobile.oauth.failed_to_open_link_no_browser": "Liên kết không mở được. Vui lòng xác minh xem trình duyệt có được cài đặt trong không gian hiện tại hay không.",
"mobile.oauth.something_wrong": "Đã xảy ra sự cố",
"mobile.oauth.switch_to_browser": "Vui lòng sử dụng trình duyệt của bạn để hoàn tất quá trình đăng nhập.",
"mobile.oauth.switch_to_browser": "Vui lòng sử dụng trình duyệt của bạn để hoàn tất quá trình đăng nhập",
"mobile.post_info.add_reaction": "Thêm phản ứng",
"mobile.post_info.copy_text": "Sao chép văn bản",
"mobile.post_info.mark_unread": "Đánh dấu chưa đọc",
"mobile.post_textbox.entire_channel.message": "Bằng cách sử dụng @all hoặc @channel, bạn sắp gửi thông báo tới {totalMembers, number} {totalMembers,plural, one {người} other {người}}. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel.message.with_timezones": "Bằng cách sử dụng @all hoặc @channel, bạn sắp gửi thông báo tới {totalMembers, number} {totalMembers,plural, one {người} other {người}} trong {timezones, number} {timezones,plult, one {múi giờ} other {múi giờ}}. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel.message.with_timezones": "Bằng cách sử dụng @all hoặc @channel, bạn sắp gửi thông báo tới {totalMembers, number} {totalMembers,plural, one {người} other {người}} trong {timezones, number} {timezones,plural, one {múi giờ} other {múi giờ}}. Bạn có chắc chắn muốn làm điều này?",
"mobile.post_textbox.entire_channel.title": "Xác nhận gửi thông báo tới toàn bộ kênh",
"mobile.post_textbox.groups.title": "Xác nhận gửi thông báo cho các nhóm",
"mobile.post_textbox.uploadFailedDesc": "Một số tệp đính kèm không thể tải lên máy chủ. Bạn có chắc chắn muốn gửi tin nhắn?",
@ -386,17 +386,17 @@
"mobile.system_message.update_channel_purpose_message.updated_to": "{username} đã cập nhật mục đích của kênh thành: {newPurpose}",
"mobile.tos_link": "Điều khoản dịch vụ",
"mobile.user_list.deactivated": "Vô hiệu hóa",
"modal.manual_status.auto_responder.message_": "Bạn có muốn chuyển trạng thái của mình thành \"{status}\" và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_away": "Bạn có muốn chuyển trạng thái của mình thành \"Trực tuyến\" và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_dnd": "Bạn có muốn chuyển trạng thái của mình thành \"Không làm phiền\" và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_offline": "Bạn có muốn chuyển trạng thái của mình thành \"Ngoại tuyến\" và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_online": "Bạn có muốn chuyển trạng thái của mình thành \"Trực tuyến\" và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_": "Bạn có muốn chuyển trạng thái của mình thành \"{status} \"và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_away": "Bạn có muốn chuyển trạng thái của mình thành \"Đi vắng \"và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_dnd": "Bạn có muốn chuyển trạng thái của mình thành \"Không làm phiền \"và tắt Trả lời tự động không?",
"modal.manual_status.auto_responder.message_offline": "Bạn có muốn chuyển trạng thái của mình thành \"Ngoại tuyến \"và tắt Trả lời Tự động không?",
"modal.manual_status.auto_responder.message_online": "Bạn có muốn chuyển trạng thái của mình thành \"Trực tuyến \"và tắt Trả lời Tự động không?",
"password_send.reset": "Cài lại Mật khẩu",
"permalink.show_dialog_warn.description": "Bạn sắp tham gia \"{channel}\" mà không được quản trị viên kênh thêm vào một cách rõ ràng. Bạn có chắc chắn muốn tham gia kênh riêng tư này không?",
"permalink.show_dialog_warn.description": "Bạn sắp tham gia {channel} mà không được quản trị viên kênh thêm vào một cách rõ ràng. Bạn có chắc chắn muốn tham gia kênh riêng tư này không?",
"post_body.check_for_out_of_channel_groups_mentions.message": "đã không nhận được thông báo bởi đề cập này bởi vì họ không có trong kênh. Họ cũng không phải là thành viên của các nhóm được liên kết với kênh này.",
"post_body.check_for_out_of_channel_mentions.link.private": "Mời những người khác vào kênh riêng này",
"post_body.check_for_out_of_channel_mentions.link.public": "thêm chúng vào kênh",
"status_dropdown.set_dnd": "Đừng làm phiền",
"post_body.check_for_out_of_channel_mentions.link.private": "thêm họ vào kênh riêng tư này",
"post_body.check_for_out_of_channel_mentions.link.public": "thêm họ vào kênh",
"status_dropdown.set_dnd": "Không làm phiền",
"status_dropdown.set_ooo": "Ra khỏi văn phòng",
"threads": "Chủ đề",
"threads.deleted": "Tin nhắn gốc đã bị xóa",
@ -409,9 +409,9 @@
"threads.unfollowMessage": "Huỷ theo dõi tin nhắn",
"threads.unfollowThread": "Huỷ theo dõi chủ đề",
"user.settings.general.field_handled_externally": "Trường này được xử lý thông qua nhà cung cấp đăng nhập của bạn. Nếu bạn muốn thay đổi nó, bạn cần phải làm như vậy thông qua nhà cung cấp đăng nhập của bạn.",
"user.settings.general.firstName": "Tên đầu tiên",
"user.settings.general.username": "Tên tài khoản",
"user.settings.notifications.email_threads.description": "Thông báo cho tôi về tất cả các câu trả lời cho chủ đề tôi đang theo dõi.",
"user.settings.general.firstName": "Tên",
"user.settings.general.username": "Tên người dùng",
"user.settings.notifications.email_threads.description": "Thông báo cho tôi về tất cả các câu trả lời cho chủ đề tôi đang theo dõi",
"account.logout_from": "Đăng xuất khỏi {serverName}",
"account.settings": "Thiết lập",
"account.your_profile": "Hồ sơ của bạn",
@ -1065,5 +1065,14 @@
"settings.about.database.title": "Cơ sở dữ liệu:",
"settings.about.server.version": "Phiên bản Máy chủ: {version} (Số bản tạo {buildNumber}",
"settings.about.server.version.noBuild": "Phiên bản Máy chủ: {version}",
"settings.about.server.version.title": "Phiên bản Máy chủ:"
"settings.about.server.version.title": "Phiên bản Máy chủ:",
"server.invalid.certificate.title": "Chứng chỉ SSL không hợp lệ",
"server.invalid.certificate.description": "Chứng chỉ cho máy chủ này không hợp lệ. \nBạn có thể đang kết nối với một máy chủ giả danh “{hostname}”, điều này có thể khiến thông tin bí mật của bạn gặp rủi ro.",
"mobile.search.results": "{count} {count, plural, one {kết quả} other {kết quả}} tìm kiếm",
"mobile.calls_incoming_gm": "<b>{name}</b> đang mời bạn tham gia cuộc gọi với <b>{num, plural, one {# người khác} other {# người khác}}</b>",
"snack.bar.info.copied": "Đã sao chép thông tin vào bảng nhớ tạm",
"mobile.calls_incoming_dm": "<b>{name}</b> đang mời bạn tham gia cuộc gọi",
"mobile.deep_link.invalid": "Liên kết bạn đang cố mở này không hợp lệ.",
"markdown.max_nodes.error": "Thông báo này quá dài để hiển thị đầy đủ trên thiết bị di động. Vui lòng xem nó trên máy tính để bàn hoặc liên hệ với quản trị viên để tăng giới hạn này.",
"mobile.calls_join_button": "Tham gia"
}

View file

@ -21,21 +21,21 @@
"apps.error.command.unknown_option": "未知字段的选项 `{fieldName}``{option}`。",
"apps.error.command.unknown_user": "未知字段的用户 `{fieldName}``{option}`。",
"apps.error.form.no_form": "未定义`form`。",
"apps.error.form.no_lookup": "`lookup` 未定义。",
"apps.error.form.no_source": "`source` 未定义。",
"apps.error.form.no_lookup": "未定义“lookup”。",
"apps.error.form.no_source": "未定义“source”。",
"apps.error.form.no_submit": "未定义`submit`",
"apps.error.form.refresh": "提取选择的字段时出错。与应用程序开发者联系。详细信息:{details}",
"apps.error.form.refresh_no_refresh": "在无刷新字段上调用刷新。",
"apps.error.form.submit.pretext": "提交模态时出错。与应用程序开发人员联系。详细信息:{details}",
"apps.error.lookup.error_preparing_request": "准备查询请求时出错:{errorMessage}",
"apps.error.malformed_binding": "此绑定格式不正确。请联系应用开发。",
"apps.error.malformed_binding": "此绑定格式不正确。请联系应用开发人员。",
"apps.error.parser": "解析错误:{error}",
"apps.error.parser.execute_non_leaf": "您必须选择子命令。",
"apps.error.parser.missing_binding": "缺少指令绑定。",
"apps.error.parser.missing_field_value": "字段值丢失。",
"apps.error.parser.missing_list_end": "预期列表结束令牌。",
"apps.error.parser.missing_quote": "预期在输入结束之前有匹配的双引号。",
"apps.error.parser.missing_source": "表单既没有提交也没有源。",
"apps.error.parser.missing_source": "表单既没有提交也没有源。",
"apps.error.parser.missing_submit": "绑定或表单中没有提交调用。",
"apps.error.parser.missing_tick": "预期在输入结束之前有匹配的勾号。",
"apps.error.parser.multiple_equal": "不允许多个 `=` 符号。",
@ -1066,5 +1066,13 @@
"settings.about.server.version": "服务器版本:{version}(构建版本{buildNumber}",
"settings.about.server.version.title": "服务器版本:",
"settings.about.app.version": "应用程序版本:{version}(构建号{number}",
"settings.about.server.version.noBuild": "服务器版本:{version}"
"settings.about.server.version.noBuild": "服务器版本:{version}",
"snack.bar.info.copied": "信息已复制到剪贴板",
"mobile.calls_join_button": "加入",
"mobile.calls_incoming_dm": "<b>{name}</b>邀请您加入通话",
"mobile.calls_incoming_gm": "<b>{name}</b> 现邀请您与其他<b> {num, plural, one {# 位} other {# 位}} </b>进行通话",
"server.invalid.certificate.description": "此服务器的证书无效。\n您可能正在连接到一个假冒为 \"{hostname}\" 的服务器,这可能会危及您的机密信息。",
"server.invalid.certificate.title": "无效的SSL证书",
"markdown.max_nodes.error": "此信息过长无法在移动客户端上完整显示。请在PC客户端上查看或联系管理员以增加消息限制长度。",
"mobile.deep_link.invalid": "您尝试打开的链接无效。"
}

View file

@ -19,6 +19,7 @@ class Alert {
return isAndroid() ? element(by.text(title)) : element(by.label(title)).atIndex(0);
};
deletePostTitle = isAndroid() ? element(by.text('Delete Post')) : element(by.label('Delete Post')).atIndex(0);
invalidSslCertTitle = isAndroid() ? element(by.text('Invalid SSL certificate')) : element(by.label('Invalid SSL certificate')).atIndex(0);
leaveChannelTitle = isAndroid() ? element(by.text('Leave channel')) : element(by.label('Leave channel')).atIndex(0);
logoutTitle = (serverDisplayName: string) => {
const title = `Are you sure you want to log out of ${serverDisplayName}?`;
@ -27,6 +28,7 @@ class Alert {
};
markAllAsReadTitle = isAndroid() ? element(by.text('Are you sure you want to mark all threads as read?')) : element(by.label('Are you sure you want to mark all threads as read?')).atIndex(0);
messageLengthTitle = isAndroid() ? element(by.text('Message Length')) : element(by.label('Message Length')).atIndex(0);
notificationsCannotBeReceivedTitle = isAndroid() ? element(by.text('Notifications cannot be received from this server')) : element(by.label('Notifications cannot be received from this server')).atIndex(0);
removeServerTitle = (serverDisplayName: string) => {
const title = `Are you sure you want to remove ${serverDisplayName}?`;
@ -47,6 +49,7 @@ class Alert {
noButton = isAndroid() ? element(by.text('NO')) : element(by.label('No')).atIndex(0);
noButton2 = isAndroid() ? element(by.text('NO')) : element(by.label('No')).atIndex(1);
okButton = isAndroid() ? element(by.text('OK')) : element(by.label('OK')).atIndex(1);
okayButton = isAndroid() ? element(by.text('Okay')) : element(by.label('Okay')).atIndex(1);
removeButton = isAndroid() ? element(by.text('REMOVE')) : element(by.label('Remove')).atIndex(0);
removeButton1 = isAndroid() ? element(by.text('REMOVE')) : element(by.label('Remove')).atIndex(1);
removeButton2 = isAndroid() ? element(by.text('REMOVE')) : element(by.label('Remove')).atIndex(2);

View file

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Alert} from '@support/ui/component';
import {isAndroid, isIos, timeouts, wait} from '@support/utils';
import {expect} from 'detox';
@ -52,6 +53,12 @@ class ServerScreen {
}
if (isIos()) {
await this.tapConnectButton();
if (serverUrl.includes('127.0.0.1')) {
// # Tap alert okay button
await waitFor(Alert.okayButton).toExist().withTimeout(timeouts.TEN_SEC);
await Alert.okayButton.tap();
}
}
};

View file

@ -8,11 +8,12 @@
// *******************************************************************
import {serverOneUrl} from '@support/test_config';
import {Alert} from '@support/ui/component';
import {
LoginScreen,
ServerScreen,
} from '@support/ui/screen';
import {timeouts, wait} from '@support/utils';
import {isIos, timeouts, wait} from '@support/utils';
import {expect} from 'detox';
describe('Server Login - Connect to Server', () => {
@ -33,6 +34,8 @@ describe('Server Login - Connect to Server', () => {
await ServerScreen.toBeVisible();
// # Clear fields
await expect(serverUrlInput).toBeVisible();
await expect(serverDisplayNameInput).toBeVisible();
await serverUrlInput.clearText();
await serverDisplayNameInput.clearText();
});
@ -67,6 +70,7 @@ describe('Server Login - Connect to Server', () => {
it('MM-T4676_3 - should show invalid url error on invalid server url', async () => {
// # Connect with invalid server url and non-empty server display name
const invalidServerUrl = 'invalid';
await device.setURLBlacklist([invalidServerUrl]);
await serverUrlInput.replaceText(invalidServerUrl);
await serverDisplayNameInput.replaceText('Server 1');
await connectButton.tap();
@ -78,27 +82,32 @@ describe('Server Login - Connect to Server', () => {
});
it('MM-T4676_4 - should show connection error on invalid ssl or invalid host', async () => {
await device.reloadReactNative();
// # Connect with invalid ssl and non-empty server display name
const connectionError = 'Cannot connect to the server.';
await serverUrlInput.replaceText('expired.badssl.com');
const expiredServerUrl = 'expired.badssl.com';
const wrongHostServerUrl = 'wrong.host.badssl.com';
await device.setURLBlacklist([expiredServerUrl, wrongHostServerUrl]);
await serverUrlInput.replaceText(expiredServerUrl);
await serverDisplayNameInput.replaceText('Server 1');
await connectButton.tap();
await wait(timeouts.ONE_SEC);
// * Verify connection error
await waitFor(serverUrlInputError).toExist().withTimeout(timeouts.TEN_SEC);
await expect(serverUrlInputError).toHaveText(connectionError);
// * Verify invalid SSL cert error
await waitFor(Alert.invalidSslCertTitle).toExist().withTimeout(timeouts.TEN_SEC);
await Alert.okButton.tap();
// # Connect with invalid host and valid server display name
await device.reloadReactNative();
await serverUrlInput.replaceText('wrong.host.badssl.com');
await serverUrlInput.replaceText(wrongHostServerUrl);
await serverDisplayNameInput.replaceText('Server 1');
await connectButton.tap();
await wait(timeouts.ONE_SEC);
// * Verify connection error
await waitFor(serverUrlInputError).toExist().withTimeout(timeouts.TEN_SEC);
await expect(serverUrlInputError).toHaveText(connectionError);
// * Verify invalid SSL cert error
await waitFor(Alert.invalidSslCertTitle).toExist().withTimeout(timeouts.TEN_SEC);
await Alert.okButton.tap();
});
it('MM-T4676_5 - should show login screen on successful connection to server', async () => {
@ -108,6 +117,12 @@ describe('Server Login - Connect to Server', () => {
await connectButton.tap();
await wait(timeouts.ONE_SEC);
if (isIos()) {
// # Tap alert okay button
await waitFor(Alert.okayButton).toExist().withTimeout(timeouts.TEN_SEC);
await Alert.okayButton.tap();
}
// * Verify on login screen
await LoginScreen.toBeVisible();
});

3347
detox/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -5,44 +5,39 @@
"author": "Mattermost, Inc.",
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-transform-modules-commonjs": "7.22.5",
"@babel/plugin-transform-runtime": "7.22.5",
"@babel/preset-env": "7.22.5",
"@jest/test-sequencer": "29.5.0",
"@types/jest": "29.5.2",
"@types/tough-cookie": "4.0.2",
"@types/uuid": "9.0.2",
"aws-sdk": "2.1398.0",
"axios": "1.4.0",
"axios-cookiejar-support": "4.0.6",
"babel-jest": "29.5.0",
"@babel/plugin-transform-modules-commonjs": "7.22.15",
"@babel/plugin-transform-runtime": "7.22.15",
"@babel/preset-env": "7.22.20",
"@jest/test-sequencer": "29.7.0",
"@types/jest": "29.5.5",
"@types/tough-cookie": "4.0.3",
"@types/uuid": "9.0.4",
"aws-sdk": "2.1462.0",
"axios": "1.5.0",
"axios-cookiejar-support": "4.0.7",
"babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.0",
"client-oauth2": "4.3.3",
"deepmerge": "4.3.1",
"detox": "20.9.1",
"detox": "20.11.4",
"form-data": "4.0.0",
"jest": "29.5.0",
"jest-circus": "29.5.0",
"jest-cli": "29.5.0",
"jest": "29.7.0",
"jest-circus": "29.7.0",
"jest-cli": "29.7.0",
"jest-html-reporters": "3.1.4",
"jest-junit": "16.0.0",
"jest-stare": "2.5.0",
"jest-stare": "2.5.1",
"junit-report-merger": "6.0.2",
"moment-timezone": "0.5.43",
"recursive-readdir": "2.2.3",
"sanitize-filename": "1.6.3",
"shelljs": "0.8.5",
"tough-cookie": "4.1.3",
"ts-jest": "29.1.0",
"tslib": "2.5.3",
"typescript": "5.1.3",
"uuid": "9.0.0",
"xml2js": "0.5.0"
},
"overrides": {
"detox": {
"jest": "^29.1.0"
}
"ts-jest": "29.1.1",
"tslib": "2.6.2",
"typescript": "5.2.2",
"uuid": "9.0.1",
"xml2js": "0.6.2"
},
"scripts": {
"e2e:android-create-emulator": "./create_android_emulator.sh",

View file

@ -3,22 +3,22 @@ GEM
specs:
CFPropertyList (3.0.6)
rexml
addressable (2.8.4)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.793.0)
aws-sdk-core (3.180.0)
aws-partitions (1.829.0)
aws-sdk-core (3.184.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.71.0)
aws-sdk-core (~> 3, >= 3.177.0)
aws-sdk-kms (1.72.0)
aws-sdk-core (~> 3, >= 3.184.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.132.0)
aws-sdk-core (~> 3, >= 3.179.0)
aws-sdk-s3 (1.136.0)
aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
@ -36,7 +36,7 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.100.0)
excon (0.103.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.7)
fastlane (2.214.0)
fastlane (2.216.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@ -87,6 +87,7 @@ GEM
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
@ -98,7 +99,7 @@ GEM
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
@ -111,7 +112,7 @@ GEM
fastlane-plugin-find_replace_string (0.1.0)
fastlane-plugin-versioning_android (0.1.1)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.46.0)
google-apis-androidpublisher_v3 (0.50.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
addressable (~> 2.5, >= 2.5.1)
@ -142,10 +143,9 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.7.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
@ -156,15 +156,14 @@ GEM
jmespath (1.6.2)
json (2.6.3)
jwt (2.7.1)
memoist (0.16.2)
mini_magick (4.12.0)
mini_mime (1.1.2)
mini_mime (1.1.5)
mini_portile2 (2.8.4)
multi_json (1.15.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
naturally (2.2.1)
nokogiri (1.15.3)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
optparse (0.1.1)
@ -183,7 +182,7 @@ GEM
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.17.0)
signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
@ -192,8 +191,8 @@ GEM
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
@ -203,10 +202,10 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
unicode-display_width (2.4.2)
webrick (1.8.1)
word_wrap (1.0.0)
xcodeproj (1.22.0)
xcodeproj (1.23.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)

View file

@ -1929,7 +1929,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 485;
CURRENT_PROJECT_VERSION = 487;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@ -1973,7 +1973,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 485;
CURRENT_PROJECT_VERSION = 487;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@ -2116,7 +2116,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 485;
CURRENT_PROJECT_VERSION = 487;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -2165,7 +2165,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 485;
CURRENT_PROJECT_VERSION = 487;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -2221,6 +2221,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -2238,6 +2239,13 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
" ",
"-Wl -ld_classic ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
};
@ -2269,6 +2277,10 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -2284,6 +2296,13 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
" ",
"-Wl -ld_classic ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;

View file

@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.8.0</string>
<string>2.9.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@ -37,7 +37,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>485</string>
<string>487</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View file

@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2.8.0</string>
<string>2.9.0</string>
<key>CFBundleVersion</key>
<string>485</string>
<string>487</string>
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>

View file

@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2.8.0</string>
<string>2.9.0</string>
<key>CFBundleVersion</key>
<string>485</string>
<string>487</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>

View file

@ -63,7 +63,7 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.4'
end
end
__apply_Xcode_12_5_M1_post_install_workaround(installer)

View file

@ -4,18 +4,18 @@ PODS:
- BVLinearGradient (2.8.2):
- React-Core
- CocoaAsyncSocket (7.6.5)
- CocoaLumberjack (3.8.0):
- CocoaLumberjack/Core (= 3.8.0)
- CocoaLumberjack/Core (3.8.0)
- CocoaLumberjack (3.8.1):
- CocoaLumberjack/Core (= 3.8.1)
- CocoaLumberjack/Core (3.8.1)
- DoubleConversion (1.1.6)
- FBLazyVector (0.71.11)
- FBReactNativeSpec (0.71.11):
- FBLazyVector (0.71.13)
- FBReactNativeSpec (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.71.11)
- RCTTypeSafety (= 0.71.11)
- React-Core (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- RCTRequired (= 0.71.13)
- RCTTypeSafety (= 0.71.13)
- React-Core (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- Flipper (0.125.0):
- Flipper-Folly (~> 2.6)
- Flipper-RSocket (~> 1.4)
@ -79,25 +79,25 @@ PODS:
- FlipperKit/FlipperKitNetworkPlugin
- fmt (6.2.1)
- glog (0.3.5)
- hermes-engine (0.71.11):
- hermes-engine/Pre-built (= 0.71.11)
- hermes-engine/Pre-built (0.71.11)
- hermes-engine (0.71.13):
- hermes-engine/Pre-built (= 0.71.13)
- hermes-engine/Pre-built (0.71.13)
- HMSegmentedControl (1.5.6)
- jail-monkey (2.8.0):
- React-Core
- JitsiWebRTC (111.0.2)
- libevent (2.1.12)
- libwebp (1.3.1):
- libwebp/demux (= 1.3.1)
- libwebp/mux (= 1.3.1)
- libwebp/sharpyuv (= 1.3.1)
- libwebp/webp (= 1.3.1)
- libwebp/demux (1.3.1):
- libwebp (1.3.2):
- libwebp/demux (= 1.3.2)
- libwebp/mux (= 1.3.2)
- libwebp/sharpyuv (= 1.3.2)
- libwebp/webp (= 1.3.2)
- libwebp/demux (1.3.2):
- libwebp/webp
- libwebp/mux (1.3.1):
- libwebp/mux (1.3.2):
- libwebp/demux
- libwebp/sharpyuv (1.3.1)
- libwebp/webp (1.3.1):
- libwebp/sharpyuv (1.3.2)
- libwebp/webp (1.3.2):
- libwebp/sharpyuv
- mattermost-react-native-turbo-log (0.2.3):
- CocoaLumberjack
@ -121,26 +121,26 @@ PODS:
- fmt (~> 6.2.1)
- glog
- libevent
- RCTRequired (0.71.11)
- RCTTypeSafety (0.71.11):
- FBLazyVector (= 0.71.11)
- RCTRequired (= 0.71.11)
- React-Core (= 0.71.11)
- React (0.71.11):
- React-Core (= 0.71.11)
- React-Core/DevSupport (= 0.71.11)
- React-Core/RCTWebSocket (= 0.71.11)
- React-RCTActionSheet (= 0.71.11)
- React-RCTAnimation (= 0.71.11)
- React-RCTBlob (= 0.71.11)
- React-RCTImage (= 0.71.11)
- React-RCTLinking (= 0.71.11)
- React-RCTNetwork (= 0.71.11)
- React-RCTSettings (= 0.71.11)
- React-RCTText (= 0.71.11)
- React-RCTVibration (= 0.71.11)
- React-callinvoker (0.71.11)
- React-Codegen (0.71.11):
- RCTRequired (0.71.13)
- RCTTypeSafety (0.71.13):
- FBLazyVector (= 0.71.13)
- RCTRequired (= 0.71.13)
- React-Core (= 0.71.13)
- React (0.71.13):
- React-Core (= 0.71.13)
- React-Core/DevSupport (= 0.71.13)
- React-Core/RCTWebSocket (= 0.71.13)
- React-RCTActionSheet (= 0.71.13)
- React-RCTAnimation (= 0.71.13)
- React-RCTBlob (= 0.71.13)
- React-RCTImage (= 0.71.13)
- React-RCTLinking (= 0.71.13)
- React-RCTNetwork (= 0.71.13)
- React-RCTSettings (= 0.71.13)
- React-RCTText (= 0.71.13)
- React-RCTVibration (= 0.71.13)
- React-callinvoker (0.71.13)
- React-Codegen (0.71.13):
- FBReactNativeSpec
- hermes-engine
- RCT-Folly
@ -151,214 +151,214 @@ PODS:
- React-jsiexecutor
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- React-Core (0.71.11):
- React-Core (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.11)
- React-cxxreact (= 0.71.11)
- React-Core/Default (= 0.71.13)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/CoreModulesHeaders (0.71.11):
- React-Core/CoreModulesHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/Default (0.71.11):
- React-Core/Default (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/DevSupport (0.71.11):
- React-Core/DevSupport (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.11)
- React-Core/RCTWebSocket (= 0.71.11)
- React-cxxreact (= 0.71.11)
- React-Core/Default (= 0.71.13)
- React-Core/RCTWebSocket (= 0.71.13)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-jsinspector (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-jsinspector (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTActionSheetHeaders (0.71.11):
- React-Core/RCTActionSheetHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTAnimationHeaders (0.71.11):
- React-Core/RCTAnimationHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTBlobHeaders (0.71.11):
- React-Core/RCTBlobHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTImageHeaders (0.71.11):
- React-Core/RCTImageHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTLinkingHeaders (0.71.11):
- React-Core/RCTLinkingHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTNetworkHeaders (0.71.11):
- React-Core/RCTNetworkHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTSettingsHeaders (0.71.11):
- React-Core/RCTSettingsHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTTextHeaders (0.71.11):
- React-Core/RCTTextHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTVibrationHeaders (0.71.11):
- React-Core/RCTVibrationHeaders (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-Core/RCTWebSocket (0.71.11):
- React-Core/RCTWebSocket (0.71.13):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.11)
- React-cxxreact (= 0.71.11)
- React-Core/Default (= 0.71.13)
- React-cxxreact (= 0.71.13)
- React-hermes
- React-jsi (= 0.71.11)
- React-jsiexecutor (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsi (= 0.71.13)
- React-jsiexecutor (= 0.71.13)
- React-perflogger (= 0.71.13)
- Yoga
- React-CoreModules (0.71.11):
- React-CoreModules (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.11)
- React-Codegen (= 0.71.11)
- React-Core/CoreModulesHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- RCTTypeSafety (= 0.71.13)
- React-Codegen (= 0.71.13)
- React-Core/CoreModulesHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- React-RCTBlob
- React-RCTImage (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-cxxreact (0.71.11):
- React-RCTImage (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-cxxreact (0.71.13):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.11)
- React-jsi (= 0.71.11)
- React-jsinspector (= 0.71.11)
- React-logger (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-runtimeexecutor (= 0.71.11)
- React-hermes (0.71.11):
- React-callinvoker (= 0.71.13)
- React-jsi (= 0.71.13)
- React-jsinspector (= 0.71.13)
- React-logger (= 0.71.13)
- React-perflogger (= 0.71.13)
- React-runtimeexecutor (= 0.71.13)
- React-hermes (0.71.13):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly/Futures (= 2021.07.22.00)
- React-cxxreact (= 0.71.11)
- React-cxxreact (= 0.71.13)
- React-jsi
- React-jsiexecutor (= 0.71.11)
- React-jsinspector (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsc (0.71.11):
- React-jsc/Fabric (= 0.71.11)
- React-jsi (= 0.71.11)
- React-jsc/Fabric (0.71.11):
- React-jsi (= 0.71.11)
- React-jsi (0.71.11):
- React-jsiexecutor (= 0.71.13)
- React-jsinspector (= 0.71.13)
- React-perflogger (= 0.71.13)
- React-jsc (0.71.13):
- React-jsc/Fabric (= 0.71.13)
- React-jsi (= 0.71.13)
- React-jsc/Fabric (0.71.13):
- React-jsi (= 0.71.13)
- React-jsi (0.71.13):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-jsiexecutor (0.71.11):
- React-jsiexecutor (0.71.13):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.71.11)
- React-jsi (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-jsinspector (0.71.11)
- React-logger (0.71.11):
- React-cxxreact (= 0.71.13)
- React-jsi (= 0.71.13)
- React-perflogger (= 0.71.13)
- React-jsinspector (0.71.13)
- React-logger (0.71.13):
- glog
- react-native-background-timer (2.4.1):
- React-Core
@ -402,90 +402,90 @@ PODS:
- React-Core
- react-native-webview (13.3.1):
- React-Core
- React-perflogger (0.71.11)
- React-RCTActionSheet (0.71.11):
- React-Core/RCTActionSheetHeaders (= 0.71.11)
- React-RCTAnimation (0.71.11):
- React-perflogger (0.71.13)
- React-RCTActionSheet (0.71.13):
- React-Core/RCTActionSheetHeaders (= 0.71.13)
- React-RCTAnimation (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.11)
- React-Codegen (= 0.71.11)
- React-Core/RCTAnimationHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTAppDelegate (0.71.11):
- RCTTypeSafety (= 0.71.13)
- React-Codegen (= 0.71.13)
- React-Core/RCTAnimationHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTAppDelegate (0.71.13):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React-Core
- ReactCommon/turbomodule/core
- React-RCTBlob (0.71.11):
- React-RCTBlob (0.71.13):
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.71.11)
- React-Core/RCTBlobHeaders (= 0.71.11)
- React-Core/RCTWebSocket (= 0.71.11)
- React-jsi (= 0.71.11)
- React-RCTNetwork (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTImage (0.71.11):
- React-Codegen (= 0.71.13)
- React-Core/RCTBlobHeaders (= 0.71.13)
- React-Core/RCTWebSocket (= 0.71.13)
- React-jsi (= 0.71.13)
- React-RCTNetwork (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTImage (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.11)
- React-Codegen (= 0.71.11)
- React-Core/RCTImageHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- React-RCTNetwork (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTLinking (0.71.11):
- React-Codegen (= 0.71.11)
- React-Core/RCTLinkingHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTNetwork (0.71.11):
- RCTTypeSafety (= 0.71.13)
- React-Codegen (= 0.71.13)
- React-Core/RCTImageHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- React-RCTNetwork (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTLinking (0.71.13):
- React-Codegen (= 0.71.13)
- React-Core/RCTLinkingHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTNetwork (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.11)
- React-Codegen (= 0.71.11)
- React-Core/RCTNetworkHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTSettings (0.71.11):
- RCTTypeSafety (= 0.71.13)
- React-Codegen (= 0.71.13)
- React-Core/RCTNetworkHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTSettings (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.11)
- React-Codegen (= 0.71.11)
- React-Core/RCTSettingsHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-RCTText (0.71.11):
- React-Core/RCTTextHeaders (= 0.71.11)
- React-RCTVibration (0.71.11):
- RCTTypeSafety (= 0.71.13)
- React-Codegen (= 0.71.13)
- React-Core/RCTSettingsHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-RCTText (0.71.13):
- React-Core/RCTTextHeaders (= 0.71.13)
- React-RCTVibration (0.71.13):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.71.11)
- React-Core/RCTVibrationHeaders (= 0.71.11)
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/core (= 0.71.11)
- React-runtimeexecutor (0.71.11):
- React-jsi (= 0.71.11)
- ReactCommon/turbomodule/bridging (0.71.11):
- React-Codegen (= 0.71.13)
- React-Core/RCTVibrationHeaders (= 0.71.13)
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/core (= 0.71.13)
- React-runtimeexecutor (0.71.13):
- React-jsi (= 0.71.13)
- ReactCommon/turbomodule/bridging (0.71.13):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.11)
- React-Core (= 0.71.11)
- React-cxxreact (= 0.71.11)
- React-jsi (= 0.71.11)
- React-logger (= 0.71.11)
- React-perflogger (= 0.71.11)
- ReactCommon/turbomodule/core (0.71.11):
- React-callinvoker (= 0.71.13)
- React-Core (= 0.71.13)
- React-cxxreact (= 0.71.13)
- React-jsi (= 0.71.13)
- React-logger (= 0.71.13)
- React-perflogger (= 0.71.13)
- ReactCommon/turbomodule/core (0.71.13):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.11)
- React-Core (= 0.71.11)
- React-cxxreact (= 0.71.11)
- React-jsi (= 0.71.11)
- React-logger (= 0.71.11)
- React-perflogger (= 0.71.11)
- React-callinvoker (= 0.71.13)
- React-Core (= 0.71.13)
- React-cxxreact (= 0.71.13)
- React-jsi (= 0.71.13)
- React-logger (= 0.71.13)
- React-perflogger (= 0.71.13)
- ReactNativeExceptionHandler (2.10.10):
- React-Core
- ReactNativeIncallManager (4.1.0):
@ -513,8 +513,8 @@ PODS:
- React-Core
- RNFastImage (8.6.3):
- React-Core
- SDWebImage (~> 5.12.3)
- SDWebImageWebPCoder (~> 0.8.4)
- SDWebImage (~> 5.18.2)
- SDWebImageWebPCoder (~> 0.13.0)
- RNFileViewer (2.1.5):
- React-Core
- RNFS (2.20.0):
@ -558,9 +558,6 @@ PODS:
- React-RCTText
- ReactCommon/turbomodule/core
- Yoga
- RNRudderSdk (1.8.0):
- React
- Rudder (~> 1.13)
- RNScreens (3.24.0):
- React-Core
- React-RCTImage
@ -573,13 +570,12 @@ PODS:
- React-Core
- RNVectorIcons (10.0.0):
- React-Core
- Rudder (1.17.0)
- SDWebImage (5.12.6):
- SDWebImage/Core (= 5.12.6)
- SDWebImage/Core (5.12.6)
- SDWebImageWebPCoder (0.8.5):
- SDWebImage (5.18.2):
- SDWebImage/Core (= 5.18.2)
- SDWebImage/Core (5.18.2)
- SDWebImageWebPCoder (0.13.0):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.9.4):
- SentryPrivate (= 8.9.4)
- SentryPrivate (8.9.4)
@ -691,7 +687,6 @@ DEPENDENCIES:
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- "RNRudderSdk (from `../node_modules/@rudderstack/rudder-sdk-react-native`)"
- RNScreens (from `../node_modules/react-native-screens`)
- "RNSentry (from `../node_modules/@sentry/react-native`)"
- RNShare (from `../node_modules/react-native-share`)
@ -722,7 +717,6 @@ SPEC REPOS:
- libevent
- libwebp
- OpenSSL-Universal
- Rudder
- SDWebImage
- SDWebImageWebPCoder
- Sentry
@ -873,8 +867,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-haptic-feedback"
RNReanimated:
:path: "../node_modules/react-native-reanimated"
RNRudderSdk:
:path: "../node_modules/@rudderstack/rudder-sdk-react-native"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSentry:
@ -905,10 +897,10 @@ SPEC CHECKSUMS:
boost: 57d2868c099736d80fcd648bf211b4431e51a558
BVLinearGradient: 916632041121a658c704df89d99f04acb038de0f
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
CocoaLumberjack: 78abfb691154e2a9df8ded4350d504ee19d90732
CocoaLumberjack: 5c7e64cdb877770859bddec4d3d5a0d7c9299df9
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: c511d4cd0210f416cb5c289bd5ae6b36d909b048
FBReactNativeSpec: a911fb22def57aef1d74215e8b6b8761d25c1c54
FBLazyVector: 24e08bf294faea0abc0278abb2fcad7f3e446f6f
FBReactNativeSpec: c949e4b726d8cf9e19b73be60ecfa26355deceb3
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
@ -920,29 +912,29 @@ SPEC CHECKSUMS:
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: 34c863b446d0135b85a6536fa5fd89f48196f848
hermes-engine: 8b9dc37355d2e12879267382f4256afd356349a1
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
jail-monkey: a71b35d482a70ecba844a90f002994012cf12a5d
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: 33dc822fbbf4503668d09f7885bbfedc76c45e96
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
mattermost-react-native-turbo-log: a00b39dafdef7905164110466e7d725f6f079751
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: f6187ec763637e6a57f5728dd9a3bdabc6d6b4e0
RCTTypeSafety: a01aca2dd3b27fa422d5239252ad38e54e958750
React: 741b4f5187e7a2137b69c88e65f940ba40600b4b
React-callinvoker: 72ba74b2d5d690c497631191ae6eeca0c043d9cf
React-Codegen: 8a7cda1633e4940de8a710f6bf5cae5dd673546e
React-Core: 72bb19702c465b6451a40501a2879532bec9acee
React-CoreModules: ffd19b082fc36b9b463fedf30955138b5426c053
React-cxxreact: 8b3dd87e3b8ea96dd4ad5c7bac8f31f1cc3da97f
React-hermes: be95942c3f47fc032da1387360413f00dae0ea68
React-jsc: 75bfda40ea4032b5018875355ab5ee089ac748bf
React-jsi: 9978e2a64c2a4371b40e109f4ef30a33deaa9bcb
React-jsiexecutor: 18b5b33c5f2687a784a61bc8176611b73524ae77
React-jsinspector: b6ed4cb3ffa27a041cd440300503dc512b761450
React-logger: 186dd536128ae5924bc38ed70932c00aa740cd5b
RCTRequired: c20235648eeb64a874f55459ceae6b081956318d
RCTTypeSafety: ca004f1fe0b76f7936f7fe7dfd761a4386cf72f5
React: b27df2b1da30335cf1bf1909056c4e1c3a3603ae
React-callinvoker: f2a69510d781d8226d51342a3cbe8a9b13573ea5
React-Codegen: ba40903fcda35154f5b4350b62ab831e4ea1f174
React-Core: 0771d135beb41b14e0e2ee9238fda50df6f18b97
React-CoreModules: 0e081b26ab034992d6a60217fc35a83e8ad9b8ed
React-cxxreact: 3ec43be907f4d818c5113e436d661836d1ab5aa9
React-hermes: 870871faa5b35c8163361e22241360de26afe07d
React-jsc: 61eedc91c322c4d393cf8369a059902de301f2c9
React-jsi: c06ec745faeea7bb8845a9b906aefa7c049c86cb
React-jsiexecutor: a2867f1f81301b1f56ad968632b6ebc45c64a530
React-jsinspector: 7e58fe86c7cc442fd11da0c9d8bef12a8d63f771
React-logger: a3f6ca0d018749852a2a6f07c154bfc6fcd4195a
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
react-native-cameraroll: 134805127580aed23403b8c2cb1548920dd77b3a
react-native-cookies: f54fcded06bb0cda05c11d86788020b43528a26c
@ -960,19 +952,19 @@ SPEC CHECKSUMS:
react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253
react-native-webrtc: 4d1669c2ed29767fe70b0169428b4466589ecf8b
react-native-webview: c2b70afb1d910cdd8810375aecc6c2894e2ba061
React-perflogger: e706562ab7eb8eb590aa83a224d26fa13963d7f2
React-RCTActionSheet: 57d4bd98122f557479a3359ad5dad8e109e20c5a
React-RCTAnimation: ccf3ef00101ea74bda73a045d79a658b36728a60
React-RCTAppDelegate: d0c28a35c65e9a0aef287ac0dafe1b71b1ac180c
React-RCTBlob: 1700b92ece4357af0a49719c9638185ad2902e95
React-RCTImage: f2e4904566ccccaa4b704170fcc5ae144ca347bf
React-RCTLinking: 52a3740e3651e30aa11dff5a6debed7395dd8169
React-RCTNetwork: ea0976f2b3ffc7877cd7784e351dc460adf87b12
React-RCTSettings: ed5ac992b23e25c65c3cc31f11b5c940ae5e3e60
React-RCTText: c9dfc6722621d56332b4f3a19ac38105e7504145
React-RCTVibration: f09f08de63e4122deb32506e20ca4cae6e4e14c1
React-runtimeexecutor: 4817d63dbc9d658f8dc0ec56bd9b83ce531129f0
ReactCommon: 08723d2ed328c5cbcb0de168f231bc7bae7f8aa1
React-perflogger: 431a655960a02f01257d631b2a9bfbb02fd21064
React-RCTActionSheet: 38c8d496d0faa63013d16f709e10a3acf6b5f100
React-RCTAnimation: 6da4d599f3262ed8021433ddd96de45ac9e731b1
React-RCTAppDelegate: 66498edcd8ba93f0bd727304be671f9f3ddf0a23
React-RCTBlob: d8f7bf9f32fbde84565a81f4bdf34398f46d45dd
React-RCTImage: 4e31e6ebf2b9705831d1855425a043b40eec1f61
React-RCTLinking: 22ac16d44e2df03e9ca9125273fc58a7c507f529
React-RCTNetwork: 4bacd206834633c23475485dbc21c18563627af4
React-RCTSettings: 4e4ace986ae92a7e1696fdac11615576b698f337
React-RCTText: 37a1341bdf1f80e9909f6b69a7a9ee747cb682d3
React-RCTVibration: 2271362cdf9ff2dae6a2156f5101e5c30b02694d
React-runtimeexecutor: 35cec6420c9d4144b0d06f9fdb093cf8f02bd52c
ReactCommon: fc9d1da17fa902910dcba550a54c16e7e1c70d2c
ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60
ReactNativeIncallManager: 2385505fa5dfdbbc78925e3b8d23b30ce0cde40e
ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306
@ -980,7 +972,7 @@ SPEC CHECKSUMS:
RNCClipboard: 3f0451a8100393908bea5c5c5b16f96d45f30bfc
RNDateTimePicker: 9b4091348e53f540180abdc54984d839a556f593
RNDeviceInfo: 5795b418ed3451ebcaf39384e6cf51f60cb931c9
RNFastImage: 0ee8f7e39df8190d3ca3a5b0c4ea0109c0ff132e
RNFastImage: d2166bfb81ca27b8c9cd21d8105c4e9adaf0b252
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: c0d04458598fcb26052494ae23dda8f8f5162b13
@ -989,15 +981,13 @@ SPEC CHECKSUMS:
RNPermissions: 8ec6088b9f52706b4ef98fc4929df617d23917f3
RNReactNativeHapticFeedback: afa5bf2794aecbb2dba2525329253da0d66656df
RNReanimated: 49cdb63e767bb7e743ff4c12f7d85722c0d008f2
RNRudderSdk: b8cbccae069ea1a16ae1fd93e1b1072c1f1b7af7
RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7
RNSentry: c167b3da6aa7f3cf85d909caae905d043a062b6c
RNShare: da6d90b6dc332f51f86498041d6e34211f96b630
RNSVG: 03e4d258ca355d7836a0a5dd4d4dc63c1eb49cbb
RNVectorIcons: 8b5bb0fa61d54cd2020af4f24a51841ce365c7e9
Rudder: 3f4ab09638452282a22b96a388b54132dcd3fca8
SDWebImage: a47aea9e3d8816015db4e523daff50cfd294499d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SDWebImage: c0de394d7cf7f9838aed1fd6bb6037654a4572e4
SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102
Sentry: 56c76eed917f7dffd46db50906afbf5c9aa2673a
SentryPrivate: f3be34b5deb9fe676fdfb1f1ad5cdb1b740c5688
simdjson: e6bfae9ce4bcdc80452d388d593816f1ca2106f3
@ -1006,9 +996,9 @@ SPEC CHECKSUMS:
SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
WatermelonDB: cd71a1085182aca9e5d2164b7af9ef2a3aaca571
Yoga: f7decafdc5e8c125e6fa0da38a687e35238420fa
Yoga: 135109c9b8c5d1a8af3a58d21cd4c7aa7f3bf555
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 25f07cb9e5eed8c84db8e8723000e8470c349058
PODFILE CHECKSUM: 8c9b3133b62f3917cfe8e505f2a5dbd3fd882183
COCOAPODS: 1.11.3

95
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "mattermost-mobile",
"version": "2.8.0",
"version": "2.9.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mattermost-mobile",
"version": "2.8.0",
"version": "2.9.0",
"hasInstallScript": true,
"license": "Apache 2.0",
"dependencies": {
@ -18,7 +18,7 @@
"@formatjs/intl-relativetimeformat": "11.2.4",
"@gorhom/bottom-sheet": "4.4.7",
"@mattermost/calls": "github:mattermost/calls-common#v0.17.0",
"@mattermost/compass-icons": "0.1.37",
"@mattermost/compass-icons": "0.1.38",
"@mattermost/react-native-emm": "1.3.5",
"@mattermost/react-native-network-client": "1.4.1",
"@mattermost/react-native-paste-input": "0.6.4",
@ -36,7 +36,6 @@
"@react-navigation/bottom-tabs": "6.5.8",
"@react-navigation/native": "6.1.7",
"@react-navigation/stack": "6.3.17",
"@rudderstack/rudder-sdk-react-native": "1.8.0",
"@sentry/react-native": "5.9.0",
"@stream-io/flat-list-mvcp": "0.10.3",
"@tsconfig/react-native": "3.0.2",
@ -55,7 +54,7 @@
"react": "18.2.0",
"react-freeze": "1.0.3",
"react-intl": "6.4.4",
"react-native": "0.71.11",
"react-native": "0.71.13",
"react-native-android-open-settings": "1.3.0",
"react-native-background-timer": "2.4.1",
"react-native-button": "3.1.0",
@ -151,7 +150,7 @@
"babel-loader": "9.1.3",
"babel-plugin-module-resolver": "5.0.0",
"deep-freeze": "0.0.1",
"detox": "20.11.3",
"detox": "20.11.4",
"eslint": "8.47.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.28.0",
@ -177,6 +176,10 @@
"underscore": "1.13.6",
"util": "0.12.5",
"uuid": "9.0.0"
},
"engines": {
"node": "^18.10.0",
"npm": "^9.0.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -3436,9 +3439,9 @@
}
},
"node_modules/@mattermost/compass-icons": {
"version": "0.1.37",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.37.tgz",
"integrity": "sha512-4me1W0hj1nu8A1gpdQA6cij/hyb2P7uIYMJQ+xrNvn5ImTRfQ67LEdyNOa/LY+oT1NO2ui6kKOs8oLUehIaneg=="
"version": "0.1.38",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.38.tgz",
"integrity": "sha512-JfLQJtvxD++7lw+jiLWs55+SOhF8wPQgfTCOEi/uyl9bRxfY736a9fPzRcRJwF80se7lPMxvAx8itwvTz0o7CQ=="
},
"node_modules/@mattermost/react-native-emm": {
"version": "1.3.5",
@ -6169,18 +6172,6 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/@rudderstack/rudder-sdk-react-native": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.8.0.tgz",
"integrity": "sha512-rY7abaXKUOCiJuNufJgP9tKv86/6KYIBPWe/p86HpNmvX4XystyRJDC0n5e26MHAmOasaNELvO5WW/G7sOa8RA==",
"dependencies": {
"async-lock": "1.4.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-native": ">= 0.41.2 < 0.80.0 || ^0.0.0-0"
}
},
"node_modules/@sentry-internal/tracing": {
"version": "7.63.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.63.0.tgz",
@ -6969,9 +6960,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "16.11.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz",
"integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA=="
"version": "16.18.53",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.53.tgz",
"integrity": "sha512-vVmHeo4tpF8zsknALU90Hh24VueYdu45ZlXzYWFbom61YR4avJqTFDC3QlWzjuTdAv6/3xHaxiO9NrtVZXrkmw=="
},
"node_modules/@types/pako": {
"version": "2.0.0",
@ -8305,11 +8296,6 @@
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"node_modules/async-lock": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz",
"integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ=="
},
"node_modules/asynciterator.prototype": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz",
@ -10167,9 +10153,9 @@
}
},
"node_modules/detox": {
"version": "20.11.3",
"resolved": "https://registry.npmjs.org/detox/-/detox-20.11.3.tgz",
"integrity": "sha512-kdoRAtDLFxXpjt1QlniI+WryMtf7Y8mrZ33Ql8cTR9qoCS/CThi4pweYAQm8yUPqAv1ZtT3eIm3EzRwjEosgLA==",
"version": "20.11.4",
"resolved": "https://registry.npmjs.org/detox/-/detox-20.11.4.tgz",
"integrity": "sha512-P48KAtK8qIDOxJKUl4q/syPkuHz67kAeFlNodBZg5aO4hJiH+RsbEkQfJSYkTCeZV800EcmUQwZK2M5amLoYaw==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@ -19121,9 +19107,9 @@
"integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ=="
},
"node_modules/react-native": {
"version": "0.71.11",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.11.tgz",
"integrity": "sha512-++8IxgUe4Ev+bTiFlLfJCdSoE5cReVP1DTpVJ8f/QtzaxA3h1008Y3Xah1Q5vsR4rZcYMO7Pn3af+wOshdQFug==",
"version": "0.71.13",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.13.tgz",
"integrity": "sha512-zEa69YQNLdv8Sf5Pn0CNDB1K9eGuNy1KoMNxXlrZ89JZ8d02b5hihZIoOCCIwhH+iPgslYwr3ZoGd3AY6FMrgw==",
"dependencies": {
"@jest/create-cache-key-function": "^29.2.1",
"@react-native-community/cli": "10.2.4",
@ -19134,6 +19120,7 @@
"@react-native/polyfills": "2.0.0",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
"base64-js": "^1.1.2",
"deprecated-react-native-prop-types": "^3.0.1",
"event-target-shim": "^5.0.1",
@ -25415,9 +25402,9 @@
}
},
"@mattermost/compass-icons": {
"version": "0.1.37",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.37.tgz",
"integrity": "sha512-4me1W0hj1nu8A1gpdQA6cij/hyb2P7uIYMJQ+xrNvn5ImTRfQ67LEdyNOa/LY+oT1NO2ui6kKOs8oLUehIaneg=="
"version": "0.1.38",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.38.tgz",
"integrity": "sha512-JfLQJtvxD++7lw+jiLWs55+SOhF8wPQgfTCOEi/uyl9bRxfY736a9fPzRcRJwF80se7lPMxvAx8itwvTz0o7CQ=="
},
"@mattermost/react-native-emm": {
"version": "1.3.5",
@ -27474,14 +27461,6 @@
}
}
},
"@rudderstack/rudder-sdk-react-native": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.8.0.tgz",
"integrity": "sha512-rY7abaXKUOCiJuNufJgP9tKv86/6KYIBPWe/p86HpNmvX4XystyRJDC0n5e26MHAmOasaNELvO5WW/G7sOa8RA==",
"requires": {
"async-lock": "1.4.0"
}
},
"@sentry-internal/tracing": {
"version": "7.63.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.63.0.tgz",
@ -28052,9 +28031,9 @@
"dev": true
},
"@types/node": {
"version": "16.11.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz",
"integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA=="
"version": "16.18.53",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.53.tgz",
"integrity": "sha512-vVmHeo4tpF8zsknALU90Hh24VueYdu45ZlXzYWFbom61YR4avJqTFDC3QlWzjuTdAv6/3xHaxiO9NrtVZXrkmw=="
},
"@types/pako": {
"version": "2.0.0",
@ -29036,11 +29015,6 @@
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"async-lock": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz",
"integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ=="
},
"asynciterator.prototype": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz",
@ -30409,9 +30383,9 @@
"dev": true
},
"detox": {
"version": "20.11.3",
"resolved": "https://registry.npmjs.org/detox/-/detox-20.11.3.tgz",
"integrity": "sha512-kdoRAtDLFxXpjt1QlniI+WryMtf7Y8mrZ33Ql8cTR9qoCS/CThi4pweYAQm8yUPqAv1ZtT3eIm3EzRwjEosgLA==",
"version": "20.11.4",
"resolved": "https://registry.npmjs.org/detox/-/detox-20.11.4.tgz",
"integrity": "sha512-P48KAtK8qIDOxJKUl4q/syPkuHz67kAeFlNodBZg5aO4hJiH+RsbEkQfJSYkTCeZV800EcmUQwZK2M5amLoYaw==",
"dev": true,
"requires": {
"ajv": "^8.6.3",
@ -37050,9 +37024,9 @@
"integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ=="
},
"react-native": {
"version": "0.71.11",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.11.tgz",
"integrity": "sha512-++8IxgUe4Ev+bTiFlLfJCdSoE5cReVP1DTpVJ8f/QtzaxA3h1008Y3Xah1Q5vsR4rZcYMO7Pn3af+wOshdQFug==",
"version": "0.71.13",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.13.tgz",
"integrity": "sha512-zEa69YQNLdv8Sf5Pn0CNDB1K9eGuNy1KoMNxXlrZ89JZ8d02b5hihZIoOCCIwhH+iPgslYwr3ZoGd3AY6FMrgw==",
"requires": {
"@jest/create-cache-key-function": "^29.2.1",
"@react-native-community/cli": "10.2.4",
@ -37063,6 +37037,7 @@
"@react-native/polyfills": "2.0.0",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
"base64-js": "^1.1.2",
"deprecated-react-native-prop-types": "^3.0.1",
"event-target-shim": "^5.0.1",

View file

@ -1,11 +1,15 @@
{
"name": "mattermost-mobile",
"version": "2.8.0",
"version": "2.9.0",
"description": "Mattermost Mobile with React Native",
"repository": "git@github.com:mattermost/mattermost-mobile.git",
"author": "Mattermost, Inc.",
"license": "Apache 2.0",
"private": true,
"engines": {
"node": "^18.10.0",
"npm": "^9.0.0"
},
"dependencies": {
"@formatjs/intl-datetimeformat": "6.10.0",
"@formatjs/intl-getcanonicallocales": "2.2.1",
@ -15,7 +19,7 @@
"@formatjs/intl-relativetimeformat": "11.2.4",
"@gorhom/bottom-sheet": "4.4.7",
"@mattermost/calls": "github:mattermost/calls-common#v0.17.0",
"@mattermost/compass-icons": "0.1.37",
"@mattermost/compass-icons": "0.1.38",
"@mattermost/react-native-emm": "1.3.5",
"@mattermost/react-native-network-client": "1.4.1",
"@mattermost/react-native-paste-input": "0.6.4",
@ -33,7 +37,6 @@
"@react-navigation/bottom-tabs": "6.5.8",
"@react-navigation/native": "6.1.7",
"@react-navigation/stack": "6.3.17",
"@rudderstack/rudder-sdk-react-native": "1.8.0",
"@sentry/react-native": "5.9.0",
"@stream-io/flat-list-mvcp": "0.10.3",
"@tsconfig/react-native": "3.0.2",
@ -52,7 +55,7 @@
"react": "18.2.0",
"react-freeze": "1.0.3",
"react-intl": "6.4.4",
"react-native": "0.71.11",
"react-native": "0.71.13",
"react-native-android-open-settings": "1.3.0",
"react-native-background-timer": "2.4.1",
"react-native-button": "3.1.0",
@ -148,7 +151,7 @@
"babel-loader": "9.1.3",
"babel-plugin-module-resolver": "5.0.0",
"deep-freeze": "0.0.1",
"detox": "20.11.3",
"detox": "20.11.4",
"eslint": "8.47.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.28.0",
@ -198,6 +201,7 @@
"pod-install": "react-native setup-ios-permissions && cd ios && pod install",
"pod-install-m1": "react-native setup-ios-permissions && cd ios && arch -x86_64 pod install",
"postinstall": "patch-package && ./scripts/postinstall.sh",
"prepare": "husky install",
"preinstall": "./scripts/preinstall.sh && npx solidarity",
"start": "react-native start",
"test": "jest --forceExit --runInBand",

View file

@ -1,106 +0,0 @@
diff --git a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
index 0c2ecf2..a04414f 100644
--- a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
+++ b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
@@ -1819,9 +1819,14 @@ class ScrollView extends React.Component<Props, State> {
// Note: we should split props.style on the inner and outer props
// however, the ScrollView still needs the baseStyle to be scrollable
const {outer, inner} = splitLayoutProps(flattenStyle(props.style));
+ let inverted;
+ if (inner.scaleY) {
+ inverted = {scaleY: -1};
+ delete inner['scaleY']
+ }
return React.cloneElement(
refreshControl,
- {style: StyleSheet.compose(baseStyle, outer)},
+ {style: StyleSheet.compose(baseStyle, outer, inverted)},
<NativeDirectionalScrollView
{...props}
style={StyleSheet.compose(baseStyle, inner)}
diff --git a/node_modules/react-native/Libraries/Lists/VirtualizedList.js b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
index 2629142..bcc5386 100644
--- a/node_modules/react-native/Libraries/Lists/VirtualizedList.js
+++ b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
@@ -30,6 +30,7 @@ import flattenStyle from '../StyleSheet/flattenStyle';
import StyleSheet from '../StyleSheet/StyleSheet';
import clamp from '../Utilities/clamp';
import infoLog from '../Utilities/infoLog';
+import Platform from '../Utilities/Platform';
import {CellRenderMask} from './CellRenderMask';
import ChildListCollection from './ChildListCollection';
import FillRateHelper from './FillRateHelper';
@@ -1841,7 +1842,10 @@ export default class VirtualizedList extends StateSafePureComponent<
const styles = StyleSheet.create({
verticallyInverted: {
- transform: [{scaleY: -1}],
+ ...Platform.select({
+ android: {scaleY: -1},
+ ios: {transform: [{scaleY: -1}]},
+ }),
},
horizontallyInverted: {
transform: [{scaleX: -1}],
diff --git a/node_modules/react-native/jest/react-native-env.js b/node_modules/react-native/jest/react-native-env.js
index 624d364..bb09c57 100644
--- a/node_modules/react-native/jest/react-native-env.js
+++ b/node_modules/react-native/jest/react-native-env.js
@@ -13,6 +13,6 @@ const NodeEnv = require('jest-environment-node').TestEnvironment;
module.exports = class ReactNativeEnv extends NodeEnv {
exportConditions() {
- return ['react-native'];
+ return ['react-native', 'node'];
}
};
diff --git a/node_modules/react-native/jest/setup.js b/node_modules/react-native/jest/setup.js
index 3738bd2..547e0c0 100644
--- a/node_modules/react-native/jest/setup.js
+++ b/node_modules/react-native/jest/setup.js
@@ -21,6 +21,7 @@ global.performance = {
now: jest.fn(Date.now),
};
+global.Promise = jest.requireActual('promise');
global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime');
global.window = global;
diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle
index 250299b..6e8e6a0 100644
--- a/node_modules/react-native/react.gradle
+++ b/node_modules/react-native/react.gradle
@@ -159,7 +159,7 @@ def enableHermesForVariant = config.enableHermesForVariant ?: {
def hermesFlagsForVariant = config.hermesFlagsForVariant ?: {
def variant ->
def hermesFlags;
- if (variant.name.toLowerCase().contains("release")) {
+ if (variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")) {
// Can't use ?: since that will also substitute valid empty lists
hermesFlags = config.hermesFlagsRelease
if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"]
@@ -175,7 +175,7 @@ def hermesFlagsForVariant = config.hermesFlagsForVariant ?: {
def disableDevForVariant = config.disableDevForVariant ?: {
def variant ->
config."devDisabledIn${variant.name.capitalize()}" ||
- variant.name.toLowerCase().contains("release")
+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
// Set bundleForVariant to a function to configure per variant,
@@ -184,13 +184,13 @@ def bundleForVariant = config.bundleForVariant ?: {
def variant ->
config."bundleIn${variant.name.capitalize()}" ||
config."bundleIn${variant.buildType.name.capitalize()}" ||
- variant.name.toLowerCase().contains("release")
+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
// Set deleteDebugFilesForVariant to a function to configure per variant,
// defaults to True for Release variants and False for debug variants
def deleteDebugFilesForVariant = config.deleteDebugFilesForVariant ?: {
- def variant -> variant.name.toLowerCase().contains("release")
+ def variant -> variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
android {

View file

@ -0,0 +1,341 @@
diff --git a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
index 0c2ecf2..a04414f 100644
--- a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
+++ b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js
@@ -1819,9 +1819,14 @@ class ScrollView extends React.Component<Props, State> {
// Note: we should split props.style on the inner and outer props
// however, the ScrollView still needs the baseStyle to be scrollable
const {outer, inner} = splitLayoutProps(flattenStyle(props.style));
+ let inverted;
+ if (inner.scaleY) {
+ inverted = {scaleY: -1};
+ delete inner['scaleY']
+ }
return React.cloneElement(
refreshControl,
- {style: StyleSheet.compose(baseStyle, outer)},
+ {style: StyleSheet.compose(baseStyle, outer, inverted)},
<NativeDirectionalScrollView
{...props}
style={StyleSheet.compose(baseStyle, inner)}
diff --git a/node_modules/react-native/Libraries/Lists/VirtualizedList.js b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
index 4534330..2c6487f 100644
--- a/node_modules/react-native/Libraries/Lists/VirtualizedList.js
+++ b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
@@ -30,6 +30,7 @@ import flattenStyle from '../StyleSheet/flattenStyle';
import StyleSheet from '../StyleSheet/StyleSheet';
import clamp from '../Utilities/clamp';
import infoLog from '../Utilities/infoLog';
+import Platform from '../Utilities/Platform';
import {CellRenderMask} from './CellRenderMask';
import ChildListCollection from './ChildListCollection';
import FillRateHelper from './FillRateHelper';
@@ -1847,7 +1848,10 @@ export default class VirtualizedList extends StateSafePureComponent<
const styles = StyleSheet.create({
verticallyInverted: {
- transform: [{scaleY: -1}],
+ ...Platform.select({
+ android: {scaleY: -1},
+ ios: {transform: [{scaleY: -1}]},
+ }),
},
horizontallyInverted: {
transform: [{scaleX: -1}],
diff --git a/node_modules/react-native/jest/react-native-env.js b/node_modules/react-native/jest/react-native-env.js
index 624d364..bb09c57 100644
--- a/node_modules/react-native/jest/react-native-env.js
+++ b/node_modules/react-native/jest/react-native-env.js
@@ -13,6 +13,6 @@ const NodeEnv = require('jest-environment-node').TestEnvironment;
module.exports = class ReactNativeEnv extends NodeEnv {
exportConditions() {
- return ['react-native'];
+ return ['react-native', 'node'];
}
};
diff --git a/node_modules/react-native/jest/setup.js b/node_modules/react-native/jest/setup.js
index 3738bd2..547e0c0 100644
--- a/node_modules/react-native/jest/setup.js
+++ b/node_modules/react-native/jest/setup.js
@@ -21,6 +21,7 @@ global.performance = {
now: jest.fn(Date.now),
};
+global.Promise = jest.requireActual('promise');
global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime');
global.window = global;
diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle
index 250299b..6e8e6a0 100644
--- a/node_modules/react-native/react.gradle
+++ b/node_modules/react-native/react.gradle
@@ -159,7 +159,7 @@ def enableHermesForVariant = config.enableHermesForVariant ?: {
def hermesFlagsForVariant = config.hermesFlagsForVariant ?: {
def variant ->
def hermesFlags;
- if (variant.name.toLowerCase().contains("release")) {
+ if (variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")) {
// Can't use ?: since that will also substitute valid empty lists
hermesFlags = config.hermesFlagsRelease
if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"]
@@ -175,7 +175,7 @@ def hermesFlagsForVariant = config.hermesFlagsForVariant ?: {
def disableDevForVariant = config.disableDevForVariant ?: {
def variant ->
config."devDisabledIn${variant.name.capitalize()}" ||
- variant.name.toLowerCase().contains("release")
+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
// Set bundleForVariant to a function to configure per variant,
@@ -184,13 +184,13 @@ def bundleForVariant = config.bundleForVariant ?: {
def variant ->
config."bundleIn${variant.name.capitalize()}" ||
config."bundleIn${variant.buildType.name.capitalize()}" ||
- variant.name.toLowerCase().contains("release")
+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
// Set deleteDebugFilesForVariant to a function to configure per variant,
// defaults to True for Release variants and False for debug variants
def deleteDebugFilesForVariant = config.deleteDebugFilesForVariant ?: {
- def variant -> variant.name.toLowerCase().contains("release")
+ def variant -> variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")
}
android {
diff --git a/node_modules/react-native/scripts/cocoapods/helpers.rb b/node_modules/react-native/scripts/cocoapods/helpers.rb
index 03e3a5c..f3ae5a1 100644
--- a/node_modules/react-native/scripts/cocoapods/helpers.rb
+++ b/node_modules/react-native/scripts/cocoapods/helpers.rb
@@ -11,6 +11,22 @@ class SysctlChecker
end
end
+# Helper class that is used to easily send commands to Xcodebuild
+# And that can be subclassed for testing purposes.
+class Xcodebuild
+ def self.version
+ `xcodebuild -version`
+ end
+end
+
+module Helpers
+ class Constants
+ def self.min_ios_version_supported
+ return '13.4'
+ end
+ end
+end
+
# Helper object to wrap system properties like RUBY_PLATFORM
# This makes it easier to mock the behaviour in tests
class Environment
diff --git a/node_modules/react-native/scripts/cocoapods/utils.rb b/node_modules/react-native/scripts/cocoapods/utils.rb
index df23da4..0560567 100644
--- a/node_modules/react-native/scripts/cocoapods/utils.rb
+++ b/node_modules/react-native/scripts/cocoapods/utils.rb
@@ -131,15 +131,29 @@ class ReactNativePodsUtils
end
end
- def self.apply_xcode_15_patch(installer)
- installer.target_installation_results.pod_target_installation_results
- .each do |pod_name, target_installation_result|
- target_installation_result.native_target.build_configurations.each do |config|
- # unary_function and binary_function are no longer provided in C++17 and newer standard modes as part of Xcode 15. They can be re-enabled with setting _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
- # Ref: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Deprecations
- config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= '$(inherited) '
- config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << '"_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION" '
+ def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild)
+ projects = self.extract_projects(installer)
+
+ gcc_preprocessor_definition_key = 'GCC_PREPROCESSOR_DEFINITIONS'
+ other_ld_flags_key = 'OTHER_LDFLAGS'
+ libcpp_cxx17_fix = '_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION'
+ xcode15_compatibility_flags = '-Wl -ld_classic '
+
+ projects.each do |project|
+ project.build_configurations.each do |config|
+ # fix for unary_function and binary_function
+ self.safe_init(config, gcc_preprocessor_definition_key)
+ self.add_value_to_setting_if_missing(config, gcc_preprocessor_definition_key, libcpp_cxx17_fix)
+
+ # fix for weak linking
+ self.safe_init(config, other_ld_flags_key)
+ if self.is_using_xcode15_or_greter(:xcodebuild_manager => xcodebuild_manager)
+ self.add_value_to_setting_if_missing(config, other_ld_flags_key, xcode15_compatibility_flags)
+ else
+ self.remove_value_to_setting_if_present(config, other_ld_flags_key, xcode15_compatibility_flags)
+ end
end
+ project.save()
end
end
@@ -197,4 +211,89 @@ class ReactNativePodsUtils
ENV['USE_FRAMEWORKS'] = nil
end
end
+
+ # ========= #
+ # Utilities #
+ # ========= #
+
+ def self.extract_projects(installer)
+ return installer.aggregate_targets
+ .map{ |t| t.user_project }
+ .uniq{ |p| p.path }
+ .push(installer.pods_project)
+ end
+
+ def self.safe_init(config, setting_name)
+ old_config = config.build_settings[setting_name]
+ if old_config == nil
+ config.build_settings[setting_name] ||= '$(inherited) '
+ end
+ end
+
+ def self.add_value_to_setting_if_missing(config, setting_name, value)
+ old_config = config.build_settings[setting_name]
+ if !old_config.include?(value)
+ config.build_settings[setting_name] << value
+ end
+ end
+
+ def self.remove_value_to_setting_if_present(config, setting_name, value)
+ old_config = config.build_settings[setting_name]
+ if old_config.include?(value)
+ # Old config can be either an Array or a String
+ if old_config.is_a?(Array)
+ old_config = old_config.join(" ")
+ end
+ new_config = old_config.gsub(value, "")
+ config.build_settings[setting_name] = new_config
+ end
+ end
+
+ def self.is_using_xcode15_or_greter(xcodebuild_manager: Xcodebuild)
+ xcodebuild_version = xcodebuild_manager.version
+
+ # The output of xcodebuild -version is something like
+ # Xcode 15.0
+ # or
+ # Xcode 14.3.1
+ # We want to capture the version digits
+ regex = /(\d+)\.(\d+)(?:\.(\d+))?/
+ if match_data = xcodebuild_version.match(regex)
+ major = match_data[1].to_i
+ return major >= 15
+ end
+
+ return false
+ end
+
+ def self.updateIphoneOSDeploymentTarget(installer)
+ pod_to_update = Set.new([
+ "boost",
+ "CocoaAsyncSocket",
+ "Flipper",
+ "Flipper-DoubleConversion",
+ "Flipper-Fmt",
+ "Flipper-Boost-iOSX",
+ "Flipper-Folly",
+ "Flipper-Glog",
+ "Flipper-PeerTalk",
+ "FlipperKit",
+ "fmt",
+ "libevent",
+ "OpenSSL-Universal",
+ "RCT-Folly",
+ "SocketRocket",
+ "YogaKit"
+ ])
+
+ installer.target_installation_results.pod_target_installation_results
+ .each do |pod_name, target_installation_result|
+ unless pod_to_update.include?(pod_name)
+ next
+ end
+ target_installation_result.native_target.build_configurations.each do |config|
+ config.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = Helpers::Constants.min_ios_version_supported
+ end
+ end
+ end
end
diff --git a/node_modules/react-native/scripts/react_native_pods.rb b/node_modules/react-native/scripts/react_native_pods.rb
index 6be4109..ea4ebaa 100644
--- a/node_modules/react-native/scripts/react_native_pods.rb
+++ b/node_modules/react-native/scripts/react_native_pods.rb
@@ -27,7 +27,7 @@ $START_TIME = Time.now.to_i
# By using this function, you won't have to manualy change your Podfile
# when we change the minimum version supported by the framework.
def min_ios_version_supported
- return '12.4'
+ return Helpers::Constants.min_ios_version_supported
end
# This function prepares the project for React Native, before processing
@@ -224,6 +224,7 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re
ReactNativePodsUtils.fix_library_search_paths(installer)
ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)
ReactNativePodsUtils.apply_xcode_15_patch(installer)
+ ReactNativePodsUtils.updateIphoneOSDeploymentTarget(installer)
NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer)
is_new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == "1"
diff --git a/node_modules/react-native/sdks/hermes-engine/utils/build-apple-framework.sh b/node_modules/react-native/sdks/hermes-engine/utils/build-apple-framework.sh
index 87faae6..caae918 100755
--- a/node_modules/react-native/sdks/hermes-engine/utils/build-apple-framework.sh
+++ b/node_modules/react-native/sdks/hermes-engine/utils/build-apple-framework.sh
@@ -52,7 +52,7 @@ function build_host_hermesc {
# Utility function to configure an Apple framework
function configure_apple_framework {
- local build_cli_tools enable_bitcode enable_debugger cmake_build_type
+ local build_cli_tools enable_bitcode enable_debugger cmake_build_type xcode_15_flags xcode_major_version
if [[ $1 == iphoneos || $1 == catalyst ]]; then
enable_bitcode="true"
@@ -77,8 +77,15 @@ function configure_apple_framework {
cmake_build_type="MinSizeRel"
fi
+ xcode_15_flags=""
+ xcode_major_version=$(xcodebuild -version | grep -oE '[0-9]*' | head -n 1)
+ if [[ $xcode_major_version -ge 15 ]]; then
+ xcode_15_flags="LINKER:-ld_classic"
+ fi
+
pushd "$HERMES_PATH" > /dev/null || exit 1
cmake -S . -B "build_$1" \
+ -DHERMES_EXTRA_LINKER_FLAGS="$xcode_15_flags" \
-DHERMES_APPLE_TARGET_PLATFORM:STRING="$1" \
-DCMAKE_OSX_ARCHITECTURES:STRING="$2" \
-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="$3" \
diff --git a/node_modules/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh b/node_modules/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh
index 37faee3..fa2ebe9 100755
--- a/node_modules/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh
+++ b/node_modules/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh
@@ -33,6 +33,13 @@ if [ -z "$deployment_target" ]; then
deployment_target=${MACOSX_DEPLOYMENT_TARGET}
fi
+xcode_15_flags=""
+xcode_major_version=$(xcodebuild -version | grep -oE '[0-9]*' | head -n 1)
+if [[ $xcode_major_version -ge 15 ]]; then
+ echo "########### Using LINKER:-ld_classic ###########"
+ xcode_15_flags="LINKER:-ld_classic"
+fi
+
architectures=$( echo "$ARCHS" | tr " " ";" )
echo "Configure Apple framework"
@@ -40,6 +47,7 @@ echo "Configure Apple framework"
"$CMAKE_BINARY" \
-S "${PODS_ROOT}/hermes-engine" \
-B "${PODS_ROOT}/hermes-engine/build/${PLATFORM_NAME}" \
+ -DHERMES_EXTRA_LINKER_FLAGS="$xcode_15_flags" \
-DHERMES_APPLE_TARGET_PLATFORM:STRING="$PLATFORM_NAME" \
-DCMAKE_OSX_ARCHITECTURES:STRING="$architectures" \
-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="$deployment_target" \

View file

@ -1,5 +1,5 @@
diff --git a/node_modules/react-native-fast-image/RNFastImage.podspec b/node_modules/react-native-fast-image/RNFastImage.podspec
index db0fada..9a2457c 100644
index db0fada..8469b1a 100644
--- a/node_modules/react-native-fast-image/RNFastImage.podspec
+++ b/node_modules/react-native-fast-image/RNFastImage.podspec
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
@ -7,8 +7,9 @@ index db0fada..9a2457c 100644
s.dependency 'React-Core'
- s.dependency 'SDWebImage', '~> 5.11.1'
+ s.dependency 'SDWebImage', '~> 5.12.3'
s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
- s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
+ s.dependency 'SDWebImage', '~> 5.18.2'
+ s.dependency 'SDWebImageWebPCoder', '~> 0.13.0'
end
diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageCookieJar.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageCookieJar.java
new file mode 100644
@ -74,7 +75,7 @@ index 811292a..79291fa 100644
.build();
OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client);
diff --git a/node_modules/react-native-fast-image/dist/index.d.ts b/node_modules/react-native-fast-image/dist/index.d.ts
index 5abb7c9..db5a1d3 100644
index 5abb7c9..b210637 100644
--- a/node_modules/react-native-fast-image/dist/index.d.ts
+++ b/node_modules/react-native-fast-image/dist/index.d.ts
@@ -43,13 +43,13 @@ export interface ImageStyle extends FlexStyle, TransformsStyle, ShadowStyleIOS {

View file

@ -413,6 +413,43 @@ index 1333a10..b908006 100644
RCT_EXPORT_METHOD(getNativeProps:(nonnull NSNumber *)reactTag resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:
diff --git a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m b/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
index e472679..4a2204b 100644
--- a/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
+++ b/node_modules/react-native-keyboard-tracking-view/lib/ObservingInputAccessoryView.m
@@ -115,21 +115,25 @@
- (void)_keyboardWillShowNotification:(NSNotification*)notification
{
- _keyboardState = KeyboardStateWillShow;
+ if (_keyboardState != KeyboardStateShown) {
+ _keyboardState = KeyboardStateWillShow;
- [self invalidateIntrinsicContentSize];
+ [self invalidateIntrinsicContentSize];
- if([_delegate respondsToSelector:@selector(observingInputAccessoryViewKeyboardWillAppear:keyboardDelta:)])
- {
- [_delegate observingInputAccessoryViewKeyboardWillAppear:self keyboardDelta:_keyboardHeight - _previousKeyboardHeight];
+ if([_delegate respondsToSelector:@selector(observingInputAccessoryViewKeyboardWillAppear:keyboardDelta:)])
+ {
+ [_delegate observingInputAccessoryViewKeyboardWillAppear:self keyboardDelta:_keyboardHeight - _previousKeyboardHeight];
+ }
}
}
- (void)_keyboardDidShowNotification:(NSNotification*)notification
{
- _keyboardState = KeyboardStateShown;
+ if (_keyboardState != KeyboardStateShown) {
+ _keyboardState = KeyboardStateShown;
- [self invalidateIntrinsicContentSize];
+ [self invalidateIntrinsicContentSize];
+ }
}
- (void)_keyboardWillHideNotification:(NSNotification*)notification
diff --git a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js b/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js
index af15edf..20b6ab6 100644
--- a/node_modules/react-native-keyboard-tracking-view/src/KeyboardTrackingView.android.js

View file

@ -186,7 +186,7 @@ diff --git a/node_modules/react-native-navigation/lib/ios/RNNComponentViewContro
index fc482a6..9406bbf 100644
--- a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m
+++ b/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m
@@ -94,6 +94,7 @@
@@ -94,6 +94,7 @@ - (void)renderReactViewIfNeeded {
}];
}];
self.reactView.backgroundColor = UIColor.clearColor;
@ -207,7 +207,7 @@ index b44f24f..bf4e1c3 100644
@implementation RNNOverlayWindow
@@ -9,6 +11,8 @@
@@ -9,6 +11,8 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([hitTestResult isKindOfClass:[UIWindow class]] ||
[hitTestResult.subviews.firstObject isKindOfClass:RNNReactView.class] ||
@ -216,6 +216,41 @@ index b44f24f..bf4e1c3 100644
[hitTestResult isKindOfClass:[RCTModalHostView class]] ||
[hitTestResult isKindOfClass:NSClassFromString(@"RCTRootComponentView")]) {
return nil;
diff --git a/node_modules/react-native-navigation/lib/ios/RNNUIBarButtonItem.m b/node_modules/react-native-navigation/lib/ios/RNNUIBarButtonItem.m
index ece1da1..26730ae 100644
--- a/node_modules/react-native-navigation/lib/ios/RNNUIBarButtonItem.m
+++ b/node_modules/react-native-navigation/lib/ios/RNNUIBarButtonItem.m
@@ -87,9 +87,28 @@ - (instancetype)initWithCustomView:(RNNReactView *)reactView
buttonOptions:(RNNButtonOptions *)buttonOptions
onPress:(RNNButtonPressCallback)onPress {
self = [super initWithCustomView:reactView];
- [reactView setFrame:CGRectMake(0, 0, 50, 50)];
[self applyOptions:buttonOptions];
-
+ reactView.sizeFlexibility = RCTRootViewSizeFlexibilityWidthAndHeight;
+ reactView.hidden = CGRectEqualToRect(reactView.frame, CGRectZero);
+
+ [NSLayoutConstraint deactivateConstraints:reactView.constraints];
+ self.widthConstraint =
+ [NSLayoutConstraint constraintWithItem:reactView
+ attribute:NSLayoutAttributeWidth
+ relatedBy:NSLayoutRelationEqual
+ toItem:nil
+ attribute:NSLayoutAttributeNotAnAttribute
+ multiplier:1.0
+ constant:reactView.intrinsicContentSize.width];
+ self.heightConstraint =
+ [NSLayoutConstraint constraintWithItem:reactView
+ attribute:NSLayoutAttributeHeight
+ relatedBy:NSLayoutRelationEqual
+ toItem:nil
+ attribute:NSLayoutAttributeNotAnAttribute
+ multiplier:1.0
+ constant:reactView.intrinsicContentSize.height];
+ [NSLayoutConstraint activateConstraints:@[ self.widthConstraint, self.heightConstraint ]];
reactView.delegate = self;
reactView.backgroundColor = [UIColor clearColor];
diff --git a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts b/node_modules/react-native-navigation/lib/src/interfaces/Options.ts
index 4851b40..e891183 100644
--- a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts

View file

@ -4,7 +4,7 @@
import DatabaseProvider from '@nozbe/watermelondb/DatabaseProvider';
import {render} from '@testing-library/react-native';
import React, {type ReactElement} from 'react';
import {createIntl, IntlProvider} from 'react-intl';
import {IntlProvider} from 'react-intl';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {ThemeContext, getDefaultThemeByAppearance} from '@context/theme';
@ -12,13 +12,6 @@ import {getTranslations} from '@i18n';
import type Database from '@nozbe/watermelondb/Database';
export function getIntlShape(locale = 'en') {
return createIntl({
locale,
messages: getTranslations(locale),
});
}
export function renderWithIntl(ui: ReactElement, {locale = 'en', ...renderOptions} = {}) {
function Wrapper({children}: {children: ReactElement}) {
return (