-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: This differential implements DMActivityHandler component. Its role is the same as ActivityHandler but it works thick threads. I opted for new compoment instead of modifying ActivityHandler since we only need one component for thick threads while there are many ActivityHandlers (one for each keyserver). Therefore I couldn't see an easy way to reuse ActivityHandler. Test Plan: 1. Create thick thread between users A and B. 2. Log in as user A on two devices (on web and on native) and log in as user B on third device. 3. Send message from B to A. Open the thread as A on web. Ensure rescinding happens on native. 4. Open the thread as A on native. Change opened thread as A on web. Send messages from B to A. Ensure that thread remains read on web. Reviewers: tomek, kamil, inka Reviewed By: tomek Subscribers: ashoat Differential Revision: https://phab.comm.dev/D13246
- Loading branch information
1 parent
af90fa4
commit 8c1cd8b
Showing
5 changed files
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// @flow | ||
import invariant from 'invariant'; | ||
import * as React from 'react'; | ||
|
||
import { updateActivityActionTypes } from '../actions/activity-actions.js'; | ||
import { | ||
type OutboundDMOperationSpecification, | ||
dmOperationSpecificationTypes, | ||
} from '../shared/dm-ops/dm-op-utils.js'; | ||
import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; | ||
import { getMostRecentNonLocalMessageID } from '../shared/message-utils.js'; | ||
import { threadIsPending } from '../shared/thread-utils.js'; | ||
import type { ActivityUpdateSuccessPayload } from '../types/activity-types.js'; | ||
import type { DMChangeThreadReadStatusOperation } from '../types/dm-ops.js'; | ||
import type { RawThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; | ||
import { threadTypeIsThick } from '../types/thread-types-enum.js'; | ||
import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; | ||
import { useSelector } from '../utils/redux-utils.js'; | ||
|
||
function useUpdateDMActivity(): ( | ||
viewerID: string, | ||
activeThreadInfo: RawThreadInfo, | ||
) => Promise<ActivityUpdateSuccessPayload> { | ||
const processAndSendDMOperation = useProcessAndSendDMOperation(); | ||
return React.useCallback( | ||
async (viewerID: string, activeThreadInfo: RawThreadInfo) => { | ||
invariant( | ||
threadTypeIsThick(activeThreadInfo.type), | ||
'thread must be thick', | ||
); | ||
const op: DMChangeThreadReadStatusOperation = { | ||
type: 'change_thread_read_status', | ||
time: Date.now(), | ||
threadID: activeThreadInfo.id, | ||
creatorID: viewerID, | ||
unread: false, | ||
}; | ||
|
||
const opSpecification: OutboundDMOperationSpecification = { | ||
type: dmOperationSpecificationTypes.OUTBOUND, | ||
op, | ||
recipients: { type: 'self_devices' }, | ||
}; | ||
|
||
await processAndSendDMOperation(opSpecification); | ||
return { activityUpdates: {}, result: { unfocusedToUnread: [] } }; | ||
}, | ||
[processAndSendDMOperation], | ||
); | ||
} | ||
|
||
function useDMActivityHandler(activeThread: ?string): void { | ||
const activeThreadInfo = useSelector(state => | ||
activeThread ? state.threadStore.threadInfos[activeThread] : null, | ||
); | ||
const activeThreadLatestMessage = useSelector(state => | ||
activeThread | ||
? getMostRecentNonLocalMessageID(activeThread, state.messageStore) | ||
: null, | ||
); | ||
const processAndSendDMOperation = useProcessAndSendDMOperation(); | ||
|
||
const prevActiveThreadRef = React.useRef<?string>(); | ||
const prevActiveThreadLatestMessageRef = React.useRef<?string>(); | ||
|
||
const viewerID = useSelector( | ||
state => state.currentUserInfo && state.currentUserInfo.id, | ||
); | ||
const updateDMActivity = useUpdateDMActivity(); | ||
const dispatchActionPromise = useDispatchActionPromise(); | ||
|
||
React.useEffect(() => { | ||
const prevActiveThread = prevActiveThreadRef.current; | ||
const prevActiveThreadLatestMessage = | ||
prevActiveThreadLatestMessageRef.current; | ||
|
||
prevActiveThreadRef.current = activeThread; | ||
prevActiveThreadLatestMessageRef.current = activeThreadLatestMessage; | ||
|
||
if ( | ||
!viewerID || | ||
!activeThread || | ||
!activeThreadInfo || | ||
!threadTypeIsThick(activeThreadInfo.type) || | ||
threadIsPending(activeThread) || | ||
(activeThread === prevActiveThread && | ||
activeThreadLatestMessage === prevActiveThreadLatestMessage) | ||
) { | ||
return; | ||
} | ||
|
||
void dispatchActionPromise( | ||
updateActivityActionTypes, | ||
updateDMActivity(viewerID, activeThreadInfo), | ||
); | ||
}, [ | ||
updateDMActivity, | ||
dispatchActionPromise, | ||
activeThread, | ||
viewerID, | ||
processAndSendDMOperation, | ||
activeThreadInfo, | ||
activeThreadLatestMessage, | ||
]); | ||
} | ||
|
||
export default useDMActivityHandler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// @flow | ||
import * as React from 'react'; | ||
|
||
import useDMActivityHandler from 'lib/handlers/dm-activity-handler.js'; | ||
import { isLoggedIn } from 'lib/selectors/user-selectors.js'; | ||
|
||
import { activeMessageListSelector } from '../navigation/nav-selectors.js'; | ||
import { NavContext } from '../navigation/navigation-context.js'; | ||
import { useSelector } from '../redux/redux-utils.js'; | ||
|
||
function DMActivityHandler(): React.Node { | ||
const active = useSelector( | ||
state => isLoggedIn(state) && state.lifecycleState !== 'background', | ||
); | ||
const navContext = React.useContext(NavContext); | ||
const activeThread = React.useMemo(() => { | ||
if (!active) { | ||
return null; | ||
} | ||
return activeMessageListSelector(navContext); | ||
}, [active, navContext]); | ||
|
||
useDMActivityHandler(activeThread); | ||
return null; | ||
} | ||
|
||
export default DMActivityHandler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// @flow | ||
import * as React from 'react'; | ||
|
||
import useDMActivityHandler from 'lib/handlers/dm-activity-handler.js'; | ||
import { isLoggedIn } from 'lib/selectors/user-selectors.js'; | ||
|
||
import { useSelector } from '../redux/redux-utils.js'; | ||
import { activeThreadSelector } from '../selectors/nav-selectors.js'; | ||
|
||
function DMActivityHandler(): React.Node { | ||
const active = useSelector( | ||
state => isLoggedIn(state) && state.lifecycleState !== 'background', | ||
); | ||
const reduxActiveThread = useSelector(activeThreadSelector); | ||
const windowActive = useSelector(state => state.windowActive); | ||
const activeThread = React.useMemo(() => { | ||
if (!active || !windowActive) { | ||
return null; | ||
} | ||
return reduxActiveThread; | ||
}, [active, windowActive, reduxActiveThread]); | ||
|
||
useDMActivityHandler(activeThread); | ||
return null; | ||
} | ||
|
||
export default DMActivityHandler; |