commit
61c64a3837
33
.eslintrc.js
33
.eslintrc.js
|
@ -156,22 +156,6 @@ module.exports = {
|
|||
__DEV__: true
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['e2e/**'],
|
||||
globals: {
|
||||
by: true,
|
||||
detox: true,
|
||||
device: true,
|
||||
element: true,
|
||||
expect: true,
|
||||
waitFor: true
|
||||
},
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'no-await-in-loop': 0,
|
||||
'no-restricted-syntax': 0
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
extends: [
|
||||
|
@ -253,6 +237,23 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['e2e/**'],
|
||||
globals: {
|
||||
by: true,
|
||||
detox: true,
|
||||
device: true,
|
||||
element: true,
|
||||
waitFor: true
|
||||
},
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'no-await-in-loop': 0,
|
||||
'no-restricted-syntax': 0,
|
||||
// TODO: remove this rule when update Detox to 20 and test if the namespace Detox is available
|
||||
'no-undef': 1
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -66,5 +66,6 @@ artifacts
|
|||
e2e/docker/rc_test_env/docker-compose.yml
|
||||
e2e/docker/data/db
|
||||
e2e/e2e_account.js
|
||||
e2e/e2e_account.ts
|
||||
|
||||
*.p8
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots SearchBox Basic 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"padding\\":14,\\"borderWidth\\":0.5,\\"borderRadius\\":2},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"underlineColorAndroid\\":\\"transparent\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"value\\":\\"\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#2f343d\\"},[{\\"position\\":\\"absolute\\",\\"top\\":14},{\\"right\\":15}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
|
||||
exports[`Storyshots SearchBox Basic 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\",\\"style\\":{\\"backgroundColor\\":\\"#ffffff\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\",\\"justifyContent\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"padding\\":14,\\"borderWidth\\":2,\\"borderRadius\\":2},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"underlineColorAndroid\\":\\"transparent\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"value\\":\\"\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#2f343d\\"},[{\\"position\\":\\"absolute\\"},{\\"right\\":15}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -147,7 +147,7 @@ android {
|
|||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode VERSIONCODE as Integer
|
||||
versionName "4.30.0"
|
||||
versionName "4.31.0"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
if (!isFoss) {
|
||||
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
|
@ -35,8 +37,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
|
||||
public class CustomPushNotification extends PushNotification {
|
||||
public static ReactApplicationContext reactApplicationContext;
|
||||
final NotificationManager notificationManager;
|
||||
|
@ -322,7 +322,12 @@ public class CustomPushNotification extends PushNotification {
|
|||
replyIntent.setAction(KEY_REPLY);
|
||||
replyIntent.putExtra("pushNotification", bundle);
|
||||
|
||||
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
PendingIntent replyPendingIntent;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
replyPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||
} else {
|
||||
replyPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
RemoteInput remoteInput = new RemoteInput.Builder(KEY_REPLY)
|
||||
.setLabel(label)
|
||||
|
@ -343,7 +348,7 @@ public class CustomPushNotification extends PushNotification {
|
|||
Intent intent = new Intent(mContext, DismissNotification.class);
|
||||
intent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
|
||||
PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, 0);
|
||||
PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
notification.setDeleteIntent(dismissPendingIntent);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@ buildscript {
|
|||
buildToolsVersion = "31.0.0"
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 31
|
||||
// TODO: Fix "android:exported" issue and target 31 again
|
||||
targetSdkVersion = 30
|
||||
targetSdkVersion = 31
|
||||
if (System.properties['os.arch'] == "aarch64") {
|
||||
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
||||
ndkVersion = "24.0.8215888"
|
||||
|
@ -27,8 +26,8 @@ buildscript {
|
|||
kotlinVersion = '1.6.10'
|
||||
supportLibVersion = "28.0.0"
|
||||
libre_build = !(isPlay.toBoolean())
|
||||
jitsi_url = isPlay ? "https://github.com/RocketChat/jitsi-maven-repository/raw/master/releases" : "https://github.com/RocketChat/jitsi-maven-repository/raw/libre/releases"
|
||||
jitsi_version = isPlay ? "3.6.0" : "3.6.0-libre"
|
||||
jitsi_url = "https://github.com/RocketChat/jitsi-maven-repository/raw/master/releases"
|
||||
jitsi_version = "3.7.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { PADDING_HORIZONTAL } from './constants';
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingBottom: 12,
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: PADDING_HORIZONTAL
|
||||
},
|
||||
title: {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Header } from '.';
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginVertical: 16
|
||||
marginBottom: 16
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@ import { StyleSheet } from 'react-native';
|
|||
|
||||
export const styles = StyleSheet.create({
|
||||
contentContainerStyleFlatList: {
|
||||
paddingVertical: 32
|
||||
paddingVertical: 16
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
import { StyleSheet, TextInputProps, View } from 'react-native';
|
||||
|
||||
import { useTheme } from '../../theme';
|
||||
import I18n from '../../i18n';
|
||||
import { FormTextInput } from '../TextInput';
|
||||
|
||||
|
@ -14,13 +15,15 @@ const styles = StyleSheet.create({
|
|||
const SearchBox = ({ onChangeText, onSubmitEditing, testID }: TextInputProps): JSX.Element => {
|
||||
const [text, setText] = useState('');
|
||||
|
||||
const { colors } = useTheme();
|
||||
|
||||
const internalOnChangeText = useCallback(value => {
|
||||
setText(value);
|
||||
onChangeText?.(value);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View testID='searchbox'>
|
||||
<View testID='searchbox' style={{ backgroundColor: colors.backgroundColor }}>
|
||||
<FormTextInput
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
|
|
|
@ -27,7 +27,7 @@ const styles = StyleSheet.create({
|
|||
height: 48,
|
||||
fontSize: 16,
|
||||
padding: 14,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderWidth: 2,
|
||||
borderRadius: 2
|
||||
},
|
||||
inputIconLeft: {
|
||||
|
@ -37,11 +37,11 @@ const styles = StyleSheet.create({
|
|||
paddingRight: 45
|
||||
},
|
||||
wrap: {
|
||||
position: 'relative'
|
||||
position: 'relative',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
iconContainer: {
|
||||
position: 'absolute',
|
||||
top: 14
|
||||
position: 'absolute'
|
||||
},
|
||||
iconLeft: {
|
||||
left: 15
|
||||
|
@ -98,7 +98,7 @@ export const FormTextInput = ({
|
|||
style={[
|
||||
styles.input,
|
||||
iconLeft && styles.inputIconLeft,
|
||||
(secureTextEntry || iconRight) && styles.inputIconRight,
|
||||
(secureTextEntry || iconRight || showClearInput) && styles.inputIconRight,
|
||||
{
|
||||
backgroundColor: colors.backgroundColor,
|
||||
borderColor: colors.separatorColor,
|
||||
|
|
|
@ -27,3 +27,44 @@ export const ShortAndLong = () => (
|
|||
</View>
|
||||
</>
|
||||
);
|
||||
export const Icons = () => (
|
||||
<>
|
||||
<View style={styles.paddingHorizontal}>
|
||||
<FormTextInput label='Right icon' placeholder='placeholder' value={item.name} iconRight={'close'} />
|
||||
<FormTextInput label='Left icon' placeholder='placeholder' value={item.longText} iconLeft={'mail'} />
|
||||
<FormTextInput label='Both icons' placeholder='placeholder' value={item.longText} iconLeft={'mail'} iconRight={'add'} />
|
||||
<FormTextInput
|
||||
label='Icon and touchable clear input'
|
||||
placeholder='placeholder'
|
||||
value={item.longText}
|
||||
onClearInput={() => {}}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Multiline = () => (
|
||||
<>
|
||||
<View style={styles.paddingHorizontal}>
|
||||
<FormTextInput label='Multiline text' placeholder='placeholder' multiline value={`${item.name}\n\n${item.longText}\n`} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
export const SecureTextEntry = () => (
|
||||
<>
|
||||
<View style={styles.paddingHorizontal}>
|
||||
<FormTextInput label='Secure text disabled' placeholder='placeholder' value={item.name} />
|
||||
<FormTextInput label='Secure text enabled' placeholder='placeholder' value={item.name} secureTextEntry />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Loading = () => (
|
||||
<>
|
||||
<View style={styles.paddingHorizontal}>
|
||||
<FormTextInput label='Loading false' placeholder='placeholder' value={item.name} loading={false} />
|
||||
<FormTextInput label='Loading true' placeholder='placeholder' value={item.name} loading />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ const styles = StyleSheet.create({
|
|||
input: {
|
||||
height: 48,
|
||||
paddingLeft: 16,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderWidth: 2,
|
||||
borderRadius: 2,
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
|
|
|
@ -35,7 +35,7 @@ export default StyleSheet.create({
|
|||
minHeight: 48,
|
||||
paddingHorizontal: 8,
|
||||
paddingBottom: 0,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderWidth: 2,
|
||||
borderRadius: 2,
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
|
|
|
@ -19,7 +19,7 @@ const styles = StyleSheet.create({
|
|||
viewContainer: {
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 16,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderWidth: 2,
|
||||
borderRadius: 2,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
|
|
@ -57,7 +57,7 @@ const AttachedActions = ({ attachment }: { attachment: IAttachment }) => {
|
|||
};
|
||||
|
||||
const Attachments: React.FC<IMessageAttachments> = React.memo(
|
||||
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply }: IMessageAttachments) => {
|
||||
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply, id }: IMessageAttachments) => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
if (!attachments || attachments.length === 0) {
|
||||
|
@ -80,7 +80,15 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
|
|||
|
||||
if (file && file.audio_url) {
|
||||
return (
|
||||
<Audio key={file.audio_url} file={file} getCustomEmoji={getCustomEmoji} isReply={isReply} style={style} theme={theme} />
|
||||
<Audio
|
||||
key={file.audio_url}
|
||||
file={file}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
isReply={isReply}
|
||||
style={style}
|
||||
theme={theme}
|
||||
messageId={id}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -106,7 +114,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
|
|||
);
|
||||
}
|
||||
|
||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />;
|
||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} messageId={id} />;
|
||||
});
|
||||
return <>{attachmentsElements}</>;
|
||||
},
|
||||
|
|
|
@ -36,6 +36,7 @@ interface IMessageAudioProps {
|
|||
theme: TSupportedThemes;
|
||||
getCustomEmoji: TGetCustomEmoji;
|
||||
scale?: number;
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
interface IMessageAudioState {
|
||||
|
@ -128,7 +129,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
|||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { file } = this.props;
|
||||
const { file, messageId } = this.props;
|
||||
const { baseUrl, user } = this.context;
|
||||
|
||||
let url = file.audio_url;
|
||||
|
@ -139,7 +140,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
|||
this.setState({ loading: true });
|
||||
try {
|
||||
if (url) {
|
||||
const audio = await downloadAudioFile(`${url}?rc_uid=${user.id}&rc_token=${user.token}`, url);
|
||||
const audio = await downloadAudioFile(`${url}?rc_uid=${user.id}&rc_token=${user.token}`, url, messageId);
|
||||
await this.sound.loadAsync({ uri: audio });
|
||||
}
|
||||
} catch {
|
||||
|
|
|
@ -90,6 +90,7 @@ interface IMessageReply {
|
|||
timeFormat?: string;
|
||||
index: number;
|
||||
getCustomEmoji: TGetCustomEmoji;
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
const Title = React.memo(
|
||||
|
@ -201,7 +202,7 @@ const Fields = React.memo(
|
|||
);
|
||||
|
||||
const Reply = React.memo(
|
||||
({ attachment, timeFormat, index, getCustomEmoji }: IMessageReply) => {
|
||||
({ attachment, timeFormat, index, getCustomEmoji, messageId }: IMessageReply) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { theme } = useTheme();
|
||||
const { baseUrl, user, jumpToMessage } = useContext(MessageContext);
|
||||
|
@ -256,6 +257,7 @@ const Reply = React.memo(
|
|||
timeFormat={timeFormat}
|
||||
style={[{ color: themes[theme].auxiliaryTintColor, fontSize: 14, marginBottom: 8 }]}
|
||||
isReply
|
||||
id={messageId}
|
||||
/>
|
||||
<UrlImage image={attachment.thumb_url} />
|
||||
<Description attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface IMessageAttachments {
|
|||
isReply?: boolean;
|
||||
showAttachment?: (file: IAttachment) => void;
|
||||
getCustomEmoji: TGetCustomEmoji;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IMessageAvatar {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react';
|
||||
|
||||
export interface IProfileParams {
|
||||
name: string;
|
||||
realname?: string;
|
||||
name?: string;
|
||||
username: string;
|
||||
email: string | null;
|
||||
newPassword: string;
|
||||
|
|
|
@ -110,7 +110,7 @@ export interface INotificationPreferences {
|
|||
enableMessageParserEarlyAdoption: boolean;
|
||||
desktopNotifications: TNotifications;
|
||||
pushNotifications: TNotifications;
|
||||
emailNotificationMode?: 'mentions' | 'nothing';
|
||||
emailNotificationMode: 'mentions' | 'nothing';
|
||||
language?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
import { sanitizeLikeString } from '../database/utils';
|
||||
import { store } from '../store/auxStore';
|
||||
import log from './helpers/log';
|
||||
|
||||
const sanitizeString = (value: string) => sanitizeLikeString(value.substring(value.lastIndexOf('/') + 1));
|
||||
|
||||
const parseFilename = (value: string) => {
|
||||
const extension = value.substring(value.lastIndexOf('.') + 1);
|
||||
const filename = sanitizeString(value.substring(value.lastIndexOf('/') + 1).split('.')[0]);
|
||||
return `${filename}.${extension}`;
|
||||
};
|
||||
|
||||
const ensureDirAsync = async (dir: string, intermediates = true): Promise<void> => {
|
||||
const info = await FileSystem.getInfoAsync(dir);
|
||||
if (info.exists && info.isDirectory) {
|
||||
|
@ -12,13 +21,14 @@ const ensureDirAsync = async (dir: string, intermediates = true): Promise<void>
|
|||
return ensureDirAsync(dir, intermediates);
|
||||
};
|
||||
|
||||
export const downloadAudioFile = async (url: string, fileUrl: string): Promise<string> => {
|
||||
export const downloadAudioFile = async (url: string, fileUrl: string, messageId: string): Promise<string> => {
|
||||
let path = '';
|
||||
try {
|
||||
const serverUrl = store.getState().server.server;
|
||||
const serverUrlParsed = serverUrl.substring(serverUrl.lastIndexOf('/') + 1);
|
||||
const serverUrlParsed = sanitizeString(serverUrl);
|
||||
const folderPath = `${FileSystem.documentDirectory}audios/${serverUrlParsed}`;
|
||||
const filePath = `${folderPath}/${fileUrl.substring(fileUrl.lastIndexOf('/') + 1)}`;
|
||||
const filename = `${messageId}_${parseFilename(fileUrl)}`;
|
||||
const filePath = `${folderPath}/${filename}`;
|
||||
await ensureDirAsync(folderPath);
|
||||
const file = await FileSystem.getInfoAsync(filePath);
|
||||
if (!file.exists) {
|
||||
|
@ -35,7 +45,7 @@ export const downloadAudioFile = async (url: string, fileUrl: string): Promise<s
|
|||
|
||||
export const deleteAllAudioFiles = async (serverUrl: string): Promise<void> => {
|
||||
try {
|
||||
const serverUrlParsed = serverUrl.substring(serverUrl.lastIndexOf('/') + 1);
|
||||
const serverUrlParsed = sanitizeString(serverUrl);
|
||||
const path = `${FileSystem.documentDirectory}audios/${serverUrlParsed}`;
|
||||
await FileSystem.deleteAsync(path);
|
||||
} catch (error) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
export function debounce(func: Function, wait?: number, immediate?: boolean) {
|
||||
let timeout: ReturnType<typeof setTimeout> | null;
|
||||
function _debounce(...args: any[]) {
|
||||
|
@ -21,3 +23,7 @@ export function debounce(func: Function, wait?: number, immediate?: boolean) {
|
|||
_debounce.stop = () => clearTimeout(timeout!);
|
||||
return _debounce;
|
||||
}
|
||||
|
||||
export function useDebounce(func: (...args: any) => any, wait?: number): (...args: any[]) => void {
|
||||
return useDebouncedCallback(func, wait || 1000);
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ import { Q } from '@nozbe/watermelondb';
|
|||
import { sanitizeLikeString } from '../database/utils';
|
||||
import database from '../database/index';
|
||||
import { spotlight } from '../services/restApi';
|
||||
import { ISearch, ISearchLocal, SubscriptionType, TSubscriptionModel } from '../../definitions';
|
||||
import { ISearch, ISearchLocal, SubscriptionType } from '../../definitions';
|
||||
import { isGroupChat } from './helpers';
|
||||
|
||||
let debounce: null | ((reason: string) => void) = null;
|
||||
|
||||
export const localSearch = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<TSubscriptionModel[]> => {
|
||||
export const localSearch = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<ISearchLocal[]> => {
|
||||
const searchText = text.trim();
|
||||
const db = database.active;
|
||||
const likeString = sanitizeLikeString(searchText);
|
||||
|
@ -26,7 +26,17 @@ export const localSearch = async ({ text = '', filterUsers = true, filterRooms =
|
|||
subscriptions = subscriptions.filter(item => item.t !== 'd' || isGroupChat(item));
|
||||
}
|
||||
|
||||
const search = subscriptions.slice(0, 7);
|
||||
const search = subscriptions.slice(0, 7).map(item => ({
|
||||
_id: item._id,
|
||||
rid: item.rid,
|
||||
name: item.name,
|
||||
fname: item.fname,
|
||||
avatarETag: item.avatarETag,
|
||||
t: item.t,
|
||||
encrypted: item.encrypted,
|
||||
lastMessage: item.lastMessage,
|
||||
status: item.status
|
||||
})) as ISearchLocal[];
|
||||
|
||||
return search;
|
||||
};
|
||||
|
|
|
@ -150,11 +150,7 @@ const ProfileStackNavigator = () => {
|
|||
>
|
||||
<ProfileStack.Screen name='ProfileView' component={ProfileView} options={ProfileView.navigationOptions} />
|
||||
<ProfileStack.Screen name='UserPreferencesView' component={UserPreferencesView} />
|
||||
<ProfileStack.Screen
|
||||
name='UserNotificationPrefView'
|
||||
component={UserNotificationPrefView}
|
||||
options={UserNotificationPrefView.navigationOptions}
|
||||
/>
|
||||
<ProfileStack.Screen name='UserNotificationPrefView' component={UserNotificationPrefView} />
|
||||
<ProfileStack.Screen name='PickerView' component={PickerView} options={PickerView.navigationOptions} />
|
||||
</ProfileStack.Navigator>
|
||||
);
|
||||
|
@ -176,7 +172,7 @@ const SettingsStackNavigator = () => {
|
|||
component={E2EEncryptionSecurityView}
|
||||
options={E2EEncryptionSecurityView.navigationOptions}
|
||||
/>
|
||||
<SettingsStack.Screen name='LanguageView' component={LanguageView} options={LanguageView.navigationOptions} />
|
||||
<SettingsStack.Screen name='LanguageView' component={LanguageView} />
|
||||
<SettingsStack.Screen name='ThemeView' component={ThemeView} />
|
||||
<SettingsStack.Screen name='DefaultBrowserView' component={DefaultBrowserView} />
|
||||
<SettingsStack.Screen
|
||||
|
|
|
@ -175,7 +175,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
component={SettingsView}
|
||||
options={props => SettingsView.navigationOptions!({ ...props, isMasterDetail: true })}
|
||||
/>
|
||||
<ModalStack.Screen name='LanguageView' component={LanguageView} options={LanguageView.navigationOptions} />
|
||||
<ModalStack.Screen name='LanguageView' component={LanguageView} />
|
||||
<ModalStack.Screen name='ThemeView' component={ThemeView} />
|
||||
<ModalStack.Screen name='DefaultBrowserView' component={DefaultBrowserView} />
|
||||
<ModalStack.Screen
|
||||
|
@ -195,11 +195,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
<ModalStack.Screen name='E2EHowItWorksView' component={E2EHowItWorksView} />
|
||||
<ModalStack.Screen name='E2EEnterYourPasswordView' component={E2EEnterYourPasswordView} />
|
||||
<ModalStack.Screen name='UserPreferencesView' component={UserPreferencesView} />
|
||||
<ModalStack.Screen
|
||||
name='UserNotificationPrefView'
|
||||
component={UserNotificationPrefView}
|
||||
options={UserNotificationPrefView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen name='UserNotificationPrefView' component={UserNotificationPrefView} />
|
||||
<ModalStack.Screen name='SecurityPrivacyView' component={SecurityPrivacyView} />
|
||||
<ModalStack.Screen
|
||||
name='E2EEncryptionSecurityView'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { FlatList, View } from 'react-native';
|
||||
import { FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
|
@ -145,14 +145,9 @@ class AddExistingChannelView extends React.Component<IAddExistingChannelViewProp
|
|||
}
|
||||
};
|
||||
|
||||
renderHeader = () => {
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
renderHeader = () => (
|
||||
<SearchBox onChangeText={(text: string) => this.onSearchChangeText(text)} testID='add-existing-channel-view-search' />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
isChecked = (rid: string) => {
|
||||
const { selected } = this.state;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
|
@ -24,7 +24,7 @@ import DropdownItemHeader from './Dropdown/DropdownItemHeader';
|
|||
import styles from './styles';
|
||||
import { ICannedResponse } from '../../definitions/ICannedResponse';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import { getRoomTitle, getUidDirectMessage, debounce } from '../../lib/methods/helpers';
|
||||
import { getRoomTitle, getUidDirectMessage, useDebounce } from '../../lib/methods/helpers';
|
||||
import { Services } from '../../lib/services';
|
||||
import { ILivechatDepartment } from '../../definitions/ILivechatDepartment';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
|
@ -88,7 +88,7 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
}
|
||||
};
|
||||
|
||||
const getDepartments = debounce(async () => {
|
||||
const getDepartments = useDebounce(async () => {
|
||||
try {
|
||||
const res = await Services.getDepartments();
|
||||
if (res.success) {
|
||||
|
@ -187,12 +187,9 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
}
|
||||
}, [departments, cannedResponses]);
|
||||
|
||||
const searchCallback = useCallback(
|
||||
debounce(async (text = '', department = '', depId = '') => {
|
||||
const searchCallback = useDebounce(async (text = '', department = '', depId = '') => {
|
||||
await getListCannedResponse({ text, department, depId, debounced: true });
|
||||
}, 1000),
|
||||
[]
|
||||
); // use debounce with useCallback https://stackoverflow.com/a/58594890
|
||||
}, 1000);
|
||||
|
||||
useEffect(() => {
|
||||
getRoomFromDb();
|
||||
|
|
|
@ -33,7 +33,7 @@ const styles = StyleSheet.create({
|
|||
marginTop: 16
|
||||
},
|
||||
containerStyle: {
|
||||
marginBottom: 28
|
||||
marginBottom: 16
|
||||
},
|
||||
list: {
|
||||
width: '100%'
|
||||
|
@ -53,8 +53,7 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 16
|
||||
},
|
||||
buttonCreate: {
|
||||
marginHorizontal: 16,
|
||||
marginTop: 24
|
||||
margin: 16
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ const DefaultBrowserView = () => {
|
|||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Close_Chat')
|
||||
title: I18n.t('Default_browser')
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import ActivityIndicator from '../../containers/ActivityIndicator';
|
|||
import I18n from '../../i18n';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
import { debounce, isIOS } from '../../lib/methods/helpers';
|
||||
import { isIOS, useDebounce } from '../../lib/methods/helpers';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import * as List from '../../containers/List';
|
||||
|
@ -81,10 +81,10 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
}
|
||||
};
|
||||
|
||||
const onSearchChangeText = debounce(async (text: string) => {
|
||||
const onSearchChangeText = useDebounce(async (text: string) => {
|
||||
setIsSearching(true);
|
||||
await load(text);
|
||||
}, 300);
|
||||
}, 500);
|
||||
|
||||
const onCancelSearchPress = () => {
|
||||
setIsSearching(false);
|
||||
|
@ -145,8 +145,7 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
navigation.setOptions(options);
|
||||
}, [navigation, isSearching]);
|
||||
|
||||
const onDiscussionPress = debounce(
|
||||
(item: TThreadModel) => {
|
||||
const onDiscussionPress = (item: TThreadModel) => {
|
||||
if (item.drid && item.t) {
|
||||
navigation.push('RoomView', {
|
||||
rid: item.drid,
|
||||
|
@ -155,10 +154,7 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
t
|
||||
});
|
||||
}
|
||||
},
|
||||
1000,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
const renderItem = ({ item }: { item: IMessageFromServer }) => (
|
||||
<Item
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
|
||||
import * as List from '../../containers/List';
|
||||
import { useTheme } from '../../theme';
|
||||
|
||||
const LanguageItem = ({
|
||||
item,
|
||||
language,
|
||||
submit
|
||||
}: {
|
||||
item: { value: string; label: string };
|
||||
language: string;
|
||||
submit: (language: string) => Promise<void>;
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
const { value, label } = item;
|
||||
const isSelected = language === value;
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
title={label}
|
||||
onPress={() => submit(value)}
|
||||
testID={`language-view-${value}`}
|
||||
right={() => (isSelected ? <List.Icon name='check' color={colors.tintColor} /> : null)}
|
||||
translateTitle={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default LanguageItem;
|
|
@ -1,77 +1,53 @@
|
|||
import React from 'react';
|
||||
import React, { useLayoutEffect } from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import RNRestart from 'react-native-restart';
|
||||
import { connect } from 'react-redux';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
import { appStart } from '../../actions/app';
|
||||
import { setUser } from '../../actions/login';
|
||||
import { themes } from '../../lib/constants';
|
||||
import * as List from '../../containers/List';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import { IApplicationState, IBaseScreen, IUser, RootEnum } from '../../definitions';
|
||||
import { RootEnum } from '../../definitions';
|
||||
import I18n, { isRTL, LANGUAGES } from '../../i18n';
|
||||
import database from '../../lib/database';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { SettingsStackParamList } from '../../stacks/types';
|
||||
import { withTheme } from '../../theme';
|
||||
import { showErrorAlert } from '../../lib/methods/helpers/info';
|
||||
import log, { events, logEvent } from '../../lib/methods/helpers/log';
|
||||
import { Services } from '../../lib/services';
|
||||
import LanguageItem from './LanguageItem';
|
||||
|
||||
interface ILanguageViewProps extends IBaseScreen<SettingsStackParamList, 'LanguageView'> {
|
||||
user: IUser;
|
||||
}
|
||||
const LanguageView = () => {
|
||||
const { languageDefault, id } = useAppSelector(state => ({
|
||||
languageDefault: getUserSelector(state).language,
|
||||
id: getUserSelector(state).id
|
||||
}));
|
||||
const language = languageDefault || 'en';
|
||||
|
||||
interface ILanguageViewState {
|
||||
language: string;
|
||||
}
|
||||
const dispatch = useDispatch();
|
||||
const navigation = useNavigation<StackNavigationProp<SettingsStackParamList, 'LanguageView'>>();
|
||||
|
||||
class LanguageView extends React.Component<ILanguageViewProps, ILanguageViewState> {
|
||||
static navigationOptions = () => ({
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Change_Language')
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
constructor(props: ILanguageViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
language: props.user ? (props.user.language as string) : 'en'
|
||||
};
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: ILanguageViewProps, nextState: ILanguageViewState) {
|
||||
const { language } = this.state;
|
||||
const { user, theme } = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.language !== language) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user.language !== user.language) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
formIsChanged = (language: string) => {
|
||||
const { user } = this.props;
|
||||
return user.language !== language;
|
||||
};
|
||||
|
||||
submit = async (language: string) => {
|
||||
if (!this.formIsChanged(language)) {
|
||||
const submit = async (language: string) => {
|
||||
if (languageDefault === language) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { dispatch, user } = this.props;
|
||||
|
||||
const shouldRestart = isRTL(language) || isRTL(user.language);
|
||||
const shouldRestart = isRTL(language) || isRTL(languageDefault);
|
||||
|
||||
dispatch(appStart({ root: RootEnum.ROOT_LOADING, text: I18n.t('Change_language_loading') }));
|
||||
|
||||
// shows loading for at least 300ms
|
||||
await Promise.all([this.changeLanguage(language), new Promise(resolve => setTimeout(resolve, 300))]);
|
||||
await Promise.all([changeLanguage(language), new Promise(resolve => setTimeout(resolve, 300))]);
|
||||
|
||||
if (shouldRestart) {
|
||||
await RNRestart.Restart();
|
||||
|
@ -80,14 +56,13 @@ class LanguageView extends React.Component<ILanguageViewProps, ILanguageViewStat
|
|||
}
|
||||
};
|
||||
|
||||
changeLanguage = async (language: string) => {
|
||||
const changeLanguage = async (language: string) => {
|
||||
logEvent(events.LANG_SET_LANGUAGE);
|
||||
const { user, dispatch } = this.props;
|
||||
|
||||
const params: { language?: string } = {};
|
||||
|
||||
// language
|
||||
if (user.language !== language) {
|
||||
if (languageDefault !== language) {
|
||||
params.language = language;
|
||||
}
|
||||
|
||||
|
@ -99,7 +74,7 @@ class LanguageView extends React.Component<ILanguageViewProps, ILanguageViewStat
|
|||
const usersCollection = serversDB.get('users');
|
||||
await serversDB.write(async () => {
|
||||
try {
|
||||
const userRecord = await usersCollection.find(user.id);
|
||||
const userRecord = await usersCollection.find(id);
|
||||
await userRecord.update(record => {
|
||||
record.language = params.language;
|
||||
});
|
||||
|
@ -114,28 +89,6 @@ class LanguageView extends React.Component<ILanguageViewProps, ILanguageViewStat
|
|||
}
|
||||
};
|
||||
|
||||
renderIcon = () => {
|
||||
const { theme } = this.props;
|
||||
return <List.Icon name='check' color={themes[theme].tintColor} />;
|
||||
};
|
||||
|
||||
renderItem = ({ item }: { item: { value: string; label: string } }) => {
|
||||
const { value, label } = item;
|
||||
const { language } = this.state;
|
||||
const isSelected = language === value;
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
title={label}
|
||||
onPress={() => this.submit(value)}
|
||||
testID={`language-view-${value}`}
|
||||
right={() => (isSelected ? this.renderIcon() : null)}
|
||||
translateTitle={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SafeAreaView testID='language-view'>
|
||||
<StatusBar />
|
||||
|
@ -145,16 +98,11 @@ class LanguageView extends React.Component<ILanguageViewProps, ILanguageViewStat
|
|||
ListHeaderComponent={List.Separator}
|
||||
ListFooterComponent={List.Separator}
|
||||
contentContainerStyle={List.styles.contentContainerStyleFlatList}
|
||||
renderItem={this.renderItem}
|
||||
renderItem={({ item }) => <LanguageItem item={item} language={language} submit={submit} />}
|
||||
ItemSeparatorComponent={List.Separator}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
user: getUserSelector(state)
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(LanguageView));
|
||||
export default LanguageView;
|
||||
|
|
|
@ -181,6 +181,7 @@ const NotificationPreferencesView = (): React.ReactElement => {
|
|||
testID='notification-preference-view-alert'
|
||||
onChangeValue={saveNotificationSettings}
|
||||
/>
|
||||
<List.Separator />
|
||||
<RenderListPicker
|
||||
preference='audioNotificationValue'
|
||||
room={room}
|
||||
|
|
|
@ -226,7 +226,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
|
|||
|
||||
// Name
|
||||
if (user.name !== name) {
|
||||
params.name = name;
|
||||
params.realname = name;
|
||||
}
|
||||
|
||||
// Username
|
||||
|
@ -295,6 +295,8 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
|
|||
|
||||
if (result) {
|
||||
logEvent(events.PROFILE_SAVE_CHANGES);
|
||||
params.name = params.realname;
|
||||
delete params.realname;
|
||||
if (customFields) {
|
||||
dispatch(setUser({ customFields, ...params }));
|
||||
} else {
|
||||
|
|
|
@ -64,7 +64,7 @@ export default function ActionsSection({ rid, t, joined }: IActionsSection): Rea
|
|||
};
|
||||
|
||||
return (
|
||||
<View style={{ paddingTop: canAddUser || canInviteUser ? 16 : 0, paddingBottom: canAddUser || canInviteUser ? 8 : 0 }}>
|
||||
<View style={{ paddingTop: canAddUser || canInviteUser ? 16 : 0, paddingBottom: canAddUser || canInviteUser ? 16 : 0 }}>
|
||||
{['c', 'p'].includes(t) && canAddUser ? (
|
||||
<>
|
||||
<List.Separator />
|
||||
|
|
|
@ -379,9 +379,7 @@ const RoomMembersView = (): React.ReactElement => {
|
|||
ListHeaderComponent={
|
||||
<>
|
||||
<ActionsSection joined={params.joined as boolean} rid={state.room.rid} t={state.room.t} />
|
||||
<View style={{ backgroundColor: colors.backgroundColor }}>
|
||||
<SearchBox onChangeText={text => updateState({ filter: text.trim() })} testID='room-members-view-search' />
|
||||
</View>
|
||||
</>
|
||||
}
|
||||
ListFooterComponent={() => (state.isLoading ? <ActivityIndicator /> : null)}
|
||||
|
|
|
@ -31,7 +31,7 @@ const List = ({ listRef, ...props }: IListProps) => (
|
|||
keyExtractor={(item: any) => item.id}
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
style={styles.list}
|
||||
inverted
|
||||
inverted={isIOS}
|
||||
removeClippedSubviews={isIOS}
|
||||
initialNumToRender={7}
|
||||
onEndReachedThreshold={0.5}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import React from 'react';
|
||||
import { RefreshControl as RNRefreshControl, RefreshControlProps, StyleSheet } from 'react-native';
|
||||
|
||||
import { useTheme } from '../../../theme';
|
||||
import { isAndroid } from '../../../lib/methods/helpers';
|
||||
|
||||
const style = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
inverted: {
|
||||
scaleY: -1
|
||||
}
|
||||
});
|
||||
|
||||
interface IRefreshControl extends RefreshControlProps {
|
||||
children: React.ReactElement;
|
||||
}
|
||||
|
||||
const RefreshControl = ({ children, onRefresh, refreshing }: IRefreshControl): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
if (isAndroid) {
|
||||
return (
|
||||
<RNRefreshControl
|
||||
onRefresh={onRefresh}
|
||||
refreshing={refreshing}
|
||||
tintColor={colors.auxiliaryText}
|
||||
style={[style.container, style.inverted]}
|
||||
>
|
||||
{children}
|
||||
</RNRefreshControl>
|
||||
);
|
||||
}
|
||||
|
||||
const refreshControl = <RNRefreshControl onRefresh={onRefresh} refreshing={refreshing} tintColor={colors.auxiliaryText} />;
|
||||
|
||||
return React.cloneElement(children, { refreshControl });
|
||||
};
|
||||
|
||||
export default RefreshControl;
|
|
@ -2,12 +2,10 @@ import { Q } from '@nozbe/watermelondb';
|
|||
import { dequal } from 'dequal';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { FlatListProps, RefreshControl, ViewToken } from 'react-native';
|
||||
import { FlatListProps, View, ViewToken, StyleSheet, Platform } from 'react-native';
|
||||
import { event, Value } from 'react-native-reanimated';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { TSupportedThemes } from '../../../theme';
|
||||
import { themes } from '../../../lib/constants';
|
||||
import ActivityIndicator from '../../../containers/ActivityIndicator';
|
||||
import { TAnyMessageModel, TMessageModel, TThreadMessageModel, TThreadModel } from '../../../definitions';
|
||||
import database from '../../../lib/database';
|
||||
|
@ -19,9 +17,20 @@ import List, { IListProps, TListRef } from './List';
|
|||
import NavBottomFAB from './NavBottomFAB';
|
||||
import { loadMissedMessages, loadThreadMessages } from '../../../lib/methods';
|
||||
import { Services } from '../../../lib/services';
|
||||
import RefreshControl from './RefreshControl';
|
||||
|
||||
const QUERY_SIZE = 50;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
inverted: {
|
||||
...Platform.select({
|
||||
android: {
|
||||
scaleY: -1
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const onScroll = ({ y }: { y: Value<number> }) =>
|
||||
event(
|
||||
[
|
||||
|
@ -40,7 +49,6 @@ export interface IListContainerProps {
|
|||
renderRow: Function;
|
||||
rid: string;
|
||||
tmid?: string;
|
||||
theme: TSupportedThemes;
|
||||
loading: boolean;
|
||||
listRef: TListRef;
|
||||
hideSystemMessages?: string[];
|
||||
|
@ -98,10 +106,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
|
||||
shouldComponentUpdate(nextProps: IListContainerProps, nextState: IListContainerState) {
|
||||
const { refreshing, highlightedMessage } = this.state;
|
||||
const { hideSystemMessages, theme, tunread, ignored, loading } = this.props;
|
||||
if (theme !== nextProps.theme) {
|
||||
return true;
|
||||
}
|
||||
const { hideSystemMessages, tunread, ignored, loading } = this.props;
|
||||
if (loading !== nextProps.loading) {
|
||||
return true;
|
||||
}
|
||||
|
@ -348,7 +353,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
renderItem: FlatListProps<any>['renderItem'] = ({ item, index }) => {
|
||||
const { messages, highlightedMessage } = this.state;
|
||||
const { renderRow } = this.props;
|
||||
return renderRow(item, messages[index + 1], highlightedMessage);
|
||||
return <View style={styles.inverted}>{renderRow(item, messages[index + 1], highlightedMessage)}</View>;
|
||||
};
|
||||
|
||||
onViewableItemsChanged: FlatListProps<any>['onViewableItemsChanged'] = ({ viewableItems }) => {
|
||||
|
@ -359,10 +364,10 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
console.count(`${this.constructor.name}.render calls`);
|
||||
const { rid, tmid, listRef } = this.props;
|
||||
const { messages, refreshing } = this.state;
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<>
|
||||
<EmptyRoom rid={rid} length={messages.length} mounted={this.mounted} />
|
||||
<RefreshControl refreshing={refreshing} onRefresh={this.onRefresh}>
|
||||
<List
|
||||
onScroll={this.onScroll}
|
||||
scrollEventThrottle={16}
|
||||
|
@ -374,10 +379,8 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
onScrollToIndexFailed={this.handleScrollToIndexFailed}
|
||||
onViewableItemsChanged={this.onViewableItemsChanged}
|
||||
viewabilityConfig={this.viewabilityConfig}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={refreshing} onRefresh={this.onRefresh} tintColor={themes[theme].auxiliaryText} />
|
||||
}
|
||||
/>
|
||||
</RefreshControl>
|
||||
<NavBottomFAB y={this.y} onPress={this.jumpToBottom} isThread={!!tmid} />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1365,8 +1365,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (showUnreadSeparator || dateSeparator) {
|
||||
return (
|
||||
<>
|
||||
{content}
|
||||
<Separator ts={dateSeparator} unread={showUnreadSeparator} />
|
||||
{content}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1514,7 +1514,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
listRef={this.flatList}
|
||||
rid={rid}
|
||||
tmid={this.tmid}
|
||||
theme={theme}
|
||||
tunread={tunread}
|
||||
ignored={ignored}
|
||||
renderRow={this.renderItem}
|
||||
|
|
|
@ -107,14 +107,7 @@ class SelectListView extends React.Component<ISelectListViewProps, ISelectListVi
|
|||
);
|
||||
};
|
||||
|
||||
renderSearch = () => {
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
<SearchBox onChangeText={(text: string) => this.search(text)} testID='select-list-view-search' />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
renderSearch = () => <SearchBox onChangeText={(text: string) => this.search(text)} testID='select-list-view-search' />;
|
||||
|
||||
search = async (text: string) => {
|
||||
try {
|
||||
|
|
|
@ -44,12 +44,11 @@ const STATUS: IStatus[] = [
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
inputContainer: {
|
||||
marginTop: 32,
|
||||
marginBottom: 32
|
||||
marginTop: 16,
|
||||
marginBottom: 16
|
||||
},
|
||||
inputLeft: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 12
|
||||
},
|
||||
inputStyle: {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import React, { useLayoutEffect } from 'react';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
import { SettingsStackParamList } from '../stacks/types';
|
||||
import I18n from '../i18n';
|
||||
import { useTheme } from '../theme';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import * as List from '../containers/List';
|
||||
import { supportSystemTheme } from '../lib/methods/helpers';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import UserPreferences from '../lib/methods/userPreferences';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { IThemePreference, TDarkLevel, TThemeMode } from '../definitions/ITheme';
|
||||
import I18n from '../i18n';
|
||||
import { THEME_PREFERENCES_KEY } from '../lib/constants';
|
||||
import { supportSystemTheme } from '../lib/methods/helpers';
|
||||
import { events, logEvent } from '../lib/methods/helpers/log';
|
||||
import { IThemePreference, TThemeMode, TDarkLevel } from '../definitions/ITheme';
|
||||
import { THEME_PREFERENCES_KEY, themes } from '../lib/constants';
|
||||
import { IBaseScreen } from '../definitions';
|
||||
import UserPreferences from '../lib/methods/userPreferences';
|
||||
import { useTheme } from '../theme';
|
||||
|
||||
const THEME_GROUP = 'THEME_GROUP';
|
||||
const DARK_GROUP = 'DARK_GROUP';
|
||||
|
@ -58,16 +57,40 @@ interface ITheme {
|
|||
group: string;
|
||||
}
|
||||
|
||||
type IThemeViewProps = IBaseScreen<SettingsStackParamList, 'ThemeView'>;
|
||||
const Item = ({
|
||||
onPress,
|
||||
label,
|
||||
value,
|
||||
isSelected
|
||||
}: {
|
||||
onPress: () => void;
|
||||
label: string;
|
||||
value: string;
|
||||
isSelected: boolean;
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
title={label}
|
||||
onPress={onPress}
|
||||
testID={`theme-view-${value}`}
|
||||
right={() => (isSelected ? <List.Icon name='check' color={colors.tintColor} /> : null)}
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ThemeView = ({ navigation }: IThemeViewProps): React.ReactElement => {
|
||||
const { theme, themePreferences, setTheme } = useTheme();
|
||||
const ThemeView = (): React.ReactElement => {
|
||||
const { themePreferences, setTheme } = useTheme();
|
||||
const { setOptions } = useNavigation();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
setOptions({
|
||||
title: I18n.t('Theme')
|
||||
});
|
||||
}, [navigation]);
|
||||
}, []);
|
||||
|
||||
const isSelected = (item: ITheme) => {
|
||||
const { group } = item;
|
||||
|
@ -92,10 +115,10 @@ const ThemeView = ({ navigation }: IThemeViewProps): React.ReactElement => {
|
|||
logEvent(events.THEME_SET_DARK_LEVEL, { dark_level: value });
|
||||
changes = { darkLevel: value as TDarkLevel };
|
||||
}
|
||||
_setTheme(changes);
|
||||
handleTheme(changes);
|
||||
};
|
||||
|
||||
const _setTheme = (theme: Partial<IThemePreference>) => {
|
||||
const handleTheme = (theme: Partial<IThemePreference>) => {
|
||||
const newTheme: IThemePreference = { ...(themePreferences as IThemePreference), ...theme };
|
||||
if (setTheme) {
|
||||
setTheme(newTheme);
|
||||
|
@ -103,34 +126,37 @@ const ThemeView = ({ navigation }: IThemeViewProps): React.ReactElement => {
|
|||
}
|
||||
};
|
||||
|
||||
const renderIcon = () => <List.Icon name='check' color={themes[theme].tintColor} />;
|
||||
|
||||
const renderItem = ({ item }: { item: ITheme }) => {
|
||||
const { label, value } = item;
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
title={label}
|
||||
onPress={() => onClick(item)}
|
||||
testID={`theme-view-${value}`}
|
||||
right={() => (isSelected(item) ? renderIcon() : null)}
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView testID='theme-view'>
|
||||
<StatusBar />
|
||||
<List.Container>
|
||||
<List.Section title='Theme'>
|
||||
<List.Separator />
|
||||
<>{themeGroup.map(item => renderItem({ item }))}</>
|
||||
<>
|
||||
{themeGroup.map(theme => (
|
||||
<Item
|
||||
onPress={() => onClick(theme)}
|
||||
label={theme.label}
|
||||
value={theme.value}
|
||||
isSelected={!!isSelected(theme)}
|
||||
key={theme.label}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</List.Section>
|
||||
<List.Section title='Dark_level'>
|
||||
<List.Separator />
|
||||
<>{darkGroup.map(item => renderItem({ item }))}</>
|
||||
<>
|
||||
{darkGroup.map(theme => (
|
||||
<Item
|
||||
onPress={() => onClick(theme)}
|
||||
label={theme.label}
|
||||
value={theme.value}
|
||||
isSelected={!!isSelected(theme)}
|
||||
key={theme.label}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</List.Section>
|
||||
</List.Container>
|
||||
</SafeAreaView>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import React, { useState } from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
|
||||
import * as List from '../../containers/List';
|
||||
import I18n from '../../i18n';
|
||||
import { useTheme } from '../../theme';
|
||||
import sharedStyles from '../Styles';
|
||||
import { OPTIONS } from './options';
|
||||
import { CustomIcon } from '../../containers/CustomIcon';
|
||||
import { useActionSheet } from '../../containers/ActionSheet';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
pickerText: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 16
|
||||
}
|
||||
});
|
||||
|
||||
type TKey = 'desktopNotifications' | 'pushNotifications' | 'emailNotificationMode';
|
||||
|
||||
interface IBaseParams {
|
||||
preference: TKey;
|
||||
value: string;
|
||||
onChangeValue: (param: { [key: string]: string }, onError: () => void) => void;
|
||||
}
|
||||
|
||||
const ListPicker = ({
|
||||
preference,
|
||||
value,
|
||||
title,
|
||||
testID,
|
||||
onChangeValue
|
||||
}: {
|
||||
title: string;
|
||||
testID: string;
|
||||
} & IBaseParams) => {
|
||||
const { showActionSheet, hideActionSheet } = useActionSheet();
|
||||
const { colors } = useTheme();
|
||||
const [option, setOption] = useState(
|
||||
value ? OPTIONS[preference].find(option => option.value === value) : OPTIONS[preference][0]
|
||||
);
|
||||
|
||||
const getOptions = () =>
|
||||
OPTIONS[preference].map(i => ({
|
||||
title: I18n.t(i.label, { defaultValue: i.label }),
|
||||
onPress: () => {
|
||||
hideActionSheet();
|
||||
onChangeValue({ [preference]: i.value.toString() }, () => setOption(option));
|
||||
setOption(i);
|
||||
},
|
||||
right: option?.value === i.value ? () => <CustomIcon name={'check'} size={20} color={colors.tintActive} /> : undefined
|
||||
}));
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
title={title}
|
||||
testID={testID}
|
||||
onPress={() => showActionSheet({ options: getOptions() })}
|
||||
right={() => (
|
||||
<Text style={[styles.pickerText, { color: colors.actionTintColor }]}>
|
||||
{option?.label ? I18n.t(option?.label, { defaultValue: option?.label }) : option?.label}
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListPicker;
|
|
@ -1,124 +1,63 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
import { themes } from '../../lib/constants';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import * as List from '../../containers/List';
|
||||
import I18n from '../../i18n';
|
||||
import { TSupportedThemes, withTheme } from '../../theme';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import sharedStyles from '../Styles';
|
||||
import { OPTIONS } from './options';
|
||||
import { ProfileStackParamList } from '../../stacks/types';
|
||||
import { IApplicationState, INotificationPreferences, IUser } from '../../definitions';
|
||||
import { INotificationPreferences } from '../../definitions';
|
||||
import { Services } from '../../lib/services';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
import ListPicker from './ListPicker';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
pickerText: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 16
|
||||
}
|
||||
});
|
||||
const UserNotificationPreferencesView = () => {
|
||||
const [preferences, setPreferences] = useState({} as INotificationPreferences);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
type TKey = 'desktopNotifications' | 'pushNotifications' | 'emailNotificationMode';
|
||||
const navigation = useNavigation<StackNavigationProp<ProfileStackParamList, 'UserNotificationPrefView'>>();
|
||||
const userId = useAppSelector(state => getUserSelector(state).id);
|
||||
|
||||
interface IUserNotificationPreferencesViewState {
|
||||
preferences: INotificationPreferences;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
interface IUserNotificationPreferencesViewProps {
|
||||
navigation: StackNavigationProp<ProfileStackParamList, 'UserNotificationPrefView'>;
|
||||
theme: TSupportedThemes;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
class UserNotificationPreferencesView extends React.Component<
|
||||
IUserNotificationPreferencesViewProps,
|
||||
IUserNotificationPreferencesViewState
|
||||
> {
|
||||
static navigationOptions = (): StackNavigationOptions => ({
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Notification_Preferences')
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
constructor(props: IUserNotificationPreferencesViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
preferences: {} as INotificationPreferences,
|
||||
loading: false
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { user } = this.props;
|
||||
const { id } = user;
|
||||
const result = await Services.getUserPreferences(id);
|
||||
useEffect(() => {
|
||||
async function getPreferences() {
|
||||
try {
|
||||
const result = await Services.getUserPreferences(userId);
|
||||
if (result.success) {
|
||||
const { preferences } = result;
|
||||
this.setState({ preferences, loading: true });
|
||||
setLoading(true);
|
||||
setPreferences(result.preferences);
|
||||
}
|
||||
} catch (error) {
|
||||
log(error);
|
||||
}
|
||||
}
|
||||
getPreferences();
|
||||
}, [userId]);
|
||||
|
||||
findDefaultOption = (key: TKey) => {
|
||||
const { preferences } = this.state;
|
||||
const option = preferences[key] ? OPTIONS[key].find(item => item.value === preferences[key]) : OPTIONS[key][0];
|
||||
return option;
|
||||
};
|
||||
|
||||
renderPickerOption = (key: TKey) => {
|
||||
const { theme } = this.props;
|
||||
const text = this.findDefaultOption(key);
|
||||
return (
|
||||
<Text style={[styles.pickerText, { color: themes[theme].actionTintColor }]}>
|
||||
{text?.label ? I18n.t(text?.label) : text?.label}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
pickerSelection = (title: string, key: TKey) => {
|
||||
const { preferences } = this.state;
|
||||
const { navigation } = this.props;
|
||||
let values = OPTIONS[key];
|
||||
|
||||
const defaultOption = this.findDefaultOption(key);
|
||||
if (OPTIONS[key][0]?.value !== 'default') {
|
||||
const defaultValue = {
|
||||
label: `${I18n.t('Default')} (${defaultOption?.label ? I18n.t(defaultOption?.label) : defaultOption?.label})`
|
||||
} as {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
values = [defaultValue, ...OPTIONS[key]];
|
||||
}
|
||||
|
||||
navigation.navigate('PickerView', {
|
||||
title,
|
||||
data: values,
|
||||
value: preferences[key],
|
||||
onChangeValue: (value: string) => this.onValueChangePicker(key, value ?? defaultOption?.value)
|
||||
});
|
||||
};
|
||||
|
||||
onValueChangePicker = (key: TKey, value: string) => this.saveNotificationPreferences({ [key]: value.toString() });
|
||||
|
||||
saveNotificationPreferences = async (params: { [key: string]: string }) => {
|
||||
const { user } = this.props;
|
||||
const { id } = user;
|
||||
const result = await Services.setUserPreferences(id, params);
|
||||
const onValueChangePicker = async (param: { [key: string]: string }, onError: () => void) => {
|
||||
try {
|
||||
const result = await Services.setUserPreferences(userId, param);
|
||||
if (result.success) {
|
||||
const {
|
||||
user: { settings }
|
||||
} = result;
|
||||
this.setState({ preferences: settings.preferences });
|
||||
setPreferences(settings.preferences);
|
||||
}
|
||||
} catch (error) {
|
||||
log(error);
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading } = this.state;
|
||||
return (
|
||||
<SafeAreaView testID='user-notification-preference-view'>
|
||||
<StatusBar />
|
||||
|
@ -127,11 +66,12 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
<>
|
||||
<List.Section title='Desktop_Notifications'>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
<ListPicker
|
||||
onChangeValue={onValueChangePicker}
|
||||
preference={'desktopNotifications'}
|
||||
title='Alert'
|
||||
testID='user-notification-preference-view-alert'
|
||||
onPress={(title: string) => this.pickerSelection(title, 'desktopNotifications')}
|
||||
right={() => this.renderPickerOption('desktopNotifications')}
|
||||
value={preferences.desktopNotifications}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Desktop_Alert_info' />
|
||||
|
@ -139,11 +79,12 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
|
||||
<List.Section title='Push_Notifications'>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
<ListPicker
|
||||
onChangeValue={onValueChangePicker}
|
||||
preference={'pushNotifications'}
|
||||
title='Alert'
|
||||
testID='user-notification-preference-view-push-notification'
|
||||
onPress={(title: string) => this.pickerSelection(title, 'pushNotifications')}
|
||||
right={() => this.renderPickerOption('pushNotifications')}
|
||||
value={preferences.pushNotifications}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='Push_Notifications_Alert_Info' />
|
||||
|
@ -151,11 +92,12 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
|
||||
<List.Section title='Email'>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
<ListPicker
|
||||
onChangeValue={onValueChangePicker}
|
||||
preference={'emailNotificationMode'}
|
||||
title='Alert'
|
||||
testID='user-notification-preference-view-email-alert'
|
||||
onPress={(title: string) => this.pickerSelection(title, 'emailNotificationMode')}
|
||||
right={() => this.renderPickerOption('emailNotificationMode')}
|
||||
value={preferences.emailNotificationMode}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Info info='You_need_to_verifiy_your_email_address_to_get_notications' />
|
||||
|
@ -167,11 +109,6 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
</List.Container>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
user: getUserSelector(state)
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(UserNotificationPreferencesView));
|
||||
export default UserNotificationPreferencesView;
|
||||
|
|
|
@ -2,5 +2,7 @@
|
|||
"timeout": 300000,
|
||||
"recursive": true,
|
||||
"bail": true,
|
||||
"file": "e2e/tests/init.js"
|
||||
"require": ["ts-node/register"],
|
||||
"file": "e2e/tests/init.ts",
|
||||
"extension": ["ts"]
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ Or
|
|||
### 2. Prepare test data
|
||||
|
||||
* If you're running your own Rocket.Chat server, ensure it's started (e.g. `meteor npm start` in the server project directory).
|
||||
* Edit `e2e/data.js`:
|
||||
* Edit `e2e/data.ts`:
|
||||
* Set the `server` to the address of the server under test
|
||||
* Create a file called `e2e_account.js`, in the same folder as `data.js`. Set the `adminUser` and `adminPassword` to an admin user on that environment (or a user with at least `create-user` and `create-c` permissions). The example of how to create this file is on `e2e/e2e_account.example.js`
|
||||
* Create a file called `e2e_account.ts`, in the same folder as `data.ts`. Set the `adminUser` and `adminPassword` to an admin user on that environment (or a user with at least `create-user` and `create-c` permissions). The example of how to create this file is on `e2e/e2e_account.example.ts`
|
||||
* Working example configs exist in `./e2e/data/`. Setting `FORCE_DEFAULT_DOCKER_DATA` to `1` in the `runTestsInDocker.sh` script will use the example config automatically
|
||||
|
||||
### 3. Running tests
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
const random = require('./helpers/random');
|
||||
// eslint-disable-next-line import/no-unresolved, import/extensions
|
||||
const account = require('./e2e_account');
|
||||
/* eslint-disable import/extensions, import/no-unresolved */
|
||||
import random from './helpers/random';
|
||||
// @ts-ignore
|
||||
import account from './e2e_account';
|
||||
|
||||
const value = random(20);
|
||||
export interface IUser {
|
||||
username: string;
|
||||
password: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export type TData = typeof data;
|
||||
export type TDataKeys = keyof TData;
|
||||
export type TDataUsers = keyof typeof data.users;
|
||||
export type TDataChannels = keyof typeof data.channels;
|
||||
export type TDataGroups = keyof typeof data.groups;
|
||||
export type TDataTeams = keyof typeof data.teams;
|
||||
|
||||
const value: string = random(20);
|
||||
const data = {
|
||||
server: 'https://mobile.rocket.chat',
|
||||
...account,
|
||||
|
@ -77,4 +91,5 @@ const data = {
|
|||
},
|
||||
random: value
|
||||
};
|
||||
module.exports = data;
|
||||
|
||||
export default data;
|
|
@ -1,7 +1,21 @@
|
|||
// eslint-disable-next-line import/no-unresolved, import/extensions
|
||||
const random = require('./helpers/random');
|
||||
// eslint-disable-next-line import/no-unresolved, import/extensions
|
||||
const account = require('./e2e_account');
|
||||
/* eslint-disable import/extensions, import/no-unresolved */
|
||||
// @ts-ignore
|
||||
import random from './helpers/random';
|
||||
// @ts-ignore
|
||||
import account from './e2e_account';
|
||||
|
||||
export interface IUser {
|
||||
username: string;
|
||||
password: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export type TData = typeof data;
|
||||
export type TDataKeys = keyof TData;
|
||||
export type TDataUsers = keyof typeof data.users;
|
||||
export type TDataChannels = keyof typeof data.channels;
|
||||
export type TDataGroups = keyof typeof data.groups;
|
||||
export type TDataTeams = keyof typeof data.teams;
|
||||
|
||||
const value = random(20);
|
||||
const data = {
|
||||
|
@ -72,4 +86,5 @@ const data = {
|
|||
},
|
||||
random: value
|
||||
};
|
||||
module.exports = data;
|
||||
|
||||
export default data;
|
|
@ -1,5 +1,19 @@
|
|||
// eslint-disable-next-line import/no-unresolved, import/extensions
|
||||
const random = require('./helpers/random');
|
||||
/* eslint-disable import/extensions, import/no-unresolved */
|
||||
// @ts-ignore
|
||||
import random from './helpers/random';
|
||||
|
||||
export interface IUser {
|
||||
username: string;
|
||||
password: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export type TData = typeof data;
|
||||
export type TDataKeys = keyof TData;
|
||||
export type TDataUsers = keyof typeof data.users;
|
||||
export type TDataChannels = keyof typeof data.channels;
|
||||
export type TDataGroups = keyof typeof data.groups;
|
||||
export type TDataTeams = keyof typeof data.teams;
|
||||
|
||||
const value = random(20);
|
||||
const data = {
|
||||
|
@ -77,4 +91,5 @@ const data = {
|
|||
},
|
||||
random: value
|
||||
};
|
||||
module.exports = data;
|
||||
|
||||
export default data;
|
|
@ -3,4 +3,4 @@ const account = {
|
|||
adminPassword: 'Change_here'
|
||||
};
|
||||
|
||||
module.exports = account;
|
||||
export default account;
|
|
@ -1,5 +1,10 @@
|
|||
const { exec } = require('child_process');
|
||||
const data = require('../data');
|
||||
import { exec } from 'child_process';
|
||||
|
||||
import { by, expect, element } from 'detox';
|
||||
|
||||
import data from '../data';
|
||||
|
||||
export type TTextMatcher = keyof Pick<Detox.ByFacade, 'text' | 'label'>;
|
||||
|
||||
const platformTypes = {
|
||||
android: {
|
||||
|
@ -7,18 +12,18 @@ const platformTypes = {
|
|||
alertButtonType: 'android.widget.Button',
|
||||
scrollViewType: 'android.widget.ScrollView',
|
||||
textInputType: 'android.widget.EditText',
|
||||
textMatcher: 'text'
|
||||
textMatcher: 'text' as TTextMatcher
|
||||
},
|
||||
ios: {
|
||||
// iOS types
|
||||
alertButtonType: '_UIAlertControllerActionView',
|
||||
scrollViewType: 'UIScrollView',
|
||||
textInputType: '_UIAlertControllerTextField',
|
||||
textMatcher: 'label'
|
||||
textMatcher: 'label' as TTextMatcher
|
||||
}
|
||||
};
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep(ms: number) {
|
||||
return new Promise(res => setTimeout(res, ms));
|
||||
}
|
||||
|
||||
|
@ -34,7 +39,7 @@ async function navigateToWorkspace(server = data.server) {
|
|||
await expect(element(by.id('workspace-view'))).toBeVisible();
|
||||
}
|
||||
|
||||
async function navigateToLogin(server) {
|
||||
async function navigateToLogin(server?: string) {
|
||||
await navigateToWorkspace(server);
|
||||
await element(by.id('workspace-view-login')).tap();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
|
@ -42,7 +47,7 @@ async function navigateToLogin(server) {
|
|||
.withTimeout(2000);
|
||||
}
|
||||
|
||||
async function navigateToRegister(server) {
|
||||
async function navigateToRegister(server?: string) {
|
||||
await navigateToWorkspace(server);
|
||||
await element(by.id('workspace-view-register')).tap();
|
||||
await waitFor(element(by.id('register-view')))
|
||||
|
@ -50,7 +55,7 @@ async function navigateToRegister(server) {
|
|||
.withTimeout(2000);
|
||||
}
|
||||
|
||||
async function login(username, password) {
|
||||
async function login(username: string, password: string) {
|
||||
await waitFor(element(by.id('login-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
@ -90,23 +95,22 @@ async function logout() {
|
|||
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||
}
|
||||
|
||||
async function mockMessage(message, isThread = false) {
|
||||
async function mockMessage(message: string, isThread = false) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const input = isThread ? 'messagebox-input-thread' : 'messagebox-input';
|
||||
await element(by.id(input)).replaceText(`${data.random}${message}`);
|
||||
await sleep(300);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await sleep(500);
|
||||
await waitFor(element(by[textMatcher](`${data.random}${message}`)))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
.withTimeout(60000);
|
||||
await element(by[textMatcher](`${data.random}${message}`))
|
||||
.atIndex(0)
|
||||
.tap();
|
||||
}
|
||||
|
||||
async function starMessage(message) {
|
||||
async function starMessage(message: string) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const messageLabel = `${data.random}${message}`;
|
||||
|
@ -120,7 +124,7 @@ async function starMessage(message) {
|
|||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function pinMessage(message) {
|
||||
async function pinMessage(message: string) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const messageLabel = `${data.random}${message}`;
|
||||
|
@ -148,24 +152,25 @@ async function tapBack() {
|
|||
await element(by.id('header-back')).atIndex(0).tap();
|
||||
}
|
||||
|
||||
async function searchRoom(room) {
|
||||
async function searchRoom(room: string) {
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(30000);
|
||||
await element(by.id('rooms-list-view-search')).tap();
|
||||
await expect(element(by.id('rooms-list-view-search-input'))).toExist();
|
||||
await waitFor(element(by.id('rooms-list-view-search-input')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.id('rooms-list-view-search-input'))).toExist();
|
||||
await sleep(300);
|
||||
await element(by.id('rooms-list-view-search-input')).replaceText(room);
|
||||
await element(by.id('rooms-list-view-search-input')).typeText(room);
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${room}`)))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
}
|
||||
|
||||
async function tryTapping(theElement, timeout, longtap = false) {
|
||||
// eslint-disable-next-line no-undef
|
||||
async function tryTapping(theElement: Detox.IndexableNativeElement, timeout: number, longtap = false) {
|
||||
try {
|
||||
if (longtap) {
|
||||
await theElement.longPress();
|
||||
|
@ -182,7 +187,7 @@ async function tryTapping(theElement, timeout, longtap = false) {
|
|||
}
|
||||
}
|
||||
|
||||
const checkServer = async server => {
|
||||
const checkServer = async (server: string) => {
|
||||
const label = `Connected to ${server}`;
|
||||
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||
await waitFor(element(by.id('sidebar-view')))
|
||||
|
@ -200,9 +205,9 @@ const checkServer = async server => {
|
|||
.withTimeout(10000);
|
||||
};
|
||||
|
||||
function runCommand(command) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
function runCommand(command: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
exec(command, (error, _stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(new Error(`exec error: ${stderr}`));
|
||||
return;
|
||||
|
@ -223,7 +228,7 @@ async function prepareAndroid() {
|
|||
await runCommand('adb shell settings put global animator_duration_scale 0.0');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
navigateToWorkspace,
|
||||
navigateToLogin,
|
||||
navigateToRegister,
|
|
@ -1,7 +1,7 @@
|
|||
const axios = require('axios').default;
|
||||
import axios from 'axios';
|
||||
|
||||
const data = require('../data');
|
||||
const random = require('./random');
|
||||
import data, { TDataChannels, TDataGroups, TDataTeams, TDataUsers } from '../data';
|
||||
import random from './random';
|
||||
|
||||
const TEAM_TYPE = {
|
||||
PUBLIC: 0,
|
||||
|
@ -17,7 +17,7 @@ const rocketchat = axios.create({
|
|||
}
|
||||
});
|
||||
|
||||
const login = async (username, password) => {
|
||||
const login = async (username: string, password: string) => {
|
||||
console.log(`Logging in as user ${username}`);
|
||||
const response = await rocketchat.post('login', {
|
||||
user: username,
|
||||
|
@ -30,7 +30,7 @@ const login = async (username, password) => {
|
|||
return { authToken, userId };
|
||||
};
|
||||
|
||||
const createUser = async (username, password, name, email) => {
|
||||
const createUser = async (username: string, password: string, name: string, email: string) => {
|
||||
console.log(`Creating user ${username}`);
|
||||
try {
|
||||
await rocketchat.post('users.create', {
|
||||
|
@ -45,7 +45,7 @@ const createUser = async (username, password, name, email) => {
|
|||
}
|
||||
};
|
||||
|
||||
const createChannelIfNotExists = async channelname => {
|
||||
const createChannelIfNotExists = async (channelname: string) => {
|
||||
console.log(`Creating public channel ${channelname}`);
|
||||
try {
|
||||
const room = await rocketchat.post('channels.create', {
|
||||
|
@ -65,7 +65,7 @@ const createChannelIfNotExists = async channelname => {
|
|||
}
|
||||
};
|
||||
|
||||
const createTeamIfNotExists = async teamname => {
|
||||
const createTeamIfNotExists = async (teamname: string) => {
|
||||
console.log(`Creating private team ${teamname}`);
|
||||
try {
|
||||
await rocketchat.post('teams.create', {
|
||||
|
@ -84,7 +84,7 @@ const createTeamIfNotExists = async teamname => {
|
|||
}
|
||||
};
|
||||
|
||||
const createGroupIfNotExists = async groupname => {
|
||||
const createGroupIfNotExists = async (groupname: string) => {
|
||||
console.log(`Creating private group ${groupname}`);
|
||||
try {
|
||||
await rocketchat.post('groups.create', {
|
||||
|
@ -102,7 +102,7 @@ const createGroupIfNotExists = async groupname => {
|
|||
}
|
||||
};
|
||||
|
||||
const changeChannelJoinCode = async (roomId, joinCode) => {
|
||||
const changeChannelJoinCode = async (roomId: string, joinCode: string) => {
|
||||
console.log(`Changing channel Join Code ${roomId}`);
|
||||
try {
|
||||
await rocketchat.post('method.call/saveRoomSettings', {
|
||||
|
@ -119,7 +119,7 @@ const changeChannelJoinCode = async (roomId, joinCode) => {
|
|||
}
|
||||
};
|
||||
|
||||
const sendMessage = async (user, channel, msg, tmid) => {
|
||||
const sendMessage = async (user: { username: string; password: string }, channel: string, msg: string, tmid?: string) => {
|
||||
console.log(`Sending message to ${channel}`);
|
||||
try {
|
||||
await login(user.username, user.password);
|
||||
|
@ -136,21 +136,21 @@ const setup = async () => {
|
|||
|
||||
for (const userKey in data.users) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.users, userKey)) {
|
||||
const user = data.users[userKey];
|
||||
const user = data.users[userKey as TDataUsers];
|
||||
await createUser(user.username, user.password, user.username, user.email);
|
||||
}
|
||||
}
|
||||
|
||||
for (const channelKey in data.channels) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.channels, channelKey)) {
|
||||
const channel = data.channels[channelKey];
|
||||
const channel = data.channels[channelKey as TDataChannels];
|
||||
const {
|
||||
data: {
|
||||
channel: { _id }
|
||||
}
|
||||
} = await createChannelIfNotExists(channel.name);
|
||||
|
||||
if (channel.joinCode) {
|
||||
if ('joinCode' in channel) {
|
||||
await changeChannelJoinCode(_id, channel.joinCode);
|
||||
}
|
||||
}
|
||||
|
@ -160,33 +160,27 @@ const setup = async () => {
|
|||
|
||||
for (const groupKey in data.groups) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.groups, groupKey)) {
|
||||
const group = data.groups[groupKey];
|
||||
const group = data.groups[groupKey as TDataGroups];
|
||||
await createGroupIfNotExists(group.name);
|
||||
}
|
||||
}
|
||||
|
||||
for (const teamKey in data.teams) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.teams, teamKey)) {
|
||||
const team = data.teams[teamKey];
|
||||
const team = data.teams[teamKey as TDataTeams];
|
||||
await createTeamIfNotExists(team.name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const get = endpoint => {
|
||||
const get = (endpoint: string) => {
|
||||
console.log(`GET /${endpoint}`);
|
||||
return rocketchat.get(endpoint);
|
||||
};
|
||||
|
||||
const post = (endpoint, body) => {
|
||||
const post = (endpoint: string, body: any) => {
|
||||
console.log(`POST /${endpoint} ${JSON.stringify(body)}`);
|
||||
return rocketchat.post(endpoint, body);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
setup,
|
||||
sendMessage,
|
||||
get,
|
||||
post,
|
||||
login
|
||||
};
|
||||
export { setup, sendMessage, get, post, login };
|
|
@ -1,4 +1,4 @@
|
|||
function random(length) {
|
||||
function random(length: number) {
|
||||
let text = '';
|
||||
const possible = 'abcdefghijklmnopqrstuvwxyz';
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
|
@ -6,4 +6,5 @@ function random(length) {
|
|||
}
|
||||
return text;
|
||||
}
|
||||
module.exports = random;
|
||||
|
||||
export default random;
|
|
@ -1,11 +1,22 @@
|
|||
const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
const data = require('../../data');
|
||||
import {
|
||||
navigateToLogin,
|
||||
login,
|
||||
sleep,
|
||||
tapBack,
|
||||
mockMessage,
|
||||
searchRoom,
|
||||
logout,
|
||||
platformTypes,
|
||||
TTextMatcher
|
||||
} from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const otheruser = data.users.alternate;
|
||||
|
||||
const checkServer = async server => {
|
||||
const checkServer = async (server: string) => {
|
||||
const label = `Connected to ${server}`;
|
||||
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||
await waitFor(element(by.id('sidebar-view')))
|
||||
|
@ -24,7 +35,7 @@ const checkBanner = async () => {
|
|||
.withTimeout(10000);
|
||||
};
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
async function navigateToRoom(roomName: string) {
|
||||
await searchRoom(`${roomName}`);
|
||||
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -60,13 +71,12 @@ async function navigateSecurityPrivacy() {
|
|||
describe('E2E Encryption', () => {
|
||||
const room = `encrypted${data.random}`;
|
||||
const newPassword = 'abc';
|
||||
let alertButtonType;
|
||||
let scrollViewType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, scrollViewType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
});
|
||||
|
@ -293,14 +303,16 @@ describe('E2E Encryption', () => {
|
|||
await element(by[textMatcher]('Yes, reset it').and(by.type(alertButtonType))).tap();
|
||||
await sleep(2000);
|
||||
|
||||
await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
|
||||
.toExist()
|
||||
.withTimeout(20000);
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('workspace-view-login')).tap();
|
||||
// FIXME: The app isn't showing this alert anymore
|
||||
// await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
|
||||
// .toExist()
|
||||
// .withTimeout(20000);
|
||||
// await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
// await waitFor(element(by.id('workspace-view')))
|
||||
// .toBeVisible()
|
||||
// .withTimeout(10000);
|
||||
// await element(by.id('workspace-view-login')).tap();
|
||||
await navigateToLogin();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
|
@ -308,7 +320,7 @@ describe('E2E Encryption', () => {
|
|||
// TODO: assert 'Save Your Encryption Password'
|
||||
await waitFor(element(by.id('listheader-encryption')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
.withTimeout(5000);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,14 +1,15 @@
|
|||
// const OTP = require('otp.js');
|
||||
// const GA = OTP.googleAuthenticator;
|
||||
import { expect } from 'detox';
|
||||
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes, TTextMatcher, sleep } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const otheruser = data.users.alternate;
|
||||
|
||||
describe('Broadcast room', () => {
|
||||
let textMatcher;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
|
@ -49,6 +50,7 @@ describe('Broadcast room', () => {
|
|||
await waitFor(element(by.id(`room-view-title-broadcast${data.random}`)))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
await sleep(500);
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view')))
|
||||
.toBeVisible()
|
||||
|
@ -123,6 +125,17 @@ describe('Broadcast room', () => {
|
|||
});
|
||||
|
||||
it('should reply broadcasted message', async () => {
|
||||
await mockMessage('broadcastreply');
|
||||
// Server is adding 2 spaces in front a reply message
|
||||
await element(by.id('messagebox-input')).replaceText(`${data.random}broadcastreply`);
|
||||
await sleep(300);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by[textMatcher](`${data.random}message`)).tap();
|
||||
await sleep(600);
|
||||
await waitFor(element(by.id(`room-view-title-broadcast${data.random}`)))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
});
|
||||
});
|
|
@ -1,5 +1,7 @@
|
|||
const { navigateToLogin, login, sleep, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToLogin, login, sleep, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const profileChangeUser = data.users.profileChanges;
|
||||
|
||||
|
@ -14,14 +16,12 @@ async function waitForToast() {
|
|||
}
|
||||
|
||||
describe('Profile screen', () => {
|
||||
let textInputType;
|
||||
let scrollViewType;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let scrollViewType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textInputType, scrollViewType, alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
({ scrollViewType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(profileChangeUser.username, profileChangeUser.password);
|
||||
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||
|
@ -107,6 +107,7 @@ describe('Profile screen', () => {
|
|||
it('should change email and password', async () => {
|
||||
await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${data.random}@rocket.chat`);
|
||||
await element(by.id('profile-view-new-password')).replaceText(`${profileChangeUser.password}new`);
|
||||
await sleep(300);
|
||||
await element(by.id('profile-view-submit')).tap();
|
||||
await waitFor(element(by.id('profile-view-enter-password-sheet')))
|
||||
.toBeVisible()
|
|
@ -1,12 +1,13 @@
|
|||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
const data = require('../../data');
|
||||
import { navigateToLogin, login, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
|
||||
describe('Settings screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,5 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const room = data.channels.detoxpublic.name;
|
||||
|
@ -20,8 +22,8 @@ async function navigateToRoomActions() {
|
|||
}
|
||||
|
||||
describe('Join public room', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,5 +1,7 @@
|
|||
const { navigateToLogin, login, sleep } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToLogin, login, sleep } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, checkServer, platformTypes, sleep } = require('../../helpers/app');
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, checkServer, sleep } from '../../helpers/app';
|
||||
|
||||
const reopenAndCheckServer = async server => {
|
||||
const reopenAndCheckServer = async (server: string) => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
|
@ -1,5 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, mockMessage, searchRoom, sleep } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, mockMessage, searchRoom } from '../../helpers/app';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const room = data.channels.detoxpublicprotected.name;
|
|
@ -1,9 +1,9 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep } = require('../../helpers/app');
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, tapBack, sleep } from '../../helpers/app';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
|
||||
async function navigateToRoom(search) {
|
||||
async function navigateToRoom(search: string) {
|
||||
await element(by.id('directory-view-search')).replaceText(search);
|
||||
await waitFor(element(by.id(`directory-view-item-${search}`)))
|
||||
.toBeVisible()
|
|
@ -1,9 +1,9 @@
|
|||
const data = require('../../data');
|
||||
const { sleep, navigateToLogin, login, checkServer, platformTypes } = require('../../helpers/app');
|
||||
import data from '../../data';
|
||||
import { sleep, navigateToLogin, login, checkServer, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
describe('Delete server', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,31 +1,32 @@
|
|||
const data = require('../../data');
|
||||
const { tapBack, checkServer, navigateToRegister, platformTypes } = require('../../helpers/app');
|
||||
const { get, login, sendMessage } = require('../../helpers/data_setup');
|
||||
import EJSON from 'ejson';
|
||||
|
||||
import data from '../../data';
|
||||
import { tapBack, checkServer, navigateToRegister, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
import { get, login, sendMessage } from '../../helpers/data_setup';
|
||||
|
||||
const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' };
|
||||
|
||||
let amp = '&';
|
||||
|
||||
const getDeepLink = (method, server, params) => {
|
||||
const getDeepLink = (method: string, server: string, params?: string) => {
|
||||
const deeplink = `rocketchat://${method}?host=${server.replace(/^(http:\/\/|https:\/\/)/, '')}${amp}${params}`;
|
||||
console.log(`Deeplinking to: ${deeplink}`);
|
||||
return deeplink;
|
||||
};
|
||||
|
||||
describe('Deep linking', () => {
|
||||
let userId;
|
||||
let authToken;
|
||||
let scrollViewType;
|
||||
let threadId;
|
||||
let textMatcher;
|
||||
let alertButtonType;
|
||||
let userId: string;
|
||||
let authToken: string;
|
||||
let scrollViewType: string;
|
||||
let threadId: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
const threadMessage = `to-thread-${data.random}`;
|
||||
before(async () => {
|
||||
const loginResult = await login(data.users.regular.username, data.users.regular.password);
|
||||
({ userId, authToken } = loginResult);
|
||||
const deviceType = device.getPlatform();
|
||||
amp = deviceType === 'android' ? '\\&' : '&';
|
||||
({ scrollViewType, textMatcher, alertButtonType } = platformTypes[deviceType]);
|
||||
({ scrollViewType, textMatcher } = platformTypes[deviceType]);
|
||||
// create a thread with api
|
||||
const result = await sendMessage(data.users.regular, data.groups.alternate2.name, threadMessage);
|
||||
threadId = result.message._id;
|
||||
|
@ -142,6 +143,41 @@ describe('Deep linking', () => {
|
|||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
||||
it('should simulate a tap on a push notification and navigate to the room', async () => {
|
||||
/**
|
||||
* Ideally, we would repeat this test to simulate a resume from background,
|
||||
* but for some reason it was not working as expected
|
||||
* This was always turning to false right before running the logic https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/18f359a8ef9691144970c0c1fad990f82096b024/app/lib/notifications/push.ts#L58
|
||||
*/
|
||||
// await device.sendToHome();
|
||||
await device.launchApp({
|
||||
newInstance: true,
|
||||
userNotification: {
|
||||
trigger: {
|
||||
type: 'push'
|
||||
},
|
||||
title: 'From push',
|
||||
body: 'Body',
|
||||
badge: 1,
|
||||
payload: {
|
||||
ejson: EJSON.stringify({
|
||||
rid: null,
|
||||
host: data.server,
|
||||
name: data.groups.private.name,
|
||||
type: 'p'
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
|
||||
.toExist()
|
||||
.withTimeout(30000);
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Others', () => {
|
|
@ -1,9 +1,11 @@
|
|||
const { navigateToLogin, login, sleep } = require('../../helpers/app');
|
||||
const { post } = require('../../helpers/data_setup');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToLogin, login, sleep } from '../../helpers/app';
|
||||
import { post } from '../../helpers/data_setup';
|
||||
import data from '../../data';
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const defaultLaunchArgs = { permissions: { notifications: 'YES' } };
|
||||
const defaultLaunchArgs = { permissions: { notifications: 'YES' } } as Detox.DeviceLaunchAppConfig;
|
||||
|
||||
const navToLanguage = async () => {
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
|
@ -1,5 +1,7 @@
|
|||
const { login, navigateToLogin, sleep } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { login, navigateToLogin } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const goToDisplayPref = async () => {
|
||||
await expect(element(by.id('rooms-list-view-sidebar'))).toBeVisible();
|
|
@ -1,11 +1,12 @@
|
|||
const detox = require('detox');
|
||||
const adapter = require('detox/runners/mocha/adapter');
|
||||
import detox from 'detox';
|
||||
import adapter from 'detox/runners/mocha/adapter';
|
||||
|
||||
const config = require('../../package.json').detox;
|
||||
const { setup } = require('../helpers/data_setup');
|
||||
const { prepareAndroid } = require('../helpers/app');
|
||||
import { detox as config } from '../../package.json';
|
||||
import { setup } from '../helpers/data_setup';
|
||||
import { prepareAndroid } from '../helpers/app';
|
||||
|
||||
before(async () => {
|
||||
// @ts-ignore
|
||||
await Promise.all([setup(), detox.init(config, { launchApp: false })]);
|
||||
await prepareAndroid(); // Make Android less flaky
|
||||
// await dataSetup()
|
||||
|
@ -14,10 +15,12 @@ before(async () => {
|
|||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
// @ts-ignore
|
||||
await adapter.beforeEach(this);
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
// @ts-ignore
|
||||
await adapter.afterEach(this);
|
||||
});
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
const data = require('../../data');
|
||||
const { platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { TTextMatcher, platformTypes } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
describe('Onboarding', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,4 +1,6 @@
|
|||
const { navigateToRegister, navigateToLogin } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToRegister, navigateToLogin } from '../../helpers/app';
|
||||
|
||||
describe('Legal screen', () => {
|
||||
describe('From Login', () => {
|
|
@ -1,9 +1,11 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
describe('Forgot password screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,9 +1,11 @@
|
|||
const { navigateToRegister, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToRegister, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
describe('Create user screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
|
@ -50,17 +52,18 @@ describe('Create user screen', () => {
|
|||
// await element(by.id('register-view-submit')).tap();
|
||||
// });
|
||||
|
||||
it('should submit email already taken and raise error', async () => {
|
||||
await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
|
||||
await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
|
||||
await element(by.id('register-view-email')).replaceText(data.users.existing.email);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by[textMatcher]('Email already exists. [403]')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
// TODO: When server handle two errors in sequence, the server return Too many requests and force to wait for some time.
|
||||
// it('should submit email already taken and raise error', async () => {
|
||||
// await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
|
||||
// await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
|
||||
// await element(by.id('register-view-email')).replaceText(data.users.existing.email);
|
||||
// await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
|
||||
// await element(by.id('register-view-submit')).tap();
|
||||
// await waitFor(element(by[textMatcher]('Email already exists. [403]')).atIndex(0))
|
||||
// .toExist()
|
||||
// .withTimeout(10000);
|
||||
// await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
// });
|
||||
|
||||
it('should submit username already taken and raise error', async () => {
|
||||
await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
|
|
@ -1,9 +1,11 @@
|
|||
const { navigateToLogin, tapBack, platformTypes, navigateToWorkspace, login } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { navigateToLogin, tapBack, platformTypes, navigateToWorkspace, login, TTextMatcher } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
describe('Login screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,5 +1,7 @@
|
|||
const { login, navigateToLogin, logout, tapBack, searchRoom } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { login, navigateToLogin, logout, tapBack, searchRoom } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
describe('Rooms list screen', () => {
|
||||
before(async () => {
|
|
@ -1,5 +1,7 @@
|
|||
const { login, navigateToLogin, logout, tapBack } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { login, navigateToLogin, logout, tapBack } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
describe('Server history', () => {
|
||||
before(async () => {
|
|
@ -1,9 +1,11 @@
|
|||
const data = require('../../data');
|
||||
const { tapBack, navigateToLogin, login, tryTapping, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { tapBack, navigateToLogin, login, tryTapping, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
describe('Create room screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,5 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const {
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import {
|
||||
navigateToLogin,
|
||||
login,
|
||||
mockMessage,
|
||||
|
@ -10,10 +12,11 @@ const {
|
|||
pinMessage,
|
||||
dismissReviewNag,
|
||||
tryTapping,
|
||||
platformTypes
|
||||
} = require('../../helpers/app');
|
||||
platformTypes,
|
||||
TTextMatcher
|
||||
} from '../../helpers/app';
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
async function navigateToRoom(roomName: string) {
|
||||
await searchRoom(`${roomName}`);
|
||||
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -23,8 +26,8 @@ async function navigateToRoom(roomName) {
|
|||
|
||||
describe('Room screen', () => {
|
||||
const mainRoom = data.groups.private.name;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
|
@ -1,5 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const {
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import {
|
||||
navigateToLogin,
|
||||
login,
|
||||
tapBack,
|
||||
|
@ -8,11 +10,13 @@ const {
|
|||
mockMessage,
|
||||
starMessage,
|
||||
pinMessage,
|
||||
platformTypes
|
||||
} = require('../../helpers/app');
|
||||
platformTypes,
|
||||
TTextMatcher
|
||||
} from '../../helpers/app';
|
||||
|
||||
const { sendMessage } = require('../../helpers/data_setup');
|
||||
|
||||
async function navigateToRoomActions(type) {
|
||||
async function navigateToRoomActions(type: string) {
|
||||
let room;
|
||||
if (type === 'd') {
|
||||
room = 'rocket.cat';
|
||||
|
@ -53,8 +57,8 @@ async function waitForToast() {
|
|||
}
|
||||
|
||||
describe('Room actions screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
await navigateToLogin();
|
||||
|
@ -398,7 +402,7 @@ describe('Room actions screen', () => {
|
|||
.withTimeout(2000);
|
||||
});
|
||||
|
||||
const openActionSheet = async username => {
|
||||
const openActionSheet = async (username: string) => {
|
||||
await waitFor(element(by.id(`room-members-view-item-${username}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
|
@ -461,7 +465,7 @@ describe('Room actions screen', () => {
|
|||
.toBeNotVisible()
|
||||
.withTimeout(60000);
|
||||
await element(by.id('room-members-view-search')).tap();
|
||||
await element(by.id('room-members-view-search')).clearText('');
|
||||
await element(by.id('room-members-view-search')).clearText();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
@ -484,7 +488,7 @@ describe('Room actions screen', () => {
|
|||
|
||||
it('should clear search', async () => {
|
||||
await element(by.id('room-members-view-search')).tap();
|
||||
await element(by.id('room-members-view-search')).clearText('');
|
||||
await element(by.id('room-members-view-search')).clearText();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
|
@ -1,5 +1,7 @@
|
|||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import { TTextMatcher, navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } from '../../helpers/app';
|
||||
import data from '../../data';
|
||||
|
||||
const channel = data.groups.private.name;
|
||||
|
||||
|
@ -12,7 +14,7 @@ const navigateToRoom = async () => {
|
|||
};
|
||||
|
||||
describe('Discussion', () => {
|
||||
let textMatcher;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,5 +1,7 @@
|
|||
const data = require('../../data');
|
||||
const {
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import {
|
||||
navigateToLogin,
|
||||
login,
|
||||
mockMessage,
|
||||
|
@ -7,10 +9,11 @@ const {
|
|||
sleep,
|
||||
searchRoom,
|
||||
platformTypes,
|
||||
dismissReviewNag
|
||||
} = require('../../helpers/app');
|
||||
dismissReviewNag,
|
||||
TTextMatcher
|
||||
} from '../../helpers/app';
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
async function navigateToRoom(roomName: string) {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
|
@ -23,7 +26,7 @@ async function navigateToRoom(roomName) {
|
|||
|
||||
describe('Threads', () => {
|
||||
const mainRoom = data.groups.private.name;
|
||||
let textMatcher;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,8 +1,8 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
describe('Group DM', () => {
|
||||
let textMatcher;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,8 +1,10 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
const { sendMessage } = require('../../helpers/data_setup');
|
||||
import { expect } from 'detox';
|
||||
|
||||
async function navigateToRoom(user) {
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, searchRoom, sleep, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
import { sendMessage } from '../../helpers/data_setup';
|
||||
|
||||
async function navigateToRoom(user: string) {
|
||||
await searchRoom(`${user}`);
|
||||
await element(by.id(`rooms-list-view-item-${user}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -12,7 +14,7 @@ async function navigateToRoom(user) {
|
|||
|
||||
describe('Mark as unread', () => {
|
||||
const user = data.users.alternate.username;
|
||||
let textMatcher;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
|
@ -1,9 +1,11 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
const privateRoomName = data.groups.private.name;
|
||||
|
||||
async function navigateToRoomInfo(type) {
|
||||
async function navigateToRoomInfo(type: string) {
|
||||
let room;
|
||||
if (type === 'd') {
|
||||
room = 'rocket.cat';
|
||||
|
@ -25,7 +27,7 @@ async function navigateToRoomInfo(type) {
|
|||
.withTimeout(2000);
|
||||
}
|
||||
|
||||
async function swipe(direction) {
|
||||
async function swipe(direction: Detox.Direction) {
|
||||
await element(by.id('room-info-edit-view-list')).swipe(direction, 'fast', 0.8);
|
||||
}
|
||||
|
||||
|
@ -34,8 +36,8 @@ async function waitForToast() {
|
|||
}
|
||||
|
||||
describe('Room info screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
|
@ -174,6 +176,7 @@ describe('Room info screen', () => {
|
|||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await sleep(2000);
|
||||
await element(by.id('room-info-edit-view-name')).replaceText(`${privateRoomName}`);
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
|
@ -182,6 +185,7 @@ describe('Room info screen', () => {
|
|||
});
|
||||
|
||||
it('should reset form', async () => {
|
||||
await sleep(2000);
|
||||
await element(by.id('room-info-edit-view-name')).replaceText('abc');
|
||||
await element(by.id('room-info-edit-view-description')).replaceText('abc');
|
||||
await element(by.id('room-info-edit-view-topic')).replaceText('abc');
|
||||
|
@ -194,6 +198,7 @@ describe('Room info screen', () => {
|
|||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-reset')).tap();
|
||||
// after reset
|
||||
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.5);
|
||||
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(privateRoomName);
|
||||
await expect(element(by.id('room-info-edit-view-description'))).toHaveText('');
|
||||
await expect(element(by.id('room-info-edit-view-topic'))).toHaveText('');
|
||||
|
@ -226,6 +231,7 @@ describe('Room info screen', () => {
|
|||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await sleep(2000);
|
||||
await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
|
@ -245,6 +251,7 @@ describe('Room info screen', () => {
|
|||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await sleep(2000);
|
||||
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
|
@ -264,6 +271,7 @@ describe('Room info screen', () => {
|
|||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await sleep(2000);
|
||||
await element(by.id('room-info-edit-view-password')).replaceText('password');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
|
@ -1,7 +1,9 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, tapBack, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, tapBack, login, searchRoom, sleep, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
async function navigateToRoom(roomName: string) {
|
||||
await searchRoom(`${roomName}`);
|
||||
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -12,8 +14,8 @@ async function navigateToRoom(roomName) {
|
|||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
let textMatcher;
|
||||
let alertButtonType;
|
||||
let textMatcher: TTextMatcher;
|
||||
let alertButtonType: string;
|
||||
|
||||
async function clearCache() {
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -123,6 +125,7 @@ describe('Room', () => {
|
|||
await waitFor(element(by[textMatcher]('30')).atIndex(1))
|
||||
.toExist()
|
||||
.withTimeout(30000);
|
||||
await sleep(1000);
|
||||
await element(by[textMatcher]('30')).atIndex(1).tap();
|
||||
await waitForLoading();
|
||||
await waitFor(element(by[textMatcher]('30')).atIndex(0))
|
||||
|
@ -194,7 +197,7 @@ describe('Room', () => {
|
|||
});
|
||||
});
|
||||
|
||||
const expectThreadMessages = async message => {
|
||||
const expectThreadMessages = async (message: string) => {
|
||||
await waitFor(element(by.id('room-view-title-thread 1')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
|
@ -1,11 +1,13 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
const teamName = `team-${data.random}`;
|
||||
|
||||
describe('Create team screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -1,7 +1,9 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
import { expect } from 'detox';
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
async function navigateToRoom(roomName: string) {
|
||||
await searchRoom(`${roomName}`);
|
||||
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -9,7 +11,7 @@ async function navigateToRoom(roomName) {
|
|||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function openActionSheet(username) {
|
||||
async function openActionSheet(username: string) {
|
||||
await waitFor(element(by.id(`room-members-view-item-${username}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
|
@ -48,7 +50,13 @@ async function waitForToast() {
|
|||
await sleep(1000);
|
||||
}
|
||||
|
||||
async function swipeTillVisible(container, find, direction = 'up', delta = 0.3, speed = 'slow') {
|
||||
async function swipeTillVisible(
|
||||
container: Detox.NativeMatcher,
|
||||
find: Detox.NativeMatcher,
|
||||
direction: Detox.Direction = 'up',
|
||||
delta = 0.3,
|
||||
speed: Detox.Speed = 'slow'
|
||||
) {
|
||||
let found = false;
|
||||
while (!found) {
|
||||
try {
|
||||
|
@ -67,8 +75,8 @@ describe('Team', () => {
|
|||
const user = data.users.alternate;
|
||||
const room = `private${data.random}-channel-team`;
|
||||
const existingRoom = data.groups.alternate.name;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
|
@ -388,7 +396,7 @@ describe('Team', () => {
|
|||
.toBeNotVisible()
|
||||
.withTimeout(60000);
|
||||
await element(by.id('room-members-view-search')).tap();
|
||||
await element(by.id('room-members-view-search')).clearText('');
|
||||
await element(by.id('room-members-view-search')).clearText();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
|
@ -1,10 +1,10 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
import data from '../../data';
|
||||
import { navigateToLogin, login, tapBack, searchRoom, platformTypes, TTextMatcher } from '../../helpers/app';
|
||||
|
||||
const toBeConverted = `to-be-converted-${data.random}`;
|
||||
const toBeMoved = `to-be-moved-${data.random}`;
|
||||
|
||||
const createChannel = async room => {
|
||||
const createChannel = async (room: string) => {
|
||||
await waitFor(element(by.id('rooms-list-view-create-channel')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
|
@ -40,7 +40,7 @@ const createChannel = async room => {
|
|||
.withTimeout(60000);
|
||||
};
|
||||
|
||||
async function navigateToRoom(room) {
|
||||
async function navigateToRoom(room: string) {
|
||||
await searchRoom(`${room}`);
|
||||
await element(by.id(`rooms-list-view-item-${room}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -48,7 +48,7 @@ async function navigateToRoom(room) {
|
|||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function navigateToRoomActions(room) {
|
||||
async function navigateToRoomActions(room: string) {
|
||||
await navigateToRoom(room);
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view')))
|
||||
|
@ -57,8 +57,8 @@ async function navigateToRoomActions(room) {
|
|||
}
|
||||
|
||||
describe('Move/Convert Team', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
let alertButtonType: string;
|
||||
let textMatcher: TTextMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"target": "es2018",
|
||||
"module": "commonjs",
|
||||
"importHelpers": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"types": ["node", "detox", "mocha"]
|
||||
},
|
||||
"include": ["./**/*.ts"],
|
||||
"exclude": ["../node_modules"]
|
||||
}
|
|
@ -13,13 +13,13 @@ PODS:
|
|||
- ExpoModulesCore
|
||||
- EXLocalAuthentication (12.2.0):
|
||||
- ExpoModulesCore
|
||||
- Expo (45.0.5):
|
||||
- Expo (46.0.9):
|
||||
- ExpoModulesCore
|
||||
- ExpoHaptics (11.2.0):
|
||||
- ExpoModulesCore
|
||||
- ExpoKeepAwake (10.1.1):
|
||||
- ExpoModulesCore
|
||||
- ExpoModulesCore (0.9.2):
|
||||
- ExpoModulesCore (0.11.4):
|
||||
- React-Core
|
||||
- ReactCommon/turbomodule/core
|
||||
- ExpoWebBrowser (10.2.1):
|
||||
|
@ -592,7 +592,7 @@ DEPENDENCIES:
|
|||
- EXAV (from `../node_modules/expo-av/ios`)
|
||||
- EXFileSystem (from `../node_modules/expo-file-system/ios`)
|
||||
- EXLocalAuthentication (from `../node_modules/expo-local-authentication/ios`)
|
||||
- Expo (from `../node_modules/expo/ios`)
|
||||
- Expo (from `../node_modules/expo`)
|
||||
- ExpoHaptics (from `../node_modules/expo-haptics/ios`)
|
||||
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
|
||||
- ExpoModulesCore (from `../node_modules/expo-modules-core/ios`)
|
||||
|
@ -719,7 +719,7 @@ EXTERNAL SOURCES:
|
|||
EXLocalAuthentication:
|
||||
:path: "../node_modules/expo-local-authentication/ios"
|
||||
Expo:
|
||||
:path: "../node_modules/expo/ios"
|
||||
:path: "../node_modules/expo"
|
||||
ExpoHaptics:
|
||||
:path: "../node_modules/expo-haptics/ios"
|
||||
ExpoKeepAwake:
|
||||
|
@ -894,10 +894,10 @@ SPEC CHECKSUMS:
|
|||
EXAV: 88f61c5af8415715b7ee51f084c1020235b85c56
|
||||
EXFileSystem: 2aa2d9289f84bca9532b9ccbd81504fa31eb1ded
|
||||
EXLocalAuthentication: 7f37b242eae73f9acf111d39bdee3f1379e68902
|
||||
Expo: b9fff0a1eac0f424fc68ea49b4347fb308e52e17
|
||||
Expo: 73412414e62f5cbc6e713def821de70b92cd3ad6
|
||||
ExpoHaptics: ad58ec96a25e57579c14a47c7d71f0de0de8656a
|
||||
ExpoKeepAwake: c0c494b442ecd8122974c13b93ccfb57bd408e88
|
||||
ExpoModulesCore: e4278a668e8c13c0269ed8b8a4200989deea2973
|
||||
ExpoModulesCore: e281bb7b78ea47e227dd5af94d04b24d8b2e1255
|
||||
ExpoWebBrowser: 4b5f9633e5f169dc948587cb6d26d2d1d1406187
|
||||
EXVideoThumbnails: 19e055dc3245b53c536da9e0ef9c618fd2118297
|
||||
FBLazyVector: a7a655862f6b09625d11c772296b01cd5164b648
|
||||
|
|
|
@ -1767,7 +1767,7 @@
|
|||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 4.30.0;
|
||||
MARKETING_VERSION = 4.31.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||
|
@ -1806,7 +1806,7 @@
|
|||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 4.30.0;
|
||||
MARKETING_VERSION = 4.31.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import <React/RCTBridgeDelegate.h>
|
||||
#import <Expo/Expo.h>
|
||||
// https://github.com/expo/expo/issues/17705#issuecomment-1196251146
|
||||
#import "ExpoModulesCore-Swift.h"
|
||||
#import "RocketChatRN-Swift.h"
|
||||
|
||||
@interface AppDelegate : EXAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate>
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
}
|
||||
[Bugsnag start];
|
||||
|
||||
// UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"RocketChatRN", nil);
|
||||
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"RocketChatRN" initialProperties:nil];
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
|
@ -60,7 +59,9 @@
|
|||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
[RNNotifications startMonitorNotifications];
|
||||
[ReplyNotification configure];
|
||||
|
||||
// AppGroup MMKV
|
||||
NSString *groupDir = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]].path;
|
||||
[MMKV initializeMMKV:nil groupDir:groupDir logLevel:MMKVLogNone];
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.30.0</string>
|
||||
<string>4.31.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -68,30 +68,16 @@
|
|||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your calendar</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Take photos to share with other users</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your contacts</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Unlock the app with FaceID</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>This permission stems from a library we use and will never be called anyway. If you see this, deny access</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>This permission stems from a library we use and will never be called anyway. If you see this, deny access</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>This permission stems from a library we use and will never be called anyway. If you see this, deny access</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Use your microphone to record audio messages</string>
|
||||
<key>NSMotionUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your device's accelerometer</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Upload photos to share with other users or to change your avatar</string>
|
||||
<key>NSRemindersUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your reminders</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>custom.ttf</string>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.30.0</string>
|
||||
<string>4.31.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>KeychainGroup</key>
|
||||
|
|
10
package.json
10
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "rocket-chat-reactnative",
|
||||
"version": "4.30.0",
|
||||
"version": "4.31.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "react-native start",
|
||||
|
@ -61,7 +61,7 @@
|
|||
"commonmark-react-renderer": "git+https://github.com/RocketChat/commonmark-react-renderer.git",
|
||||
"dequal": "^2.0.2",
|
||||
"ejson": "2.2.1",
|
||||
"expo": "^45.0.5",
|
||||
"expo": "^46.0.9",
|
||||
"expo-apple-authentication": "4.2.1",
|
||||
"expo-av": "11.2.3",
|
||||
"expo-file-system": "14.0.0",
|
||||
|
@ -104,7 +104,7 @@
|
|||
"react-native-mmkv-storage": "^0.7.6",
|
||||
"react-native-modal": "13.0.1",
|
||||
"react-native-navigation-bar-color": "2.0.1",
|
||||
"react-native-notifications": "^4.2.4",
|
||||
"react-native-notifications": "4.2.4",
|
||||
"react-native-notifier": "1.6.1",
|
||||
"react-native-orientation-locker": "1.1.8",
|
||||
"react-native-picker-select": "^8.0.4",
|
||||
|
@ -137,6 +137,7 @@
|
|||
"ua-parser-js": "^1.0.2",
|
||||
"uri-js": "^4.4.1",
|
||||
"url-parse": "1.5.10",
|
||||
"use-debounce": "^8.0.4",
|
||||
"use-deep-compare-effect": "1.6.1",
|
||||
"xregexp": "5.0.2",
|
||||
"yup": "^0.32.11"
|
||||
|
@ -165,6 +166,7 @@
|
|||
"@types/i18n-js": "^3.8.2",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/lodash": "^4.14.171",
|
||||
"@types/mocha": "^9.1.1",
|
||||
"@types/react": "^17.0.14",
|
||||
"@types/react-native": "0.68.1",
|
||||
"@types/react-native-background-timer": "^2.0.0",
|
||||
|
@ -205,6 +207,7 @@
|
|||
"react-test-renderer": "17.0.2",
|
||||
"reactotron-redux": "3.1.3",
|
||||
"reactotron-redux-saga": "4.2.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"jest": {
|
||||
|
@ -244,6 +247,7 @@
|
|||
}
|
||||
},
|
||||
"detox": {
|
||||
"test-runner": "mocha",
|
||||
"runner-config": "e2e/.mocharc.json",
|
||||
"specs": "e2e/tests",
|
||||
"configurations": {
|
||||
|
|
|
@ -41,3 +41,61 @@ index f9c858b..94ea188 100644
|
|||
|
||||
public abstract class NotificationManagerCompatFacade {
|
||||
public static NotificationManagerCompat from(@NonNull Context context) {
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RCTConvert+RNNotifications.h b/node_modules/react-native-notifications/lib/ios/RCTConvert+RNNotifications.h
|
||||
index 8b2c269..8667351 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RCTConvert+RNNotifications.h
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RCTConvert+RNNotifications.h
|
||||
@@ -1,5 +1,5 @@
|
||||
#import <React/RCTConvert.h>
|
||||
-@import UserNotifications;
|
||||
+#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@interface RCTConvert (UIMutableUserNotificationAction)
|
||||
+ (UIMutableUserNotificationAction *)UIMutableUserNotificationAction:(id)json;
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.h b/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.h
|
||||
index 4bc5292..4839d55 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.h
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.h
|
||||
@@ -4,7 +4,7 @@ typedef void (^RCTPromiseResolveBlock)(id result);
|
||||
typedef void (^RCTResponseSenderBlock)(NSArray *response);
|
||||
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
|
||||
|
||||
-@import UserNotifications;
|
||||
+#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@interface RNNotificationCenter : NSObject
|
||||
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RNNotificationEventHandler.h b/node_modules/react-native-notifications/lib/ios/RNNotificationEventHandler.h
|
||||
index a07c6e9..8e3ca6a 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RNNotificationEventHandler.h
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RNNotificationEventHandler.h
|
||||
@@ -1,5 +1,5 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
-@import UserNotifications;
|
||||
+#import <UserNotifications/UserNotifications.h>
|
||||
#import "RNNotificationsStore.h"
|
||||
#import "RNEventEmitter.h"
|
||||
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RNNotificationParser.h b/node_modules/react-native-notifications/lib/ios/RNNotificationParser.h
|
||||
index 7aa2bfb..c1c019c 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RNNotificationParser.h
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RNNotificationParser.h
|
||||
@@ -1,5 +1,5 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
-@import UserNotifications;
|
||||
+#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@interface RNNotificationParser : NSObject
|
||||
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RNNotificationsStore.h b/node_modules/react-native-notifications/lib/ios/RNNotificationsStore.h
|
||||
index 4f8a171..7e4f9ca 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RNNotificationsStore.h
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RNNotificationsStore.h
|
||||
@@ -1,6 +1,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
-@import UserNotifications;
|
||||
+#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@interface RNNotificationsStore : NSObject
|
||||
|
||||
|
|
407
yarn.lock
407
yarn.lock
|
@ -1324,16 +1324,7 @@
|
|||
"@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
|
||||
"@babel/plugin-proposal-optional-chaining" "^7.18.9"
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.17.12":
|
||||
version "7.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz#094a417e31ce7e692d84bab06c8e2a607cbeef03"
|
||||
integrity sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.17.12"
|
||||
"@babel/helper-remap-async-to-generator" "^7.16.8"
|
||||
"@babel/plugin-syntax-async-generators" "^7.8.4"
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.18.10":
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.0.0", "@babel/plugin-proposal-async-generator-functions@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952"
|
||||
integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==
|
||||
|
@ -1343,6 +1334,15 @@
|
|||
"@babel/helper-remap-async-to-generator" "^7.18.9"
|
||||
"@babel/plugin-syntax-async-generators" "^7.8.4"
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.17.12":
|
||||
version "7.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz#094a417e31ce7e692d84bab06c8e2a607cbeef03"
|
||||
integrity sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.17.12"
|
||||
"@babel/helper-remap-async-to-generator" "^7.16.8"
|
||||
"@babel/plugin-syntax-async-generators" "^7.8.4"
|
||||
|
||||
"@babel/plugin-proposal-class-properties@^7.0.0":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e"
|
||||
|
@ -2344,6 +2344,14 @@
|
|||
"@babel/helper-module-transforms" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d"
|
||||
integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==
|
||||
dependencies:
|
||||
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-named-capturing-groups-regex@^7.17.12":
|
||||
version "7.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz#9c4a5a5966e0434d515f2675c227fd8cc8606931"
|
||||
|
@ -2352,14 +2360,6 @@
|
|||
"@babel/helper-create-regexp-features-plugin" "^7.17.12"
|
||||
"@babel/helper-plugin-utils" "^7.17.12"
|
||||
|
||||
"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d"
|
||||
integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==
|
||||
dependencies:
|
||||
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-new-target@^7.17.12":
|
||||
version "7.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3"
|
||||
|
@ -3407,6 +3407,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@cspotcode/source-map-support@^0.8.0":
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
|
||||
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||
dependencies:
|
||||
"@jridgewell/trace-mapping" "0.3.9"
|
||||
|
||||
"@discoveryjs/json-ext@^0.5.3":
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
|
||||
|
@ -3572,26 +3579,26 @@
|
|||
mv "~2"
|
||||
safe-json-stringify "~1"
|
||||
|
||||
"@expo/cli@0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.1.5.tgz#2427e3c3b6be1936b2e6ffb595fc9c83e37e4be1"
|
||||
integrity sha512-27LNT3b9MtBHEosmvJiC9Ug9aJpQAK9T3cC8ekaB9cHnVcJw+mJs2kdVBYpV1aBjKkH7T57aiWWimZp0O7m1wQ==
|
||||
"@expo/cli@0.2.11":
|
||||
version "0.2.11"
|
||||
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.2.11.tgz#25d8db8e46c6f02ef3edc189fdb6e29c922dd377"
|
||||
integrity sha512-TIlylp3nghiEdlVliZRcBg8Yb++tnU92HinuQQZznVGFXFCoqJ210SPUJS1j3rxxltt8NhIJjL9OTO7PYRqnsQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
"@expo/code-signing-certificates" "^0.0.2"
|
||||
"@expo/config" "~6.0.23"
|
||||
"@expo/config-plugins" "~4.1.4"
|
||||
"@expo/dev-server" "~0.1.110"
|
||||
"@expo/config" "~7.0.1"
|
||||
"@expo/config-plugins" "~5.0.1"
|
||||
"@expo/dev-server" "~0.1.119"
|
||||
"@expo/devcert" "^1.0.0"
|
||||
"@expo/json-file" "^8.2.35"
|
||||
"@expo/metro-config" "~0.3.16"
|
||||
"@expo/metro-config" "~0.3.18"
|
||||
"@expo/osascript" "^2.0.31"
|
||||
"@expo/package-manager" "~0.0.52"
|
||||
"@expo/package-manager" "~0.0.53"
|
||||
"@expo/plist" "^0.0.18"
|
||||
"@expo/prebuild-config" "~4.0.0"
|
||||
"@expo/prebuild-config" "~5.0.3"
|
||||
"@expo/rudder-sdk-node" "1.1.1"
|
||||
"@expo/spawn-async" "1.5.0"
|
||||
"@expo/xcpretty" "^4.1.1"
|
||||
"@expo/xcpretty" "^4.2.1"
|
||||
"@urql/core" "2.3.6"
|
||||
"@urql/exchange-retry" "0.3.0"
|
||||
accepts "^1.3.8"
|
||||
|
@ -3601,6 +3608,7 @@
|
|||
cacache "^15.3.0"
|
||||
chalk "^4.0.0"
|
||||
ci-info "^3.3.0"
|
||||
debug "^4.3.4"
|
||||
env-editor "^0.4.1"
|
||||
form-data "^3.0.1"
|
||||
freeport-async "2.0.0"
|
||||
|
@ -3626,6 +3634,7 @@
|
|||
requireg "^0.2.2"
|
||||
resolve-from "^5.0.0"
|
||||
semver "^6.3.0"
|
||||
send "^0.18.0"
|
||||
slugify "^1.3.4"
|
||||
structured-headers "^0.4.1"
|
||||
tar "^6.0.5"
|
||||
|
@ -3644,7 +3653,7 @@
|
|||
node-forge "^1.2.1"
|
||||
nullthrows "^1.1.1"
|
||||
|
||||
"@expo/config-plugins@4.1.5", "@expo/config-plugins@^4.0.14", "@expo/config-plugins@^4.1.5", "@expo/config-plugins@~4.1.4":
|
||||
"@expo/config-plugins@^4.0.14", "@expo/config-plugins@^4.1.5":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-4.1.5.tgz#9d357d2cda9c095e511b51583ede8a3b76174068"
|
||||
integrity sha512-RVvU40RtZt12HavuDAe+LDIq9lHj7sheOfMEHdmpJ/uTA8pgvkbc56XF6JHQD+yRr6+uhhb+JnAasGq49dsQbw==
|
||||
|
@ -3665,7 +3674,7 @@
|
|||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/config-plugins@~5.0.1":
|
||||
"@expo/config-plugins@~5.0.0", "@expo/config-plugins@~5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-5.0.1.tgz#66bc8d15785bdcd3598e466344f8c0518390179d"
|
||||
integrity sha512-1OfnsOrfeSkB0VZfT01UjQ5Uq6p+yYbq8yNkj0e99K/6NLHpyvIxj+5tZIV0nQXgkOcqBIABL2uA7lwB8CkaBQ==
|
||||
|
@ -3696,24 +3705,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-46.0.2.tgz#191f225ebfcbe624868ddc40efae79593f948dd8"
|
||||
integrity sha512-PXkmOgNwRyBfgVT1HmFZhfh3Qm7WKKyV6mk3/5HJ/LzPh1t+Zs2JrWX8U2YncTLV1QzV7nV8tnkyvszzqnZEzQ==
|
||||
|
||||
"@expo/config@6.0.24", "@expo/config@^6.0.14", "@expo/config@~6.0.23":
|
||||
version "6.0.24"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config/-/config-6.0.24.tgz#3602da8fdfa817e290a52fb328fc8ed9d6bc61e7"
|
||||
integrity sha512-OcACI1md1Yo5TQmUxxueJ/RaTlR2Mgl6KswTFOYCL1XJERF/jjAx95zhWXH+JQGdlM0yB0vqM6vB6GbUFRvLxA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "~7.10.4"
|
||||
"@expo/config-plugins" "4.1.5"
|
||||
"@expo/config-types" "^45.0.0"
|
||||
"@expo/json-file" "8.2.36"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
require-from-string "^2.0.2"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.3.2"
|
||||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
"@expo/config@~7.0.0":
|
||||
"@expo/config@7.0.1", "@expo/config@~7.0.0", "@expo/config@~7.0.1":
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config/-/config-7.0.1.tgz#d8e2e5410bb0b8e305690bbc76e6bb76f6a6de31"
|
||||
integrity sha512-4lu0wr45XXJ2MXiLAm2+fmOyy/jjqF3NuDm92fO6nuulRzEEvTP4w3vsibJ690rT81ohtvhpruKhkRs0wSjKWA==
|
||||
|
@ -3730,13 +3722,13 @@
|
|||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
"@expo/dev-server@~0.1.110":
|
||||
version "0.1.113"
|
||||
resolved "https://registry.yarnpkg.com/@expo/dev-server/-/dev-server-0.1.113.tgz#db4a52af1817fbfbc9dbe52d8673ddc159d0b92c"
|
||||
integrity sha512-PT3HT+3h4ZS1bw6Zz8fqjNeryKOWe1FqGdnz4RSASxZGCzib6VHLfLbJeYHkq7t+ashSXRoAw3XW/9yVdbUqLA==
|
||||
"@expo/dev-server@~0.1.119":
|
||||
version "0.1.119"
|
||||
resolved "https://registry.yarnpkg.com/@expo/dev-server/-/dev-server-0.1.119.tgz#d85036d8ddfd5668fd50ef373616b55580dc7670"
|
||||
integrity sha512-DcVnj4/YA+b+Ljsz2qffHHN5LbouXFKeE9ER0Yjq5vIb2moV1q3U6LezndFLCf42Uev7C2vSa8YCcP3WOpxuMw==
|
||||
dependencies:
|
||||
"@expo/bunyan" "4.0.0"
|
||||
"@expo/metro-config" "0.3.18"
|
||||
"@expo/metro-config" "~0.3.18"
|
||||
"@expo/osascript" "2.0.33"
|
||||
body-parser "1.19.0"
|
||||
chalk "^4.0.0"
|
||||
|
@ -3794,12 +3786,12 @@
|
|||
json5 "^1.0.1"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/metro-config@0.3.18", "@expo/metro-config@~0.3.16":
|
||||
version "0.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.3.18.tgz#72705b3a0a3fb863b1a068f2b5f4cb43828cb26b"
|
||||
integrity sha512-DWtwV67kD8X2uOKIs5QyHlHD+6L6RAgudZZDBmu433ZvL62HAUYfjEi3+i0jeMiUqN85o1vbXg6xqWnBCpS50g==
|
||||
"@expo/metro-config@~0.3.18":
|
||||
version "0.3.22"
|
||||
resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.3.22.tgz#fa4a0729ec8ecbc9c9fb79c63ecc66a299505c82"
|
||||
integrity sha512-R81sLbaeUBjN8IXcxiVx7GcpSj8z7szILl1b5yJDb38WdIFwxhrseA5wXaTT1yMhI+59w6n99T2qtFV2yD5qYA==
|
||||
dependencies:
|
||||
"@expo/config" "6.0.24"
|
||||
"@expo/config" "7.0.1"
|
||||
"@expo/json-file" "8.2.36"
|
||||
chalk "^4.1.0"
|
||||
debug "^4.3.2"
|
||||
|
@ -3816,10 +3808,10 @@
|
|||
"@expo/spawn-async" "^1.5.0"
|
||||
exec-async "^2.2.0"
|
||||
|
||||
"@expo/package-manager@~0.0.52":
|
||||
version "0.0.54"
|
||||
resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-0.0.54.tgz#b56254d06b8a1476dddb2c59be1c0f7b192bab22"
|
||||
integrity sha512-Sr7UsDh9Pcta1gAFZJgszodewEvg/XSRV1oV+iTrkUEhP7NziMrK5dE71O2FHmKGfdrDQgLexvq8HLZdfRskKw==
|
||||
"@expo/package-manager@~0.0.53":
|
||||
version "0.0.56"
|
||||
resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-0.0.56.tgz#214a8db48752cde968827c20c5b54a88187b5422"
|
||||
integrity sha512-PGk34uz4XDyhoNIlPh2D+BDsiXYuW2jXavTiax8d32uvHlRO6FN0cAsqlWD6fx3H2hRn8cU/leTuc4M7pYovCQ==
|
||||
dependencies:
|
||||
"@expo/json-file" "8.2.36"
|
||||
"@expo/spawn-async" "^1.5.0"
|
||||
|
@ -3841,18 +3833,17 @@
|
|||
base64-js "^1.2.3"
|
||||
xmlbuilder "^14.0.0"
|
||||
|
||||
"@expo/prebuild-config@~4.0.0":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-4.0.2.tgz#f6317a7b88cf6eec777c2547e88660c63f153223"
|
||||
integrity sha512-+AQ/EVgcySl3cvYMmZLaEyGkxvQnO+UFU2mshmUoUh5lTIFTNKl1aVo0UmYW2/JehmKu6bxOrr/lL5byHv+fcQ==
|
||||
"@expo/prebuild-config@~5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-5.0.3.tgz#f475797a592f074b5a66f02aef27c6c14c54591e"
|
||||
integrity sha512-G4j1H3WFjRaiQ+FgFNULrnIm7RsQyjc4xp6lLTP2ydBv79wO3x8wAdeZvaZh7eOkfu9BESpQzACT1uuJTag5jg==
|
||||
dependencies:
|
||||
"@expo/config" "6.0.24"
|
||||
"@expo/config-plugins" "4.1.5"
|
||||
"@expo/config-types" "^45.0.0"
|
||||
"@expo/config" "7.0.1"
|
||||
"@expo/config-plugins" "~5.0.1"
|
||||
"@expo/config-types" "^46.0.0"
|
||||
"@expo/image-utils" "0.3.20"
|
||||
"@expo/json-file" "8.2.36"
|
||||
debug "^4.3.1"
|
||||
expo-modules-autolinking "0.8.1"
|
||||
fs-extra "^9.0.0"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.3.2"
|
||||
|
@ -3895,10 +3886,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-13.0.0.tgz#e2989b85e95a82bce216f88cf8fb583ab050ec95"
|
||||
integrity sha512-TI+l71+5aSKnShYclFa14Kum+hQMZ86b95SH6tQUG3qZEmLTarvWpKwqtTwQKqvlJSJrpFiSFu3eCuZokY6zWA==
|
||||
|
||||
"@expo/xcpretty@^4.1.1":
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@expo/xcpretty/-/xcpretty-4.1.3.tgz#cbe04f654571c0ee733dbe729d5593b3bcfbf487"
|
||||
integrity sha512-testj0jpEe1IwRfnmQ3shizTXOY6IGcuMJg1vtmXy2bC9sPTLK1wjliRJp2xCJGcp1ZbEA1/eptzX+6MDnYjrA==
|
||||
"@expo/xcpretty@^4.2.1":
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/xcpretty/-/xcpretty-4.2.2.tgz#7890f86b017015be8a20242ae74fe6ed4b80a92c"
|
||||
integrity sha512-Lke/geldJqUV0Dfxg5/QIOugOzdqZ/rQ9yHKSgGbjZtG1uiSqWyFwWvXmrdd3/sIdX33eykGvIcf+OrvvcXVUw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "7.10.4"
|
||||
chalk "^4.1.0"
|
||||
|
@ -4604,7 +4595,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec"
|
||||
integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.0":
|
||||
"@jridgewell/trace-mapping@0.3.9", "@jridgewell/trace-mapping@^0.3.0":
|
||||
version "0.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
|
||||
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||
|
@ -5841,6 +5832,26 @@
|
|||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
|
||||
|
||||
"@tsconfig/node12@^1.0.7":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
|
||||
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
|
||||
|
||||
"@tsconfig/node14@^1.0.0":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
|
||||
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
|
||||
|
||||
"@tsconfig/node16@^1.0.2":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||
|
||||
"@types/anymatch@*":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
||||
|
@ -6124,6 +6135,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||
|
||||
"@types/mocha@^9.1.1":
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
|
||||
integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
|
||||
|
||||
"@types/node-fetch@^2.5.7":
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da"
|
||||
|
@ -6762,6 +6778,11 @@ acorn-jsx@^5.3.1:
|
|||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
|
||||
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^6.4.1:
|
||||
version "6.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
|
||||
|
@ -6772,7 +6793,7 @@ acorn@^7.4.0:
|
|||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.5.0:
|
||||
acorn@^8.4.1, acorn@^8.5.0:
|
||||
version "8.8.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
|
||||
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
|
||||
|
@ -7049,6 +7070,11 @@ arg@4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0"
|
||||
integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==
|
||||
|
||||
arg@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
|
@ -7544,10 +7570,10 @@ babel-plugin-react-docgen@^4.2.1:
|
|||
lodash "^4.17.15"
|
||||
react-docgen "^5.0.0"
|
||||
|
||||
babel-plugin-react-native-web@~0.17.1:
|
||||
version "0.17.7"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.17.7.tgz#1580e27a2e3c6692127535d3880fe1e247ef6414"
|
||||
integrity sha512-UBLfIsfU3vi//Ab4i0WSWAfm1whLTK9uJoH0RPZ6a67eS/h9JGYjKy7+1RpHxSBviHi9NIMiYfWseTLjyIsE1g==
|
||||
babel-plugin-react-native-web@~0.18.2:
|
||||
version "0.18.7"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.18.7.tgz#d32750aca96e5518122504338196502034393261"
|
||||
integrity sha512-DF7huAePyphXsqWhGyshjQAU9qektOqOSP2NHevtUBhsgLu57D4gEGZM1xPtbJYvW6/DoxuaXUAqjYqfexT+gQ==
|
||||
|
||||
babel-plugin-require-context-hook@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
@ -7592,17 +7618,17 @@ babel-preset-current-node-syntax@^1.0.0:
|
|||
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
|
||||
"@babel/plugin-syntax-top-level-await" "^7.8.3"
|
||||
|
||||
babel-preset-expo@~9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-9.1.0.tgz#4cbac7d28618bb68bc9c2a0e7dccda7b207b61ab"
|
||||
integrity sha512-dFcgT7AY5n15bLnfOM6R25f8Lh7YSALj4zeGze6aspYHfVrREYcovVG0eMGpY9V24fnwByNRv85lElc1jAj1Mw==
|
||||
babel-preset-expo@~9.2.0:
|
||||
version "9.2.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-9.2.0.tgz#d01793e3a556065f103b3095fbbc959d52f08e88"
|
||||
integrity sha512-aM2htiNx0H49H+MWCp9+cKVSdcdNSn0tbE5Dln/GO1xna4ZlnA30clbfClcYJFUcZtW90IsYeZwQ/hj8zyWhNA==
|
||||
dependencies:
|
||||
"@babel/plugin-proposal-decorators" "^7.12.9"
|
||||
"@babel/plugin-transform-react-jsx" "^7.12.17"
|
||||
"@babel/preset-env" "^7.12.9"
|
||||
babel-plugin-module-resolver "^4.1.0"
|
||||
babel-plugin-react-native-web "~0.17.1"
|
||||
metro-react-native-babel-preset "~0.67.0"
|
||||
babel-plugin-react-native-web "~0.18.2"
|
||||
metro-react-native-babel-preset "~0.70.3"
|
||||
|
||||
babel-preset-fbjs@^3.4.0:
|
||||
version "3.4.0"
|
||||
|
@ -9146,6 +9172,11 @@ create-react-context@0.3.0:
|
|||
gud "^1.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
create-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-fetch@^3.0.4:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
|
||||
|
@ -9626,6 +9657,11 @@ diff@5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
|
||||
integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
|
@ -10582,17 +10618,19 @@ expo-apple-authentication@4.2.1:
|
|||
dependencies:
|
||||
"@expo/config-plugins" "^4.0.14"
|
||||
|
||||
expo-application@~4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-application/-/expo-application-4.1.0.tgz#e0214ff7cf73db5a5e97e609ffbab3cc98288030"
|
||||
integrity sha512-Z2kctgVMpYZB1Iwaxd+XcMBq7h8EEY50GGrwxXsb1OHHQKN+WEVGBWxjvtPkAroqCdujLaB5HBay46gvUHRDQg==
|
||||
expo-application@~4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/expo-application/-/expo-application-4.2.2.tgz#c9500819723c59eaee5ca9832bf17d1fd4139f74"
|
||||
integrity sha512-bFEaFRUdV6aK2iBd+HzkHNPYsyj88EAhaQW5leznmO0qQMJxpAQ3eoUXMey1hfDBh1qgkkHgSyCZ9BIgMAGJ1g==
|
||||
|
||||
expo-asset@~8.5.0:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-asset/-/expo-asset-8.5.0.tgz#d83ed8e42f1aa3d74aeca67b87c90e17f1661b0f"
|
||||
integrity sha512-k3QErZYxb6e6rPkJ1sG5yIJ7bhd4RFvnFStz0ZCO6SfktGygBAjTz5aTOLaaomiCIObRiBQ4byky/RLdli/NLw==
|
||||
expo-asset@~8.6.1:
|
||||
version "8.6.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-asset/-/expo-asset-8.6.1.tgz#86355b3e231e8aa6cf68a456ce9746dff1478b48"
|
||||
integrity sha512-urbUp1YtwH2J0Qc3inGQJdqTjWKML77SeMNgff+iR9MUE8gDkFqSCDjrBi7i5Oj5DDtq43mmtDg8G8ei6Vchcg==
|
||||
dependencies:
|
||||
blueimp-md5 "^2.10.0"
|
||||
expo-constants "~13.2.2"
|
||||
expo-file-system "~14.1.0"
|
||||
invariant "^2.2.4"
|
||||
md5-file "^3.2.3"
|
||||
path-browserify "^1.0.0"
|
||||
|
@ -10605,20 +10643,20 @@ expo-av@11.2.3:
|
|||
dependencies:
|
||||
"@expo/config-plugins" "^4.0.14"
|
||||
|
||||
expo-constants@~13.1.1:
|
||||
version "13.1.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-13.1.1.tgz#78c26c760cc63cd5608bc4b51bd159d7339d8054"
|
||||
integrity sha512-QRVHrrMCLenBzWZ8M+EvCXM+jjdQzFMW27YQHRac3SGGoND1hWr81scOmGwlFo2wLZrYXm8HcYt1E6ry3IIwrA==
|
||||
expo-constants@~13.2.2, expo-constants@~13.2.4:
|
||||
version "13.2.4"
|
||||
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-13.2.4.tgz#eab4a553f074b2c60ad7a158d3b82e3484a94606"
|
||||
integrity sha512-Zobau8EuTk2GgafwkfGnWM6CmSLB7X8qnQXVuXe0nd3v92hfQUmRWGhJwH88uxXj3LrfqctM6PaJ8taG1vxfBw==
|
||||
dependencies:
|
||||
"@expo/config" "^6.0.14"
|
||||
"@expo/config" "~7.0.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
expo-error-recovery@~3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-error-recovery/-/expo-error-recovery-3.1.0.tgz#c841772e11ed55180e30ebf809580ab051b70535"
|
||||
integrity sha512-qUxCW7kPB6AVX5h3ZPVnxw4LLZWsRwAPBtRDlh1UDN7GWZ+CQN1SNk0w0BPotjNtSlXEZSFDqKqtoDDAUYjNmg==
|
||||
expo-error-recovery@~3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-error-recovery/-/expo-error-recovery-3.2.0.tgz#3a4543382904a5e70829cb41d7fc0f022c2bef6e"
|
||||
integrity sha512-XZ630ks5HNxa9oc2Ya1hEn1ez031Cy4VnyxerPC2o9fKNKSrD/64cRqGF9NkGM3X2uf8+PCB9adxVflAIXBf6w==
|
||||
|
||||
expo-file-system@14.0.0, expo-file-system@~14.0.0:
|
||||
expo-file-system@14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-14.0.0.tgz#8367af10969a486fcba2f1e1c7cc0148f855e962"
|
||||
integrity sha512-Asva7ehLUq/PIem6Y+/OQvoIqhFqYDd7l4l49yDRDgLSbK2I7Fr8qGhDeDpnUXrMVamg2uwt9zRGhyrjFNRhVw==
|
||||
|
@ -10626,10 +10664,18 @@ expo-file-system@14.0.0, expo-file-system@~14.0.0:
|
|||
"@expo/config-plugins" "^4.0.14"
|
||||
uuid "^3.4.0"
|
||||
|
||||
expo-font@~10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-10.1.0.tgz#2e8f8954943c5afca8444c1ffb1d74623c6a4fb6"
|
||||
integrity sha512-vmhzpE95Ym4iOj8IELof+C/3Weert2B3LyxV5rBjGosjzBdov+o+S6b5mN7Yc9kyEGykwB6k7npL45X3hFYDQA==
|
||||
expo-file-system@~14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-14.1.0.tgz#4fa410873ef12ac8bec873593f7489f4305a14b8"
|
||||
integrity sha512-lJcPGQ8yKXVknVkD5TmcJnR/TpQbEL0JP8hknLejfq3FIqPqI/LBFn31YiP37grxW8lITz1al8pq5T6CSUjAzQ==
|
||||
dependencies:
|
||||
"@expo/config-plugins" "~5.0.0"
|
||||
uuid "^3.4.0"
|
||||
|
||||
expo-font@~10.2.0:
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-10.2.0.tgz#881f767e13b2b534a4d3ffaedcf675ce6b63439d"
|
||||
integrity sha512-2V4EcpmhNoppaLn+lPprZVS+3bmV9hxLPKttKh2u8ghjH/oX9bv3u4JVo77SYh0EfrWO4toqVyXn8pXH8GpbIg==
|
||||
dependencies:
|
||||
fontfaceobserver "^2.1.0"
|
||||
|
||||
|
@ -10638,11 +10684,16 @@ expo-haptics@11.2.0:
|
|||
resolved "https://registry.yarnpkg.com/expo-haptics/-/expo-haptics-11.2.0.tgz#0ffb9f82395e88f9f66ceebb0f3279739311412c"
|
||||
integrity sha512-ijuWU2ljLBGjIf7OQCvnBQIu/chezndnWkfi518XxvK0hudA4+fAe98mqHO6hom9GexNRxhQZbXc0hcVnxkaiA==
|
||||
|
||||
expo-keep-awake@10.1.1, expo-keep-awake@~10.1.1:
|
||||
expo-keep-awake@10.1.1:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-10.1.1.tgz#03023c130f7e3824b738e3fdd5353b8a2c0c1980"
|
||||
integrity sha512-9zC0sdhQljUeMr2yQ7o4kzEZXVAy82fFOAZE1+TwPL7qR0b0sphe7OJ5T1GX1qLcwuVaJ8YewaPoLSHRk79+Rg==
|
||||
|
||||
expo-keep-awake@~10.2.0:
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-10.2.0.tgz#46f04740bccd321732bbbed93491e2076d5dbbd7"
|
||||
integrity sha512-kIRtO4Hmrvxh4E45IPWG/NiUZsuRe1AQwBT09pq+kx8nm6tUS4B9TeL6+1NFy+qVBLbGKDqoQD5Ez7XYTFtBeQ==
|
||||
|
||||
expo-local-authentication@12.2.0:
|
||||
version "12.2.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-local-authentication/-/expo-local-authentication-12.2.0.tgz#a1534d2f1a3e63483d20a1cff303b1a312b8e1ef"
|
||||
|
@ -10651,10 +10702,10 @@ expo-local-authentication@12.2.0:
|
|||
"@expo/config-plugins" "^4.0.14"
|
||||
invariant "^2.2.4"
|
||||
|
||||
expo-modules-autolinking@0.8.1:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-0.8.1.tgz#533c38192847d2272e9af986f8f4c58aae6dfff3"
|
||||
integrity sha512-S8qfaXCv//7tQWV9M+JKx3CF7ypYhDdSUbkUQdaVO/r8D76/aRTArY/aRw1yEfaAOzyK8C8diDToV1itl51DfQ==
|
||||
expo-modules-autolinking@0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-0.10.3.tgz#31bfcf3e4b613a7c3949fb1f1e9c23eea4c14caf"
|
||||
integrity sha512-av9ln2zwUt303g98raX7sDmESgL3SXs1sbbtIjh1rL7R0676XIUacIKgbydR0/4tMbOShWx14Z9fozpk9xIAJA==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
commander "^7.2.0"
|
||||
|
@ -10662,10 +10713,10 @@ expo-modules-autolinking@0.8.1:
|
|||
find-up "^5.0.0"
|
||||
fs-extra "^9.1.0"
|
||||
|
||||
expo-modules-core@0.9.2:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-0.9.2.tgz#657a3d804e73f3d41e6fa35d40a44aee5a4a287e"
|
||||
integrity sha512-p/C0GJxFIIDGwmrWi70Q0ggfsgeUFS25ZkkBgoaHT7MVgiMjlKA/DCC3D6ZUkHl/JlzUm0aTftIGS8LWXsnZBw==
|
||||
expo-modules-core@0.11.4:
|
||||
version "0.11.4"
|
||||
resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-0.11.4.tgz#6b7a27bb212f3fbf7d6803f747f6491aa73a2a09"
|
||||
integrity sha512-8dEYICk7hUi1GPz5hWm8dBuZDGc+4Tm7zDhSIhKApo5jY/5vB4Bk+fjPo693iWn6pp3+XBHT8Ri8rJ3G7wH1vQ==
|
||||
dependencies:
|
||||
compare-versions "^3.4.0"
|
||||
invariant "^2.2.4"
|
||||
|
@ -10682,24 +10733,24 @@ expo-web-browser@10.2.1:
|
|||
dependencies:
|
||||
compare-urls "^2.0.0"
|
||||
|
||||
expo@^45.0.5:
|
||||
version "45.0.5"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-45.0.5.tgz#ff99ad44a59ffabf473c43abbff35d17b10862fe"
|
||||
integrity sha512-ND+Fo/iLZK1ubMvPFzraIQBvtGL7a4ZHGIP8N1PjcOtTGrCc6X7IWyLkfPMAck2yhd80ZTbos8vTU3SAUuBcJw==
|
||||
expo@^46.0.9:
|
||||
version "46.0.9"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-46.0.9.tgz#4b4b943343c45c3a05c71da49c1cfd5555ab5f85"
|
||||
integrity sha512-UsBjm0BL7w+OyF6kypVPrk3jhg9cCXF0D9CaOWQ+cedm7oT4mTVQx9+A45VsDvLzNWBjJejZQZ1PFKqOY5HNcQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
"@expo/cli" "0.1.5"
|
||||
"@expo/cli" "0.2.11"
|
||||
"@expo/vector-icons" "^13.0.0"
|
||||
babel-preset-expo "~9.1.0"
|
||||
babel-preset-expo "~9.2.0"
|
||||
cross-spawn "^6.0.5"
|
||||
expo-application "~4.1.0"
|
||||
expo-asset "~8.5.0"
|
||||
expo-constants "~13.1.1"
|
||||
expo-file-system "~14.0.0"
|
||||
expo-font "~10.1.0"
|
||||
expo-keep-awake "~10.1.1"
|
||||
expo-modules-autolinking "0.8.1"
|
||||
expo-modules-core "0.9.2"
|
||||
expo-application "~4.2.2"
|
||||
expo-asset "~8.6.1"
|
||||
expo-constants "~13.2.4"
|
||||
expo-file-system "~14.1.0"
|
||||
expo-font "~10.2.0"
|
||||
expo-keep-awake "~10.2.0"
|
||||
expo-modules-autolinking "0.10.3"
|
||||
expo-modules-core "0.11.4"
|
||||
fbemitter "^3.0.0"
|
||||
getenv "^1.0.0"
|
||||
invariant "^2.2.4"
|
||||
|
@ -10708,7 +10759,7 @@ expo@^45.0.5:
|
|||
pretty-format "^26.5.2"
|
||||
uuid "^3.4.0"
|
||||
optionalDependencies:
|
||||
expo-error-recovery "~3.1.0"
|
||||
expo-error-recovery "~3.2.0"
|
||||
|
||||
express@^4.17.1:
|
||||
version "4.18.1"
|
||||
|
@ -14279,6 +14330,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
|
|||
dependencies:
|
||||
semver "^6.0.0"
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
makeerror@1.0.12:
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
|
||||
|
@ -14575,7 +14631,7 @@ metro-minify-uglify@0.67.0:
|
|||
dependencies:
|
||||
uglify-es "^3.1.9"
|
||||
|
||||
metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0, metro-react-native-babel-preset@~0.67.0:
|
||||
metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0:
|
||||
version "0.67.0"
|
||||
resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.67.0.tgz#53aec093f53a09b56236a9bb534d76658efcbec7"
|
||||
integrity sha512-tgTG4j0SKwLHbLRELMmgkgkjV1biYkWlGGKOmM484/fJC6bpDikdaFhfjsyE+W+qt7I5szbCPCickMTNQ+zwig==
|
||||
|
@ -14621,6 +14677,51 @@ metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0,
|
|||
"@babel/template" "^7.0.0"
|
||||
react-refresh "^0.4.0"
|
||||
|
||||
metro-react-native-babel-preset@~0.70.3:
|
||||
version "0.70.3"
|
||||
resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.70.3.tgz#1c77ec4544ecd5fb6c803e70b21284d7483e4842"
|
||||
integrity sha512-4Nxc1zEiHEu+GTdEMEsHnRgfaBkg8f/Td3+FcQ8NTSvs+xL3LBrQy6N07idWSQZHIdGFf+tTHvRfSIWLD8u8Tg==
|
||||
dependencies:
|
||||
"@babel/core" "^7.14.0"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
"@babel/plugin-proposal-export-default-from" "^7.0.0"
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.0.0"
|
||||
"@babel/plugin-proposal-optional-catch-binding" "^7.0.0"
|
||||
"@babel/plugin-proposal-optional-chaining" "^7.0.0"
|
||||
"@babel/plugin-syntax-dynamic-import" "^7.0.0"
|
||||
"@babel/plugin-syntax-export-default-from" "^7.0.0"
|
||||
"@babel/plugin-syntax-flow" "^7.2.0"
|
||||
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0"
|
||||
"@babel/plugin-syntax-optional-chaining" "^7.0.0"
|
||||
"@babel/plugin-transform-arrow-functions" "^7.0.0"
|
||||
"@babel/plugin-transform-async-to-generator" "^7.0.0"
|
||||
"@babel/plugin-transform-block-scoping" "^7.0.0"
|
||||
"@babel/plugin-transform-classes" "^7.0.0"
|
||||
"@babel/plugin-transform-computed-properties" "^7.0.0"
|
||||
"@babel/plugin-transform-destructuring" "^7.0.0"
|
||||
"@babel/plugin-transform-exponentiation-operator" "^7.0.0"
|
||||
"@babel/plugin-transform-flow-strip-types" "^7.0.0"
|
||||
"@babel/plugin-transform-function-name" "^7.0.0"
|
||||
"@babel/plugin-transform-literals" "^7.0.0"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.0.0"
|
||||
"@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0"
|
||||
"@babel/plugin-transform-parameters" "^7.0.0"
|
||||
"@babel/plugin-transform-react-display-name" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.0.0"
|
||||
"@babel/plugin-transform-runtime" "^7.0.0"
|
||||
"@babel/plugin-transform-shorthand-properties" "^7.0.0"
|
||||
"@babel/plugin-transform-spread" "^7.0.0"
|
||||
"@babel/plugin-transform-sticky-regex" "^7.0.0"
|
||||
"@babel/plugin-transform-template-literals" "^7.0.0"
|
||||
"@babel/plugin-transform-typescript" "^7.5.0"
|
||||
"@babel/plugin-transform-unicode-regex" "^7.0.0"
|
||||
"@babel/template" "^7.0.0"
|
||||
react-refresh "^0.4.0"
|
||||
|
||||
metro-react-native-babel-transformer@0.67.0, metro-react-native-babel-transformer@^0.67.0:
|
||||
version "0.67.0"
|
||||
resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.67.0.tgz#756d32eb3c05cab3d72fcb1700f8fd09322bb07f"
|
||||
|
@ -17111,7 +17212,7 @@ react-native-navigation-bar-color@2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/react-native-navigation-bar-color/-/react-native-navigation-bar-color-2.0.1.tgz#ee2be25cc37105f7da355717b0a9a32c9c059ae6"
|
||||
integrity sha512-1kE/oxWt+HYjRxdZdvke9tJ365xaee5n3+euOQA1En8zQuSbOxiE4SYEGM7TeaWnmLJ0l37mRnPHaB2H4mGh0A==
|
||||
|
||||
react-native-notifications@^4.2.4:
|
||||
react-native-notifications@4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native-notifications/-/react-native-notifications-4.2.4.tgz#0d686eb1576d3d9cb73dd9db1ee4f212e00f7d89"
|
||||
integrity sha512-ffToxERa2bRUsXShCO19yXY6c6l4Esq7MqRKAb4mPSn+T428X7Je7WYvWOIOVw/BMGJ3R0lPrZk52vDpoYqanw==
|
||||
|
@ -18222,7 +18323,7 @@ semver@^7.3.4, semver@^7.3.7:
|
|||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
send@0.18.0:
|
||||
send@0.18.0, send@^0.18.0:
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
|
||||
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
|
||||
|
@ -19589,6 +19690,25 @@ ts-interface-checker@^0.1.9:
|
|||
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
|
||||
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
|
||||
|
||||
ts-node@^10.9.1:
|
||||
version "10.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "^0.8.0"
|
||||
"@tsconfig/node10" "^1.0.7"
|
||||
"@tsconfig/node12" "^1.0.7"
|
||||
"@tsconfig/node14" "^1.0.0"
|
||||
"@tsconfig/node16" "^1.0.2"
|
||||
acorn "^8.4.1"
|
||||
acorn-walk "^8.1.1"
|
||||
arg "^4.1.0"
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
v8-compile-cache-lib "^3.0.1"
|
||||
yn "3.1.1"
|
||||
|
||||
ts-pnp@^1.1.6:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
|
||||
|
@ -20093,6 +20213,11 @@ use-composed-ref@^1.3.0:
|
|||
resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.3.0.tgz#3d8104db34b7b264030a9d916c5e94fbe280dbda"
|
||||
integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==
|
||||
|
||||
use-debounce@^8.0.4:
|
||||
version "8.0.4"
|
||||
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-8.0.4.tgz#27e93b2f010bd0b8ad06e9fc7de891d9ee5d6b8e"
|
||||
integrity sha512-fGqsYQzl8kLHF2QpQSgIwgOgJmnh6j5L6SIzQiHdLfwp3q1egUL3btq5Bg2SJysH6A0ILLgT2IqXZKoNJr0nFw==
|
||||
|
||||
use-deep-compare-effect@1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/use-deep-compare-effect/-/use-deep-compare-effect-1.6.1.tgz#061a0ac5400aa0461e33dddfaa2a98bca873182a"
|
||||
|
@ -20212,6 +20337,11 @@ uuid@^8.0.0, uuid@^8.3.2:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
v8-compile-cache-lib@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
||||
|
@ -20827,6 +20957,11 @@ yargs@^17.3.1:
|
|||
y18n "^5.0.5"
|
||||
yargs-parser "^21.0.0"
|
||||
|
||||
yn@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||
|
||||
yocto-queue@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
|
|
Loading…
Reference in New Issue