Merge remote-tracking branch 'upstream/development' into nt/optimise-editor

# Conflicts:
#	src/screens/editor/screen/editorScreen.tsx
This commit is contained in:
Nouman Tahir 2022-06-08 19:44:46 +05:00
commit c97c5b7879
16 changed files with 138 additions and 29 deletions

View File

@ -144,7 +144,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch
versionName "3.0.30"
versionName "3.0.31"
resValue "string", "build_config_package", "app.esteem.mobile.android"
multiDexEnabled true
// react-native-image-crop-picker

View File

@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.30</string>
<string>3.0.31</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2809</string>
<string>2810</string>
<key>LSRequiresIPhoneOS</key>
<true />
<key>NSAppTransportSecurity</key>

View File

@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.30</string>
<string>3.0.31</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2809</string>
<string>2810</string>
</dict>
</plist>

View File

@ -1132,7 +1132,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2809;
CURRENT_PROJECT_VERSION = 2810;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 75B6RXTKGT;
EXCLUDED_ARCHS = "";
@ -1211,7 +1211,7 @@
CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2809;
CURRENT_PROJECT_VERSION = 2810;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 75B6RXTKGT;
EXCLUDED_ARCHS = "";

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.30</string>
<string>3.0.31</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.30</string>
<string>3.0.31</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2809</string>
<string>2810</string>
</dict>
</plist>

View File

@ -833,4 +833,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 0282022703ad578ab2d9afbf3147ba3b373b4311
COCOAPODS: 1.11.3
COCOAPODS: 1.11.2

View File

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>3.0.30</string>
<string>3.0.31</string>
<key>CFBundleVersion</key>
<string>2809</string>
<string>2810</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>

View File

