mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-23 05:13:04 +03:00
Merge remote-tracking branch 'upstream/development' into nt/navigation
# Conflicts: # src/screens/register/registerScreen.js
This commit is contained in:
commit
6580f79153
@ -144,7 +144,7 @@ android {
|
|||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch
|
versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch
|
||||||
versionName "3.0.33"
|
versionName "3.0.34"
|
||||||
resValue "string", "build_config_package", "app.esteem.mobile.android"
|
resValue "string", "build_config_package", "app.esteem.mobile.android"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
// react-native-image-crop-picker
|
// react-native-image-crop-picker
|
||||||
|
@ -10,6 +10,16 @@ public class SplashActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Intent intent = new Intent(this, MainActivity.class);
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
|
||||||
|
//workaround for getInitialNotification and onNotificationOpenedApp returning null always
|
||||||
|
//TOOD: use react-native-bootsplash instead of react-native-splash-screen as recommended by firebase
|
||||||
|
//firebase issue ref: https://github.com/invertase/react-native-firebase/issues/3469
|
||||||
|
//ecency project card ref: https://github.com/orgs/ecency/projects/2#card-85455956
|
||||||
|
Bundle extras = getIntent().getExtras();
|
||||||
|
if (extras != null) {
|
||||||
|
intent.putExtras(extras);
|
||||||
|
}
|
||||||
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.33</string>
|
<string>3.0.34</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2812</string>
|
<string>2813</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true />
|
<true />
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.33</string>
|
<string>3.0.34</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2812</string>
|
<string>2813</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -1132,7 +1132,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 2812;
|
CURRENT_PROJECT_VERSION = 2813;
|
||||||
DEAD_CODE_STRIPPING = NO;
|
DEAD_CODE_STRIPPING = NO;
|
||||||
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
||||||
EXCLUDED_ARCHS = "";
|
EXCLUDED_ARCHS = "";
|
||||||
@ -1211,7 +1211,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 2812;
|
CURRENT_PROJECT_VERSION = 2813;
|
||||||
DEAD_CODE_STRIPPING = NO;
|
DEAD_CODE_STRIPPING = NO;
|
||||||
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
||||||
EXCLUDED_ARCHS = "";
|
EXCLUDED_ARCHS = "";
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.33</string>
|
<string>3.0.34</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
@ -62,6 +62,8 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>To access your photos, Ecency needs your permission to help you share your photos.</string>
|
<string>To access your photos, Ecency needs your permission to help you share your photos.</string>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Ecency requires FaceID access to allow you quick and secure access.</string>
|
||||||
<key>NSLocationAlwaysUsageDescription</key>
|
<key>NSLocationAlwaysUsageDescription</key>
|
||||||
<string>To get accurate location for sharing</string>
|
<string>To get accurate location for sharing</string>
|
||||||
<key>NSLocationWhenInUseUsageDescription</key>
|
<key>NSLocationWhenInUseUsageDescription</key>
|
||||||
@ -74,8 +76,6 @@
|
|||||||
<string>Photo Library Access for allowing user to download and upload photos</string>
|
<string>Photo Library Access for allowing user to download and upload photos</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Photo Usage Access for allowing user to upload photos</string>
|
<string>Photo Usage Access for allowing user to upload photos</string>
|
||||||
<key>NSFaceIDUsageDescription</key>
|
|
||||||
<string>Ecency requires FaceID access to allow you quick and secure access.</string>
|
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Entypo.ttf</string>
|
<string>Entypo.ttf</string>
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.33</string>
|
<string>3.0.34</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2812</string>
|
<string>2813</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.0.33</string>
|
<string>3.0.34</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2812</string>
|
<string>2813</string>
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionAttributes</key>
|
<key>NSExtensionAttributes</key>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ecency",
|
"name": "ecency",
|
||||||
"version": "3.0.33",
|
"version": "3.0.34",
|
||||||
"displayName": "Ecency",
|
"displayName": "Ecency",
|
||||||
"private": true,
|
"private": true,
|
||||||
"rnpm": {
|
"rnpm": {
|
||||||
|
@ -45,14 +45,15 @@ const CommentView = ({
|
|||||||
incrementRepliesCount
|
incrementRepliesCount
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const actionSheet = useRef(null);
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const actionSheet = useRef(null);
|
||||||
|
const repliesContainerRef = useRef<AnimatedView>(null);
|
||||||
|
|
||||||
const isMuted = useAppSelector(state => state.account.currentAccount.mutes?.indexOf(comment.author) > -1);
|
const isMuted = useAppSelector(state => state.account.currentAccount.mutes?.indexOf(comment.author) > -1);
|
||||||
const lastCacheUpdate = useAppSelector((state) => state.cache.lastUpdate);
|
const lastCacheUpdate = useAppSelector((state) => state.cache.lastUpdate);
|
||||||
const cachedComments = useAppSelector((state) => state.cache.comments);
|
const cachedComments = useAppSelector((state) => state.cache.comments);
|
||||||
|
|
||||||
const [_isShowSubComments, setIsShowSubComments] = useState(isShowSubComments || false);
|
const [_isShowSubComments, setIsShowSubComments] = useState(false);
|
||||||
const [isPressedShowButton, setIsPressedShowButton] = useState(false);
|
const [isPressedShowButton, setIsPressedShowButton] = useState(false);
|
||||||
const [activeVotes, setActiveVotes] = useState([]);
|
const [activeVotes, setActiveVotes] = useState([]);
|
||||||
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
|
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
|
||||||
@ -61,6 +62,16 @@ const CommentView = ({
|
|||||||
const [replies, setReplies] = useState(comment.replies);
|
const [replies, setReplies] = useState(comment.replies);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(isShowSubComments){
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(repliesContainerRef.current){
|
||||||
|
setIsShowSubComments(true);
|
||||||
|
repliesContainerRef.current.slideInRight(300);
|
||||||
|
}
|
||||||
|
},150)
|
||||||
|
}
|
||||||
|
},[])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (comment) {
|
if (comment) {
|
||||||
@ -81,71 +92,86 @@ const CommentView = ({
|
|||||||
) {
|
) {
|
||||||
//TODO: update comment count and show sub comment if required;
|
//TODO: update comment count and show sub comment if required;
|
||||||
const cachedComment = cachedComments.get(postPath);
|
const cachedComment = cachedComments.get(postPath);
|
||||||
if(cachedComment.updated === cachedComment.created){
|
if (cachedComment.updated === cachedComment.created) {
|
||||||
if(commentNumber > 1 && incrementRepliesCount){
|
if (commentNumber > 1 && incrementRepliesCount) {
|
||||||
incrementRepliesCount();
|
incrementRepliesCount();
|
||||||
}
|
}
|
||||||
setChildCount(childCount + 1);
|
setChildCount(childCount + 1);
|
||||||
setReplies(replies ? [...replies, cachedComment] : [cachedComment]);
|
setReplies(replies ? [...replies, cachedComment] : [cachedComment]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_isShowSubComments){
|
if (!_isShowSubComments) {
|
||||||
_showSubCommentsToggle(true);
|
_showSubCommentsToggle(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [lastCacheUpdate]);
|
}, [lastCacheUpdate]);
|
||||||
|
|
||||||
const _showSubCommentsToggle = (force) => {
|
const _showSubCommentsToggle = (force) => {
|
||||||
if(((replies && replies.length > 0) || force)){
|
if (((replies && replies.length > 0) || force)) {
|
||||||
setIsShowSubComments(!_isShowSubComments);
|
|
||||||
setIsPressedShowButton(true);
|
|
||||||
} else if(openReplyThread) {
|
|
||||||
openReplyThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
if (repliesContainerRef.current) {
|
||||||
|
if (_isShowSubComments) {
|
||||||
const _handleCacheVoteIncrement = () => {
|
repliesContainerRef.current.slideOutRight(300).then(()=>{
|
||||||
//fake increment vote using based on local change
|
setIsShowSubComments(false);
|
||||||
setCacheVoteIcrement(1);
|
});
|
||||||
};
|
} else {
|
||||||
|
setIsShowSubComments(true);
|
||||||
const _incrementRepliesCount = () => {
|
repliesContainerRef.current.slideInRight(300);
|
||||||
if(commentNumber > 1 && incrementRepliesCount){
|
}
|
||||||
incrementRepliesCount();
|
|
||||||
}
|
|
||||||
setChildCount(childCount + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const _handleOnReplyPress = () => {
|
|
||||||
if (isLoggedIn) {
|
|
||||||
dispatch(showReplyModal(comment));
|
|
||||||
} else {
|
|
||||||
console.log('Not LoggedIn');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _renderReadMoreButton = () => (
|
|
||||||
<TextWithIcon
|
|
||||||
wrapperStyle={styles.rightButton}
|
|
||||||
textStyle={!isPressedShowButton && styles.moreText}
|
|
||||||
iconType="MaterialIcons"
|
|
||||||
isClickable
|
|
||||||
iconStyle={styles.iconStyle}
|
|
||||||
iconSize={16}
|
|
||||||
onPress={() => openReplyThread && openReplyThread()}
|
|
||||||
text={
|
|
||||||
!isPressedShowButton
|
|
||||||
? intl.formatMessage({ id: 'comments.read_more' })
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
/>
|
|
||||||
|
|
||||||
)
|
setIsPressedShowButton(true);
|
||||||
|
|
||||||
const _renderReplies = () => {
|
} else if (openReplyThread) {
|
||||||
return (
|
openReplyThread();
|
||||||
<AnimatedView animation="zoomIn" duration={300}>
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const _handleCacheVoteIncrement = () => {
|
||||||
|
//fake increment vote using based on local change
|
||||||
|
setCacheVoteIcrement(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const _incrementRepliesCount = () => {
|
||||||
|
if (commentNumber > 1 && incrementRepliesCount) {
|
||||||
|
incrementRepliesCount();
|
||||||
|
}
|
||||||
|
setChildCount(childCount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const _handleOnReplyPress = () => {
|
||||||
|
if (isLoggedIn) {
|
||||||
|
dispatch(showReplyModal(comment));
|
||||||
|
} else {
|
||||||
|
console.log('Not LoggedIn');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _renderReadMoreButton = () => (
|
||||||
|
<TextWithIcon
|
||||||
|
wrapperStyle={styles.rightButton}
|
||||||
|
textStyle={!isPressedShowButton && styles.moreText}
|
||||||
|
iconType="MaterialIcons"
|
||||||
|
isClickable
|
||||||
|
iconStyle={styles.iconStyle}
|
||||||
|
iconSize={16}
|
||||||
|
onPress={() => openReplyThread && openReplyThread()}
|
||||||
|
text={
|
||||||
|
!isPressedShowButton
|
||||||
|
? intl.formatMessage({ id: 'comments.read_more' })
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
const _renderReplies = () => {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatedView ref={repliesContainerRef}>
|
||||||
|
{_isShowSubComments &&
|
||||||
<Comments
|
<Comments
|
||||||
isShowComments={isShowComments}
|
isShowComments={isShowComments}
|
||||||
commentNumber={commentNumber + 1}
|
commentNumber={commentNumber + 1}
|
||||||
@ -163,163 +189,163 @@ const CommentView = ({
|
|||||||
fetchedAt={fetchedAt}
|
fetchedAt={fetchedAt}
|
||||||
incrementRepliesCount={_incrementRepliesCount}
|
incrementRepliesCount={_incrementRepliesCount}
|
||||||
handleOnReplyPress={_handleOnReplyPress}
|
handleOnReplyPress={_handleOnReplyPress}
|
||||||
/>
|
/>}
|
||||||
</AnimatedView>
|
</AnimatedView>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const _renderComment = () => {
|
const _renderComment = () => {
|
||||||
return ((
|
return ((
|
||||||
<View style={[{ marginLeft: 2, marginTop: -6 }]}>
|
<View style={[{ marginLeft: 2, marginTop: -6 }]}>
|
||||||
<CommentBody
|
<CommentBody
|
||||||
commentDepth={comment.depth}
|
commentDepth={comment.depth}
|
||||||
reputation={comment.author_reputation}
|
reputation={comment.author_reputation}
|
||||||
handleOnUserPress={handleOnUserPress}
|
handleOnUserPress={handleOnUserPress}
|
||||||
handleOnLongPress={handleOnLongPress}
|
handleOnLongPress={handleOnLongPress}
|
||||||
body={comment.body}
|
body={comment.body}
|
||||||
created={comment.created}
|
created={comment.created}
|
||||||
key={`key-${comment.permlink}`}
|
key={`key-${comment.permlink}`}
|
||||||
isMuted={isMuted}
|
isMuted={isMuted}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<View style={styles.footerWrapper}>
|
<View style={styles.footerWrapper}>
|
||||||
{_renderActionPanel()}
|
{_renderActionPanel()}
|
||||||
</View>
|
</View>
|
||||||
{ commentNumber > 1 &&
|
{commentNumber > 1 &&
|
||||||
childCount > 0 &&
|
childCount > 0 &&
|
||||||
!replies?.length &&
|
!replies?.length &&
|
||||||
_renderReadMoreButton()
|
_renderReadMoreButton()
|
||||||
}
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</View>
|
</View>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const _renderActionPanel = () => {
|
const _renderActionPanel = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Upvote
|
<Upvote
|
||||||
activeVotes={activeVotes}
|
activeVotes={activeVotes}
|
||||||
isShowPayoutValue
|
isShowPayoutValue
|
||||||
content={comment}
|
content={comment}
|
||||||
handleCacheVoteIncrement={_handleCacheVoteIncrement}
|
handleCacheVoteIncrement={_handleCacheVoteIncrement}
|
||||||
parentType={postTypes.COMMENT}
|
parentType={postTypes.COMMENT}
|
||||||
/>
|
/>
|
||||||
<TextWithIcon
|
<TextWithIcon
|
||||||
iconName="heart-outline"
|
iconName="heart-outline"
|
||||||
iconSize={20}
|
iconSize={20}
|
||||||
wrapperStyle={styles.leftButton}
|
wrapperStyle={styles.leftButton}
|
||||||
|
iconType="MaterialCommunityIcons"
|
||||||
|
isClickable
|
||||||
|
onPress={() =>
|
||||||
|
handleOnVotersPress &&
|
||||||
|
activeVotes.length > 0 &&
|
||||||
|
handleOnVotersPress(activeVotes, comment)
|
||||||
|
}
|
||||||
|
text={activeVotes.length + cacheVoteIcrement}
|
||||||
|
textStyle={styles.voteCountText}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{isLoggedIn && (
|
||||||
|
<IconButton
|
||||||
|
size={20}
|
||||||
|
iconStyle={styles.leftIcon}
|
||||||
|
style={styles.leftButton}
|
||||||
|
name="comment-outline"
|
||||||
|
onPress={_handleOnReplyPress}
|
||||||
iconType="MaterialCommunityIcons"
|
iconType="MaterialCommunityIcons"
|
||||||
isClickable
|
|
||||||
onPress={() =>
|
|
||||||
handleOnVotersPress &&
|
|
||||||
activeVotes.length > 0 &&
|
|
||||||
handleOnVotersPress(activeVotes, comment)
|
|
||||||
}
|
|
||||||
text={activeVotes.length + cacheVoteIcrement}
|
|
||||||
textStyle={styles.voteCountText}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{isLoggedIn && (
|
|
||||||
|
{currentAccountUsername === comment.author && (
|
||||||
|
<Fragment>
|
||||||
<IconButton
|
<IconButton
|
||||||
size={20}
|
size={20}
|
||||||
iconStyle={styles.leftIcon}
|
iconStyle={styles.leftIcon}
|
||||||
style={styles.leftButton}
|
style={styles.leftButton}
|
||||||
name="comment-outline"
|
name="create"
|
||||||
onPress={_handleOnReplyPress}
|
onPress={() => handleOnEditPress && handleOnEditPress(comment)}
|
||||||
iconType="MaterialCommunityIcons"
|
iconType="MaterialIcons"
|
||||||
/>
|
/>
|
||||||
)}
|
{!childCount && !activeVotes.length && comment.isDeletable && (
|
||||||
|
<Fragment>
|
||||||
|
<IconButton
|
||||||
|
size={20}
|
||||||
|
iconStyle={styles.leftIcon}
|
||||||
|
style={styles.leftButton}
|
||||||
|
name="delete-forever"
|
||||||
|
onPress={() => actionSheet.current.show()}
|
||||||
|
iconType="MaterialIcons"
|
||||||
|
/>
|
||||||
|
<OptionsModal
|
||||||
|
ref={actionSheet}
|
||||||
|
options={[
|
||||||
|
intl.formatMessage({ id: 'alert.delete' }),
|
||||||
|
intl.formatMessage({ id: 'alert.cancel' }),
|
||||||
|
]}
|
||||||
|
title={intl.formatMessage({ id: 'alert.delete' })}
|
||||||
|
destructiveButtonIndex={0}
|
||||||
|
cancelButtonIndex={1}
|
||||||
|
onPress={(index) => {
|
||||||
|
index === 0 ? handleDeleteComment(comment.permlink) : null;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
{currentAccountUsername === comment.author && (
|
{commentNumber === 1 && childCount > 0 && (
|
||||||
<Fragment>
|
<View style={styles.rightButtonWrapper}>
|
||||||
<IconButton
|
<TextWithIcon
|
||||||
size={20}
|
wrapperStyle={styles.rightButton}
|
||||||
iconStyle={styles.leftIcon}
|
iconName={_isShowSubComments ? 'keyboard-arrow-up' : 'keyboard-arrow-down'}
|
||||||
style={styles.leftButton}
|
textStyle={styles.moreText}
|
||||||
name="create"
|
iconType="MaterialIcons"
|
||||||
onPress={() => handleOnEditPress && handleOnEditPress(comment)}
|
isClickable
|
||||||
iconType="MaterialIcons"
|
iconStyle={styles.iconStyle}
|
||||||
/>
|
iconSize={16}
|
||||||
{!childCount && !activeVotes.length && comment.isDeletable && (
|
onPress={() => _showSubCommentsToggle()}
|
||||||
<Fragment>
|
text={`${childCount} ${intl.formatMessage({ id: 'comments.more_replies' })}`}
|
||||||
<IconButton
|
/>
|
||||||
size={20}
|
</View>
|
||||||
iconStyle={styles.leftIcon}
|
)}
|
||||||
style={styles.leftButton}
|
|
||||||
name="delete-forever"
|
|
||||||
onPress={() => actionSheet.current.show()}
|
|
||||||
iconType="MaterialIcons"
|
|
||||||
/>
|
|
||||||
<OptionsModal
|
|
||||||
ref={actionSheet}
|
|
||||||
options={[
|
|
||||||
intl.formatMessage({ id: 'alert.delete' }),
|
|
||||||
intl.formatMessage({ id: 'alert.cancel' }),
|
|
||||||
]}
|
|
||||||
title={intl.formatMessage({ id: 'alert.delete' })}
|
|
||||||
destructiveButtonIndex={0}
|
|
||||||
cancelButtonIndex={1}
|
|
||||||
onPress={(index) => {
|
|
||||||
index === 0 ? handleDeleteComment(comment.permlink) : null;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
{commentNumber === 1 && childCount > 0 && (
|
const customContainerStyle = commentNumber > 2 ? { marginLeft: 44 } : null
|
||||||
<View style={styles.rightButtonWrapper}>
|
|
||||||
<TextWithIcon
|
|
||||||
wrapperStyle={styles.rightButton}
|
|
||||||
iconName={_isShowSubComments ? 'keyboard-arrow-up' : 'keyboard-arrow-down'}
|
|
||||||
textStyle={styles.moreText}
|
|
||||||
iconType="MaterialIcons"
|
|
||||||
isClickable
|
|
||||||
iconStyle={styles.iconStyle}
|
|
||||||
iconSize={16}
|
|
||||||
onPress={() => _showSubCommentsToggle()}
|
|
||||||
text={`${childCount} ${intl.formatMessage({ id: 'comments.more_replies' })}`}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</>
|
return (
|
||||||
)
|
<Fragment>
|
||||||
}
|
<View style={{ ...styles.commentContainer, ...customContainerStyle }}>
|
||||||
|
<PostHeaderDescription
|
||||||
|
key={comment.permlink}
|
||||||
|
date={getTimeFromNow(comment.created)}
|
||||||
|
name={comment.author}
|
||||||
|
reputation={comment.author_reputation}
|
||||||
|
size={avatarSize || 40}
|
||||||
|
currentAccountUsername={currentAccountUsername}
|
||||||
|
isShowOwnerIndicator={mainAuthor === comment.author}
|
||||||
|
isHideImage={isHideImage}
|
||||||
|
inlineTime={true}
|
||||||
|
customStyle={{ alignItems: 'flex-start', paddingLeft: 12 }}
|
||||||
|
showDotMenuButton={true}
|
||||||
|
handleOnDotPress={handleOnLongPress}
|
||||||
|
secondaryContentComponent={_renderComment()}
|
||||||
|
/>
|
||||||
|
|
||||||
const customContainerStyle = commentNumber > 2 ? {marginLeft: 44}:null
|
{commentNumber > 0 && _renderReplies()}
|
||||||
|
</View>
|
||||||
return (
|
</Fragment>
|
||||||
<Fragment>
|
);
|
||||||
<View style={{...styles.commentContainer, ...customContainerStyle}}>
|
|
||||||
<PostHeaderDescription
|
|
||||||
key={comment.permlink}
|
|
||||||
date={getTimeFromNow(comment.created)}
|
|
||||||
name={comment.author}
|
|
||||||
reputation={comment.author_reputation}
|
|
||||||
size={avatarSize || 40}
|
|
||||||
currentAccountUsername={currentAccountUsername}
|
|
||||||
isShowOwnerIndicator={mainAuthor === comment.author}
|
|
||||||
isHideImage={isHideImage}
|
|
||||||
inlineTime={true}
|
|
||||||
customStyle={{alignItems:'flex-start', paddingLeft: 12}}
|
|
||||||
showDotMenuButton={true}
|
|
||||||
handleOnDotPress={handleOnLongPress}
|
|
||||||
secondaryContentComponent={_renderComment()}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{_isShowSubComments && commentNumber > 0 && _renderReplies()}
|
|
||||||
</View>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CommentView;
|
export default CommentView;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import { withNavigation } from '@react-navigation/compat';
|
import { withNavigation } from '@react-navigation/compat';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
@ -19,7 +19,8 @@ import ROUTES from '../../../constants/routeNames';
|
|||||||
// Component
|
// Component
|
||||||
import CommentsView from '../view/commentsView';
|
import CommentsView from '../view/commentsView';
|
||||||
import { useAppSelector } from '../../../hooks';
|
import { useAppSelector } from '../../../hooks';
|
||||||
import { deleteCommentCacheEntry } from '../../../redux/actions/cacheActions';
|
import { updateCommentCache } from '../../../redux/actions/cacheActions';
|
||||||
|
import { CommentCacheStatus } from '../../../redux/reducers/cacheReducer';
|
||||||
|
|
||||||
const CommentsContainer = ({
|
const CommentsContainer = ({
|
||||||
author,
|
author,
|
||||||
@ -66,7 +67,11 @@ const CommentsContainer = ({
|
|||||||
}, [commentCount, selectedFilter]);
|
}, [commentCount, selectedFilter]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPropComments(comments);
|
let _comments = comments;
|
||||||
|
if (_comments) {
|
||||||
|
_comments = _handleCachedComment(comments);
|
||||||
|
}
|
||||||
|
setPropComments(_comments);
|
||||||
}, [comments]);
|
}, [comments]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -190,12 +195,15 @@ const CommentsContainer = ({
|
|||||||
|
|
||||||
var ignoreCache = false;
|
var ignoreCache = false;
|
||||||
var replaceAtIndex = -1;
|
var replaceAtIndex = -1;
|
||||||
|
var removeAtIndex = -1;
|
||||||
_comments.forEach((comment, index) => {
|
_comments.forEach((comment, index) => {
|
||||||
if (cachedComment.permlink === comment.permlink) {
|
if (cachedComment.permlink === comment.permlink) {
|
||||||
if (cachedComment.updated < comment.updated) {
|
if (cachedComment.updated < comment.updated) {
|
||||||
//comment is present with latest data
|
//comment is present with latest data
|
||||||
ignoreCache = true;
|
ignoreCache = true;
|
||||||
console.log('Ignore cache as comment is now present');
|
console.log('Ignore cache as comment is now present');
|
||||||
|
} else if (cachedComment.status === CommentCacheStatus.DELETED) {
|
||||||
|
removeAtIndex = index;
|
||||||
} else {
|
} else {
|
||||||
//comment is present in list but data is old
|
//comment is present in list but data is old
|
||||||
replaceAtIndex = index;
|
replaceAtIndex = index;
|
||||||
@ -203,10 +211,18 @@ const CommentsContainer = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//means deleted comment is not being retuend in fresh data, cache needs to be ignored
|
||||||
|
if (cachedComment.status === CommentCacheStatus.DELETED && removeAtIndex < 0) {
|
||||||
|
ignoreCache = true;
|
||||||
|
}
|
||||||
|
|
||||||
//manipulate comments with cached data
|
//manipulate comments with cached data
|
||||||
if (!ignoreCache) {
|
if (!ignoreCache) {
|
||||||
let newComments = [];
|
let newComments = [];
|
||||||
if (replaceAtIndex >= 0) {
|
if (removeAtIndex >= 0) {
|
||||||
|
newComments = _comments;
|
||||||
|
newComments.splice(removeAtIndex, 1);
|
||||||
|
} else if (replaceAtIndex >= 0) {
|
||||||
_comments[replaceAtIndex] = cachedComment;
|
_comments[replaceAtIndex] = cachedComment;
|
||||||
newComments = [..._comments];
|
newComments = [..._comments];
|
||||||
} else {
|
} else {
|
||||||
@ -266,10 +282,11 @@ const CommentsContainer = ({
|
|||||||
let filteredComments;
|
let filteredComments;
|
||||||
|
|
||||||
deleteComment(currentAccount, pinCode, _permlink).then(() => {
|
deleteComment(currentAccount, pinCode, _permlink).then(() => {
|
||||||
let cachePath = null;
|
let deletedItem = null;
|
||||||
|
|
||||||
const _applyFilter = (item) => {
|
const _applyFilter = (item) => {
|
||||||
if (item.permlink === _permlink) {
|
if (item.permlink === _permlink) {
|
||||||
cachePath = `${item.parent_author}/${item.parent_permlink}`;
|
deletedItem = item;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -284,7 +301,12 @@ const CommentsContainer = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove cached entry based on parent
|
// remove cached entry based on parent
|
||||||
dispatch(deleteCommentCacheEntry(cachePath));
|
if (deletedItem) {
|
||||||
|
const cachePath = `${deletedItem.parent_author}/${deletedItem.parent_permlink}`;
|
||||||
|
deletedItem.status = CommentCacheStatus.DELETED;
|
||||||
|
delete deletedItem.updated;
|
||||||
|
dispatch(updateCommentCache(cachePath, deletedItem, { isUpdate: true }));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,4 +18,11 @@ export default EStyleSheet.create({
|
|||||||
color: '$white',
|
color: '$white',
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
},
|
},
|
||||||
|
emptyText: {
|
||||||
|
color: '$primaryDarkGray',
|
||||||
|
fontSize: 16,
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginTop: 5,
|
||||||
|
padding: 32,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, Fragment, useRef } from 'react';
|
import React, { useState, Fragment, useRef } from 'react';
|
||||||
import { FlatList } from 'react-native';
|
import { FlatList, Text } from 'react-native';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
@ -44,21 +44,21 @@ const CommentsView = ({
|
|||||||
|
|
||||||
|
|
||||||
const _openCommentMenu = (item) => {
|
const _openCommentMenu = (item) => {
|
||||||
if(commentMenu.current){
|
if (commentMenu.current) {
|
||||||
setSelectedComment(item);
|
setSelectedComment(item);
|
||||||
commentMenu.current.show();
|
commentMenu.current.show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _openReplyThread = (item) => {
|
const _openReplyThread = (item) => {
|
||||||
if(item && openReplyThread){
|
if (item && openReplyThread) {
|
||||||
openReplyThread(item)
|
openReplyThread(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _readMoreComments = () => {
|
const _readMoreComments = () => {
|
||||||
if(comments[0] && openReplyThread){
|
if (comments[0] && openReplyThread) {
|
||||||
openReplyThread(comments[0])
|
openReplyThread(comments[0])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,7 +111,7 @@ const CommentsView = ({
|
|||||||
key={get(item, 'permlink')}
|
key={get(item, 'permlink')}
|
||||||
marginLeft={marginLeft}
|
marginLeft={marginLeft}
|
||||||
handleOnLongPress={() => _openCommentMenu(item)}
|
handleOnLongPress={() => _openCommentMenu(item)}
|
||||||
openReplyThread={()=> _openReplyThread(item)}
|
openReplyThread={() => _openReplyThread(item)}
|
||||||
fetchedAt={fetchedAt}
|
fetchedAt={fetchedAt}
|
||||||
incrementRepliesCount={incrementRepliesCount}
|
incrementRepliesCount={incrementRepliesCount}
|
||||||
/>
|
/>
|
||||||
@ -120,19 +120,34 @@ const CommentsView = ({
|
|||||||
|
|
||||||
|
|
||||||
const styleOerride = commentNumber > 1 ? {
|
const styleOerride = commentNumber > 1 ? {
|
||||||
backgroundColor:EStyleSheet.value('$primaryLightBackground'),
|
backgroundColor: EStyleSheet.value('$primaryLightBackground'),
|
||||||
marginTop:8,
|
marginTop: 8,
|
||||||
}:null
|
} : null
|
||||||
|
|
||||||
|
const _renderEmptyContent = () => {
|
||||||
|
if(commentNumber > 1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const _onPress = () => {
|
||||||
|
handleOnReplyPress()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Text onPress={_onPress} style={styles.emptyText}>
|
||||||
|
{intl.formatMessage({ id: "comments.no_comments" })}
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<FlatList
|
<FlatList
|
||||||
style={{...styles.list, ...styleOerride }}
|
style={{ ...styles.list, ...styleOerride }}
|
||||||
contentContainerStyle={{padding:0}}
|
contentContainerStyle={{ padding: 0 }}
|
||||||
data={comments}
|
data={comments}
|
||||||
renderItem={_renderItem}
|
renderItem={_renderItem}
|
||||||
keyExtractor={(item) => get(item, 'permlink')}
|
keyExtractor={(item) => get(item, 'permlink')}
|
||||||
|
ListEmptyComponent={_renderEmptyContent()}
|
||||||
{...flatListProps}
|
{...flatListProps}
|
||||||
/>
|
/>
|
||||||
<OptionsModal
|
<OptionsModal
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
|
|
||||||
|
export default EStyleSheet.create({
|
||||||
|
container: {
|
||||||
|
padding: 16,
|
||||||
|
height: 40,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginVertical: 16,
|
||||||
|
},
|
||||||
|
inputContainer: {
|
||||||
|
marginLeft: 12,
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 12,
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '$primaryLightBackground',
|
||||||
|
borderWidth: EStyleSheet.hairlineWidth,
|
||||||
|
borderColor: '$primaryDarkGray',
|
||||||
|
},
|
||||||
|
inputPlaceholder: {
|
||||||
|
color: '$primaryDarkGray',
|
||||||
|
fontSize: 16,
|
||||||
|
marginTop: 5,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
});
|
@ -1,3 +0,0 @@
|
|||||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
|
||||||
|
|
||||||
export default EStyleSheet.create({});
|
|
@ -1,38 +1,52 @@
|
|||||||
import React, { useState, Fragment } from 'react';
|
import React, { useState, Fragment, useImperativeHandle, forwardRef, useRef } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl, useIntl } from 'react-intl';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { FilterBar } from '../../filterBar';
|
import { FilterBar } from '../../filterBar';
|
||||||
import { Comments } from '../../comments';
|
import { Comments } from '../../comments';
|
||||||
import COMMENT_FILTER, { VALUE } from '../../../constants/options/comment';
|
import COMMENT_FILTER, { VALUE } from '../../../constants/options/comment';
|
||||||
|
import { WriteCommentButton } from './writeCommentButton';
|
||||||
|
|
||||||
// Styles
|
const CommentsDisplayView = forwardRef(
|
||||||
import styles from './commentDisplayStyles';
|
(
|
||||||
|
{
|
||||||
|
author,
|
||||||
|
commentCount,
|
||||||
|
fetchPost,
|
||||||
|
permlink,
|
||||||
|
mainAuthor,
|
||||||
|
handleOnVotersPress,
|
||||||
|
handleOnReplyPress,
|
||||||
|
fetchedAt,
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const CommentsDisplayView = ({
|
const writeCommentRef = useRef(null);
|
||||||
author,
|
|
||||||
commentCount,
|
|
||||||
fetchPost,
|
|
||||||
intl,
|
|
||||||
permlink,
|
|
||||||
mainAuthor,
|
|
||||||
handleOnVotersPress,
|
|
||||||
handleOnReplyPress,
|
|
||||||
fetchedAt,
|
|
||||||
}) => {
|
|
||||||
const [selectedFilter, setSelectedFilter] = useState('trending');
|
|
||||||
const [selectedOptionIndex, setSelectedOptionIndex] = useState(0);
|
|
||||||
|
|
||||||
const _handleOnDropdownSelect = (option, index) => {
|
const [selectedFilter, setSelectedFilter] = useState('trending');
|
||||||
setSelectedFilter(option);
|
const [selectedOptionIndex, setSelectedOptionIndex] = useState(0);
|
||||||
setSelectedOptionIndex(index);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
useImperativeHandle(ref, () => ({
|
||||||
<Fragment>
|
bounceCommentButton: () => {
|
||||||
{commentCount > 0 && (
|
console.log('bouncing comment button');
|
||||||
|
if (writeCommentRef.current) {
|
||||||
|
writeCommentRef.current.bounce();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const _handleOnDropdownSelect = (option, index) => {
|
||||||
|
setSelectedFilter(option);
|
||||||
|
setSelectedOptionIndex(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
<WriteCommentButton ref={writeCommentRef} onPress={handleOnReplyPress} />
|
||||||
<FilterBar
|
<FilterBar
|
||||||
dropdownIconName="arrow-drop-down"
|
dropdownIconName="arrow-drop-down"
|
||||||
options={VALUE.map((val) => intl.formatMessage({ id: `comment_filter.${val}` }))}
|
options={VALUE.map((val) => intl.formatMessage({ id: `comment_filter.${val}` }))}
|
||||||
@ -56,9 +70,9 @@ const CommentsDisplayView = ({
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
</Fragment>
|
||||||
</Fragment>
|
);
|
||||||
);
|
},
|
||||||
};
|
);
|
||||||
|
|
||||||
export default injectIntl(CommentsDisplayView);
|
export default CommentsDisplayView;
|
||||||
|
56
src/components/commentsDisplay/view/writeCommentButton.tsx
Normal file
56
src/components/commentsDisplay/view/writeCommentButton.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { View, Text } from 'react-native'
|
||||||
|
import React, { forwardRef, useImperativeHandle, useRef } from 'react'
|
||||||
|
import UserAvatar from '../../userAvatar';
|
||||||
|
import { View as AnimatedView } from 'react-native-animatable';
|
||||||
|
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||||
|
import styles from './WriteCommentButtonStyles';
|
||||||
|
import { useAppSelector } from '../../../hooks';
|
||||||
|
import showLoginAlert from '../../../utils/showLoginAlert';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
interface WriteCommentButton {
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WriteCommentButton = forwardRef(({ onPress }, ref) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const animatedContainer = useRef<AnimatedView>();
|
||||||
|
|
||||||
|
const isLoggedIn = useAppSelector(state => state.application.isLoggedIn);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
bounce: () => {
|
||||||
|
console.log("bouncing")
|
||||||
|
if (animatedContainer.current) {
|
||||||
|
animatedContainer.current.swing(1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const _onPress = () => {
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
showLoginAlert({ intl })
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (onPress) {
|
||||||
|
onPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatedView ref={animatedContainer}>
|
||||||
|
<TouchableOpacity onPress={_onPress}>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<UserAvatar username="demo.com" />
|
||||||
|
<View style={styles.inputContainer}>
|
||||||
|
<Text style={styles.inputPlaceholder}>
|
||||||
|
{intl.formatMessage({id:'quick_reply.placeholder'})}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</AnimatedView>
|
||||||
|
|
||||||
|
)
|
||||||
|
})
|
@ -1,6 +1,7 @@
|
|||||||
import { get, isEmpty, some } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import React, { useEffect, useRef, useState} from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { Animated, Text, TouchableOpacity, View } from 'react-native';
|
import { Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import { View as AnimatedView } from 'react-native-animatable';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { IconButton } from '..';
|
import { IconButton } from '..';
|
||||||
import { toastNotification } from '../../redux/actions/uiAction';
|
import { toastNotification } from '../../redux/actions/uiAction';
|
||||||
@ -13,148 +14,136 @@ import { navigate } from '../../navigation/service';
|
|||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
interface RemoteMessage {
|
interface RemoteMessage {
|
||||||
data:{
|
data: {
|
||||||
id:string;
|
id: string;
|
||||||
source:string;
|
source: string;
|
||||||
target:string;
|
target: string;
|
||||||
permlink1:string;
|
permlink1: string;
|
||||||
permlink2:string;
|
permlink2: string;
|
||||||
permlink3:string;
|
permlink3: string;
|
||||||
type:'mention'|'reply';
|
type: 'mention' | 'reply';
|
||||||
};
|
};
|
||||||
notification:{
|
notification: {
|
||||||
body:string;
|
body: string;
|
||||||
title:string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
remoteMessage:RemoteMessage
|
remoteMessage: RemoteMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ForegroundNotification = ({remoteMessage}:Props) => {
|
const ForegroundNotification = ({ remoteMessage }: Props) => {
|
||||||
let hideTimeout = null;
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const [duration] = useState(5000);
|
const hideTimeoutRef = useRef<any>(null);
|
||||||
const [activeId, setActiveId] = useState('');
|
const containerRef = useRef<AnimatedView>(null);
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
|
||||||
const [username, setUsername] = useState('');
|
const [duration] = useState(5000);
|
||||||
const [title, setTitle] = useState('');
|
const [activeId, setActiveId] = useState('');
|
||||||
const [body, setBody] = useState('');
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
const [body, setBody] = useState('');
|
||||||
|
|
||||||
|
|
||||||
const animatedValue = useRef(new Animated.Value(-CONTAINER_HEIGHT)).current;
|
useEffect(() => {
|
||||||
|
|
||||||
|
if (remoteMessage) {
|
||||||
|
const { source, target, type, id } = remoteMessage.data;
|
||||||
|
if (activeId !== id && (type === 'reply' || type === 'mention')) {
|
||||||
|
|
||||||
useEffect(() => {
|
let titlePrefixId = '';
|
||||||
|
switch (type) {
|
||||||
if(remoteMessage){
|
case 'reply':
|
||||||
const {source, target, type, id} = remoteMessage.data;
|
titlePrefixId = 'notification.reply_on'
|
||||||
if(activeId !== id && (type === 'reply' || type === 'mention')){
|
break;
|
||||||
|
case 'mention':
|
||||||
let titlePrefixId = '';
|
titlePrefixId = 'notification.mention_on'
|
||||||
switch(type){
|
break;
|
||||||
case 'reply':
|
|
||||||
titlePrefixId = 'notification.reply_on'
|
|
||||||
break;
|
|
||||||
case 'mention':
|
|
||||||
titlePrefixId = 'notification.mention_on'
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setActiveId(id);
|
|
||||||
setUsername(source);
|
|
||||||
setTitle(`${intl.formatMessage({id:titlePrefixId})} @${target}`)
|
|
||||||
setBody(intl.formatMessage({id:'notification.reply_body'}));
|
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setActiveId(id);
|
||||||
|
setUsername(source);
|
||||||
|
setTitle(`${intl.formatMessage({ id: titlePrefixId })} @${target}`)
|
||||||
|
setBody(intl.formatMessage({ id: 'notification.reply_body' }));
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ()=>{
|
return () => {
|
||||||
if(hideTimeout){
|
if (hideTimeoutRef.current) {
|
||||||
clearTimeout(hideTimeout);
|
clearTimeout(hideTimeoutRef.current);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [remoteMessage]);
|
}
|
||||||
|
}, [remoteMessage]);
|
||||||
|
|
||||||
const show = () => {
|
const show = () => {
|
||||||
// Will change fadeAnim value to 1 in 5 seconds
|
setIsVisible(true)
|
||||||
Animated.timing(animatedValue, {
|
hideTimeoutRef.current = setTimeout(() => {
|
||||||
toValue: 0,
|
hide();
|
||||||
duration: 350
|
}, duration)
|
||||||
}).start();
|
|
||||||
|
|
||||||
setIsVisible(true);
|
};
|
||||||
|
|
||||||
hideTimeout = setTimeout(()=>{
|
const hide = async () => {
|
||||||
hide();
|
if (containerRef.current) {
|
||||||
}, duration)
|
await containerRef.current.fadeOutUp(300);
|
||||||
|
|
||||||
};
|
setIsVisible(false);
|
||||||
|
if(hideTimeoutRef.current){
|
||||||
const hide = () => {
|
clearTimeout(hideTimeoutRef.current);
|
||||||
if(hideTimeout || isVisible){
|
|
||||||
// Will change fadeAnim value to 0 in 3 seconds
|
|
||||||
Animated.timing(animatedValue, {
|
|
||||||
toValue: -CONTAINER_HEIGHT,
|
|
||||||
duration: 200
|
|
||||||
}).start(()=>{
|
|
||||||
dispatch(toastNotification(''))
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsVisible(false);
|
|
||||||
clearTimeout(hideTimeout);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const _onPress = () => {
|
|
||||||
const {data} = remoteMessage;
|
|
||||||
const fullPermlink =
|
|
||||||
get(data, 'permlink1', '') + get(data, 'permlink2', '') + get(data, 'permlink3', '');
|
|
||||||
|
|
||||||
let params = {
|
|
||||||
author: get(remoteMessage, 'source', ''),
|
|
||||||
permlink: fullPermlink,
|
|
||||||
};
|
|
||||||
let key = fullPermlink
|
|
||||||
let routeName = ROUTES.SCREENS.POST;
|
|
||||||
|
|
||||||
navigate({
|
|
||||||
routeName,
|
|
||||||
params,
|
|
||||||
key,
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const _onPress = () => {
|
||||||
|
const { data } = remoteMessage;
|
||||||
|
const fullPermlink =
|
||||||
|
get(data, 'permlink1', '') + get(data, 'permlink2', '') + get(data, 'permlink3', '');
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
author: get(data, 'source', ''),
|
||||||
|
permlink: fullPermlink,
|
||||||
|
};
|
||||||
|
let key = fullPermlink
|
||||||
|
let routeName = ROUTES.SCREENS.POST;
|
||||||
|
|
||||||
|
navigate({
|
||||||
|
routeName,
|
||||||
|
params,
|
||||||
|
key,
|
||||||
|
});
|
||||||
|
hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
isVisible &&
|
||||||
style={{
|
<AnimatedView
|
||||||
...styles.container,
|
ref={containerRef}
|
||||||
transform: [{ translateY: animatedValue }],
|
style={styles.container}
|
||||||
}}
|
animation='slideInDown'
|
||||||
>
|
duration={500}>
|
||||||
|
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
|
|
||||||
<TouchableOpacity onPress={_onPress} style={{flexShrink:1}}>
|
<TouchableOpacity onPress={_onPress} style={{ flexShrink: 1 }}>
|
||||||
<View style={{flexDirection:'row', alignItems:'center', marginRight:24}}>
|
<View style={{ flexDirection: 'row', alignItems: 'center', marginRight: 24 }}>
|
||||||
<UserAvatar username={username}/>
|
<UserAvatar username={username} />
|
||||||
|
|
||||||
<View style={{flexShrink:1}}>
|
<View style={{ flexShrink: 1 }}>
|
||||||
<Text style={styles.text} numberOfLines={1}>{title}</Text>
|
<Text style={styles.text} numberOfLines={1}>{title}</Text>
|
||||||
<Text style={styles.text} numberOfLines={1}>{body}</Text>
|
<Text style={styles.text} numberOfLines={1}>{body}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
name='close'
|
name='close'
|
||||||
color="white"
|
color="white"
|
||||||
@ -162,8 +151,7 @@ const ForegroundNotification = ({remoteMessage}:Props) => {
|
|||||||
onPress={hide}
|
onPress={hide}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
</AnimatedView>
|
||||||
</Animated.View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export default EStyleSheet.create({
|
|||||||
ios:getStatusBarHeight() + 12,
|
ios:getStatusBarHeight() + 12,
|
||||||
android:8,
|
android:8,
|
||||||
}),
|
}),
|
||||||
backgroundColor: '$primaryDarkText',
|
backgroundColor: '$darkGrayBackground',
|
||||||
shadowColor: '#5f5f5fbf',
|
shadowColor: '#5f5f5fbf',
|
||||||
shadowOpacity: 0.3,
|
shadowOpacity: 0.3,
|
||||||
shadowOffset: {
|
shadowOffset: {
|
||||||
|
@ -26,6 +26,8 @@ interface Props extends TextInputProps {
|
|||||||
inputStyle:TextStyle;
|
inputStyle:TextStyle;
|
||||||
isValid:boolean;
|
isValid:boolean;
|
||||||
onChange?:(value:string)=>void;
|
onChange?:(value:string)=>void;
|
||||||
|
onFocus?:()=>void;
|
||||||
|
onBlur?:()=>void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FormInputView = ({
|
const FormInputView = ({
|
||||||
@ -44,6 +46,7 @@ const FormInputView = ({
|
|||||||
isValid,
|
isValid,
|
||||||
value,
|
value,
|
||||||
onBlur,
|
onBlur,
|
||||||
|
onFocus,
|
||||||
...props
|
...props
|
||||||
}:Props) => {
|
}:Props) => {
|
||||||
const [_value, setValue] = useState(value || '');
|
const [_value, setValue] = useState(value || '');
|
||||||
@ -62,6 +65,9 @@ const FormInputView = ({
|
|||||||
|
|
||||||
const _handleOnFocus = () => {
|
const _handleOnFocus = () => {
|
||||||
setInputBorderColor('#357ce6');
|
setInputBorderColor('#357ce6');
|
||||||
|
if(onFocus){
|
||||||
|
onFocus();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _handleOnBlur = () => {
|
const _handleOnBlur = () => {
|
||||||
|
@ -1,43 +1,67 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { View as AnimatedView } from 'react-native-animatable'
|
import { View as AnimatedView } from 'react-native-animatable'
|
||||||
import { Portal } from 'react-native-portalize';
|
import { Portal } from 'react-native-portalize';
|
||||||
import styles from '../children/inputSupportModal.styles';
|
import styles from '../children/inputSupportModal.styles';
|
||||||
import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
||||||
|
|
||||||
export interface InputSupportModalProps {
|
export interface InputSupportModalProps {
|
||||||
visible:boolean;
|
visible: boolean;
|
||||||
onClose:()=>void;
|
onClose: () => void;
|
||||||
children?:any
|
children?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InputSupportModal = ({children, visible, onClose}: InputSupportModalProps, ref) => {
|
export const InputSupportModal = ({ children, visible, onClose }: InputSupportModalProps, ref) => {
|
||||||
|
|
||||||
|
const container = useRef<AnimatedView>(null);
|
||||||
|
const innerContainer = useRef<AnimatedView>(null);
|
||||||
|
|
||||||
|
const [showModal, setShowModal] = useState(visible);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
setShowModal(true);
|
||||||
|
}
|
||||||
|
else if (!visible && container.current && innerContainer.current) {
|
||||||
|
innerContainer.current.slideOutDown(1000)
|
||||||
|
setTimeout(async () => {
|
||||||
|
await container.current?.fadeOut(200)
|
||||||
|
setShowModal(false);
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}, [visible])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return showModal && (
|
||||||
<Portal>
|
<Portal>
|
||||||
{
|
|
||||||
visible && (
|
|
||||||
<AnimatedView
|
|
||||||
style={styles.container}
|
|
||||||
duration={300}
|
|
||||||
animation='fadeInUp'>
|
|
||||||
<>
|
|
||||||
<View style={styles.container} onTouchEnd={onClose} />
|
|
||||||
{
|
|
||||||
Platform.select({
|
|
||||||
ios: (
|
|
||||||
<KeyboardAvoidingView behavior="padding" style={{backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>
|
|
||||||
{children}
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
),
|
|
||||||
android: <View>{children}</View>,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</>
|
<AnimatedView
|
||||||
</AnimatedView>
|
ref={container}
|
||||||
)
|
animation='fadeIn'
|
||||||
}
|
duration={300}
|
||||||
|
style={styles.container} >
|
||||||
|
|
||||||
|
<AnimatedView
|
||||||
|
ref={innerContainer}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
animation='slideInUp'
|
||||||
|
duration={300}>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
onTouchEnd={onClose} />
|
||||||
|
|
||||||
|
{
|
||||||
|
Platform.select({
|
||||||
|
ios: (
|
||||||
|
<KeyboardAvoidingView behavior="padding" style={{}}>
|
||||||
|
{children}
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
),
|
||||||
|
android: <View>{children}</View>,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</AnimatedView>
|
||||||
|
</AnimatedView>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { Dimensions } from 'react-native';
|
|
||||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
import getWindowDimensions from '../../../utils/getWindowDimensions';
|
import getWindowDimensions from '../../../utils/getWindowDimensions';
|
||||||
|
|
||||||
@ -14,7 +13,8 @@ export default EStyleSheet.create({
|
|||||||
backgroundColor: '$primaryBackgroundColor',
|
backgroundColor: '$primaryBackgroundColor',
|
||||||
},
|
},
|
||||||
headerLine: {
|
headerLine: {
|
||||||
bottom: 10,
|
marginTop: -4,
|
||||||
|
marginBottom: 4,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState, Fragment } from 'react';
|
import React, { useCallback, useEffect, useRef, useState, Fragment } from 'react';
|
||||||
import { View, Text, ScrollView, SafeAreaView, RefreshControl } from 'react-native';
|
import { View, Text, ScrollView, RefreshControl } from 'react-native';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
|
||||||
// Providers
|
// Providers
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { userActivity } from '../../../providers/ecency/ePoint';
|
import { userActivity } from '../../../providers/ecency/ePoint';
|
||||||
|
|
||||||
@ -22,7 +21,6 @@ import { ParentPost } from '../../parentPost';
|
|||||||
// Styles
|
// Styles
|
||||||
import styles from './postDisplayStyles';
|
import styles from './postDisplayStyles';
|
||||||
import { OptionsModal } from '../../atoms';
|
import { OptionsModal } from '../../atoms';
|
||||||
import { QuickReplyModal } from '../..';
|
|
||||||
import getWindowDimensions from '../../../utils/getWindowDimensions';
|
import getWindowDimensions from '../../../utils/getWindowDimensions';
|
||||||
import { useAppDispatch } from '../../../hooks';
|
import { useAppDispatch } from '../../../hooks';
|
||||||
import { showReplyModal } from '../../../redux/actions/uiAction';
|
import { showReplyModal } from '../../../redux/actions/uiAction';
|
||||||
@ -37,7 +35,6 @@ const PostDisplayView = ({
|
|||||||
isNewPost,
|
isNewPost,
|
||||||
fetchPost,
|
fetchPost,
|
||||||
handleOnEditPress,
|
handleOnEditPress,
|
||||||
handleOnReplyPress,
|
|
||||||
handleOnVotersPress,
|
handleOnVotersPress,
|
||||||
handleOnReblogsPress,
|
handleOnReblogsPress,
|
||||||
post,
|
post,
|
||||||
@ -53,6 +50,11 @@ const PostDisplayView = ({
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
|
const commentsRef = useRef<CommentsDisplay>();
|
||||||
|
const scrollRef = useRef<ScrollView>();
|
||||||
|
const commentsReached = useRef<boolean>(false);
|
||||||
|
|
||||||
|
|
||||||
const [postHeight, setPostHeight] = useState(0);
|
const [postHeight, setPostHeight] = useState(0);
|
||||||
const [scrollHeight, setScrollHeight] = useState(0);
|
const [scrollHeight, setScrollHeight] = useState(0);
|
||||||
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
|
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
|
||||||
@ -87,16 +89,30 @@ const PostDisplayView = ({
|
|||||||
|
|
||||||
const _handleOnScroll = (event) => {
|
const _handleOnScroll = (event) => {
|
||||||
const { y } = event.nativeEvent.contentOffset;
|
const { y } = event.nativeEvent.contentOffset;
|
||||||
|
console.log("scroll height", y)
|
||||||
setScrollHeight(HEIGHT + y);
|
setScrollHeight(HEIGHT + y);
|
||||||
|
|
||||||
|
const _commentButtonBounceOffset = y + (HEIGHT/1.7);
|
||||||
|
if(!commentsReached.current && commentsRef.current && _commentButtonBounceOffset > postHeight ){
|
||||||
|
commentsRef.current.bounceCommentButton();
|
||||||
|
commentsReached.current = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const _handleOnPostLayout = (event) => {
|
const _handleOnPostLayout = (event) => {
|
||||||
const { height } = event.nativeEvent.layout;
|
const { height } = event.nativeEvent.layout;
|
||||||
|
console.log('post height', height)
|
||||||
setPostHeight(height);
|
setPostHeight(height);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _scrollToComments = () => {
|
||||||
|
if(scrollRef.current){
|
||||||
|
const pos = postHeight;
|
||||||
|
scrollRef.current.scrollTo({y:pos})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const _handleOnReblogsPress = () => {
|
const _handleOnReblogsPress = () => {
|
||||||
if (reblogs.length > 0 && handleOnReblogsPress) {
|
if (reblogs.length > 0 && handleOnReblogsPress) {
|
||||||
handleOnReblogsPress();
|
handleOnReblogsPress();
|
||||||
@ -144,7 +160,7 @@ const PostDisplayView = ({
|
|||||||
isClickable
|
isClickable
|
||||||
text={get(post, 'children', 0)}
|
text={get(post, 'children', 0)}
|
||||||
textMarginLeft={20}
|
textMarginLeft={20}
|
||||||
onPress={() => _showQuickReplyModal(post)}
|
onPress={() => _scrollToComments()}
|
||||||
// onPress={() => handleOnReplyPress && handleOnReplyPress()}
|
// onPress={() => handleOnReplyPress && handleOnReplyPress()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -211,9 +227,9 @@ const PostDisplayView = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// show quick reply modal
|
// show quick reply modal
|
||||||
const _showQuickReplyModal = (post) => {
|
const _showQuickReplyModal = (_post = post) => {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
dispatch(showReplyModal(post));
|
dispatch(showReplyModal(_post));
|
||||||
} else {
|
} else {
|
||||||
console.log('Not LoggedIn');
|
console.log('Not LoggedIn');
|
||||||
}
|
}
|
||||||
@ -222,6 +238,7 @@ const PostDisplayView = ({
|
|||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
ref={scrollRef}
|
||||||
style={styles.scroll}
|
style={styles.scroll}
|
||||||
contentContainerStyle={[styles.scrollContent]}
|
contentContainerStyle={[styles.scrollContent]}
|
||||||
onScroll={(event) => _handleOnScroll(event)}
|
onScroll={(event) => _handleOnScroll(event)}
|
||||||
@ -262,7 +279,9 @@ const PostDisplayView = ({
|
|||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{post && !postBodyLoading && (isGetComment || isLoadedComments) && (
|
{post && !postBodyLoading && (isGetComment || isLoadedComments) && (
|
||||||
<CommentsDisplay
|
|
||||||
|
<CommentsDisplay
|
||||||
|
ref={commentsRef}
|
||||||
author={author || post.author}
|
author={author || post.author}
|
||||||
mainAuthor={author || post.author}
|
mainAuthor={author || post.author}
|
||||||
permlink={post.permlink}
|
permlink={post.permlink}
|
@ -724,7 +724,8 @@
|
|||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
"reveal_comment": "Reveal comment",
|
"reveal_comment": "Reveal comment",
|
||||||
"read_more": "Read more comments",
|
"read_more": "Read more comments",
|
||||||
"more_replies": "replies"
|
"more_replies": "replies",
|
||||||
|
"no_comments":"Be the first to respond..."
|
||||||
},
|
},
|
||||||
"search_result": {
|
"search_result": {
|
||||||
"others": "Others",
|
"others": "Others",
|
||||||
@ -817,7 +818,7 @@
|
|||||||
"year":"years"
|
"year":"years"
|
||||||
},
|
},
|
||||||
"quick_reply":{
|
"quick_reply":{
|
||||||
"placeholder":"Add a comment",
|
"placeholder":"Add a comment...",
|
||||||
"comment": "Comment",
|
"comment": "Comment",
|
||||||
"reply": "REPLY",
|
"reply": "REPLY",
|
||||||
"close":"CLOSE"
|
"close":"CLOSE"
|
||||||
|
@ -252,7 +252,7 @@
|
|||||||
"feedback_fail": "Ocurrió un error al intentar abrir el cliente del correo electrónico",
|
"feedback_fail": "Ocurrió un error al intentar abrir el cliente del correo electrónico",
|
||||||
"server_fail": "Servidor no disponible",
|
"server_fail": "Servidor no disponible",
|
||||||
"show_imgs": "Mostrar imágenes",
|
"show_imgs": "Mostrar imágenes",
|
||||||
"delete_account": "Delete Account"
|
"delete_account": "Eliminar cuenta"
|
||||||
},
|
},
|
||||||
"voters": {
|
"voters": {
|
||||||
"voters_info": "Información de votantes",
|
"voters_info": "Información de votantes",
|
||||||
@ -550,9 +550,9 @@
|
|||||||
"confirm_report_body": "¿Estás seguro de que quieres reportar?"
|
"confirm_report_body": "¿Estás seguro de que quieres reportar?"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"confirm_delete_title": "Confirm Delete",
|
"confirm_delete_title": "Confirmar eliminación",
|
||||||
"confirm_delete_body": "Are you sure you want to delete account? It will erase all of your data",
|
"confirm_delete_body": "¿Estás seguro de que deseas eliminar la cuenta? Se borrarán todos tus datos",
|
||||||
"request_sent": "Your request for deletion is sent"
|
"request_sent": "Su solicitud de eliminación está enviada"
|
||||||
},
|
},
|
||||||
"favorites": {
|
"favorites": {
|
||||||
"title": "Favoritos",
|
"title": "Favoritos",
|
||||||
|
@ -252,7 +252,7 @@
|
|||||||
"feedback_fail": "Sähköpostipalvelin alhaalla",
|
"feedback_fail": "Sähköpostipalvelin alhaalla",
|
||||||
"server_fail": "Ei yhteyttä palvelimeen",
|
"server_fail": "Ei yhteyttä palvelimeen",
|
||||||
"show_imgs": "Näytä kuvat",
|
"show_imgs": "Näytä kuvat",
|
||||||
"delete_account": "Delete Account"
|
"delete_account": "Poista tili"
|
||||||
},
|
},
|
||||||
"voters": {
|
"voters": {
|
||||||
"voters_info": "Äänestystiedot",
|
"voters_info": "Äänestystiedot",
|
||||||
@ -269,8 +269,8 @@
|
|||||||
"login": "KIRJAUDU SISÄÄN",
|
"login": "KIRJAUDU SISÄÄN",
|
||||||
"steemconnect_description": "Jos et halua säilyttää kryptattua salasanaa laitteessasi, voit käyttää Hivesigneriä.",
|
"steemconnect_description": "Jos et halua säilyttää kryptattua salasanaa laitteessasi, voit käyttää Hivesigneriä.",
|
||||||
"steemconnect_fee_description": "tietoa",
|
"steemconnect_fee_description": "tietoa",
|
||||||
"not_loggedin_alert": "Not LoggedIn",
|
"not_loggedin_alert": "Ei Kirjautunut",
|
||||||
"not_loggedin_alert_desc": "Please login first"
|
"not_loggedin_alert_desc": "Kirjaudu ensin sisään"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"button": "Luo tili",
|
"button": "Luo tili",
|
||||||
@ -550,9 +550,9 @@
|
|||||||
"confirm_report_body": "Haluatko varmasti tehdä ilmiannon?"
|
"confirm_report_body": "Haluatko varmasti tehdä ilmiannon?"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"confirm_delete_title": "Confirm Delete",
|
"confirm_delete_title": "Vahvista poistaminen",
|
||||||
"confirm_delete_body": "Are you sure you want to delete account? It will erase all of your data",
|
"confirm_delete_body": "Oletko varma, että haluat poistaa tilin? Se poistaa kaikki tietosi",
|
||||||
"request_sent": "Your request for deletion is sent"
|
"request_sent": "Pyyntösi poistamisesta on lähetetty"
|
||||||
},
|
},
|
||||||
"favorites": {
|
"favorites": {
|
||||||
"title": "Suosikit",
|
"title": "Suosikit",
|
||||||
@ -592,7 +592,7 @@
|
|||||||
"pin-community": "Kiinnitä yhteisölle",
|
"pin-community": "Kiinnitä yhteisölle",
|
||||||
"unpin-community": "Poista kiinnitys yhteisöstä",
|
"unpin-community": "Poista kiinnitys yhteisöstä",
|
||||||
"edit-history": "Muokkaushistoria",
|
"edit-history": "Muokkaushistoria",
|
||||||
"mute": "Mute / Block"
|
"mute": "Mykistä / Estä"
|
||||||
},
|
},
|
||||||
"deep_link": {
|
"deep_link": {
|
||||||
"no_existing_user": "Käyttäjää ei ole",
|
"no_existing_user": "Käyttäjää ei ole",
|
||||||
|
@ -10,9 +10,9 @@ import {
|
|||||||
DELETE_DRAFT_CACHE_ENTRY,
|
DELETE_DRAFT_CACHE_ENTRY,
|
||||||
UPDATE_SUBSCRIBED_COMMUNITY_CACHE,
|
UPDATE_SUBSCRIBED_COMMUNITY_CACHE,
|
||||||
DELETE_SUBSCRIBED_COMMUNITY_CACHE,
|
DELETE_SUBSCRIBED_COMMUNITY_CACHE,
|
||||||
CLEAR_SUBSCRIBED_COMMUNITIES_CACHE,
|
CLEAR_SUBSCRIBED_COMMUNITIES_CACHE
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
import { Comment, Draft, SubscribedCommunity, Vote } from '../reducers/cacheReducer';
|
import { Comment, CommentCacheStatus, Draft, SubscribedCommunity, Vote } from '../reducers/cacheReducer';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +46,8 @@ export const updateCommentCache = (commentPath: string, comment: Comment, option
|
|||||||
throw new Error("either of json_metadata in comment data or parentTags in options must be provided");
|
throw new Error("either of json_metadata in comment data or parentTags in options must be provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
comment.created = comment.created || updatedStamp; //created will be set only once for new comment;
|
comment.created = comment.created || updatedStamp; //created will be set only once for new comment;
|
||||||
comment.updated = comment.updated || updatedStamp;
|
comment.updated = comment.updated || updatedStamp;
|
||||||
comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000;//600000;
|
comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000;//600000;
|
||||||
@ -55,6 +57,7 @@ export const updateCommentCache = (commentPath: string, comment: Comment, option
|
|||||||
comment.total_payout = comment.total_payout || 0;
|
comment.total_payout = comment.total_payout || 0;
|
||||||
comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags)
|
comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags)
|
||||||
comment.isDeletable = comment.isDeletable || true;
|
comment.isDeletable = comment.isDeletable || true;
|
||||||
|
comment.status = comment.status || CommentCacheStatus.PENDING;
|
||||||
|
|
||||||
comment.body = renderPostBody({
|
comment.body = renderPostBody({
|
||||||
author: comment.author,
|
author: comment.author,
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY, DELETE_DRAFT_CACHE_ENTRY, UPDATE_DRAFT_CACHE, UPDATE_SUBSCRIBED_COMMUNITY_CACHE, DELETE_SUBSCRIBED_COMMUNITY_CACHE, CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, } from "../constants/constants";
|
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY, DELETE_DRAFT_CACHE_ENTRY, UPDATE_DRAFT_CACHE, UPDATE_SUBSCRIBED_COMMUNITY_CACHE, DELETE_SUBSCRIBED_COMMUNITY_CACHE, CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, UPDATE_COMMENT_CACHE_ENTRY_STATUS, } from "../constants/constants";
|
||||||
|
|
||||||
|
export enum CommentCacheStatus {
|
||||||
|
PENDING = 'PENDING',
|
||||||
|
POSTPONED = 'PUBLISHED',
|
||||||
|
DELETED = 'DELETED',
|
||||||
|
}
|
||||||
|
|
||||||
export interface Vote {
|
export interface Vote {
|
||||||
amount: number;
|
amount: number;
|
||||||
@ -24,6 +30,7 @@ export interface Comment {
|
|||||||
created?: string, //handle created and updated separatly
|
created?: string, //handle created and updated separatly
|
||||||
updated?: string,
|
updated?: string,
|
||||||
expiresAt?: number,
|
expiresAt?: number,
|
||||||
|
status: CommentCacheStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Draft {
|
export interface Draft {
|
||||||
|
@ -18,7 +18,6 @@ import SplashScreen from 'react-native-splash-screen'
|
|||||||
// Constants
|
// Constants
|
||||||
import AUTH_TYPE from '../../../constants/authType';
|
import AUTH_TYPE from '../../../constants/authType';
|
||||||
import ROUTES from '../../../constants/routeNames';
|
import ROUTES from '../../../constants/routeNames';
|
||||||
import postUrlParser from '../../../utils/postUrlParser';
|
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import {
|
import {
|
||||||
@ -34,7 +33,7 @@ import {
|
|||||||
setLastUpdateCheck,
|
setLastUpdateCheck,
|
||||||
getTheme,
|
getTheme,
|
||||||
} from '../../../realm/realm';
|
} from '../../../realm/realm';
|
||||||
import { getUser, getPost, getDigitPinCode, getMutes } from '../../../providers/hive/dhive';
|
import { getUser, getDigitPinCode, getMutes } from '../../../providers/hive/dhive';
|
||||||
import { getPointsSummary } from '../../../providers/ecency/ePoint';
|
import { getPointsSummary } from '../../../providers/ecency/ePoint';
|
||||||
import {
|
import {
|
||||||
migrateToMasterKeyWithAccessToken,
|
migrateToMasterKeyWithAccessToken,
|
||||||
@ -62,7 +61,6 @@ import {
|
|||||||
login,
|
login,
|
||||||
logoutDone,
|
logoutDone,
|
||||||
setConnectivityStatus,
|
setConnectivityStatus,
|
||||||
setAnalyticsStatus,
|
|
||||||
setPinCode as savePinCode,
|
setPinCode as savePinCode,
|
||||||
isRenderRequired,
|
isRenderRequired,
|
||||||
logout,
|
logout,
|
||||||
@ -85,21 +83,12 @@ import lightTheme from '../../../themes/lightTheme';
|
|||||||
import persistAccountGenerator from '../../../utils/persistAccountGenerator';
|
import persistAccountGenerator from '../../../utils/persistAccountGenerator';
|
||||||
import parseVersionNumber from '../../../utils/parseVersionNumber';
|
import parseVersionNumber from '../../../utils/parseVersionNumber';
|
||||||
import { setMomentLocale } from '../../../utils/time';
|
import { setMomentLocale } from '../../../utils/time';
|
||||||
import parseAuthUrl from '../../../utils/parseAuthUrl';
|
|
||||||
import { purgeExpiredCache } from '../../../redux/actions/cacheActions';
|
import { purgeExpiredCache } from '../../../redux/actions/cacheActions';
|
||||||
import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction';
|
import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction';
|
||||||
import MigrationHelpers from '../../../utils/migrationHelpers';
|
import MigrationHelpers from '../../../utils/migrationHelpers';
|
||||||
import { deepLinkParser } from '../../../utils/deepLinkParser';
|
import { deepLinkParser } from '../../../utils/deepLinkParser';
|
||||||
|
import bugsnapInstance from '../../../config/bugsnag';
|
||||||
|
|
||||||
// Workaround
|
|
||||||
let previousAppState = 'background';
|
|
||||||
export const setPreviousAppState = () => {
|
|
||||||
previousAppState = AppState.currentState;
|
|
||||||
const appStateTimeout = setTimeout(() => {
|
|
||||||
previousAppState = AppState.currentState;
|
|
||||||
clearTimeout(appStateTimeout);
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
|
|
||||||
let firebaseOnNotificationOpenedAppListener = null;
|
let firebaseOnNotificationOpenedAppListener = null;
|
||||||
let firebaseOnMessageListener = null;
|
let firebaseOnMessageListener = null;
|
||||||
@ -131,7 +120,6 @@ class ApplicationContainer extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AppState.addEventListener('change', this._handleAppStateChange);
|
AppState.addEventListener('change', this._handleAppStateChange);
|
||||||
setPreviousAppState();
|
|
||||||
|
|
||||||
this.removeAppearanceListener = Appearance.addChangeListener(this._appearanceChangeListener);
|
this.removeAppearanceListener = Appearance.addChangeListener(this._appearanceChangeListener);
|
||||||
|
|
||||||
@ -338,7 +326,7 @@ class ApplicationContainer extends Component {
|
|||||||
if (appState.match(/active|forground/) && nextAppState === 'inactive') {
|
if (appState.match(/active|forground/) && nextAppState === 'inactive') {
|
||||||
this._startPinCodeTimer();
|
this._startPinCodeTimer();
|
||||||
}
|
}
|
||||||
setPreviousAppState();
|
|
||||||
this.setState({
|
this.setState({
|
||||||
appState: nextAppState,
|
appState: nextAppState,
|
||||||
});
|
});
|
||||||
@ -375,7 +363,7 @@ class ApplicationContainer extends Component {
|
|||||||
let key = null;
|
let key = null;
|
||||||
let routeName = null;
|
let routeName = null;
|
||||||
|
|
||||||
if (previousAppState !== 'active' && !!notification) {
|
if (!!notification) {
|
||||||
const push = get(notification, 'data');
|
const push = get(notification, 'data');
|
||||||
const type = get(push, 'type', '');
|
const type = get(push, 'type', '');
|
||||||
const fullPermlink =
|
const fullPermlink =
|
||||||
@ -477,11 +465,11 @@ class ApplicationContainer extends Component {
|
|||||||
|
|
||||||
firebaseOnMessageListener = messaging().onMessage((remoteMessage) => {
|
firebaseOnMessageListener = messaging().onMessage((remoteMessage) => {
|
||||||
console.log('Notification Received: foreground', remoteMessage);
|
console.log('Notification Received: foreground', remoteMessage);
|
||||||
// this._showNotificationToast(remoteMessage);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
foregroundNotificationData: remoteMessage,
|
foregroundNotificationData: remoteMessage,
|
||||||
});
|
});
|
||||||
this._pushNavigate(remoteMessage);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
firebaseOnNotificationOpenedAppListener = messaging().onNotificationOpenedApp(
|
firebaseOnNotificationOpenedAppListener = messaging().onNotificationOpenedApp(
|
||||||
@ -672,26 +660,40 @@ class ApplicationContainer extends Component {
|
|||||||
|
|
||||||
|
|
||||||
//update notification settings and update push token for each signed accoutn useing access tokens
|
//update notification settings and update push token for each signed accoutn useing access tokens
|
||||||
_registerDeviceForNotifications = (settings?:any) => {
|
_registerDeviceForNotifications = (settings?: any) => {
|
||||||
const { otherAccounts, notificationDetails, isNotificationsEnabled } = this.props;
|
const { currentAccount, otherAccounts, notificationDetails, isNotificationsEnabled } = this.props;
|
||||||
|
|
||||||
const isEnabled = settings ? !!settings.notification : isNotificationsEnabled;
|
const isEnabled = settings ? !!settings.notification : isNotificationsEnabled;
|
||||||
settings = settings || notificationDetails;
|
settings = settings || notificationDetails;
|
||||||
|
|
||||||
|
const _enabledNotificationForAccount = (account) => {
|
||||||
//updateing fcm token with settings;
|
|
||||||
otherAccounts.forEach((account) => {
|
|
||||||
//since there can be more than one accounts, process access tokens separate
|
|
||||||
const encAccessToken = account?.local?.accessToken;
|
const encAccessToken = account?.local?.accessToken;
|
||||||
//decrypt access token
|
//decrypt access token
|
||||||
let accessToken = null;
|
let accessToken = null;
|
||||||
if (encAccessToken) {
|
if (encAccessToken) {
|
||||||
//NOTE: default pin decryption works also for custom pin as other account
|
//NOTE: default pin decryption works also for custom pin as other account
|
||||||
//keys are not yet being affected by changed pin, which I think we should dig more
|
//keys are not yet being affected by changed pin, which I think we should dig more
|
||||||
accessToken = decryptKey(encAccessToken, Config.DEFAULT_PIN);
|
accessToken = decryptKey(account.name, Config.DEFAULT_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._enableNotification(account.name, isEnabled, settings, accessToken);
|
this._enableNotification(account.name, isEnabled, settings, accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//updateing fcm token with settings;
|
||||||
|
otherAccounts.forEach((account) => {
|
||||||
|
//since there can be more than one accounts, process access tokens separate
|
||||||
|
if (account?.local?.accessToken) {
|
||||||
|
_enabledNotificationForAccount(account)
|
||||||
|
} else {
|
||||||
|
console.warn("access token not present, reporting to bugsnag")
|
||||||
|
bugsnapInstance.notify(new Error(`Reporting missing access token in other accounts section: account:${account.name} with local data ${JSON.stringify(account?.local)}`))
|
||||||
|
|
||||||
|
//fallback to current account access token to register atleast logged in account
|
||||||
|
if (currentAccount.name === account.name) {
|
||||||
|
_enabledNotificationForAccount(currentAccount)
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { View, StatusBar, Platform, Image, Text, SafeAreaView } from 'react-native';
|
import {
|
||||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
View,
|
||||||
|
StatusBar,
|
||||||
|
Platform,
|
||||||
|
Image,
|
||||||
|
Text,
|
||||||
|
SafeAreaView,
|
||||||
|
Keyboard,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
} from 'react-native';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
import * as Animatable from 'react-native-animatable';
|
||||||
import RegisterContainer from './registerContainer';
|
import RegisterContainer from './registerContainer';
|
||||||
|
|
||||||
// Internal Components
|
// Internal Components
|
||||||
@ -16,6 +24,7 @@ import styles from './registerStyles';
|
|||||||
|
|
||||||
import ESTEEM_LOGO from '../../assets/like_new.png';
|
import ESTEEM_LOGO from '../../assets/like_new.png';
|
||||||
import ESTEEM_SMALL_LOGO from '../../assets/ecency_logo_transparent.png';
|
import ESTEEM_SMALL_LOGO from '../../assets/ecency_logo_transparent.png';
|
||||||
|
import getWindowDimensions from '../../utils/getWindowDimensions';
|
||||||
|
|
||||||
const RegisterScreen = ({ navigation, route }) => {
|
const RegisterScreen = ({ navigation, route }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@ -27,6 +36,19 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
const [refUsername, setRefUsername] = useState(route.params?.referredUser ?? '');
|
const [refUsername, setRefUsername] = useState(route.params?.referredUser ?? '');
|
||||||
const [isRefUsernameValid, setIsRefUsernameValid] = useState(true);
|
const [isRefUsernameValid, setIsRefUsernameValid] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
|
||||||
|
setKeyboardIsOpen(true);
|
||||||
|
});
|
||||||
|
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||||
|
setKeyboardIsOpen(false);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
keyboardDidHideListener.remove();
|
||||||
|
keyboardDidShowListener.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const _handleEmailChange = (value) => {
|
const _handleEmailChange = (value) => {
|
||||||
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||||
setIsEmailValid(re.test(value));
|
setIsEmailValid(re.test(value));
|
||||||
@ -74,7 +96,11 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{!keyboardIsOpen && (
|
<Animatable.View
|
||||||
|
animation={keyboardIsOpen ? hideAnimation : showAnimation}
|
||||||
|
delay={0}
|
||||||
|
duration={300}
|
||||||
|
>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<View style={styles.titleText}>
|
<View style={styles.titleText}>
|
||||||
<Text style={styles.title}>{intl.formatMessage({ id: 'register.title' })}</Text>
|
<Text style={styles.title}>{intl.formatMessage({ id: 'register.title' })}</Text>
|
||||||
@ -84,15 +110,13 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
</View>
|
</View>
|
||||||
<Image style={styles.mascot} source={ESTEEM_LOGO} />
|
<Image style={styles.mascot} source={ESTEEM_LOGO} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
</Animatable.View>
|
||||||
<View style={styles.body}>
|
<KeyboardAvoidingView
|
||||||
<KeyboardAwareScrollView
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||||
onKeyboardWillShow={() => setKeyboardIsOpen(true)}
|
style={styles.formWrapper}
|
||||||
onKeyboardWillHide={() => setKeyboardIsOpen(false)}
|
keyboardShouldPersistTaps
|
||||||
enableAutoAutomaticScroll={Platform.OS === 'ios'}
|
>
|
||||||
contentContainerStyle={styles.formWrapper}
|
<View style={styles.body}>
|
||||||
enableOnAndroid={true}
|
|
||||||
>
|
|
||||||
<FormInput
|
<FormInput
|
||||||
rightIconName="at"
|
rightIconName="at"
|
||||||
leftIconName="close"
|
leftIconName="close"
|
||||||
@ -107,6 +131,7 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
isFirstImage
|
isFirstImage
|
||||||
value={username}
|
value={username}
|
||||||
inputStyle={styles.input}
|
inputStyle={styles.input}
|
||||||
|
onFocus={() => setKeyboardIsOpen(true)}
|
||||||
/>
|
/>
|
||||||
<FormInput
|
<FormInput
|
||||||
rightIconName="mail"
|
rightIconName="mail"
|
||||||
@ -120,6 +145,7 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
type="emailAddress"
|
type="emailAddress"
|
||||||
value={email}
|
value={email}
|
||||||
inputStyle={styles.input}
|
inputStyle={styles.input}
|
||||||
|
onFocus={() => setKeyboardIsOpen(true)}
|
||||||
/>
|
/>
|
||||||
<FormInput
|
<FormInput
|
||||||
rightIconName="person"
|
rightIconName="person"
|
||||||
@ -134,14 +160,14 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
isFirstImage
|
isFirstImage
|
||||||
value={refUsername}
|
value={refUsername}
|
||||||
inputStyle={styles.input}
|
inputStyle={styles.input}
|
||||||
|
onFocus={() => setKeyboardIsOpen(true)}
|
||||||
/>
|
/>
|
||||||
<InformationArea
|
<InformationArea
|
||||||
description={intl.formatMessage({ id: 'register.form_description' })}
|
description={intl.formatMessage({ id: 'register.form_description' })}
|
||||||
iconName="ios-information-circle-outline"
|
iconName="ios-information-circle-outline"
|
||||||
link="https://ecency.com/terms-of-service"
|
link="https://ecency.com/terms-of-service"
|
||||||
/>
|
/>
|
||||||
</KeyboardAwareScrollView>
|
</View>
|
||||||
|
|
||||||
<View style={styles.footerButtons}>
|
<View style={styles.footerButtons}>
|
||||||
<TextButton
|
<TextButton
|
||||||
style={styles.cancelButton}
|
style={styles.cancelButton}
|
||||||
@ -166,11 +192,34 @@ const RegisterScreen = ({ navigation, route }) => {
|
|||||||
style={styles.mainButton}
|
style={styles.mainButton}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</KeyboardAvoidingView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
)}
|
)}
|
||||||
</RegisterContainer>
|
</RegisterContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { height } = getWindowDimensions();
|
||||||
|
const bodyHeight = height / 5;
|
||||||
|
const showAnimation = {
|
||||||
|
from: {
|
||||||
|
opacity: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
opacity: 1,
|
||||||
|
height: bodyHeight,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideAnimation = {
|
||||||
|
from: {
|
||||||
|
opacity: 1,
|
||||||
|
height: bodyHeight,
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
opacity: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
export default RegisterScreen;
|
export default RegisterScreen;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
import autoMergeLevel1 from 'redux-persist/es/stateReconciler/autoMergeLevel1';
|
|
||||||
|
|
||||||
export default EStyleSheet.create({
|
export default EStyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
@ -12,12 +11,9 @@ export default EStyleSheet.create({
|
|||||||
},
|
},
|
||||||
footerButtons: {
|
footerButtons: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'flex-end',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
alignSelf: 'flex-end',
|
height: 80,
|
||||||
marginRight: 10,
|
|
||||||
bottom: 24,
|
|
||||||
right: 24,
|
|
||||||
},
|
},
|
||||||
cancelButton: {
|
cancelButton: {
|
||||||
marginRight: 10,
|
marginRight: 10,
|
||||||
@ -25,6 +21,7 @@ export default EStyleSheet.create({
|
|||||||
formWrapper: {
|
formWrapper: {
|
||||||
marginHorizontal: 30,
|
marginHorizontal: 30,
|
||||||
marginVertical: 10,
|
marginVertical: 10,
|
||||||
|
flex: 1,
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
color: '$primaryDarkText',
|
color: '$primaryDarkText',
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { Platform } from "react-native"
|
import { Platform } from "react-native"
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return Platform.OS === 'android' && Platform.Version === 26
|
return Platform.OS === 'android'
|
||||||
|
&& (
|
||||||
|
Platform.Version === 26
|
||||||
|
|| Platform.Version === 27
|
||||||
|
)
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import ROUTES from '../../src/constants/routeNames';
|
import ROUTES from '../../src/constants/routeNames';
|
||||||
|
import { navigate } from '../navigation/service';
|
||||||
|
|
||||||
const showLoginAlert = ({ navigation, intl }) => {
|
const showLoginAlert = ({ intl }) => {
|
||||||
return Alert.alert(
|
return Alert.alert(
|
||||||
intl.formatMessage({ id: 'login.not_loggedin_alert' }),
|
intl.formatMessage({ id: 'login.not_loggedin_alert' }),
|
||||||
intl.formatMessage({ id: 'login.not_loggedin_alert_desc' }),
|
intl.formatMessage({ id: 'login.not_loggedin_alert_desc' }),
|
||||||
@ -14,7 +15,7 @@ const showLoginAlert = ({ navigation, intl }) => {
|
|||||||
{
|
{
|
||||||
text: intl.formatMessage({ id: 'login.login' }),
|
text: intl.formatMessage({ id: 'login.login' }),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
navigation.navigate(ROUTES.SCREENS.LOGIN);
|
navigate({routeName:ROUTES.SCREENS.LOGIN});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user