Merge branch 'development' into sa/quick-reply-on-post

This commit is contained in:
noumantahir 2022-01-17 21:27:27 +05:00
commit 47a10ede92
24 changed files with 237 additions and 125 deletions

View File

@ -772,4 +772,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 9c48318ea254e2c78005a7a0c2d8bfc14ddd783d
COCOAPODS: 1.11.2
COCOAPODS: 1.10.1

View File

@ -29,7 +29,7 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"@bugsnag/react-native": "^7.11.0",
"@ecency/render-helper": "^2.2.9",
"@ecency/render-helper": "^2.2.12",
"@esteemapp/dhive": "0.15.0",
"@esteemapp/react-native-autocomplete-input": "^4.2.1",
"@esteemapp/react-native-multi-slider": "^1.1.0",

View File

@ -47,7 +47,7 @@ import { TouchableWithoutFeedback } from "react-native-gesture-handler";
}
return (
<TouchableWithoutFeedback onPress={onPress} disabled={!isAnchored}>
<TouchableWithoutFeedback onPress={onPress} disabled={isAnchored}>
<FastImage
style={imgStyle}
source={{uri:imgUrl}}

View File

@ -45,13 +45,10 @@ const PostCardView = ({
isMuted,
}) => {
//local state to manage fake upvote if available
const [activeVotesCount, setActiveVotesCount] = useState(0);
const activeVotesCount = activeVotes ? activeVotes.length : 0;
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
const [calcImgHeight, setCalcImgHeight] = useState(imageHeight || 300);
useEffect(() => {
setActiveVotesCount(activeVotes ? activeVotes.length : 0);
}, [activeVotes]);
// Component Functions
const _handleOnUserPress = (username) => {
if (handleOnUserPress) {
@ -76,7 +73,7 @@ const PostCardView = ({
const _handleIncrementVoteCount = () => {
//fake increment vote using based on local change
setActiveVotesCount(activeVotesCount + 1);
setCacheVoteIcrement(1);
};
const rebloggedBy = get(content, 'reblogged_by[0]', null);
@ -183,7 +180,7 @@ const PostCardView = ({
iconStyle={styles.commentIcon}
iconType="MaterialCommunityIcons"
isClickable
text={activeVotesCount}
text={activeVotesCount + cacheVoteIcrement}
onPress={_handleOnVotersPress}
/>
</TouchableOpacity>

View File

@ -21,7 +21,6 @@ import styles from './commentBodyStyles';
// Services and Actions
import { writeToClipboard } from '../../../../utils/clipboard';
import { toastNotification } from '../../../../redux/actions/uiAction';
import getYoutubeId from '../../../../utils/getYoutubeId';
import VideoPlayerSheet from './videoPlayerSheet';
import { LongPressGestureHandler, State } from 'react-native-gesture-handler';
import { useCallback } from 'react';
@ -29,6 +28,7 @@ import { OptionsModal } from '../../../atoms';
import { useAppDispatch } from '../../../../hooks';
import { isCommunity } from '../../../../utils/communityValidation';
import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters';
import { startsWith } from 'core-js/core/string';
const WIDTH = Dimensions.get('window').width;
@ -54,6 +54,7 @@ const CommentBody = ({
const [revealComment, setRevealComment] = useState(reputation > 0 && !isMuted);
const [videoUrl, setVideoUrl] = useState(null);
const [youtubeVideoId, setYoutubeVideoId] = useState(null)
const [videoStartTime, setVideoStartTime] = useState(0);
const intl = useIntl();
const actionImage = useRef(null);
@ -265,10 +266,10 @@ const CommentBody = ({
}
};
const _handleYoutubePress = (embedUrl) => {
const videoId = getYoutubeId(embedUrl);
const _handleYoutubePress = (videoId, startTime) => {
if (videoId && youtubePlayerRef.current) {
setYoutubeVideoId(videoId);
setVideoStartTime(startTime);
youtubePlayerRef.current.setModalVisible(true);
}
};
@ -276,6 +277,7 @@ const CommentBody = ({
const _handleVideoPress = (embedUrl) => {
if (embedUrl && youtubePlayerRef.current) {
setVideoUrl(embedUrl);
setVideoStartTime(0)
youtubePlayerRef.current.setModalVisible(true);
}
};
@ -366,7 +368,7 @@ const CommentBody = ({
setVideoUrl(null);
}}
>
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} videoUrl={videoUrl} />
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} videoUrl={videoUrl} startTime={videoStartTime} />
</ActionsSheetView>
</Fragment>
);

View File

@ -15,7 +15,6 @@ import { toastNotification } from '../../../../redux/actions/uiAction';
// Constants
import { default as ROUTES } from '../../../../constants/routeNames';
import getYoutubeId from '../../../../utils/getYoutubeId';
import VideoPlayerSheet from './videoPlayerSheet';
import { OptionsModal } from '../../../atoms';
import { isCommunity } from '../../../../utils/communityValidation';
@ -33,6 +32,7 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
const [html, setHtml] = useState('');
const [youtubeVideoId, setYoutubeVideoId] = useState(null);
const [videoUrl, setVideoUrl] = useState(null);
const [videoStartTime, setVideoStartTime] = useState(0);
const intl = useIntl();
const actionImage = useRef(null);
@ -45,10 +45,10 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
}
}, [body]);
const _handleYoutubePress = (embedUrl) => {
const videoId = getYoutubeId(embedUrl);
const _handleYoutubePress = (videoId, startTime) => {
if (videoId && youtubePlayerRef.current) {
setYoutubeVideoId(videoId);
setVideoStartTime(startTime);
youtubePlayerRef.current.setModalVisible(true);
}
};
@ -56,6 +56,7 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
const _handleVideoPress = (embedUrl) => {
if (embedUrl && youtubePlayerRef.current) {
setVideoUrl(embedUrl);
setVideoStartTime(0);
youtubePlayerRef.current.setModalVisible(true);
}
};
@ -293,7 +294,11 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
setVideoUrl(null);
}}
>
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} videoUrl={videoUrl} />
<VideoPlayerSheet
youtubeVideoId={youtubeVideoId}
videoUrl={videoUrl}
startTime={videoStartTime}
/>
</ActionSheetView>
<OptionsModal

View File

@ -1,16 +1,16 @@
import React, {useState} from 'react';
import { Dimensions } from 'react-native';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import AutoHeightWebView from 'react-native-autoheight-webview';
import WebView from 'react-native-webview';
import YoutubeIframe from 'react-native-youtube-iframe';
import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe';
interface VideoPlayerSheetProps {
youtubeVideoId?:string;
videoUrl?:string;
startTime?:number;
}
const VideoPlayerSheet = ({youtubeVideoId, videoUrl}: VideoPlayerSheetProps) => {
const VideoPlayerSheet = ({youtubeVideoId, videoUrl, startTime}: VideoPlayerSheetProps) => {
const PLAYER_HEIGHT = Dimensions.get('screen').width * (9/16);
@ -30,6 +30,10 @@ const VideoPlayerSheet = ({youtubeVideoId, videoUrl}: VideoPlayerSheetProps) =>
setLoading(false)
}
const initialParams:InitialPlayerParams = {
start:startTime
}
return (
<View style={styles.container}>
@ -37,6 +41,7 @@ const VideoPlayerSheet = ({youtubeVideoId, videoUrl}: VideoPlayerSheetProps) =>
<YoutubeIframe
height={PLAYER_HEIGHT}
videoId={youtubeVideoId}
initialPlayerParams={initialParams}
onReady={_onReady}
play={shouldPlay}
onChangeState={_onChangeState}

View File

@ -8,7 +8,10 @@ export interface LinkData {
tag?:string,
proposal?:string,
videoHref?:string,
youtubeId?:string,
startTime?:number,
filter?:string,
community?:string,
}
export const parseLinkData = (tnode:TNode):LinkData => {
@ -17,10 +20,27 @@ export const parseLinkData = (tnode:TNode):LinkData => {
}
if(tnode.classes.includes('markdown-external-link')){
//inline external links can contain video links, for such tags and video id or url is contained as
//attribute if that is the case, use in app video modal to play content
//for now, only youtube id is supported
const youtubeId = tnode.attributes['data-youtube']
const startTime= tnode.attributes['data-start-time'];
if(youtubeId){
return {
type:'markdown-external-link',
href: tnode.attributes['data-href']
type:'markdown-video-link-youtube',
youtubeId:youtubeId,
startTime:parseInt(startTime) || 0,
}
}
//TOOD: support other video link later
//use default markdown-external-link with url;
return {
type:'markdown-external-link',
href: tnode.attributes['data-href']
}
}
@ -90,15 +110,23 @@ export const parseLinkData = (tnode:TNode):LinkData => {
}
if(tnode.classes.includes('markdown-community-link')){
return {
type: 'markdown-community-link',
community: tnode.attributes['data-community'],
filter: tnode.attributes['data-filter'],
}
}
if (tnode.classes.includes('markdown-video-link-youtube')) {
var embedUrl = tnode.attributes['data-embed-src'];
var youtubeId = tnode.attributes['data-youtube'];
const startTime= tnode.attributes['data-start-time'];
if (embedUrl) {
if (youtubeId) {
return {
type: 'markdown-video-link-youtube',
tag: embedUrl
youtubeId : youtubeId,
startTime : parseInt(startTime) || 0,
};
}
}

View File

@ -9,7 +9,7 @@ import { AutoHeightImage } from "../autoHeightImage/autoHeightImage";
interface PostHtmlRendererProps {
contentWidth:number;
body:string;
onLoaded:()=>void;
onLoaded?:()=>void;
setSelectedImage:(imgUrl:string)=>void;
setSelectedLink:(url:string)=>void;
onElementIsImage:(imgUrl:string)=>void;
@ -17,7 +17,7 @@ interface PostHtmlRendererProps {
handleOnUserPress:(username:string)=>void;
handleTagPress:(tag:string, filter?:string)=>void;
handleVideoPress:(videoUrl:string)=>void;
handleYoutubePress:(videoId:string)=>void;
handleYoutubePress:(videoId:string, startTime:number)=>void;
}
export const PostHtmlRenderer = memo(({
@ -37,6 +37,7 @@ export const PostHtmlRenderer = memo(({
//new renderer functions
body = body.replace(/<center>/g, '<div class="text-center">').replace(/<\/center>/g,'</div>');
console.log("Comment body:", body);
const _handleOnLinkPress = (data:LinkData) => {
@ -51,8 +52,11 @@ export const PostHtmlRenderer = memo(({
author,
permlink,
tag,
youtubeId,
startTime,
filter,
videoHref,
community
} = data;
try {
@ -85,7 +89,7 @@ export const PostHtmlRenderer = memo(({
break;
case 'markdown-video-link-youtube':
if(handleYoutubePress){
handleYoutubePress(tag)
handleYoutubePress(youtubeId, startTime)
}
break;
@ -98,6 +102,13 @@ export const PostHtmlRenderer = memo(({
case 'markdown-proposal-link':
setSelectedLink(href);
break;
case 'markdown-community-link':
//tag press also handles community by default
if(handleTagPress){
handleTagPress(community, filter)
}
break;
default:
break;
@ -147,6 +158,26 @@ export const PostHtmlRenderer = memo(({
/>
);
}
//this method checks if image is a child of table column
//and calculates img width accordingly,
//returns full width if img is not part of table
const getMaxImageWidth = (tnode:TNode)=>{
//return full width if not parent exist
if(!tnode.parent || tnode.parent.tagName === 'body'){
return contentWidth;
}
//return divided width based on number td tags
if(tnode.parent.tagName === 'td'){
const cols = tnode.parent.parent.children.length
return contentWidth/cols;
}
//check next parent
return getMaxImageWidth(tnode.parent);
}
const _imageRenderer = ({
@ -160,16 +191,17 @@ export const PostHtmlRenderer = memo(({
};
const isVideoThumb = tnode.classes?.indexOf('video-thumbnail') >= 0;
const isAnchored = !(tnode.parent?.classes?.indexOf('markdown-external-link') >= 0)
const isAnchored = tnode.parent?.tagName === 'a';
if(isVideoThumb){
return <VideoThumb contentWidth={contentWidth} uri={imgUrl}/>;
}
else {
const maxImgWidth = getMaxImageWidth(tnode);
return (
<AutoHeightImage
contentWidth={contentWidth}
contentWidth={maxImgWidth}
imgUrl={imgUrl}
isAnchored={isAnchored}
onPress={_onPress}

View File

@ -17,7 +17,6 @@ export default EStyleSheet.create({
marginBottom:6,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
flexWrap:'wrap'
} as TextStyle,

View File

@ -143,7 +143,6 @@ const PostDisplayContainer = ({
post={post}
activeVotes={activeVotes}
activeVotesCount={activeVotesCount}
setActiveVotesCount={setActiveVotesCount}
reblogs={reblogs}
/>
);

View File

@ -41,15 +41,14 @@ const PostDisplayView = ({
activeVotes,
reblogs,
activeVotesCount,
setActiveVotesCount,
}) => {
const [postHeight, setPostHeight] = useState(0);
const [scrollHeight, setScrollHeight] = useState(0);
const [cacheVoteIcrement, setCacheVoteIcrement] = useState(0);
const [isLoadedComments, setIsLoadedComments] = useState(false);
const actionSheet = useRef(null);
const [refreshing, setRefreshing] = useState(false);
const [postBodyLoading, setPostBodyLoading] = useState(false);
const [tags, setTags] = useState([]);
// Component Life Cycles
@ -94,7 +93,7 @@ const PostDisplayView = ({
};
const _handleIncrementActiveVotesCount = () => {
setActiveVotesCount(activeVotesCount + 1);
setCacheVoteIcrement(1);
};
const _getTabBar = (isFixedFooter = false) => {
@ -114,7 +113,7 @@ const PostDisplayView = ({
iconType="MaterialCommunityIcons"
isClickable
onPress={() => handleOnVotersPress && handleOnVotersPress()}
text={activeVotesCount}
text={activeVotesCount + cacheVoteIcrement}
textMarginLeft={20}
/>
<TextWithIcon

View File

@ -24,7 +24,6 @@ import {
filterSelected,
setOtherPosts,
setInitPosts,
resetLocalVoteMap,
} from '../../../redux/actions/postsAction';
import { hidePostsThumbnails } from '../../../redux/actions/uiAction';
import { fetchLeaderboard, followUser, unfollowUser } from '../../../redux/actions/userAction';
@ -90,10 +89,6 @@ const PostsContainer = ({
const [recommendedCommunities, setRecommendedCommunities] = useState([]);
const [newPostsPopupPictures, setNewPostsPopupPictures] = useState(null);
const _resetLocalVoteMap = () => {
dispatch(resetLocalVoteMap());
};
const _setFeedPosts = (_posts, scrollPos = 0) => {
if (isFeedScreen) {
dispatch(setFeedPosts(_posts, scrollPos));
@ -305,7 +300,6 @@ const PostsContainer = ({
if (isFeedScreen) {
AppState.addEventListener('change', _handleAppStateChange);
_setFeedPosts(initPosts || []);
_resetLocalVoteMap();
} else {
_setFeedPosts([]);
}

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { connect, useSelector } from 'react-redux';
import { connect } from 'react-redux';
import get from 'lodash/get';
// Realm
@ -7,7 +7,6 @@ import { setUpvotePercent } from '../../../realm/realm';
// Services and Actions
import { setUpvotePercent as upvoteAction } from '../../../redux/actions/applicationActions';
import { updateLocalVoteMap } from '../../../redux/actions/postsAction';
// Utils
import { getTimeFromNow } from '../../../utils/time';
@ -16,6 +15,8 @@ import parseAsset from '../../../utils/parseAsset';
// Component
import UpvoteView from '../view/upvoteView';
import { updateVoteCache } from '../../../redux/actions/cacheActions';
import { useAppSelector } from '../../../hooks';
/*
* Props Name Description Value
@ -41,7 +42,8 @@ const UpvoteContainer = (props) => {
const [isVoted, setIsVoted] = useState(null);
const [isDownVoted, setIsDownVoted] = useState(null);
const [totalPayout, setTotalPayout] = useState(get(content, 'total_payout'));
const localVoteMap = useSelector((state) => state.posts.localVoteMap);
const cachedVotes = useAppSelector((state) => state.cache.votes);
const lastCacheUpdate = useAppSelector((state) => state.cache.lastUpdate);
useEffect(() => {
let _isMounted = true;
@ -54,8 +56,8 @@ const UpvoteContainer = (props) => {
setIsVoted(_isVoted && parseInt(_isVoted, 10) / 10000);
setIsDownVoted(_isDownVoted && (parseInt(_isDownVoted, 10) / 10000) * -1);
if (localVoteMap) {
_handleLocalVote();
if (cachedVotes && cachedVotes.size > 0) {
_handleCachedVote();
}
}
};
@ -64,6 +66,19 @@ const UpvoteContainer = (props) => {
return () => (_isMounted = false);
}, [activeVotes]);
useEffect(() => {
const postPath = `${content.author || ''}/${content.permlink || ''}`;
//this conditional makes sure on targetted already fetched post is updated
//with new cache status, this is to avoid duplicate cache merging
if (
lastCacheUpdate &&
lastCacheUpdate.postPath === postPath &&
content.post_fetched_at < lastCacheUpdate.updatedAt
) {
_handleCachedVote();
}
}, [lastCacheUpdate]);
const _setUpvotePercent = (value) => {
if (value) {
setUpvotePercent(String(value));
@ -71,14 +86,15 @@ const UpvoteContainer = (props) => {
}
};
const _handleLocalVote = () => {
const postId = `${content.author || ''}-${content.permlink || ''}`;
const _handleCachedVote = () => {
const postPath = `${content.author || ''}/${content.permlink || ''}`;
const postFetchedAt = get(content, 'post_fetched_at', 0);
const localVote = localVoteMap[postId] || null;
if (localVote) {
const { votedAt, amount, isDownvote, incrementStep } = localVote;
if (postFetchedAt > votedAt) {
if (cachedVotes.has(postPath)) {
const cachedVote = cachedVotes.get(postPath);
const { expiresAt, amount, isDownvote, incrementStep } = cachedVote;
if (postFetchedAt > expiresAt) {
return;
}
@ -97,24 +113,21 @@ const UpvoteContainer = (props) => {
const amountNum = parseFloat(amount);
let incrementStep = 0;
if (!isVoted && !isDownVoted && incrementVoteCount) {
if (!isVoted && !isDownVoted) {
incrementStep = 1;
incrementVoteCount();
}
setIsDownVoted(isDownvote ? true : false);
setIsVoted(isDownvote ? false : true);
setTotalPayout(totalPayout + amountNum);
//update redux
const postId = `${content.author || ''}-${content.permlink || ''}`;
const postPath = `${content.author || ''}/${content.permlink || ''}`;
const curTime = new Date().getTime();
const vote = {
votedAt: new Date().getTime(),
votedAt: curTime,
amount: amountNum,
isDownvote,
incrementStep,
expiresAt: curTime + 30000,
};
dispatch(updateLocalVoteMap(postId, vote));
dispatch(updateVoteCache(postPath, vote));
};
const author = get(content, 'author');

View File

@ -0,0 +1,20 @@
import {
UPDATE_VOTE_CACHE,
PURGE_EXPIRED_CACHE
} from '../constants/constants';
import { Vote } from '../reducers/cacheReducer';
export const updateVoteCache = (postPath:string, vote:Vote) => ({
payload:{
postPath,
vote
},
type: UPDATE_VOTE_CACHE
})
export const purgeExpiredCache = () => ({
type: PURGE_EXPIRED_CACHE
})

View File

@ -6,8 +6,6 @@ import {
RESET,
FILTER_SELECTED,
SET_INIT_POSTS,
UPDATE_LOCAL_VOTE_MAP,
RESET_LOCAL_VOTE_MAP,
SET_FEED_SCREEN_FILTERS,
} from '../constants/constants';
@ -31,23 +29,7 @@ export const setOtherPosts = (posts, scrollPosition = 0) => ({
});
export const updateLocalVoteMap = (postId:string, localVote:{
votedAt: number,
amount: number,
isDownvote: boolean,
incrementStep: number
}) => ({
payload: {
postId,
localVote,
},
type: UPDATE_LOCAL_VOTE_MAP,
});
export const resetLocalVoteMap = () => ({
type: RESET_LOCAL_VOTE_MAP,
});
export const fetchPosts = (payload) => ({
payload,
type: FETCH_POSTS,

View File

@ -81,8 +81,6 @@ export const SUBSCRIBE_COMMUNITY_FAIL = 'SUBSCRIBE_COMMUNITY_FAIL';
export const LEAVE_COMMUNITY = 'LEAVE_COMMUNITY';
export const LEAVE_COMMUNITY_SUCCESS = 'LEAVE_COMMUNITY_SUCCESS';
export const LEAVE_COMMUNITY_FAIL = 'LEAVE_COMMUNITY_FAIL';
export const UPDATE_LOCAL_VOTE_MAP = 'UPDATE_LOCAL_VOTE_MAP';
export const RESET_LOCAL_VOTE_MAP = 'RESET_LOCAL_VOTE_MAP';
// USER
export const FOLLOW_USER = 'FOLLOW_USER';
@ -105,3 +103,7 @@ export const SET_OWN_PROFILE_TABS = 'SET_OWN_PROFILE_TABS';
export const SET_BENEFICIARIES = 'SET_BENEFICIARIES';
export const REMOVE_BENEFICIARIES = 'REMOVE_BENEFICIARIES';
export const TEMP_BENEFICIARIES_ID = 'temp-beneficiaries';
//CACHE
export const PURGE_EXPIRED_CACHE = 'PURGE_EXPIRED_CACHE';
export const UPDATE_VOTE_CACHE = 'UPDATE_VOTE_CACHE';

View File

@ -0,0 +1,57 @@
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE } from "../constants/constants";
export interface Vote {
amount:number;
isDownvote:boolean;
incrementStep:number;
votedAt:number;
expiresAt:number;
}
interface State {
votes:Map<string, Vote>
lastUpdate:{
postPath:string,
updatedAt:number,
}
}
const initialState:State = {
votes:new Map(),
lastUpdate:null,
};
export default function (state = initialState, action) {
const {type, payload} = action;
switch (type) {
case UPDATE_VOTE_CACHE:
if(!state.votes){
state.votes = new Map<string, Vote>();
}
state.votes.set(payload.postPath, payload.vote);
return {
...state, //spread operator in requried here, otherwise persist do not register change
lastUpdate:{
postPath:payload.postPath,
updatedAt: new Date().getTime()
}
};
case PURGE_EXPIRED_CACHE:
const currentTime = new Date().getTime();
if(state.votes && state.votes.entries){
Array.from(state.votes).forEach((entry)=>{
if(entry[1].expiresAt < currentTime){
state.votes.delete(entry[0]);
}
})
}
return {
...state
}
default:
return state;
}
}

View File

@ -8,6 +8,7 @@ import communities from './communitiesReducer';
import user from './userReducer';
import customTabsReducer from './customTabsReducer';
import editorReducer from './editorReducer';
import cacheReducer from './cacheReducer';
export default combineReducers({
account: accountReducer,
@ -19,4 +20,5 @@ export default combineReducers({
ui,
communities,
user,
cache: cacheReducer,
});

View File

@ -7,8 +7,6 @@ import {
FETCH_POSTS,
FETCH_POSTS_SUCCESS,
RESET,
UPDATE_LOCAL_VOTE_MAP,
RESET_LOCAL_VOTE_MAP,
SET_FEED_SCREEN_FILTERS,
} from '../constants/constants';
@ -19,7 +17,6 @@ const initialState = {
posts: [],
loading: false,
selectedFilterValue: '',
localVoteMap: new Map(),
feedScreenFilters:DEFAULT_FEED_FILTERS
};
@ -44,20 +41,6 @@ export default function (state = initialState, action) {
otherScrollPosition: action.payload.scrollPosition,
posts: action.payload,
};
case UPDATE_LOCAL_VOTE_MAP:
const { postId, localVote } = action.payload;
const voteMap = state.localVoteMap || new Map();
voteMap[postId] = localVote;
return {
...state,
localVoteMap: voteMap,
};
case RESET_LOCAL_VOTE_MAP:
return {
...state,
localVoteMap: new Map(),
};
case FILTER_SELECTED: {
return {

View File

@ -1,11 +1,17 @@
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { persistStore, persistReducer } from 'redux-persist';
import { persistStore, persistReducer, createTransform } from 'redux-persist';
import AsyncStorage from '@react-native-community/async-storage';
import Reactotron from '../../../reactotron-config';
import reducer from '../reducers';
const transformCacheVoteMap = createTransform(
(inboundState:any) => ({ ...inboundState, votes : Array.from(inboundState.votes)}),
(outboundState) => ({ ...outboundState, votes:new Map(outboundState.votes)}),
{whitelist:['cache']}
);
// Middleware: Redux Persist Config
const persistConfig = {
// Root
@ -15,6 +21,7 @@ const persistConfig = {
// Blacklist (Don't Save Specific Reducers)
blacklist: ['nav', 'application', 'communities', 'user'],
timeout: 0,
transforms:[transformCacheVoteMap]
};
// Middleware: Redux Persist Persisted Reducer

View File

@ -94,12 +94,7 @@ import {
toastNotification,
updateActiveBottomTab,
} from '../../../redux/actions/uiAction';
import {
resetLocalVoteMap,
setFeedPosts,
setFeedScreenFilters,
setInitPosts,
} from '../../../redux/actions/postsAction';
import { setFeedPosts, setInitPosts } from '../../../redux/actions/postsAction';
import { encryptKey } from '../../../utils/crypto';
@ -109,6 +104,7 @@ import persistAccountGenerator from '../../../utils/persistAccountGenerator';
import parseVersionNumber from '../../../utils/parseVersionNumber';
import { getTimeFromNow, setMomentLocale } from '../../../utils/time';
import parseAuthUrl from '../../../utils/parseAuthUrl';
import { purgeExpiredCache } from '../../../redux/actions/cacheActions';
// Workaround
let previousAppState = 'background';
@ -777,7 +773,7 @@ class ApplicationContainer extends Component {
dispatch(hideActionModal());
dispatch(hideProfileModal());
dispatch(toastNotification(''));
dispatch(resetLocalVoteMap());
dispatch(purgeExpiredCache());
dispatch(setRcOffer(false));
const settings = await getSettings();

View File

@ -1,10 +0,0 @@
export default (url) => {
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
var match = url.match(regExp);
var videoId = (match&&match[7].length==11)? match[7] : false;
console.log("Extracting id ", videoId, url);
return videoId;
}

View File

@ -1031,10 +1031,10 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@ecency/render-helper@^2.2.9":
version "2.2.9"
resolved "https://registry.yarnpkg.com/@ecency/render-helper/-/render-helper-2.2.9.tgz#067a4f3d3c27bcb814648c692a4dfb868035436b"
integrity sha512-Oiz2N7qbwRAuS7dtbSRmCr7Yp2wUyEmBNtEun1byYoE+1g4k7dxJLsigs9ErrJzZ/yFQVcLEB1YrfjZczl/vfQ==
"@ecency/render-helper@^2.2.12":
version "2.2.12"
resolved "https://registry.yarnpkg.com/@ecency/render-helper/-/render-helper-2.2.12.tgz#2eed5cf2fb05e9a6581a06e37fe0fda60d664450"
integrity sha512-QGUS0rkXJiO5QUXggo5u1HZs89pNsIc0F7lD5lWhwHWG5l/CZV9WHrzsxHmtwE5AomlE6KqrZ/B6Ly8nWc5ytA==
dependencies:
he "^1.2.0"
lolight "^1.4.0"