mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-23 05:13:04 +03:00
Merge branch 'development' of github.com:esteemapp/esteem-mobile into bugfix/post-display
This commit is contained in:
commit
03136101d6
@ -16,7 +16,7 @@ export default EStyleSheet.create({
|
|||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
marginHorizontal: 19,
|
marginHorizontal: 20,
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
},
|
},
|
||||||
navItem: {
|
navItem: {
|
||||||
|
@ -48,7 +48,7 @@ export default class TitleAreaView extends Component {
|
|||||||
const { text, height } = this.state;
|
const { text, height } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={globalStyles.containerHorizontal16}>
|
<View style={[globalStyles.containerHorizontal16, { height: Math.max(35, height) }]}>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[styles.textInput, { height: Math.max(35, height) }]}
|
style={[styles.textInput, { height: Math.max(35, height) }]}
|
||||||
placeholderTextColor="#c1c5c7"
|
placeholderTextColor="#c1c5c7"
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { replaceBetween } from './utils';
|
import { replaceBetween } from './utils';
|
||||||
|
|
||||||
export default async ({ getState, item, setState }) => {
|
export default async ({ text, selection, setTextAndSelection, item }) => {
|
||||||
const states = getState();
|
|
||||||
let { text } = states;
|
|
||||||
const { selection } = states;
|
|
||||||
let newText;
|
let newText;
|
||||||
let newSelection;
|
let newSelection;
|
||||||
|
|
||||||
@ -35,6 +32,5 @@ export default async ({ getState, item, setState }) => {
|
|||||||
newSelection = { start: selection.start + 3, end: selection.start + 3 };
|
newSelection = { start: selection.start + 3, end: selection.start + 3 };
|
||||||
}
|
}
|
||||||
|
|
||||||
await setState({ text: newText, textUpdated: true });
|
setTextAndSelection({ text: newText, selection: newSelection });
|
||||||
await setState({ newSelection });
|
|
||||||
};
|
};
|
||||||
|
@ -3,8 +3,7 @@ import { isStringWebLink, replaceBetween } from './utils';
|
|||||||
export const writeUrlTextHere = 'https://example.com';
|
export const writeUrlTextHere = 'https://example.com';
|
||||||
export const writeTextHereString = 'Text here';
|
export const writeTextHereString = 'Text here';
|
||||||
|
|
||||||
export default async ({ getState, item, setState, isImage = null }) => {
|
export default async ({ text, selection, setTextAndSelection, item, isImage = null }) => {
|
||||||
const { selection, text } = getState();
|
|
||||||
const imagePrefix = isImage ? '!' : '';
|
const imagePrefix = isImage ? '!' : '';
|
||||||
const itemText = item ? item.text : writeTextHereString;
|
const itemText = item ? item.text : writeTextHereString;
|
||||||
const itemUrl = item ? item.url : writeUrlTextHere;
|
const itemUrl = item ? item.url : writeUrlTextHere;
|
||||||
@ -41,7 +40,5 @@ export default async ({ getState, item, setState, isImage = null }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await setState({ text: newText, textUpdated: true }, async () => {
|
setTextAndSelection({ text: newText, selection: newSelection });
|
||||||
await setState({ newSelection });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { replaceBetween } from './utils';
|
import { replaceBetween } from './utils';
|
||||||
|
|
||||||
export default ({ getState, item, setState }) => {
|
export default async ({ text, selection, setTextAndSelection, item }) => {
|
||||||
const { text, selection } = getState();
|
|
||||||
const newText = replaceBetween(
|
const newText = replaceBetween(
|
||||||
text,
|
text,
|
||||||
selection,
|
selection,
|
||||||
@ -14,8 +13,6 @@ export default ({ getState, item, setState }) => {
|
|||||||
} else {
|
} else {
|
||||||
newPosition = selection.end + item.wrapper.length * 2;
|
newPosition = selection.end + item.wrapper.length * 2;
|
||||||
}
|
}
|
||||||
|
const newSelection = { start: newPosition, end: newPosition };
|
||||||
setState({ text: newText, textUpdated: true }, () => {
|
setTextAndSelection({ text: newText, selection: newSelection });
|
||||||
setState({ newSelection: { start: newPosition, end: newPosition } });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { replaceBetween } from './utils';
|
import { replaceBetween } from './utils';
|
||||||
|
|
||||||
export default async ({ getState, item, setState }) => {
|
export default async ({ text, selection, setTextAndSelection, item }) => {
|
||||||
const { text, selection } = getState();
|
|
||||||
let newText = replaceBetween(
|
let newText = replaceBetween(
|
||||||
text,
|
text,
|
||||||
selection,
|
selection,
|
||||||
@ -42,7 +41,6 @@ export default async ({ getState, item, setState }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await setState({ text: newText, textUpdated: true }, async () => {
|
const newSelection = { start: newPosition, end: newPosition };
|
||||||
await setState({ newSelection: { start: newPosition, end: newPosition } });
|
setTextAndSelection({ text: newText, selection: newSelection });
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import regexValidator from './webLinkValidator';
|
import regexValidator from './webLinkValidator';
|
||||||
|
|
||||||
export const replaceBetween = (text: string, selection: Object, what: string) =>
|
export const replaceBetween = (text, selection, what) =>
|
||||||
text.substring(0, selection.start) + what + text.substring(selection.end);
|
text.substring(0, selection.start) + what + text.substring(selection.end);
|
||||||
|
|
||||||
export const isStringWebLink = (text: string): boolean => {
|
export const isStringWebLink = text => {
|
||||||
const pattern = regexValidator;
|
const pattern = regexValidator;
|
||||||
return pattern.test(text);
|
return pattern.test(text);
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { View, KeyboardAvoidingView, FlatList, Text, Platform, ScrollView } from 'react-native';
|
import { View, KeyboardAvoidingView, FlatList, Text, Platform, ScrollView } from 'react-native';
|
||||||
import ActionSheet from 'react-native-actionsheet';
|
import ActionSheet from 'react-native-actionsheet';
|
||||||
import { renderPostBody } from '@esteemapp/esteem-render-helpers';
|
import { renderPostBody } from '@esteemapp/esteem-render-helpers';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import applyImageLink from './formats/applyWebLinkFormat';
|
|
||||||
import Formats from './formats/formats';
|
import Formats from './formats/formats';
|
||||||
|
import applyImageLink from './formats/applyWebLinkFormat';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { IconButton } from '../../iconButton';
|
import { IconButton } from '../../iconButton';
|
||||||
@ -18,73 +18,83 @@ import { ThemeContainer } from '../../../containers';
|
|||||||
// Styles
|
// Styles
|
||||||
import styles from './markdownEditorStyles';
|
import styles from './markdownEditorStyles';
|
||||||
|
|
||||||
export default class MarkdownEditorView extends Component {
|
const MarkdownEditorView = ({
|
||||||
constructor(props) {
|
draftBody,
|
||||||
super(props);
|
handleIsFormValid,
|
||||||
this.state = {
|
handleOpenImagePicker,
|
||||||
text: props.draftBody || '',
|
intl,
|
||||||
selection: { start: 0, end: 0 },
|
isPreviewActive,
|
||||||
textUpdated: false,
|
isReply,
|
||||||
newSelection: null,
|
isLoading,
|
||||||
};
|
initialFields,
|
||||||
|
onChange,
|
||||||
|
handleOnTextChange,
|
||||||
|
handleIsValid,
|
||||||
|
componentID,
|
||||||
|
uploadedImage,
|
||||||
|
}) => {
|
||||||
|
const [text, setText] = useState(draftBody || '');
|
||||||
|
const [selection, setSelection] = useState({ start: 0, end: 0 });
|
||||||
|
const [editable, setEditable] = useState(null);
|
||||||
|
|
||||||
this.inputRef = React.createRef();
|
const inputRef = useRef(null);
|
||||||
this.galleryRef = React.createRef();
|
const galleryRef = useRef(null);
|
||||||
this.clearRef = React.createRef();
|
const clearRef = useRef(null);
|
||||||
}
|
|
||||||
|
|
||||||
// Lifecycle functions
|
useEffect(() => {
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
if (!isPreviewActive) {
|
||||||
const { draftBody, uploadedImage, isPreviewActive } = this.props;
|
_setTextAndSelection({ selection: { start: 0, end: 0 }, text });
|
||||||
if (!nextProps.isPreviewActive && isPreviewActive) {
|
|
||||||
this.setState({
|
|
||||||
selection: { start: 0, end: 0 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (nextProps.draftBody && draftBody !== nextProps.draftBody) {
|
|
||||||
this.setState({
|
|
||||||
text: nextProps.draftBody,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}, [isPreviewActive]);
|
||||||
|
|
||||||
if (
|
useEffect(() => {
|
||||||
nextProps.uploadedImage &&
|
if (text === '' && draftBody !== '') {
|
||||||
nextProps.uploadedImage.url &&
|
_setTextAndSelection({ selection: { start: 0, end: 0 }, text: draftBody });
|
||||||
nextProps.uploadedImage !== uploadedImage
|
}
|
||||||
) {
|
}, [draftBody]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (editable === null) {
|
||||||
|
// workaround for android context menu issue
|
||||||
|
setEditable(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
setEditable(!isLoading);
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
setEditable(!isLoading);
|
||||||
|
}
|
||||||
|
}, [isLoading]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (uploadedImage && uploadedImage.url) {
|
||||||
applyImageLink({
|
applyImageLink({
|
||||||
getState: this._getState,
|
text,
|
||||||
setState: async (state, callback) => {
|
selection,
|
||||||
await this.setState(state, callback);
|
setTextAndSelection: _setTextAndSelection,
|
||||||
},
|
item: { url: uploadedImage.url, text: uploadedImage.hash },
|
||||||
item: { url: nextProps.uploadedImage.url, text: nextProps.uploadedImage.hash },
|
isImage: !!uploadedImage,
|
||||||
isImage: !!nextProps.uploadedImage,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}, [uploadedImage]);
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
useEffect(() => {
|
||||||
const { text } = this.state;
|
setText(draftBody);
|
||||||
const { handleIsFormValid } = this.props;
|
}, [draftBody]);
|
||||||
|
|
||||||
if (prevState.text !== text) {
|
useEffect(() => {
|
||||||
const nextText = text.replace(prevState.text, '');
|
const nextText = text.replace(text, '');
|
||||||
|
|
||||||
if (nextText && nextText.length > 0) {
|
if (nextText && nextText.length > 0) {
|
||||||
this._changeText(text);
|
_changeText(text);
|
||||||
|
|
||||||
if (handleIsFormValid) {
|
if (handleIsFormValid) {
|
||||||
handleIsFormValid(text);
|
handleIsFormValid(text);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, [text]);
|
||||||
|
|
||||||
// Component functions
|
const _changeText = input => {
|
||||||
_changeText = input => {
|
setText(input);
|
||||||
const { onChange, handleOnTextChange, handleIsValid, componentID } = this.props;
|
|
||||||
|
|
||||||
this.setState({ text: input });
|
|
||||||
|
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(input);
|
onChange(input);
|
||||||
@ -99,36 +109,31 @@ export default class MarkdownEditorView extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleOnSelectionChange = event => {
|
const _handleOnSelectionChange = async event => {
|
||||||
const { newSelection } = this.state;
|
setSelection(event.nativeEvent.selection);
|
||||||
|
};
|
||||||
|
|
||||||
if (newSelection) {
|
const _setTextAndSelection = ({ selection: _selection, text: _text }) => {
|
||||||
this.setState({
|
inputRef.current.setNativeProps({
|
||||||
selection: newSelection,
|
text: _text,
|
||||||
newSelection: null,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
selection: event.nativeEvent.selection,
|
|
||||||
});
|
});
|
||||||
|
// Workaround for iOS selection update issue
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef.current.setNativeProps({
|
||||||
|
selection: _selection,
|
||||||
|
});
|
||||||
|
setSelection(_selection);
|
||||||
|
}, 200);
|
||||||
|
_changeText(_text);
|
||||||
};
|
};
|
||||||
|
|
||||||
_getState = () => {
|
const _renderPreview = () => (
|
||||||
return this.state;
|
<ScrollView style={styles.previewContainer}>
|
||||||
};
|
{text ? <PostBody body={renderPostBody(text)} /> : <Text>...</Text>}
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
|
||||||
_renderPreview = () => {
|
const _renderMarkupButton = ({ item }) => (
|
||||||
const { text } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ScrollView style={styles.previewContainer}>
|
|
||||||
{text ? <PostBody body={renderPostBody(text)} /> : <Text>...</Text>}
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
_renderMarkupButton = ({ item, getState, setState }) => (
|
|
||||||
<View style={styles.buttonWrapper}>
|
<View style={styles.buttonWrapper}>
|
||||||
<IconButton
|
<IconButton
|
||||||
size={20}
|
size={20}
|
||||||
@ -136,20 +141,20 @@ export default class MarkdownEditorView extends Component {
|
|||||||
iconStyle={styles.icon}
|
iconStyle={styles.icon}
|
||||||
iconType={item.iconType}
|
iconType={item.iconType}
|
||||||
name={item.icon}
|
name={item.icon}
|
||||||
onPress={() => item.onPress({ getState, setState, item })}
|
onPress={() =>
|
||||||
|
item.onPress({ text, selection, setTextAndSelection: _setTextAndSelection, item })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
_renderEditorButtons = ({ getState, setState }) => (
|
const _renderEditorButtons = () => (
|
||||||
<StickyBar>
|
<StickyBar>
|
||||||
<View style={styles.leftButtonsWrapper}>
|
<View style={styles.leftButtonsWrapper}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={Formats}
|
data={Formats}
|
||||||
keyboardShouldPersistTaps="always"
|
keyboardShouldPersistTaps="always"
|
||||||
renderItem={({ item, index }) =>
|
renderItem={({ item, index }) => index !== 9 && _renderMarkupButton({ item })}
|
||||||
index !== 9 && this._renderMarkupButton({ item, getState, setState })
|
|
||||||
}
|
|
||||||
horizontal
|
horizontal
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -160,10 +165,12 @@ export default class MarkdownEditorView extends Component {
|
|||||||
iconStyle={styles.icon}
|
iconStyle={styles.icon}
|
||||||
iconType="FontAwesome"
|
iconType="FontAwesome"
|
||||||
name="link"
|
name="link"
|
||||||
onPress={() => Formats[9].onPress({ getState, setState })}
|
onPress={() =>
|
||||||
|
Formats[9].onPress({ text, selection, setTextAndSelection: _setTextAndSelection })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
onPress={() => this.galleryRef.current.show()}
|
onPress={() => galleryRef.current.show()}
|
||||||
style={styles.rightIcons}
|
style={styles.rightIcons}
|
||||||
size={20}
|
size={20}
|
||||||
iconStyle={styles.icon}
|
iconStyle={styles.icon}
|
||||||
@ -172,7 +179,7 @@ export default class MarkdownEditorView extends Component {
|
|||||||
/>
|
/>
|
||||||
<View style={styles.clearButtonWrapper}>
|
<View style={styles.clearButtonWrapper}>
|
||||||
<IconButton
|
<IconButton
|
||||||
onPress={() => this.clearRef.current.show()}
|
onPress={() => clearRef.current.show()}
|
||||||
size={20}
|
size={20}
|
||||||
iconStyle={styles.clearIcon}
|
iconStyle={styles.clearIcon}
|
||||||
iconType="FontAwesome"
|
iconType="FontAwesome"
|
||||||
@ -184,91 +191,81 @@ export default class MarkdownEditorView extends Component {
|
|||||||
</StickyBar>
|
</StickyBar>
|
||||||
);
|
);
|
||||||
|
|
||||||
_handleClear = () => {
|
const _handleClear = index => {
|
||||||
const { initialFields } = this.props;
|
if (index === 0) {
|
||||||
|
initialFields();
|
||||||
initialFields();
|
setText('');
|
||||||
|
_setTextAndSelection({ text: '', selection: { start: 0, end: 0 } });
|
||||||
this.setState({ text: '' });
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { handleOpenImagePicker, intl, isPreviewActive, isReply, isLoading } = this.props;
|
<KeyboardAvoidingView
|
||||||
const { text, selection } = this.state;
|
style={styles.container}
|
||||||
|
keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })}
|
||||||
|
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
||||||
|
>
|
||||||
|
{!isPreviewActive ? (
|
||||||
|
<ThemeContainer>
|
||||||
|
{({ isDarkTheme }) => (
|
||||||
|
<TextInput
|
||||||
|
multiline
|
||||||
|
autoCorrect={false}
|
||||||
|
onChangeText={_changeText}
|
||||||
|
onSelectionChange={_handleOnSelectionChange}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder',
|
||||||
|
})}
|
||||||
|
placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'}
|
||||||
|
selectionColor="#357ce6"
|
||||||
|
style={styles.textWrapper}
|
||||||
|
underlineColorAndroid="transparent"
|
||||||
|
innerRef={inputRef}
|
||||||
|
editable={editable}
|
||||||
|
contextMenuHidden={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ThemeContainer>
|
||||||
|
) : (
|
||||||
|
_renderPreview()
|
||||||
|
)}
|
||||||
|
{!isPreviewActive && _renderEditorButtons()}
|
||||||
|
<ActionSheet
|
||||||
|
ref={galleryRef}
|
||||||
|
options={[
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'editor.open_gallery',
|
||||||
|
}),
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'editor.capture_photo',
|
||||||
|
}),
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'alert.cancel',
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
cancelButtonIndex={2}
|
||||||
|
onPress={index => {
|
||||||
|
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ActionSheet
|
||||||
|
ref={clearRef}
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: 'alert.clear_alert',
|
||||||
|
})}
|
||||||
|
options={[
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'alert.clear',
|
||||||
|
}),
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'alert.cancel',
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
cancelButtonIndex={1}
|
||||||
|
onPress={_handleClear}
|
||||||
|
/>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
export default MarkdownEditorView;
|
||||||
<KeyboardAvoidingView
|
|
||||||
style={styles.container}
|
|
||||||
keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })}
|
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
|
||||||
>
|
|
||||||
{!isPreviewActive ? (
|
|
||||||
<ThemeContainer>
|
|
||||||
{({ isDarkTheme }) => (
|
|
||||||
<TextInput
|
|
||||||
multiline
|
|
||||||
onChangeText={this._changeText}
|
|
||||||
onSelectionChange={this._handleOnSelectionChange}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder',
|
|
||||||
})}
|
|
||||||
placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'}
|
|
||||||
selection={selection}
|
|
||||||
selectionColor="#357ce6"
|
|
||||||
style={styles.textWrapper}
|
|
||||||
underlineColorAndroid="transparent"
|
|
||||||
value={text}
|
|
||||||
innerRef={this.inputRef}
|
|
||||||
editable={!isLoading}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ThemeContainer>
|
|
||||||
) : (
|
|
||||||
this._renderPreview()
|
|
||||||
)}
|
|
||||||
{!isPreviewActive &&
|
|
||||||
this._renderEditorButtons({
|
|
||||||
getState: this._getState,
|
|
||||||
setState: (state, callback) => {
|
|
||||||
this.inputRef.current.focus();
|
|
||||||
this.setState(state, callback);
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
<ActionSheet
|
|
||||||
ref={this.galleryRef}
|
|
||||||
options={[
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'editor.open_gallery',
|
|
||||||
}),
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'editor.capture_photo',
|
|
||||||
}),
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'alert.cancel',
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
cancelButtonIndex={2}
|
|
||||||
onPress={index => {
|
|
||||||
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ActionSheet
|
|
||||||
ref={this.clearRef}
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'alert.clear_alert',
|
|
||||||
})}
|
|
||||||
options={[
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'alert.clear',
|
|
||||||
}),
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'alert.cancel',
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
cancelButtonIndex={1}
|
|
||||||
onPress={index => index === 0 && this._handleClear()}
|
|
||||||
/>
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,5 +4,6 @@ export default EStyleSheet.create({
|
|||||||
icon: {
|
icon: {
|
||||||
color: '$iconColor',
|
color: '$iconColor',
|
||||||
marginRight: 2.7,
|
marginRight: 2.7,
|
||||||
|
fontSize: 25,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -359,12 +359,7 @@ class PostsView extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { refreshing, posts, isShowFilterBar } = this.state;
|
const { refreshing, posts, isShowFilterBar } = this.state;
|
||||||
const {
|
const { filterOptions, selectedOptionIndex, isHideImage, handleImagesHide } = this.props;
|
||||||
filterOptions,
|
|
||||||
selectedOptionIndex,
|
|
||||||
isHideImage,
|
|
||||||
handleImagesHide,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
|
@ -9,8 +9,9 @@ export default EStyleSheet.create({
|
|||||||
},
|
},
|
||||||
upvoteIcon: {
|
upvoteIcon: {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
fontSize: 20,
|
fontSize: 24,
|
||||||
color: '$primaryBlue',
|
color: '$primaryBlue',
|
||||||
|
marginRight: 5,
|
||||||
},
|
},
|
||||||
popoverSlider: {
|
popoverSlider: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -249,12 +249,14 @@ class UpvoteView extends Component {
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<Icon
|
<View hitSlop={{ top: 10, bottom: 10, left: 10, right: 5 }}>
|
||||||
style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]}
|
<Icon
|
||||||
active={!isLoggedIn}
|
style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]}
|
||||||
iconType={isDownVoted ? 'AntDesign' : iconType}
|
active={!isLoggedIn}
|
||||||
name={isDownVoted ? 'downcircle' : iconName}
|
iconType={isDownVoted ? 'AntDesign' : iconType}
|
||||||
/>
|
name={isDownVoted ? 'downcircle' : iconName}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { TouchableOpacity } from 'react-native';
|
import { TouchableOpacity } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { NavigationActions } from 'react-navigation';
|
|
||||||
|
|
||||||
import FastImage from 'react-native-fast-image';
|
import FastImage from 'react-native-fast-image';
|
||||||
import styles from './userAvatarStyles';
|
import styles from './userAvatarStyles';
|
||||||
|
import NavigationService from '../../../navigation/service';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import ROUTES from '../../../constants/routeNames';
|
import ROUTES from '../../../constants/routeNames';
|
||||||
@ -30,21 +30,18 @@ class UserAvatarView extends Component {
|
|||||||
// Component Functions
|
// Component Functions
|
||||||
_handleOnAvatarPress = username => {
|
_handleOnAvatarPress = username => {
|
||||||
const {
|
const {
|
||||||
dispatch,
|
|
||||||
currentUsername: { name },
|
currentUsername: { name },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const routeName = name === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE;
|
const routeName = name === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE;
|
||||||
|
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName,
|
routeName: routeName,
|
||||||
params: {
|
params: {
|
||||||
username,
|
username,
|
||||||
},
|
},
|
||||||
key: username,
|
key: username,
|
||||||
action: NavigationActions.navigate({ routeName }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -61,7 +58,9 @@ class UserAvatarView extends Component {
|
|||||||
let _size;
|
let _size;
|
||||||
const _avatar = username
|
const _avatar = username
|
||||||
? {
|
? {
|
||||||
uri: avatarUrl || (name === username ? avatar : getResizedAvatar(username, imageSize)),
|
uri:
|
||||||
|
avatarUrl ||
|
||||||
|
(name === username && avatar ? avatar : getResizedAvatar(username, imageSize)),
|
||||||
}
|
}
|
||||||
: DEFAULT_IMAGE;
|
: DEFAULT_IMAGE;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import { Provider, connect } from 'react-redux';
|
|||||||
import { PersistGate } from 'redux-persist/integration/react';
|
import { PersistGate } from 'redux-persist/integration/react';
|
||||||
import { IntlProvider } from 'react-intl';
|
import { IntlProvider } from 'react-intl';
|
||||||
import { useScreens } from 'react-native-screens';
|
import { useScreens } from 'react-native-screens';
|
||||||
import { setTopLevelNavigator } from './navigation/service';
|
|
||||||
|
|
||||||
import { flattenMessages } from './utils/flattenMessages';
|
import { flattenMessages } from './utils/flattenMessages';
|
||||||
import messages from './config/locales';
|
import messages from './config/locales';
|
||||||
@ -30,11 +29,7 @@ const App = connect(mapStateToProps)(_renderApp);
|
|||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App
|
<App />
|
||||||
ref={navigatorRef => {
|
|
||||||
setTopLevelNavigator(navigatorRef);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -52,7 +52,7 @@ const BaseNavigator = createBottomTabNavigator(
|
|||||||
screen: Profile,
|
screen: Profile,
|
||||||
navigationOptions: () => ({
|
navigationOptions: () => ({
|
||||||
tabBarIcon: ({ tintColor }) => (
|
tabBarIcon: ({ tintColor }) => (
|
||||||
<Icon iconType="MaterialIcons" name="credit-card" color={tintColor} size={26} />
|
<Icon iconType="MaterialIcons" name="person-outline" color={tintColor} size={26} />
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2,15 +2,21 @@ import { NavigationActions } from 'react-navigation';
|
|||||||
|
|
||||||
let _navigator;
|
let _navigator;
|
||||||
|
|
||||||
export const setTopLevelNavigator = navigatorRef => {
|
const setTopLevelNavigator = navigatorRef => {
|
||||||
_navigator = navigatorRef;
|
_navigator = navigatorRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const navigate = (routeName, params) => {
|
const navigate = navigationProps => {
|
||||||
_navigator.dispatch(
|
_navigator.dispatch(
|
||||||
NavigationActions.navigate({
|
NavigationActions.navigate({
|
||||||
routeName,
|
...navigationProps,
|
||||||
params,
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// add other navigation functions that you need and export them
|
||||||
|
|
||||||
|
export default {
|
||||||
|
navigate,
|
||||||
|
setTopLevelNavigator,
|
||||||
|
};
|
||||||
|
@ -38,6 +38,7 @@ import {
|
|||||||
import { getUser, getPost } from '../../../providers/steem/dsteem';
|
import { getUser, getPost } from '../../../providers/steem/dsteem';
|
||||||
import { switchAccount } from '../../../providers/steem/auth';
|
import { switchAccount } from '../../../providers/steem/auth';
|
||||||
import { setPushToken } from '../../../providers/esteem/esteem';
|
import { setPushToken } from '../../../providers/esteem/esteem';
|
||||||
|
import NavigationService from '../../../navigation/service';
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
import {
|
import {
|
||||||
@ -260,13 +261,11 @@ class ApplicationContainer extends Component {
|
|||||||
if (routeName && (profile || content)) {
|
if (routeName && (profile || content)) {
|
||||||
this.navigationTimeout = setTimeout(() => {
|
this.navigationTimeout = setTimeout(() => {
|
||||||
clearTimeout(this.navigationTimeout);
|
clearTimeout(this.navigationTimeout);
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName,
|
routeName,
|
||||||
params,
|
params,
|
||||||
key: permlink || author,
|
key: permlink || author,
|
||||||
action: NavigationActions.navigate({ routeName }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -402,13 +401,11 @@ class ApplicationContainer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!some(params, isEmpty)) {
|
if (!some(params, isEmpty)) {
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName,
|
routeName,
|
||||||
params,
|
params,
|
||||||
key,
|
key,
|
||||||
action: NavigationActions.navigate({ routeName }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
|||||||
import { createAppContainer } from 'react-navigation';
|
import { createAppContainer } from 'react-navigation';
|
||||||
|
|
||||||
import AppNavitation from '../../../navigation/routes';
|
import AppNavitation from '../../../navigation/routes';
|
||||||
|
import NavigationService from '../../../navigation/service';
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { toastNotification as toastNotificationAction } from '../../../redux/actions/uiAction';
|
import { toastNotification as toastNotificationAction } from '../../../redux/actions/uiAction';
|
||||||
@ -59,7 +60,11 @@ class ApplicationScreen extends Component {
|
|||||||
)}
|
)}
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{!isConnected && <NoInternetConnection />}
|
{!isConnected && <NoInternetConnection />}
|
||||||
<Navigation />
|
<Navigation
|
||||||
|
ref={navigatorRef => {
|
||||||
|
NavigationService.setTopLevelNavigator(navigatorRef);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
{isShowToastNotification && (
|
{isShowToastNotification && (
|
||||||
|
@ -3,10 +3,10 @@ import { Alert } from 'react-native';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import Config from 'react-native-config';
|
import Config from 'react-native-config';
|
||||||
import { NavigationActions } from 'react-navigation';
|
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
|
||||||
// Actions & Services
|
// Actions & Services
|
||||||
|
import NavigationService from '../../../navigation/service';
|
||||||
import {
|
import {
|
||||||
setUserDataWithPinCode,
|
setUserDataWithPinCode,
|
||||||
verifyPinCode,
|
verifyPinCode,
|
||||||
@ -111,12 +111,10 @@ class PinCodeContainer extends Component {
|
|||||||
if (callback) callback(pin, oldPinCode);
|
if (callback) callback(pin, oldPinCode);
|
||||||
dispatch(closePinCodeModal());
|
dispatch(closePinCodeModal());
|
||||||
if (navigateTo) {
|
if (navigateTo) {
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName: navigateTo,
|
routeName: navigateTo,
|
||||||
params: navigateParams,
|
params: navigateParams,
|
||||||
action: NavigationActions.navigate({ routeName: navigateTo }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -174,12 +172,10 @@ class PinCodeContainer extends Component {
|
|||||||
if (callback) callback(pin, oldPinCode);
|
if (callback) callback(pin, oldPinCode);
|
||||||
dispatch(closePinCodeModal());
|
dispatch(closePinCodeModal());
|
||||||
if (navigateTo) {
|
if (navigateTo) {
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName: navigateTo,
|
routeName: navigateTo,
|
||||||
params: navigateParams,
|
params: navigateParams,
|
||||||
action: NavigationActions.navigate({ routeName: navigateTo }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -215,12 +211,10 @@ class PinCodeContainer extends Component {
|
|||||||
dispatch(closePinCodeModal());
|
dispatch(closePinCodeModal());
|
||||||
if (callback) callback(pin, oldPinCode);
|
if (callback) callback(pin, oldPinCode);
|
||||||
if (navigateTo) {
|
if (navigateTo) {
|
||||||
const navigateAction = NavigationActions.navigate({
|
NavigationService.navigate({
|
||||||
routeName: navigateTo,
|
routeName: navigateTo,
|
||||||
params: navigateParams,
|
params: navigateParams,
|
||||||
action: NavigationActions.navigate({ routeName: navigateTo }),
|
|
||||||
});
|
});
|
||||||
dispatch(navigateAction);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
@ -236,21 +236,23 @@ class SettingsContainer extends Component {
|
|||||||
dispatch(changeNotificationSettings({ action, type: actionType }));
|
dispatch(changeNotificationSettings({ action, type: actionType }));
|
||||||
setNotificationSettings({ action, type: actionType });
|
setNotificationSettings({ action, type: actionType });
|
||||||
|
|
||||||
if (actionType === 'notification') {
|
Object.keys(notificationDetails).map(item => {
|
||||||
await Push.setEnabled(action);
|
const notificationType = item.replace('Notification', '');
|
||||||
this._setPushToken(action ? [1, 2, 3, 4, 5, 6] : notifyTypes);
|
|
||||||
} else {
|
|
||||||
Object.keys(notificationDetails).map(item => {
|
|
||||||
const notificationType = item.replace('Notification', '');
|
|
||||||
|
|
||||||
if (notificationType === actionType.replace('notification.', '')) {
|
if (notificationType === actionType.replace('notification.', '')) {
|
||||||
if (action) {
|
if (action) {
|
||||||
notifyTypes.push(notifyTypesConst[notificationType]);
|
|
||||||
}
|
|
||||||
} else if (notificationDetails[item]) {
|
|
||||||
notifyTypes.push(notifyTypesConst[notificationType]);
|
notifyTypes.push(notifyTypesConst[notificationType]);
|
||||||
}
|
}
|
||||||
});
|
} else if (notificationDetails[item]) {
|
||||||
|
notifyTypes.push(notifyTypesConst[notificationType]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
notifyTypes.sort();
|
||||||
|
|
||||||
|
if (actionType === 'notification') {
|
||||||
|
await Push.setEnabled(action);
|
||||||
|
this._setPushToken(action ? notifyTypes : []);
|
||||||
|
} else {
|
||||||
this._setPushToken(notifyTypes);
|
this._setPushToken(notifyTypes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -286,21 +288,25 @@ class SettingsContainer extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_setPushToken = async notifyTypes => {
|
_setPushToken = async notifyTypes => {
|
||||||
const { isNotificationSettingsOpen, isLoggedIn, username } = this.props;
|
const { isLoggedIn, otherAccounts = [] } = this.props;
|
||||||
|
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
const token = await AppCenter.getInstallId();
|
const token = await AppCenter.getInstallId();
|
||||||
|
|
||||||
getExistUser().then(isExistUser => {
|
getExistUser().then(isExistUser => {
|
||||||
if (isExistUser) {
|
if (isExistUser) {
|
||||||
const data = {
|
otherAccounts.forEach(item => {
|
||||||
username,
|
const { isNotificationSettingsOpen } = this.props;
|
||||||
token,
|
|
||||||
system: Platform.OS,
|
const data = {
|
||||||
allows_notify: Number(isNotificationSettingsOpen),
|
username: item.username,
|
||||||
notify_types: notifyTypes,
|
token,
|
||||||
};
|
system: Platform.OS,
|
||||||
setPushToken(data);
|
allows_notify: Number(isNotificationSettingsOpen),
|
||||||
|
notify_types: notifyTypes,
|
||||||
|
};
|
||||||
|
setPushToken(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -401,6 +407,7 @@ const mapStateToProps = state => ({
|
|||||||
|
|
||||||
username: state.account.currentAccount && state.account.currentAccount.name,
|
username: state.account.currentAccount && state.account.currentAccount.name,
|
||||||
currentAccount: state.account.currentAccount,
|
currentAccount: state.account.currentAccount,
|
||||||
|
otherAccounts: state.account.otherAccounts,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default injectIntl(connect(mapStateToProps)(SettingsContainer));
|
export default injectIntl(connect(mapStateToProps)(SettingsContainer));
|
||||||
|
@ -31,10 +31,10 @@ class TransferView extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
from: props.currentAccountName,
|
from: props.currentAccountName,
|
||||||
destination: '',
|
destination: props.transferType === 'powerUp' ? props.currentAccountName : '',
|
||||||
amount: '',
|
amount: '',
|
||||||
memo: '',
|
memo: '',
|
||||||
isUsernameValid: false,
|
isUsernameValid: props.transferType === 'powerUp' && props.currentAccountName ? true : false,
|
||||||
steemConnectTransfer: false,
|
steemConnectTransfer: false,
|
||||||
isTransfering: false,
|
isTransfering: false,
|
||||||
};
|
};
|
||||||
@ -217,22 +217,26 @@ class TransferView extends Component {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<TransferFormItem
|
{transferType !== 'powerUp' && (
|
||||||
label={intl.formatMessage({ id: 'transfer.memo' })}
|
<TransferFormItem
|
||||||
rightComponent={() =>
|
label={intl.formatMessage({ id: 'transfer.memo' })}
|
||||||
this._renderInput(
|
rightComponent={() =>
|
||||||
intl.formatMessage({ id: 'transfer.memo_placeholder' }),
|
this._renderInput({
|
||||||
'memo',
|
placeholder: intl.formatMessage({ id: 'transfer.memo_placeholder' }),
|
||||||
'default',
|
state: 'memo',
|
||||||
true,
|
keyboardType: 'default',
|
||||||
)
|
isTextArea: true,
|
||||||
}
|
})
|
||||||
/>
|
}
|
||||||
<TransferFormItem
|
/>
|
||||||
rightComponent={() =>
|
)}
|
||||||
this._renderDescription(intl.formatMessage({ id: 'transfer.memo_desc' }))
|
{transferType !== 'powerUp' && (
|
||||||
}
|
<TransferFormItem
|
||||||
/>
|
rightComponent={() =>
|
||||||
|
this._renderDescription(intl.formatMessage({ id: 'transfer.memo_desc' }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.bottomContent}>
|
<View style={styles.bottomContent}>
|
||||||
<MainButton
|
<MainButton
|
||||||
|
Loading…
Reference in New Issue
Block a user