@ -1,6 +1,6 @@
{
"name": "ecency",
"version": "3.0.30",
"version": "3.0.31",
"displayName": "Ecency",
"private": true,
"rnpm": {

View File

@ -8,17 +8,24 @@ import { useSelector, useDispatch } from 'react-redux';
import { delay, generateReplyPermlink } from '../../utils/editor';
import { postComment } from '../../providers/hive/dhive';
import { toastNotification } from '../../redux/actions/uiAction';
import { updateCommentCache } from '../../redux/actions/cacheActions';
import {
deleteDraftCacheEntry,
updateCommentCache,
updateDraftCache,
} from '../../redux/actions/cacheActions';
import { default as ROUTES } from '../../constants/routeNames';
import get from 'lodash/get';
import { navigate } from '../../navigation/service';
import { postBodySummary } from '@ecency/render-helper';
import { Draft } from '../../redux/reducers/cacheReducer';
import { RootState } from '../../redux/store/store';
export interface QuickReplyModalContentProps {
fetchPost?: any;
selectedPost?: any;
inputRef?: any;
sheetModalRef?: any;
handleCloseRef?: any;
}
export const QuickReplyModalContent = ({
@ -26,25 +33,61 @@ export const QuickReplyModalContent = ({
selectedPost,
inputRef,
sheetModalRef,
handleCloseRef,
}: QuickReplyModalContentProps) => {
const intl = useIntl();
const dispatch = useDispatch();
const currentAccount = useSelector((state) => state.account.currentAccount);
const pinCode = useSelector((state) => state.application.pin);
const currentAccount = useSelector((state: RootState) => state.account.currentAccount);
const pinCode = useSelector((state: RootState) => state.application.pin);
const drafts = useSelector((state: RootState) => state.cache.drafts);
const [commentValue, setCommentValue] = useState('');
const [isSending, setIsSending] = useState(false);
const [quickCommentDraft, setQuickCommentDraft] = useState<Draft>(null);
const headerText =
selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS));
selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any));
const parentAuthor = selectedPost ? selectedPost.author : '';
const parentPermlink = selectedPost ? selectedPost.permlink : '';
const draftId = `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; //different draftId for each user acount
// reset the state when post changes
useEffect(() => {
setCommentValue('');
handleCloseRef.current = handleSheetClose;
}, [commentValue]);
// load quick comment value from cache
useEffect(() => {
if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) {
const quickComment: Draft = drafts.get(draftId);
setCommentValue(quickComment.body);
setQuickCommentDraft(quickComment);
} else {
setCommentValue('');
}
}, [selectedPost]);
// handlers
const handleSheetClose = () => {
_addQuickCommentIntoCache();
};
// add quick comment value into cache
const _addQuickCommentIntoCache = () => {
const date = new Date();
const updatedStamp = date.toISOString().substring(0, 19);
const quickCommentDraftData: Draft = {
author: currentAccount.name,
body: commentValue,
created: quickCommentDraft ? quickCommentDraft.created : updatedStamp,
updated: updatedStamp,
expiresAt: date.getTime() + 604800000, // 7 days expiry time
};
//add quick comment cache entry
dispatch(updateDraftCache(draftId, quickCommentDraftData));
};
// handle close press
const _handleClosePress = () => {
sheetModalRef.current?.setModalVisible(false);
@ -128,7 +171,10 @@ export const QuickReplyModalContent = ({
},
),
);
// delete quick comment draft cache if it exist
if (drafts.has(draftId)) {
dispatch(deleteDraftCacheEntry(draftId));
}
clearTimeout(stateTimer);
}, 3000);
})
@ -142,6 +188,7 @@ export const QuickReplyModalContent = ({
);
stateTimer = setTimeout(() => {
setIsSending(false);
_addQuickCommentIntoCache(); //add comment value into cache if there is error while posting comment
clearTimeout(stateTimer);
}, 500);
});
@ -237,7 +284,9 @@ export const QuickReplyModalContent = ({
<View style={styles.inputContainer}>
<TextInput
innerRef={inputRef}
onChangeText={setCommentValue}
onChangeText={(value) => {
setCommentValue(value);
}}
value={commentValue}
// autoFocus
placeholder={intl.formatMessage({

View File

@ -14,6 +14,7 @@ const QuickReplyModal = ({ fetchPost }: QuickReplyModalProps, ref) => {
const [selectedPost, setSelectedPost] = useState(null);
const sheetModalRef = useRef<ActionSheet>();
const inputRef = useRef<TextInput>(null);
const handleCloseRef = useRef(null);
//CALLBACK_METHOD
useImperativeHandle(ref, () => ({
@ -36,12 +37,14 @@ const QuickReplyModal = ({ fetchPost }: QuickReplyModalProps, ref) => {
containerStyle={styles.sheetContent}
keyboardHandlerEnabled
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
onClose={() => handleCloseRef.current()}
>
<QuickReplyModalContent
fetchPost={fetchPost}
selectedPost={selectedPost}
inputRef={inputRef}
sheetModalRef={sheetModalRef}
handleCloseRef={handleCloseRef}
/>
</ActionSheet>
</Portal>

View File

@ -5,9 +5,11 @@ import {
UPDATE_VOTE_CACHE,
PURGE_EXPIRED_CACHE,
UPDATE_COMMENT_CACHE,
DELETE_COMMENT_CACHE_ENTRY
DELETE_COMMENT_CACHE_ENTRY,
UPDATE_DRAFT_CACHE,
DELETE_DRAFT_CACHE_ENTRY,
} from '../constants/constants';
import { Comment, Vote } from '../reducers/cacheReducer';
import { Comment, Draft, Vote } from '../reducers/cacheReducer';
@ -72,6 +74,19 @@ import { Comment, Vote } from '../reducers/cacheReducer';
type: DELETE_COMMENT_CACHE_ENTRY
})
export const updateDraftCache = (id:string, draft:Draft) => ({
payload:{
id,
draft
},
type: UPDATE_DRAFT_CACHE
})
export const deleteDraftCacheEntry = (id:string) => ({
payload:id,
type: DELETE_DRAFT_CACHE_ENTRY
})
export const purgeExpiredCache = () => ({
type: PURGE_EXPIRED_CACHE
})

View File

@ -111,6 +111,8 @@ export const PURGE_EXPIRED_CACHE = 'PURGE_EXPIRED_CACHE';
export const UPDATE_VOTE_CACHE = 'UPDATE_VOTE_CACHE';
export const UPDATE_COMMENT_CACHE = 'UPDATE_COMMENT_CACHE';
export const DELETE_COMMENT_CACHE_ENTRY = 'DELETE_COMMENT_CACHE_ENTRY';
export const UPDATE_DRAFT_CACHE = 'UPDATE_DRAFT_CACHE';
export const DELETE_DRAFT_CACHE_ENTRY = 'DELETE_DRAFT_CACHE_ENTRY';
// TOOLTIPS
export const REGISTER_TOOLTIP = 'REGISTER_TOOLTIP';

View File

@ -1,4 +1,4 @@
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY } from "../constants/constants";
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY, DELETE_DRAFT_CACHE_ENTRY, UPDATE_DRAFT_CACHE, } from "../constants/constants";
export interface Vote {
amount:number;
@ -26,19 +26,29 @@ export interface Comment {
expiresAt?:number,
}
export interface Draft {
author: string,
body?:string,
created?:string,
updated?:string,
expiresAt:number;
}
interface State {
votes:Map<string, Vote>
comments:Map<string, Comment> //TODO: handle comment array per post, if parent is same
drafts: Map<string, Draft>
lastUpdate:{
postPath:string,
updatedAt:number,
type:'vote'|'comment',
type:'vote'|'comment'|'draft',
}
}
const initialState:State = {
votes:new Map(),
comments:new Map(),
drafts: new Map(),
lastUpdate:null,
};
@ -79,6 +89,26 @@ const initialState:State = {
}
return { ...state }
case UPDATE_DRAFT_CACHE:
if(!state.drafts){
state.drafts = new Map<string, Draft>();
}
state.drafts.set(payload.id, payload.draft);
return {
...state, //spread operator in requried here, otherwise persist do not register change
lastUpdate: {
postPath: payload.id,
updatedAt: new Date().getTime(),
type: 'draft',
},
};
case DELETE_DRAFT_CACHE_ENTRY:
if (state.drafts && state.drafts.has(payload)) {
state.drafts.delete(payload);
}
return { ...state }
case PURGE_EXPIRED_CACHE:
const currentTime = new Date().getTime();
@ -97,6 +127,14 @@ const initialState:State = {
}
})
}
if(state.drafts && state.drafts.size){
Array.from(state.drafts).forEach((entry)=>{
if(entry[1].expiresAt < currentTime){
state.drafts.delete(entry[0]);
}
})
}
return {
...state

View File

@ -11,12 +11,14 @@ const transformCacheVoteMap = createTransform(
(inboundState:any) => ({
...inboundState,
votes : Array.from(inboundState.votes),
comments : Array.from(inboundState.comments)
comments : Array.from(inboundState.comments),
drafts : Array.from(inboundState.drafts),
}),
(outboundState) => ({
...outboundState,
votes:new Map(outboundState.votes),
comments:new Map(outboundState.comments)
comments:new Map(outboundState.comments),
drafts: new Map(outboundState.drafts)
}),
{whitelist:['cache']}
);

View File

@ -444,7 +444,7 @@ class EditorScreen extends Component {
)}
<MarkdownEditor
componentID="body"
draftBody={quickReplyText ? quickReplyText : fields && fields.body}
draftBody={isReply ? quickReplyText : fields && fields.body}
isFormValid={isFormValid}
handleOpenImagePicker={handleOnImagePicker}
intl={intl}