Merge 4.26.2 into single-server (#4001)
This commit is contained in:
parent
9d2175485c
commit
b3c37ede7e
|
@ -1,45 +1,8 @@
|
||||||
import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
|
import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
|
||||||
import { render } from '@testing-library/react-native';
|
import { render } from '@testing-library/react-native';
|
||||||
|
|
||||||
jest.mock('rn-fetch-blob', () => ({
|
|
||||||
fs: {
|
|
||||||
dirs: {
|
|
||||||
DocumentDir: '/data/com.rocket.chat/documents',
|
|
||||||
DownloadDir: '/data/com.rocket.chat/downloads'
|
|
||||||
},
|
|
||||||
exists: jest.fn(() => null)
|
|
||||||
},
|
|
||||||
fetch: jest.fn(() => null),
|
|
||||||
config: jest.fn(() => null)
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('react-native-file-viewer', () => ({
|
|
||||||
open: jest.fn(() => null)
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('../app/lib/database', () => jest.fn(() => null));
|
|
||||||
global.Date.now = jest.fn(() => new Date('2019-10-10').getTime());
|
global.Date.now = jest.fn(() => new Date('2019-10-10').getTime());
|
||||||
|
|
||||||
jest.mock('react-native-mmkv-storage', () => {
|
|
||||||
return {
|
|
||||||
Loader: jest.fn().mockImplementation(() => {
|
|
||||||
return {
|
|
||||||
setProcessingMode: jest.fn().mockImplementation(() => {
|
|
||||||
return {
|
|
||||||
withEncryption: jest.fn().mockImplementation(() => {
|
|
||||||
return {
|
|
||||||
initialize: jest.fn()
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
create: jest.fn(),
|
|
||||||
MODES: { MULTI_PROCESS: '' }
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const converter = new Stories2SnapsConverter();
|
const converter = new Stories2SnapsConverter();
|
||||||
|
|
||||||
initStoryshots({
|
initStoryshots({
|
||||||
|
|
|
@ -144,7 +144,7 @@ android {
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode VERSIONCODE as Integer
|
versionCode VERSIONCODE as Integer
|
||||||
versionName "4.26.1"
|
versionName "4.26.2"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
if (!isFoss) {
|
if (!isFoss) {
|
||||||
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { avatarURL } from '../../utils/avatar';
|
||||||
import { SubscriptionType } from '../../definitions/ISubscription';
|
import { SubscriptionType } from '../../definitions/ISubscription';
|
||||||
import Emoji from '../markdown/Emoji';
|
import Emoji from '../markdown/Emoji';
|
||||||
import { IAvatar } from './interfaces';
|
import { IAvatar } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const Avatar = React.memo(
|
const Avatar = React.memo(
|
||||||
({
|
({
|
||||||
|
@ -18,7 +19,6 @@ const Avatar = React.memo(
|
||||||
user,
|
user,
|
||||||
onPress,
|
onPress,
|
||||||
emoji,
|
emoji,
|
||||||
theme,
|
|
||||||
getCustomEmoji,
|
getCustomEmoji,
|
||||||
avatarETag,
|
avatarETag,
|
||||||
isStatic,
|
isStatic,
|
||||||
|
@ -34,6 +34,8 @@ const Avatar = React.memo(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const avatarStyle = {
|
const avatarStyle = {
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
|
@ -44,7 +46,7 @@ const Avatar = React.memo(
|
||||||
if (emoji) {
|
if (emoji) {
|
||||||
image = (
|
image = (
|
||||||
<Emoji
|
<Emoji
|
||||||
theme={theme!}
|
theme={theme}
|
||||||
baseUrl={server}
|
baseUrl={server}
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
isMessageContainsOnlyEmoji
|
isMessageContainsOnlyEmoji
|
||||||
|
|
|
@ -5,13 +5,11 @@ import { Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import { getUserSelector } from '../../selectors/login';
|
import { getUserSelector } from '../../selectors/login';
|
||||||
import { TSubscriptionModel, TUserModel } from '../../definitions';
|
import { IApplicationState, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||||
import Avatar from './Avatar';
|
import Avatar from './Avatar';
|
||||||
import { IAvatar } from './interfaces';
|
import { IAvatar } from './interfaces';
|
||||||
|
|
||||||
class AvatarContainer extends React.Component<IAvatar, any> {
|
class AvatarContainer extends React.Component<IAvatar, any> {
|
||||||
private mounted: boolean;
|
|
||||||
|
|
||||||
private subscription?: Subscription;
|
private subscription?: Subscription;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -21,16 +19,11 @@ class AvatarContainer extends React.Component<IAvatar, any> {
|
||||||
|
|
||||||
constructor(props: IAvatar) {
|
constructor(props: IAvatar) {
|
||||||
super(props);
|
super(props);
|
||||||
this.mounted = false;
|
|
||||||
this.state = { avatarETag: '' };
|
this.state = { avatarETag: '' };
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidUpdate(prevProps: IAvatar) {
|
||||||
this.mounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: any) {
|
|
||||||
const { text, type } = this.props;
|
const { text, type } = this.props;
|
||||||
if (prevProps.text !== text || prevProps.type !== type) {
|
if (prevProps.text !== text || prevProps.type !== type) {
|
||||||
this.init();
|
this.init();
|
||||||
|
@ -88,12 +81,7 @@ class AvatarContainer extends React.Component<IAvatar, any> {
|
||||||
const observable = record.observe() as Observable<TSubscriptionModel | TUserModel>;
|
const observable = record.observe() as Observable<TSubscriptionModel | TUserModel>;
|
||||||
this.subscription = observable.subscribe(r => {
|
this.subscription = observable.subscribe(r => {
|
||||||
const { avatarETag } = r;
|
const { avatarETag } = r;
|
||||||
if (this.mounted) {
|
|
||||||
this.setState({ avatarETag });
|
this.setState({ avatarETag });
|
||||||
} else {
|
|
||||||
// @ts-ignore
|
|
||||||
this.state.avatarETag = avatarETag;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -105,12 +93,12 @@ class AvatarContainer extends React.Component<IAvatar, any> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
user: getUserSelector(state),
|
user: getUserSelector(state),
|
||||||
server: state.share.server.server || state.server.server,
|
server: state.share.server.server || state.server.server,
|
||||||
serverVersion: state.share.server.version || state.server.version,
|
serverVersion: state.share.server.version || state.server.version,
|
||||||
blockUnauthenticatedAccess:
|
blockUnauthenticatedAccess:
|
||||||
state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess ??
|
(state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess as boolean) ??
|
||||||
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
|
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,12 +16,11 @@ export interface IAvatar {
|
||||||
id?: string;
|
id?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
};
|
};
|
||||||
theme?: string;
|
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
getCustomEmoji?: TGetCustomEmoji;
|
getCustomEmoji?: TGetCustomEmoji;
|
||||||
avatarETag?: string;
|
avatarETag?: string;
|
||||||
isStatic?: boolean | string;
|
isStatic?: boolean | string;
|
||||||
rid?: string;
|
rid?: string;
|
||||||
blockUnauthenticatedAccess?: boolean;
|
blockUnauthenticatedAccess?: boolean;
|
||||||
serverVersion: string;
|
serverVersion: string | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,7 +285,7 @@ class LoginServices extends React.PureComponent<ILoginServicesProps, ILoginServi
|
||||||
toValue: height,
|
toValue: height,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
easing: Easing.inOut(Easing.quad),
|
easing: Easing.inOut(Easing.quad),
|
||||||
useNativeDriver: true
|
useNativeDriver: false
|
||||||
}).start();
|
}).start();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||||
import { Alert, Clipboard, Share } from 'react-native';
|
import { Alert, Share } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ interface IItem {
|
||||||
|
|
||||||
interface IModalContent {
|
interface IModalContent {
|
||||||
message?: TMessageModel;
|
message?: TMessageModel;
|
||||||
onClose: Function;
|
onClose: () => void;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,11 @@ const styles = StyleSheet.create({
|
||||||
interface ISearchBox extends TextInputProps {
|
interface ISearchBox extends TextInputProps {
|
||||||
value?: string;
|
value?: string;
|
||||||
hasCancel?: boolean;
|
hasCancel?: boolean;
|
||||||
onCancelPress?: Function;
|
onCancelPress?: () => void;
|
||||||
inputRef?: React.Ref<RNTextInput>;
|
inputRef?: React.Ref<RNTextInput>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CancelButton = ({ onCancelPress }: { onCancelPress?: Function }) => {
|
const CancelButton = ({ onCancelPress }: { onCancelPress?: () => void }) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<Touchable onPress={onCancelPress} style={styles.cancel}>
|
<Touchable onPress={onCancelPress} style={styles.cancel}>
|
||||||
|
@ -84,7 +84,7 @@ const SearchBox = ({ hasCancel, onCancelPress, inputRef, ...props }: ISearchBox)
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{hasCancel ? <CancelButton onCancelPress={onCancelPress} /> : null}
|
{hasCancel && onCancelPress ? <CancelButton onCancelPress={onCancelPress} /> : null}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,10 @@ import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
import Button from '../Button';
|
import Button from '../Button';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import { IActions } from './interfaces';
|
import { IActions } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
export const Actions = ({ blockId, appId, elements, parser, theme }: IActions) => {
|
export const Actions = ({ blockId, appId, elements, parser }: IActions) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const [showMoreVisible, setShowMoreVisible] = useState(() => elements && elements.length > 5);
|
const [showMoreVisible, setShowMoreVisible] = useState(() => elements && elements.length > 5);
|
||||||
const renderedElements = showMoreVisible ? elements?.slice(0, 5) : elements;
|
const renderedElements = showMoreVisible ? elements?.slice(0, 5) : elements;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
import DateTimePicker from '@react-native-community/datetimepicker';
|
import DateTimePicker, { Event } from '@react-native-community/datetimepicker';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -11,6 +11,7 @@ import { themes } from '../../constants/colors';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import { isAndroid } from '../../utils/deviceInfo';
|
import { isAndroid } from '../../utils/deviceInfo';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
import ActivityIndicator from '../ActivityIndicator';
|
import ActivityIndicator from '../ActivityIndicator';
|
||||||
import { IDatePicker } from './interfaces';
|
import { IDatePicker } from './interfaces';
|
||||||
|
|
||||||
|
@ -36,14 +37,17 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DatePicker = ({ element, language, action, context, theme, loading, value, error }: IDatePicker) => {
|
export const DatePicker = ({ element, language, action, context, loading, value, error }: IDatePicker) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const [show, onShow] = useState(false);
|
const [show, onShow] = useState(false);
|
||||||
const initial_date = element?.initial_date;
|
const initial_date = element?.initial_date;
|
||||||
const placeholder = element?.placeholder;
|
const placeholder = element?.placeholder;
|
||||||
|
|
||||||
const [currentDate, onChangeDate] = useState(new Date(initial_date || value));
|
const [currentDate, onChangeDate] = useState(new Date(initial_date || value));
|
||||||
|
|
||||||
const onChange = ({ nativeEvent: { timestamp } }: any, date: any) => {
|
// timestamp as number exists in Event
|
||||||
|
// @ts-ignore
|
||||||
|
const onChange = ({ nativeEvent: { timestamp } }: Event, date?: Date) => {
|
||||||
const newDate = date || new Date(timestamp);
|
const newDate = date || new Date(timestamp);
|
||||||
onChangeDate(newDate);
|
onChangeDate(newDate);
|
||||||
action({ value: moment(newDate).format('YYYY-MM-DD') });
|
action({ value: moment(newDate).format('YYYY-MM-DD') });
|
||||||
|
@ -52,7 +56,9 @@ export const DatePicker = ({ element, language, action, context, theme, loading,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let button = <Button title={textParser([placeholder])} onPress={() => onShow(!show)} loading={loading} theme={theme} />;
|
let button = placeholder ? (
|
||||||
|
<Button title={textParser([placeholder])} onPress={() => onShow(!show)} loading={loading} theme={theme} />
|
||||||
|
) : null;
|
||||||
|
|
||||||
if (context === BLOCK_CONTEXT.FORM) {
|
if (context === BLOCK_CONTEXT.FORM) {
|
||||||
button = (
|
button = (
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
import ImageContainer from '../message/Image';
|
import ImageContainer from '../message/Image';
|
||||||
import Navigation from '../../lib/Navigation';
|
import Navigation from '../../lib/Navigation';
|
||||||
import { IThumb, IImage, IElement } from './interfaces';
|
import { IThumb, IImage, IElement } from './interfaces';
|
||||||
import { TThemeMode } from '../../definitions/ITheme';
|
import { IAttachment } from '../../definitions';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
image: {
|
image: {
|
||||||
|
@ -27,23 +27,22 @@ export const Thumb = ({ element, size = 88 }: IThumb) => (
|
||||||
<FastImage style={[{ width: size, height: size }, styles.image]} source={{ uri: element?.imageUrl }} />
|
<FastImage style={[{ width: size, height: size }, styles.image]} source={{ uri: element?.imageUrl }} />
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Media = ({ element, theme }: IImage) => {
|
export const Media = ({ element }: IImage) => {
|
||||||
const showAttachment = (attachment: any) => Navigation.navigate('AttachmentView', { attachment });
|
const showAttachment = (attachment: IAttachment) => Navigation.navigate('AttachmentView', { attachment });
|
||||||
const imageUrl = element?.imageUrl ?? '';
|
const imageUrl = element?.imageUrl ?? '';
|
||||||
// @ts-ignore
|
|
||||||
// TODO: delete ts-ignore after refactor Markdown and ImageContainer
|
return <ImageContainer file={{ image_url: imageUrl }} imageUrl={imageUrl} showAttachment={showAttachment} />;
|
||||||
return <ImageContainer file={{ image_url: imageUrl }} imageUrl={imageUrl} showAttachment={showAttachment} theme={theme} />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const genericImage = (theme: TThemeMode, element: IElement, context?: number) => {
|
const genericImage = (element: IElement, context?: number) => {
|
||||||
switch (context) {
|
switch (context) {
|
||||||
case BLOCK_CONTEXT.SECTION:
|
case BLOCK_CONTEXT.SECTION:
|
||||||
return <Thumb element={element} />;
|
return <Thumb element={element} />;
|
||||||
case BLOCK_CONTEXT.CONTEXT:
|
case BLOCK_CONTEXT.CONTEXT:
|
||||||
return <ThumbContext element={element} />;
|
return <ThumbContext element={element} />;
|
||||||
default:
|
default:
|
||||||
return <Media element={element} theme={theme} />;
|
return <Media element={element} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Image = ({ element, context, theme }: IImage) => genericImage(theme, element, context);
|
export const Image = ({ element, context }: IImage) => genericImage(element, context);
|
||||||
|
|
|
@ -7,26 +7,23 @@ import { themes } from '../../../constants/colors';
|
||||||
import { textParser } from '../utils';
|
import { textParser } from '../utils';
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { IItemData } from '.';
|
||||||
|
|
||||||
interface IChip {
|
interface IChip {
|
||||||
item: {
|
item: IItemData;
|
||||||
value: string;
|
onSelect: (item: IItemData) => void;
|
||||||
imageUrl: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
onSelect: Function;
|
|
||||||
style?: object;
|
style?: object;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IChips {
|
interface IChips {
|
||||||
items: [];
|
items: IItemData[];
|
||||||
onSelect: Function;
|
onSelect: (item: IItemData) => void;
|
||||||
style?: object;
|
style?: object;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyExtractor = (item: any) => item.value.toString();
|
const keyExtractor = (item: IItemData) => item.value.toString();
|
||||||
|
|
||||||
const Chip = ({ item, onSelect, style, theme }: IChip) => (
|
const Chip = ({ item, onSelect, style, theme }: IChip) => (
|
||||||
<Touchable
|
<Touchable
|
||||||
|
|
|
@ -9,10 +9,10 @@ import styles from './styles';
|
||||||
|
|
||||||
interface IInput {
|
interface IInput {
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
onPress: Function;
|
onPress: () => void;
|
||||||
theme: string;
|
theme: string;
|
||||||
inputStyle?: object;
|
inputStyle?: object;
|
||||||
disabled?: boolean | object;
|
disabled?: boolean | null;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
innerInputStyle?: object;
|
innerInputStyle?: object;
|
||||||
|
|
|
@ -8,34 +8,31 @@ import * as List from '../../List';
|
||||||
import { textParser } from '../utils';
|
import { textParser } from '../utils';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { IItemData } from '.';
|
||||||
|
|
||||||
interface IItem {
|
interface IItem {
|
||||||
item: {
|
item: IItemData;
|
||||||
value: { name: string };
|
selected?: string;
|
||||||
text: { text: string };
|
|
||||||
imageUrl: string;
|
|
||||||
};
|
|
||||||
selected: any;
|
|
||||||
onSelect: Function;
|
onSelect: Function;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IItems {
|
interface IItems {
|
||||||
items: [];
|
items: IItemData[];
|
||||||
selected: [];
|
selected: string[];
|
||||||
onSelect: Function;
|
onSelect: Function;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyExtractor = (item: any) => item.value.toString();
|
const keyExtractor = (item: IItemData) => item.value.toString();
|
||||||
|
|
||||||
// RectButton doesn't work on modal (Android)
|
// RectButton doesn't work on modal (Android)
|
||||||
const Item = ({ item, selected, onSelect, theme }: IItem) => {
|
const Item = ({ item, selected, onSelect, theme }: IItem) => {
|
||||||
const itemName = item.value.name || item.text.text.toLowerCase();
|
const itemName = item.value || item.text.text.toLowerCase();
|
||||||
return (
|
return (
|
||||||
<Touchable
|
<Touchable
|
||||||
testID={`multi-select-item-${itemName}`}
|
testID={`multi-select-item-${itemName}`}
|
||||||
key={item}
|
key={itemName}
|
||||||
onPress={() => onSelect(item)}
|
onPress={() => onSelect(item)}
|
||||||
style={[styles.item, { backgroundColor: themes[theme].backgroundColor }]}>
|
style={[styles.item, { backgroundColor: themes[theme].backgroundColor }]}>
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Animated, Easing, KeyboardAvoidingView, Modal, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
import {
|
||||||
|
Animated,
|
||||||
|
Easing,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Modal,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableWithoutFeedback,
|
||||||
|
View,
|
||||||
|
TextStyle
|
||||||
|
} from 'react-native';
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
|
|
||||||
import Button from '../../Button';
|
import Button from '../../Button';
|
||||||
|
@ -8,26 +18,31 @@ import { textParser } from '../utils';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
import { isIOS } from '../../../utils/deviceInfo';
|
import { isIOS } from '../../../utils/deviceInfo';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
import { BlockContext, IText } from '../interfaces';
|
||||||
import Chips from './Chips';
|
import Chips from './Chips';
|
||||||
import Items from './Items';
|
import Items from './Items';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
export interface IItemData {
|
||||||
|
value: string;
|
||||||
|
text: { text: string };
|
||||||
|
imageUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface IMultiSelect {
|
interface IMultiSelect {
|
||||||
options: any[];
|
options?: IItemData[];
|
||||||
onChange: Function;
|
onChange: Function;
|
||||||
placeholder: {
|
placeholder?: IText;
|
||||||
text: string;
|
context?: BlockContext;
|
||||||
};
|
|
||||||
context?: number;
|
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
multiselect?: boolean;
|
multiselect?: boolean;
|
||||||
onSearch?: () => void;
|
onSearch?: () => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
inputStyle?: object;
|
inputStyle?: TextStyle;
|
||||||
value?: any[];
|
value?: any[];
|
||||||
disabled?: boolean | object;
|
disabled?: boolean | null;
|
||||||
theme: string;
|
|
||||||
innerInputStyle?: object;
|
innerInputStyle?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +69,9 @@ export const MultiSelect = React.memo(
|
||||||
onClose = () => {},
|
onClose = () => {},
|
||||||
disabled,
|
disabled,
|
||||||
inputStyle,
|
inputStyle,
|
||||||
theme,
|
|
||||||
innerInputStyle
|
innerInputStyle
|
||||||
}: IMultiSelect) => {
|
}: IMultiSelect) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const [selected, select] = useState<any>(Array.isArray(values) ? values : []);
|
const [selected, select] = useState<any>(Array.isArray(values) ? values : []);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [search, onSearchChange] = useState('');
|
const [search, onSearchChange] = useState('');
|
||||||
|
@ -95,7 +110,7 @@ export const MultiSelect = React.memo(
|
||||||
}).start(() => setShowContent(false));
|
}).start(() => setShowContent(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = (item: any) => {
|
const onSelect = (item: IItemData) => {
|
||||||
const {
|
const {
|
||||||
value,
|
value,
|
||||||
text: { text }
|
text: { text }
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Touchable from 'react-native-platform-touchable';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import ActivityIndicator from '../ActivityIndicator';
|
import ActivityIndicator from '../ActivityIndicator';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
import { BUTTON_HIT_SLOP } from '../message/utils';
|
import { BUTTON_HIT_SLOP } from '../message/utils';
|
||||||
import * as List from '../List';
|
import * as List from '../List';
|
||||||
import { IOption, IOptions, IOverflow } from './interfaces';
|
import { IOption, IOptions, IOverflow } from './interfaces';
|
||||||
|
@ -43,9 +44,10 @@ const Options = ({ options, onOptionPress, parser, theme }: IOptions) => (
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const touchable: { [key: string]: any } = {};
|
const touchable: { [key: string]: Touchable | null } = {};
|
||||||
|
|
||||||
export const Overflow = ({ element, loading, action, parser, theme }: IOverflow) => {
|
export const Overflow = ({ element, loading, action, parser }: IOverflow) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const options = element?.options || [];
|
const options = element?.options || [];
|
||||||
const blockId = element?.blockId || '';
|
const blockId = element?.blockId || '';
|
||||||
const [show, onShow] = useState(false);
|
const [show, onShow] = useState(false);
|
||||||
|
@ -58,7 +60,7 @@ export const Overflow = ({ element, loading, action, parser, theme }: IOverflow)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Touchable
|
<Touchable
|
||||||
ref={(ref: any) => (touchable[blockId] = ref)}
|
ref={ref => (touchable[blockId] = ref)}
|
||||||
background={Touchable.Ripple(themes[theme].bannerBackground)}
|
background={Touchable.Ripple(themes[theme].bannerBackground)}
|
||||||
onPress={() => onShow(!show)}
|
onPress={() => onShow(!show)}
|
||||||
hitSlop={BUTTON_HIT_SLOP}
|
hitSlop={BUTTON_HIT_SLOP}
|
||||||
|
@ -71,6 +73,7 @@ export const Overflow = ({ element, loading, action, parser, theme }: IOverflow)
|
||||||
</Touchable>
|
</Touchable>
|
||||||
<Popover
|
<Popover
|
||||||
isVisible={show}
|
isVisible={show}
|
||||||
|
// fromView exists in Popover Component
|
||||||
/* @ts-ignore*/
|
/* @ts-ignore*/
|
||||||
fromView={touchable[blockId]}
|
fromView={touchable[blockId]}
|
||||||
onRequestClose={() => onShow(false)}>
|
onRequestClose={() => onShow(false)}>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { IAccessoryComponent, IFields, ISection } from './interfaces';
|
import { IAccessoryComponent, IFields, ISection } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
content: {
|
content: {
|
||||||
|
@ -37,10 +38,14 @@ const Fields = ({ fields, parser, theme }: IFields) => (
|
||||||
|
|
||||||
const accessoriesRight = ['image', 'overflow'];
|
const accessoriesRight = ['image', 'overflow'];
|
||||||
|
|
||||||
export const Section = ({ blockId, appId, text, fields, accessory, parser, theme }: ISection) => (
|
export const Section = ({ blockId, appId, text, fields, accessory, parser }: ISection) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
<View style={[styles.content, accessory && accessoriesRight.includes(accessory.type) ? styles.row : styles.column]}>
|
<View style={[styles.content, accessory && accessoriesRight.includes(accessory.type) ? styles.row : styles.column]}>
|
||||||
{text ? <View style={styles.text}>{parser.text(text)}</View> : null}
|
{text ? <View style={styles.text}>{parser.text(text)}</View> : null}
|
||||||
{fields ? <Fields fields={fields} theme={theme} parser={parser} /> : null}
|
{fields ? <Fields fields={fields} theme={theme} parser={parser} /> : null}
|
||||||
{accessory ? <Accessory element={{ blockId, appId, ...accessory }} parser={parser} /> : null}
|
{accessory ? <Accessory element={{ blockId, appId, ...accessory }} parser={parser} /> : null}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { CustomIcon } from '../../lib/Icons';
|
||||||
import { textParser } from './utils';
|
import { textParser } from './utils';
|
||||||
import { isAndroid, isIOS } from '../../utils/deviceInfo';
|
import { isAndroid, isIOS } from '../../utils/deviceInfo';
|
||||||
import ActivityIndicator from '../ActivityIndicator';
|
import ActivityIndicator from '../ActivityIndicator';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
import { IText, Option } from './interfaces';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
iosPadding: {
|
iosPadding: {
|
||||||
|
@ -34,19 +36,16 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ISelect {
|
interface ISelect {
|
||||||
options: {
|
options?: Option[];
|
||||||
text: string;
|
placeholder?: IText;
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
placeholder: string;
|
|
||||||
onChange: Function;
|
onChange: Function;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
disabled: boolean;
|
disabled?: boolean;
|
||||||
value: [];
|
value: [];
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Select = ({ options = [], placeholder, onChange, loading, disabled, value: initialValue, theme }: ISelect) => {
|
export const Select = ({ options = [], placeholder, onChange, loading, disabled, value: initialValue }: ISelect) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const [selected, setSelected] = useState(!Array.isArray(initialValue) && initialValue);
|
const [selected, setSelected] = useState(!Array.isArray(initialValue) && initialValue);
|
||||||
const items = options.map(option => ({ label: textParser([option.text]), value: option.value }));
|
const items = options.map(option => ({ label: textParser([option.text]), value: option.value }));
|
||||||
const pickerStyle = {
|
const pickerStyle = {
|
||||||
|
@ -80,6 +79,7 @@ export const Select = ({ options = [], placeholder, onChange, loading, disabled,
|
||||||
}}
|
}}
|
||||||
Icon={Icon}
|
Icon={Icon}
|
||||||
textInputProps={{
|
textInputProps={{
|
||||||
|
// style property was Omitted in lib, but can be used normally
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
style: { ...styles.pickerText, color: selected ? themes[theme].titleText : themes[theme].auxiliaryText }
|
style: { ...styles.pickerText, color: selected ? themes[theme].titleText : themes[theme].auxiliaryText }
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { Input } from './Input';
|
||||||
import { DatePicker } from './DatePicker';
|
import { DatePicker } from './DatePicker';
|
||||||
import { Overflow } from './Overflow';
|
import { Overflow } from './Overflow';
|
||||||
import { ThemeContext } from '../../theme';
|
import { ThemeContext } from '../../theme';
|
||||||
import { BlockContext, IButton, IInputIndex, IParser, IText } from './interfaces';
|
import { BlockContext, IActions, IButton, IElement, IInputIndex, IParser, ISection, IText } from './interfaces';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
input: {
|
input: {
|
||||||
|
@ -78,35 +78,28 @@ class MessageParser extends UiKitParserMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
divider() {
|
divider() {
|
||||||
const { theme } = useContext(ThemeContext);
|
return <Divider />;
|
||||||
// @ts-ignore
|
|
||||||
return <Divider theme={theme} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
section(args: any) {
|
section(args: ISection) {
|
||||||
const { theme } = useContext(ThemeContext);
|
return <Section {...args} parser={this.current} />;
|
||||||
return <Section {...args} theme={theme} parser={this} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actions(args: any) {
|
actions(args: IActions) {
|
||||||
const { theme } = useContext(ThemeContext);
|
return <Actions {...args} parser={this.current} />;
|
||||||
return <Actions {...args} theme={theme} parser={this} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overflow(element: any, context: any) {
|
overflow(element: IElement, context: BlockContext) {
|
||||||
const [{ loading }, action]: any = useBlockContext(element, context);
|
const [{ loading }, action] = useBlockContext(element, context);
|
||||||
const { theme }: any = useContext(ThemeContext);
|
return <Overflow element={element} context={context} loading={loading} action={action} parser={this.current} />;
|
||||||
return <Overflow element={element} context={context} loading={loading} action={action} theme={theme} parser={this.current} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
datePicker(element: any, context: any) {
|
datePicker(element: IElement, context: BlockContext) {
|
||||||
const [{ loading, value, error, language }, action]: any = useBlockContext(element, context);
|
const [{ loading, value, error, language }, action] = useBlockContext(element, context);
|
||||||
const { theme }: any = useContext(ThemeContext);
|
|
||||||
return (
|
return (
|
||||||
<DatePicker
|
<DatePicker
|
||||||
element={element}
|
element={element}
|
||||||
language={language}
|
language={language}
|
||||||
theme={theme}
|
|
||||||
value={value}
|
value={value}
|
||||||
action={action}
|
action={action}
|
||||||
context={context}
|
context={context}
|
||||||
|
@ -116,9 +109,8 @@ class MessageParser extends UiKitParserMessage {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
image(element: any, context: any) {
|
image(element: IElement, context: BlockContext) {
|
||||||
const { theme }: any = useContext(ThemeContext);
|
return <Image element={element} context={context} />;
|
||||||
return <Image element={element} theme={theme} context={context} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context(args: any) {
|
context(args: any) {
|
||||||
|
@ -126,24 +118,19 @@ class MessageParser extends UiKitParserMessage {
|
||||||
return <Context {...args} theme={theme} parser={this} />;
|
return <Context {...args} theme={theme} parser={this} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
multiStaticSelect(element: any, context: any) {
|
multiStaticSelect(element: IElement, context: BlockContext) {
|
||||||
const [{ loading, value }, action]: any = useBlockContext(element, context);
|
const [{ loading, value }, action] = useBlockContext(element, context);
|
||||||
const { theme } = useContext(ThemeContext);
|
return <MultiSelect {...element} value={value} onChange={action} context={context} loading={loading} multiselect />;
|
||||||
return (
|
|
||||||
<MultiSelect {...element} theme={theme} value={value} onChange={action} context={context} loading={loading} multiselect />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
staticSelect(element: any, context: any) {
|
staticSelect(element: IElement, context: BlockContext) {
|
||||||
const [{ loading, value }, action]: any = useBlockContext(element, context);
|
const [{ loading, value }, action] = useBlockContext(element, context);
|
||||||
const { theme } = useContext(ThemeContext);
|
return <Select {...element} value={value} onChange={action} loading={loading} />;
|
||||||
return <Select {...element} theme={theme} value={value} onChange={action} loading={loading} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectInput(element: any, context: any) {
|
selectInput(element: IElement, context: BlockContext) {
|
||||||
const [{ loading, value }, action]: any = useBlockContext(element, context);
|
const [{ loading, value }, action] = useBlockContext(element, context);
|
||||||
const { theme } = useContext(ThemeContext);
|
return <MultiSelect {...element} value={value} onChange={action} context={context} loading={loading} />;
|
||||||
return <MultiSelect {...element} theme={theme} value={value} onChange={action} context={context} loading={loading} />;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,8 +147,8 @@ class ModalParser extends UiKitParserModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
input({ element, blockId, appId, label, description, hint }: IInputIndex, context: number) {
|
input({ element, blockId, appId, label, description, hint }: IInputIndex, context: number) {
|
||||||
const [{ error }]: any = useBlockContext({ ...element, appId, blockId }, context);
|
const [{ error }] = useBlockContext({ ...element, appId, blockId }, context);
|
||||||
const { theme }: any = useContext(ThemeContext);
|
const { theme } = useContext(ThemeContext);
|
||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
parser={this.current}
|
parser={this.current}
|
||||||
|
@ -175,17 +162,15 @@ class ModalParser extends UiKitParserModal {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
image(element: any, context: any) {
|
image(element: IElement, context: BlockContext) {
|
||||||
const { theme }: any = useContext(ThemeContext);
|
return <Image element={element} context={context} />;
|
||||||
return <Image element={element} theme={theme} context={context} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
plainInput(element: any, context: any) {
|
plainInput(element: IElement, context: BlockContext) {
|
||||||
const [{ loading, value, error }, action]: any = useBlockContext(element, context);
|
const [{ loading, value, error }, action] = useBlockContext(element, context);
|
||||||
const { theme } = useContext(ThemeContext);
|
const { theme } = useContext(ThemeContext);
|
||||||
const { multiline, actionId, placeholder } = element;
|
const { multiline, actionId, placeholder } = element;
|
||||||
return (
|
return (
|
||||||
// @ts-ignore
|
|
||||||
<TextInput
|
<TextInput
|
||||||
key={actionId}
|
key={actionId}
|
||||||
placeholder={plainText(placeholder)}
|
placeholder={plainText(placeholder)}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { TThemeMode } from '../../definitions/ITheme';
|
|
||||||
|
|
||||||
export enum ElementTypes {
|
export enum ElementTypes {
|
||||||
IMAGE = 'image',
|
IMAGE = 'image',
|
||||||
BUTTON = 'button',
|
BUTTON = 'button',
|
||||||
|
@ -87,10 +85,11 @@ export interface IElement {
|
||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
appId?: string;
|
appId?: string;
|
||||||
blockId?: string;
|
blockId?: string;
|
||||||
|
multiline?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IText {
|
export interface IText {
|
||||||
type: ElementTypes;
|
type?: ElementTypes;
|
||||||
text: string;
|
text: string;
|
||||||
emoji?: boolean;
|
emoji?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -98,12 +97,15 @@ export interface IText {
|
||||||
export interface Option {
|
export interface Option {
|
||||||
text: IText;
|
text: IText;
|
||||||
value: string;
|
value: string;
|
||||||
|
imageUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IButton {
|
export interface IButton {
|
||||||
type: ElementTypes;
|
type: ElementTypes;
|
||||||
text: IText;
|
text: IText;
|
||||||
actionId: string;
|
actionId: string;
|
||||||
|
blockId: string;
|
||||||
|
appId: string;
|
||||||
value?: any;
|
value?: any;
|
||||||
style?: any;
|
style?: any;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +179,6 @@ export interface IParser {
|
||||||
}
|
}
|
||||||
export interface IActions extends Block {
|
export interface IActions extends Block {
|
||||||
parser?: IParser;
|
parser?: IParser;
|
||||||
theme: TThemeMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IContext extends Block {
|
export interface IContext extends Block {
|
||||||
|
@ -191,7 +192,6 @@ export interface IDatePicker extends Partial<Block> {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
value: string;
|
value: string;
|
||||||
error: string;
|
error: string;
|
||||||
theme: TThemeMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInput extends Partial<Block> {
|
export interface IInput extends Partial<Block> {
|
||||||
|
@ -199,7 +199,7 @@ export interface IInput extends Partial<Block> {
|
||||||
description: string;
|
description: string;
|
||||||
error: string;
|
error: string;
|
||||||
hint: string;
|
hint: string;
|
||||||
theme: TThemeMode;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInputIndex {
|
export interface IInputIndex {
|
||||||
|
@ -217,8 +217,7 @@ export interface IThumb {
|
||||||
}
|
}
|
||||||
export interface IImage {
|
export interface IImage {
|
||||||
element: IElement;
|
element: IElement;
|
||||||
theme: TThemeMode;
|
context?: BlockContext;
|
||||||
context?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UiKit/Overflow
|
// UiKit/Overflow
|
||||||
|
@ -226,14 +225,13 @@ export interface IOverflow extends Partial<Block> {
|
||||||
action: Function;
|
action: Function;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
parser: IParser;
|
parser: IParser;
|
||||||
theme: TThemeMode;
|
|
||||||
context: number;
|
context: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PropsOption {
|
interface PropsOption {
|
||||||
onOptionPress: Function;
|
onOptionPress: Function;
|
||||||
parser: IParser;
|
parser: IParser;
|
||||||
theme: TThemeMode;
|
theme: string;
|
||||||
}
|
}
|
||||||
export interface IOptions extends PropsOption {
|
export interface IOptions extends PropsOption {
|
||||||
options: Option[];
|
options: Option[];
|
||||||
|
@ -262,12 +260,11 @@ export interface ISection {
|
||||||
text?: IText;
|
text?: IText;
|
||||||
accessory?: IAccessory;
|
accessory?: IAccessory;
|
||||||
parser: IParser;
|
parser: IParser;
|
||||||
theme: TThemeMode;
|
|
||||||
fields?: any[];
|
fields?: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFields {
|
export interface IFields {
|
||||||
parser: IParser;
|
parser: IParser;
|
||||||
theme: TThemeMode;
|
theme: string;
|
||||||
fields: any[];
|
fields: any[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
|
|
||||||
import { BlockContext } from './interfaces';
|
import { BlockContext, IText } from './interfaces';
|
||||||
|
|
||||||
export const textParser = ([{ text }]: any) => text;
|
export const textParser = ([{ text }]: IText[]) => text;
|
||||||
|
|
||||||
export const defaultContext: any = {
|
export const defaultContext: any = {
|
||||||
action: (...args: any) => console.log(args),
|
action: (...args: any) => console.log(args),
|
||||||
|
@ -27,7 +27,14 @@ type TFunctionReturn = (value: any) => Promise<void>;
|
||||||
|
|
||||||
type TReturn = [TObjectReturn, TFunctionReturn];
|
type TReturn = [TObjectReturn, TFunctionReturn];
|
||||||
|
|
||||||
export const useBlockContext = ({ blockId, actionId, appId, initialValue }: any, context: BlockContext): TReturn => {
|
interface IUseBlockContext {
|
||||||
|
blockId?: string;
|
||||||
|
actionId: string;
|
||||||
|
appId?: string;
|
||||||
|
initialValue?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBlockContext = ({ blockId, actionId, appId, initialValue }: IUseBlockContext, context: BlockContext): TReturn => {
|
||||||
const { action, appId: appIdFromContext, viewId, state, language, errors, values = {} } = useContext(KitContext);
|
const { action, appId: appIdFromContext, viewId, state, language, errors, values = {} } = useContext(KitContext);
|
||||||
const { value = initialValue } = values[actionId] || {};
|
const { value = initialValue } = values[actionId] || {};
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Clipboard, Text } from 'react-native';
|
import { Text } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Text, Clipboard } from 'react-native';
|
import { Text } from 'react-native';
|
||||||
import { Link as LinkProps } from '@rocket.chat/message-parser';
|
import { Link as LinkProps } from '@rocket.chat/message-parser';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
|
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
|
|
|
@ -13,6 +13,15 @@ import MessageContext from './Context';
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import { IAttachment } from '../../definitions';
|
import { IAttachment } from '../../definitions';
|
||||||
import CollapsibleQuote from './Components/CollapsibleQuote';
|
import CollapsibleQuote from './Components/CollapsibleQuote';
|
||||||
|
import openLink from '../../utils/openLink';
|
||||||
|
import { themes } from '../../constants/colors';
|
||||||
|
|
||||||
|
export type TElement = {
|
||||||
|
type: string;
|
||||||
|
msg?: string;
|
||||||
|
url?: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
const AttachedActions = ({ attachment }: IMessageAttachedActions) => {
|
const AttachedActions = ({ attachment }: IMessageAttachedActions) => {
|
||||||
if (!attachment.actions) {
|
if (!attachment.actions) {
|
||||||
|
@ -21,15 +30,26 @@ const AttachedActions = ({ attachment }: IMessageAttachedActions) => {
|
||||||
const { onAnswerButtonPress } = useContext(MessageContext);
|
const { onAnswerButtonPress } = useContext(MessageContext);
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const attachedButtons = attachment.actions.map((element: { type: string; msg: string; text: string }) => {
|
const attachedButtons = attachment.actions.map((element: TElement) => {
|
||||||
if (element.type === 'button') {
|
const onPress = () => {
|
||||||
return <Button theme={theme} onPress={() => onAnswerButtonPress(element.msg)} title={element.text} />;
|
if (element.msg) {
|
||||||
|
onAnswerButtonPress(element.msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.url) {
|
||||||
|
openLink(element.url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (element.type === 'button') {
|
||||||
|
return <Button theme={theme} onPress={onPress} title={element.text} />;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.text}>{attachment.text}</Text>
|
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{attachment.text}</Text>
|
||||||
{attachedButtons}
|
{attachedButtons}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -54,7 +74,6 @@ const Attachments = React.memo(
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
style={style}
|
style={style}
|
||||||
isReply={isReply}
|
isReply={isReply}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,6 @@ import React from 'react';
|
||||||
import MessageContext from '../../Context';
|
import MessageContext from '../../Context';
|
||||||
import CollapsibleQuote from '.';
|
import CollapsibleQuote from '.';
|
||||||
|
|
||||||
// For some reason a general mock didn't work, I have to do a search
|
|
||||||
jest.mock('react-native-mmkv-storage', () => ({
|
|
||||||
Loader: jest.fn().mockImplementation(() => ({
|
|
||||||
setProcessingMode: jest.fn().mockImplementation(() => ({
|
|
||||||
withEncryption: jest.fn().mockImplementation(() => ({
|
|
||||||
initialize: jest.fn()
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
})),
|
|
||||||
create: jest.fn(),
|
|
||||||
MODES: { MULTI_PROCESS: '' }
|
|
||||||
}));
|
|
||||||
|
|
||||||
const testAttachment = {
|
const testAttachment = {
|
||||||
ts: '1970-01-01T00:00:00.000Z',
|
ts: '1970-01-01T00:00:00.000Z',
|
||||||
title: 'Engineering (9 today)',
|
title: 'Engineering (9 today)',
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { formatAttachmentUrl } from '../../lib/utils';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
import { IAttachment } from '../../definitions';
|
import { IAttachment } from '../../definitions';
|
||||||
|
|
||||||
type TMessageButton = {
|
type TMessageButton = {
|
||||||
|
@ -32,8 +33,7 @@ interface IMessageImage {
|
||||||
showAttachment?: Function;
|
showAttachment?: Function;
|
||||||
style?: StyleProp<TextStyle>[];
|
style?: StyleProp<TextStyle>[];
|
||||||
isReply?: boolean;
|
isReply?: boolean;
|
||||||
theme: string;
|
getCustomEmoji?: TGetCustomEmoji;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImageProgress = createImageProgress(FastImage);
|
const ImageProgress = createImageProgress(FastImage);
|
||||||
|
@ -61,7 +61,8 @@ export const MessageImage = React.memo(({ img, theme }: TMessageImage) => (
|
||||||
));
|
));
|
||||||
|
|
||||||
const ImageContainer = React.memo(
|
const ImageContainer = React.memo(
|
||||||
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, theme }: IMessageImage) => {
|
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply }: IMessageImage) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
const { baseUrl, user } = useContext(MessageContext);
|
const { baseUrl, user } = useContext(MessageContext);
|
||||||
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
|
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
|
||||||
if (!img) {
|
if (!img) {
|
||||||
|
@ -100,7 +101,7 @@ const ImageContainer = React.memo(
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme
|
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file)
|
||||||
);
|
);
|
||||||
|
|
||||||
ImageContainer.displayName = 'MessageImageContainer';
|
ImageContainer.displayName = 'MessageImageContainer';
|
||||||
|
|
|
@ -4,13 +4,13 @@ import Avatar from '../Avatar';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { IMessageAvatar } from './interfaces';
|
import { IMessageAvatar } from './interfaces';
|
||||||
|
import { SubscriptionType } from '../../definitions';
|
||||||
|
|
||||||
const MessageAvatar = React.memo(
|
const MessageAvatar = React.memo(({ isHeader, avatar, author, small, navToRoomInfo, emoji, getCustomEmoji }: IMessageAvatar) => {
|
||||||
({ isHeader, avatar, author, small, navToRoomInfo, emoji, getCustomEmoji, theme }: IMessageAvatar) => {
|
|
||||||
const { user } = useContext(MessageContext);
|
const { user } = useContext(MessageContext);
|
||||||
if (isHeader && author) {
|
if (isHeader && author) {
|
||||||
const navParam = {
|
const navParam = {
|
||||||
t: 'd',
|
t: SubscriptionType.DIRECT,
|
||||||
rid: author._id
|
rid: author._id
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
@ -23,13 +23,11 @@ const MessageAvatar = React.memo(
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
avatar={avatar}
|
avatar={avatar}
|
||||||
emoji={emoji}
|
emoji={emoji}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
MessageAvatar.displayName = 'MessageAvatar';
|
MessageAvatar.displayName = 'MessageAvatar';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Clipboard, StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import FastImage from '@rocket.chat/react-native-fast-image';
|
import FastImage from '@rocket.chat/react-native-fast-image';
|
||||||
import { dequal } from 'dequal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ export interface IMessageAvatar {
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
navToRoomInfo: Function;
|
navToRoomInfo: Function;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageBlocks {
|
export interface IMessageBlocks {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { IUser } from './IUser';
|
||||||
|
|
||||||
export interface IAttachment {
|
export interface IAttachment {
|
||||||
ts?: string | Date;
|
ts?: string | Date;
|
||||||
title: string;
|
title?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
title_link?: string;
|
title_link?: string;
|
||||||
|
|
|
@ -3,7 +3,6 @@ declare module 'commonmark';
|
||||||
declare module 'commonmark-react-renderer';
|
declare module 'commonmark-react-renderer';
|
||||||
declare module 'remove-markdown';
|
declare module 'remove-markdown';
|
||||||
declare module 'react-native-image-progress';
|
declare module 'react-native-image-progress';
|
||||||
declare module 'react-native-platform-touchable';
|
|
||||||
declare module 'react-native-ui-lib/keyboard';
|
declare module 'react-native-ui-lib/keyboard';
|
||||||
declare module '@rocket.chat/ui-kit';
|
declare module '@rocket.chat/ui-kit';
|
||||||
declare module '@rocket.chat/sdk';
|
declare module '@rocket.chat/sdk';
|
||||||
|
|
|
@ -32,9 +32,9 @@ export function subscribeUsersPresence(this: IRocketChat) {
|
||||||
sdk.subscribe('stream-notify-logged', 'Users:NameChanged');
|
sdk.subscribe('stream-notify-logged', 'Users:NameChanged');
|
||||||
}
|
}
|
||||||
|
|
||||||
let ids: string[] = [];
|
let usersBatch: string[] = [];
|
||||||
|
|
||||||
export default async function getUsersPresence() {
|
export default async function getUsersPresence(usersParams: string[]) {
|
||||||
const serverVersion = reduxStore.getState().server.version as string;
|
const serverVersion = reduxStore.getState().server.version as string;
|
||||||
const { user: loggedUser } = reduxStore.getState().login;
|
const { user: loggedUser } = reduxStore.getState().login;
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ export default async function getUsersPresence() {
|
||||||
// if server is greather than or equal 3.0.0
|
// if server is greather than or equal 3.0.0
|
||||||
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '3.0.0')) {
|
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '3.0.0')) {
|
||||||
// if not have any id
|
// if not have any id
|
||||||
if (!ids.length) {
|
if (!usersParams.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Request userPresence on demand
|
// Request userPresence on demand
|
||||||
params = { ids: ids.join(',') };
|
params = { ids: usersParams.join(',') };
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -57,13 +57,13 @@ export default async function getUsersPresence() {
|
||||||
const result = (await sdk.get('users.presence' as any, params as any)) as any;
|
const result = (await sdk.get('users.presence' as any, params as any)) as any;
|
||||||
|
|
||||||
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '4.1.0')) {
|
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '4.1.0')) {
|
||||||
sdk.subscribeRaw('stream-user-presence', ['', { added: ids }]);
|
sdk.subscribeRaw('stream-user-presence', ['', { added: usersParams }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const { users } = result;
|
const { users } = result;
|
||||||
|
|
||||||
const activeUsers = ids.reduce((ret: IActiveUsers, id) => {
|
const activeUsers = usersParams.reduce((ret: IActiveUsers, id) => {
|
||||||
const user = users.find((u: IUser) => u._id === id) ?? { _id: id, status: 'offline' };
|
const user = users.find((u: IUser) => u._id === id) ?? { _id: id, status: 'offline' };
|
||||||
const { _id, status, statusText } = user;
|
const { _id, status, statusText } = user;
|
||||||
|
|
||||||
|
@ -77,7 +77,6 @@ export default async function getUsersPresence() {
|
||||||
InteractionManager.runAfterInteractions(() => {
|
InteractionManager.runAfterInteractions(() => {
|
||||||
reduxStore.dispatch(setActiveUsers(activeUsers));
|
reduxStore.dispatch(setActiveUsers(activeUsers));
|
||||||
});
|
});
|
||||||
ids = [];
|
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const userCollection = db.get('users');
|
const userCollection = db.get('users');
|
||||||
|
@ -110,12 +109,13 @@ let usersTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
export function getUserPresence(uid: string) {
|
export function getUserPresence(uid: string) {
|
||||||
if (!usersTimer) {
|
if (!usersTimer) {
|
||||||
usersTimer = setTimeout(() => {
|
usersTimer = setTimeout(() => {
|
||||||
getUsersPresence();
|
getUsersPresence(usersBatch);
|
||||||
|
usersBatch = [];
|
||||||
usersTimer = null;
|
usersTimer = null;
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid) {
|
if (uid) {
|
||||||
ids.push(uid);
|
usersBatch.push(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { RootEnum } from '../definitions';
|
||||||
import appConfig from '../../app.json';
|
import appConfig from '../../app.json';
|
||||||
|
|
||||||
export const initLocalSettings = function* initLocalSettings() {
|
export const initLocalSettings = function* initLocalSettings() {
|
||||||
const sortPreferences = yield RocketChat.getSortPreferences();
|
const sortPreferences = RocketChat.getSortPreferences();
|
||||||
yield put(setAllPreferences(sortPreferences));
|
yield put(setAllPreferences(sortPreferences));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ const restore = function* restore() {
|
||||||
const serversCollection = serversDB.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
const servers = yield serversCollection.query().fetch();
|
const servers = yield serversCollection.query().fetch();
|
||||||
const isBiometryEnabled = servers.some(server => !!server.biometry);
|
const isBiometryEnabled = servers.some(server => !!server.biometry);
|
||||||
yield UserPreferences.setBoolAsync(BIOMETRY_ENABLED_KEY, isBiometryEnabled);
|
UserPreferences.setBool(BIOMETRY_ENABLED_KEY, isBiometryEnabled);
|
||||||
yield UserPreferences.setBoolAsync(BIOMETRY_MIGRATION_KEY, true);
|
UserPreferences.setBool(BIOMETRY_MIGRATION_KEY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { server } = appConfig;
|
const { server } = appConfig;
|
||||||
|
|
|
@ -55,7 +55,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE
|
||||||
const serverHistoryRecord = serversHistory[0];
|
const serverHistoryRecord = serversHistory[0];
|
||||||
// this is updating on every login just to save `updated_at`
|
// this is updating on every login just to save `updated_at`
|
||||||
// keeping this server as the most recent on autocomplete order
|
// keeping this server as the most recent on autocomplete order
|
||||||
await serverHistoryRecord.update(s => {
|
await serverHistoryRecord.update((s) => {
|
||||||
s.username = result.username;
|
s.username = result.username;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -151,12 +151,12 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
||||||
yield serversDB.action(async () => {
|
yield serversDB.action(async () => {
|
||||||
try {
|
try {
|
||||||
const userRecord = await usersCollection.find(user.id);
|
const userRecord = await usersCollection.find(user.id);
|
||||||
await userRecord.update(record => {
|
await userRecord.update((record) => {
|
||||||
record._raw = sanitizedRaw({ id: user.id, ...record._raw }, usersCollection.schema);
|
record._raw = sanitizedRaw({ id: user.id, ...record._raw }, usersCollection.schema);
|
||||||
Object.assign(record, u);
|
Object.assign(record, u);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await usersCollection.create(record => {
|
await usersCollection.create((record) => {
|
||||||
record._raw = sanitizedRaw({ id: user.id }, usersCollection.schema);
|
record._raw = sanitizedRaw({ id: user.id }, usersCollection.schema);
|
||||||
Object.assign(record, u);
|
Object.assign(record, u);
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,7 +84,9 @@ class AttachmentView extends React.Component<IAttachmentViewProps, IAttachmentVi
|
||||||
const attachment = route.params?.attachment;
|
const attachment = route.params?.attachment;
|
||||||
let { title } = attachment;
|
let { title } = attachment;
|
||||||
try {
|
try {
|
||||||
|
if (title) {
|
||||||
title = decodeURI(title);
|
title = decodeURI(title);
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,14 +48,13 @@ const SelectChannel = ({
|
||||||
<>
|
<>
|
||||||
<Text style={[styles.label, { color: themes[theme].titleText }]}>{I18n.t('Parent_channel_or_group')}</Text>
|
<Text style={[styles.label, { color: themes[theme].titleText }]}>{I18n.t('Parent_channel_or_group')}</Text>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
theme={theme}
|
|
||||||
inputStyle={styles.inputStyle}
|
inputStyle={styles.inputStyle}
|
||||||
onChange={onChannelSelect}
|
onChange={onChannelSelect}
|
||||||
onSearch={getChannels}
|
onSearch={getChannels}
|
||||||
value={initial && [initial]}
|
value={initial && [initial]}
|
||||||
disabled={initial}
|
disabled={!!initial}
|
||||||
options={channels.map(channel => ({
|
options={channels.map(channel => ({
|
||||||
value: channel,
|
value: channel.name || channel.fname,
|
||||||
text: { text: RocketChat.getRoomTitle(channel) },
|
text: { text: RocketChat.getRoomTitle(channel) },
|
||||||
imageUrl: getAvatar(channel)
|
imageUrl: getAvatar(channel)
|
||||||
}))}
|
}))}
|
||||||
|
|
|
@ -77,7 +77,6 @@ const SelectUsers = ({
|
||||||
<>
|
<>
|
||||||
<Text style={[styles.label, { color: themes[theme].titleText }]}>{I18n.t('Invite_users')}</Text>
|
<Text style={[styles.label, { color: themes[theme].titleText }]}>{I18n.t('Invite_users')}</Text>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
theme={theme}
|
|
||||||
inputStyle={styles.inputStyle}
|
inputStyle={styles.inputStyle}
|
||||||
onSearch={getUsers}
|
onSearch={getUsers}
|
||||||
onChange={onUserSelect}
|
onChange={onUserSelect}
|
||||||
|
|
|
@ -73,7 +73,7 @@ const Item = ({ item, onPress }: IItem): JSX.Element => {
|
||||||
testID={`discussions-view-${item.msg}`}
|
testID={`discussions-view-${item.msg}`}
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}>
|
style={{ backgroundColor: themes[theme].backgroundColor }}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Avatar style={styles.avatar} text={item?.u?.username} size={36} borderRadius={4} theme={theme} />
|
<Avatar style={styles.avatar} text={item?.u?.username} size={36} borderRadius={4} />
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<View style={styles.titleContainer}>
|
<View style={styles.titleContainer}>
|
||||||
<Text style={[styles.title, { color: themes[theme].titleText }]} numberOfLines={1}>
|
<Text style={[styles.title, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Clipboard, ScrollView, StyleSheet, Text, View } from 'react-native';
|
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { encryptionSetBanner } from '../actions/encryption';
|
import { encryptionSetBanner } from '../actions/encryption';
|
||||||
|
|
|
@ -275,7 +275,6 @@ const LivechatEditView = ({
|
||||||
value={tagParamSelected}
|
value={tagParamSelected}
|
||||||
context={BLOCK_CONTEXT.FORM}
|
context={BLOCK_CONTEXT.FORM}
|
||||||
multiselect
|
multiselect
|
||||||
theme={theme}
|
|
||||||
disabled={!permissions[1]}
|
disabled={!permissions[1]}
|
||||||
inputStyle={styles.multiSelect}
|
inputStyle={styles.multiSelect}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -464,7 +464,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
|
||||||
|
|
||||||
renderSystemMessages = () => {
|
renderSystemMessages = () => {
|
||||||
const { systemMessages, enableSysMes } = this.state;
|
const { systemMessages, enableSysMes } = this.state;
|
||||||
const { theme } = this.props;
|
|
||||||
|
|
||||||
if (!enableSysMes) {
|
if (!enableSysMes) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -481,7 +480,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
|
||||||
value={systemMessages as string[]}
|
value={systemMessages as string[]}
|
||||||
context={BLOCK_CONTEXT.FORM}
|
context={BLOCK_CONTEXT.FORM}
|
||||||
multiselect
|
multiselect
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,8 @@ import CookieManager from '@react-native-cookies/cookies';
|
||||||
import { StackNavigationOptions } from '@react-navigation/stack';
|
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||||
import FastImage from '@rocket.chat/react-native-fast-image';
|
import FastImage from '@rocket.chat/react-native-fast-image';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Clipboard, Linking, Share } from 'react-native';
|
import { Linking, Share } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { appStart } from '../../actions/app';
|
import { appStart } from '../../actions/app';
|
||||||
|
|
|
@ -166,7 +166,11 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
dispatch(setUser({ status: item.id }));
|
dispatch(setUser({ status: item.id }));
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showErrorAlert(I18n.t(e.data.errorType));
|
const messageError =
|
||||||
|
e.data && e.data.error.includes('[error-too-many-requests]')
|
||||||
|
? I18n.t('error-too-many-requests', { seconds: e.data.error.replace(/\D/g, '') })
|
||||||
|
: e.data.errorType;
|
||||||
|
showErrorAlert(messageError);
|
||||||
logEvent(events.SET_STATUS_FAIL);
|
logEvent(events.SET_STATUS_FAIL);
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ interface IItem {
|
||||||
toggleFollowThread: (isFollowing: boolean, id: string) => void;
|
toggleFollowThread: (isFollowing: boolean, id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Item = ({ item, useRealName, user, badgeColor, onPress, toggleFollowThread }: IItem) => {
|
const Item = ({ item, useRealName, user, badgeColor, onPress, toggleFollowThread }: IItem): React.ReactElement => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const username = (useRealName && item?.u?.name) || item?.u?.username;
|
const username = (useRealName && item?.u?.name) || item?.u?.username;
|
||||||
let time;
|
let time;
|
||||||
|
@ -79,7 +79,7 @@ const Item = ({ item, useRealName, user, badgeColor, onPress, toggleFollowThread
|
||||||
testID={`thread-messages-view-${item.msg}`}
|
testID={`thread-messages-view-${item.msg}`}
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}>
|
style={{ backgroundColor: themes[theme].backgroundColor }}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Avatar style={styles.avatar} text={item?.u?.username} size={36} borderRadius={4} theme={theme} />
|
<Avatar style={styles.avatar} text={item?.u?.username} size={36} borderRadius={4} />
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<View style={styles.titleContainer}>
|
<View style={styles.titleContainer}>
|
||||||
<Text style={[styles.title, { color: themes[theme].titleText }]} numberOfLines={1}>
|
<Text style={[styles.title, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||||
|
|
|
@ -506,6 +506,8 @@ PODS:
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNCAsyncStorage (1.12.1):
|
- RNCAsyncStorage (1.12.1):
|
||||||
- React-Core
|
- React-Core
|
||||||
|
- RNCClipboard (1.8.5):
|
||||||
|
- React-Core
|
||||||
- RNCMaskedView (0.1.11):
|
- RNCMaskedView (0.1.11):
|
||||||
- React
|
- React
|
||||||
- RNConfigReader (1.0.0):
|
- RNConfigReader (1.0.0):
|
||||||
|
@ -693,6 +695,7 @@ DEPENDENCIES:
|
||||||
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
||||||
- RNBootSplash (from `../node_modules/react-native-bootsplash`)
|
- RNBootSplash (from `../node_modules/react-native-bootsplash`)
|
||||||
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
|
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
|
||||||
|
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||||
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
|
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
|
||||||
- RNConfigReader (from `../node_modules/react-native-config-reader`)
|
- RNConfigReader (from `../node_modules/react-native-config-reader`)
|
||||||
- "RNCPicker (from `../node_modules/@react-native-community/picker`)"
|
- "RNCPicker (from `../node_modules/@react-native-community/picker`)"
|
||||||
|
@ -879,6 +882,8 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native-bootsplash"
|
:path: "../node_modules/react-native-bootsplash"
|
||||||
RNCAsyncStorage:
|
RNCAsyncStorage:
|
||||||
:path: "../node_modules/@react-native-community/async-storage"
|
:path: "../node_modules/@react-native-community/async-storage"
|
||||||
|
RNCClipboard:
|
||||||
|
:path: "../node_modules/@react-native-clipboard/clipboard"
|
||||||
RNCMaskedView:
|
RNCMaskedView:
|
||||||
:path: "../node_modules/@react-native-community/masked-view"
|
:path: "../node_modules/@react-native-community/masked-view"
|
||||||
RNConfigReader:
|
RNConfigReader:
|
||||||
|
@ -950,7 +955,7 @@ SPEC CHECKSUMS:
|
||||||
EXVideoThumbnails: 442c3abadb51a81551a3b53705b7560de390e6f7
|
EXVideoThumbnails: 442c3abadb51a81551a3b53705b7560de390e6f7
|
||||||
EXWebBrowser: 76783ba5dcb8699237746ecf41a9643d428a4cc5
|
EXWebBrowser: 76783ba5dcb8699237746ecf41a9643d428a4cc5
|
||||||
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
|
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
|
||||||
FBReactNativeSpec: 110d69378fce79af38271c39894b59fec7890221
|
FBReactNativeSpec: 686ac17e193dcf7d5df4d772b224504dd2f3ad81
|
||||||
Firebase: 919186c8e119dd9372a45fd1dd17a8a942bc1892
|
Firebase: 919186c8e119dd9372a45fd1dd17a8a942bc1892
|
||||||
FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4
|
FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4
|
||||||
FirebaseCore: 8cd4f8ea22075e0ee582849b1cf79d8816506085
|
FirebaseCore: 8cd4f8ea22075e0ee582849b1cf79d8816506085
|
||||||
|
@ -1024,6 +1029,7 @@ SPEC CHECKSUMS:
|
||||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||||
RNBootSplash: 4844706cbb56a3270556c9b94e59dedadccd47e4
|
RNBootSplash: 4844706cbb56a3270556c9b94e59dedadccd47e4
|
||||||
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
|
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
|
||||||
|
RNCClipboard: cc054ad1e8a33d2a74cd13e565588b4ca928d8fd
|
||||||
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
|
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
|
||||||
RNConfigReader: 396da6a6444182a76e8ae0930b9436c7575045cb
|
RNConfigReader: 396da6a6444182a76e8ae0930b9436c7575045cb
|
||||||
RNCPicker: 914b557e20b3b8317b084aca9ff4b4edb95f61e4
|
RNCPicker: 914b557e20b3b8317b084aca9ff4b4edb95f61e4
|
||||||
|
|
|
@ -1672,7 +1672,7 @@
|
||||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
MARKETING_VERSION = 4.26.1;
|
MARKETING_VERSION = 4.26.2;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
||||||
|
@ -1709,7 +1709,7 @@
|
||||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
MARKETING_VERSION = 4.26.1;
|
MARKETING_VERSION = 4.26.2;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>4.26.1</string>
|
<string>4.26.2</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>XPC!</string>
|
<string>XPC!</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>4.26.1</string>
|
<string>4.26.2</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>KeychainGroup</key>
|
<key>KeychainGroup</key>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock.js';
|
||||||
|
|
||||||
|
jest.mock('@react-native-clipboard/clipboard', () => mockClipboard);
|
||||||
|
|
||||||
|
jest.mock('react-native-mmkv-storage', () => ({
|
||||||
|
Loader: jest.fn().mockImplementation(() => ({
|
||||||
|
setProcessingMode: jest.fn().mockImplementation(() => ({
|
||||||
|
withEncryption: jest.fn().mockImplementation(() => ({
|
||||||
|
initialize: jest.fn()
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
})),
|
||||||
|
create: jest.fn(),
|
||||||
|
MODES: { MULTI_PROCESS: '' }
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('rn-fetch-blob', () => ({
|
||||||
|
fs: {
|
||||||
|
dirs: {
|
||||||
|
DocumentDir: '/data/com.rocket.chat/documents',
|
||||||
|
DownloadDir: '/data/com.rocket.chat/downloads'
|
||||||
|
},
|
||||||
|
exists: jest.fn(() => null)
|
||||||
|
},
|
||||||
|
fetch: jest.fn(() => null),
|
||||||
|
config: jest.fn(() => null)
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('react-native-file-viewer', () => ({
|
||||||
|
open: jest.fn(() => null)
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('./app/lib/database', () => jest.fn(() => null));
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rocket-chat-reactnative",
|
"name": "rocket-chat-reactnative",
|
||||||
"version": "4.26.1",
|
"version": "4.26.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-native start",
|
"start": "react-native start",
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
"@bugsnag/react-native": "^7.10.5",
|
"@bugsnag/react-native": "^7.10.5",
|
||||||
"@codler/react-native-keyboard-aware-scroll-view": "^1.0.1",
|
"@codler/react-native-keyboard-aware-scroll-view": "^1.0.1",
|
||||||
"@nozbe/watermelondb": "0.23.0",
|
"@nozbe/watermelondb": "0.23.0",
|
||||||
|
"@react-native-clipboard/clipboard": "^1.8.5",
|
||||||
"@react-native-community/art": "^1.2.0",
|
"@react-native-community/art": "^1.2.0",
|
||||||
"@react-native-community/async-storage": "1.12.1",
|
"@react-native-community/async-storage": "1.12.1",
|
||||||
"@react-native-community/blur": "^3.6.0",
|
"@react-native-community/blur": "^3.6.0",
|
||||||
|
@ -208,7 +209,8 @@
|
||||||
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
|
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
|
||||||
},
|
},
|
||||||
"setupFilesAfterEnv": [
|
"setupFilesAfterEnv": [
|
||||||
"@testing-library/jest-native/extend-expect"
|
"@testing-library/jest-native/extend-expect",
|
||||||
|
"./jest.setup.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"snyk": true,
|
"snyk": true,
|
||||||
|
|
|
@ -23,7 +23,7 @@ index 602d51d..920d975 100644
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "RNFetchBlob";
|
return "RNFetchBlob";
|
||||||
diff --git a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
diff --git a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||||
index cdbe6b1..1699c6c 100644
|
index cdbe6b1..c0ce9bd 100644
|
||||||
--- a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
--- a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||||
+++ b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
+++ b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||||
@@ -15,6 +15,9 @@
|
@@ -15,6 +15,9 @@
|
||||||
|
@ -36,7 +36,7 @@ index cdbe6b1..1699c6c 100644
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, ResponseFormat) {
|
typedef NS_ENUM(NSUInteger, ResponseFormat) {
|
||||||
UTF8,
|
UTF8,
|
||||||
@@ -450,16 +453,107 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
|
@@ -450,16 +453,108 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,14 +106,14 @@ index cdbe6b1..1699c6c 100644
|
||||||
+ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF];
|
+ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF];
|
||||||
+
|
+
|
||||||
+ return [[NSString stringWithFormat:@"%@", hex] lowercaseString];
|
+ return [[NSString stringWithFormat:@"%@", hex] lowercaseString];
|
||||||
+}
|
}
|
||||||
+
|
|
||||||
+-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
|
+-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
|
||||||
+{
|
+{
|
||||||
+ NSString *host = challenge.protectionSpace.host;
|
+ NSString *host = challenge.protectionSpace.host;
|
||||||
+
|
+
|
||||||
+ // Read the clientSSL info from MMKV
|
+ // Read the clientSSL info from MMKV
|
||||||
+ __block NSDictionary *clientSSL;
|
+ __block NSString *clientSSL;
|
||||||
+ SecureStorage *secureStorage = [[SecureStorage alloc] init];
|
+ SecureStorage *secureStorage = [[SecureStorage alloc] init];
|
||||||
+
|
+
|
||||||
+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
|
+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
|
||||||
|
@ -123,21 +123,22 @@ index cdbe6b1..1699c6c 100644
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||||
+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding];
|
+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess];
|
+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess];
|
||||||
+ clientSSL = [mmkv getObjectOfClass:[NSDictionary class] forKey:host];
|
+ clientSSL = [mmkv getStringForKey:host];
|
||||||
+
|
+
|
||||||
+ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
+ if ([clientSSL length] != 0) {
|
||||||
+
|
+ NSData *data = [clientSSL dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
+ if (clientSSL != (id)[NSNull null]) {
|
+ id dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||||
+ NSString *path = [clientSSL objectForKey:@"path"];
|
+ NSString *path = [dict objectForKey:@"path"];
|
||||||
+ NSString *password = [clientSSL objectForKey:@"password"];
|
+ NSString *password = [dict objectForKey:@"password"];
|
||||||
+ credential = [self getUrlCredential:challenge path:path password:password];
|
+ credential = [self getUrlCredential:challenge path:path password:password];
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
|
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
|
||||||
}
|
+}
|
||||||
|
+
|
||||||
+// - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
|
+// - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
|
||||||
+// {
|
+// {
|
||||||
+// if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
|
+// if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue