-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Fix "New" marker for the chat #1977
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d6d7efa
74d7b5c
7700a2a
79d18ca
575ebe1
6394e39
2536b82
4ef6b21
f4b5d79
5d1cc73
928a2b8
0188cb9
4e6a172
fde2830
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,17 @@ | ||
| import React from 'react'; | ||
| import {Animated, View} from 'react-native'; | ||
| import PropTypes from 'prop-types'; | ||
| import styles, {getOpacityStyle} from '../styles/styles'; | ||
| import {View} from 'react-native'; | ||
| import styles from '../styles/styles'; | ||
| import Text from './Text'; | ||
|
|
||
| const propTypes = { | ||
| // Animated opacity | ||
| // eslint-disable-next-line react/forbid-prop-types | ||
| animatedOpacity: PropTypes.object.isRequired, | ||
| }; | ||
|
|
||
| const UnreadActionIndicator = props => ( | ||
| <Animated.View style={[ | ||
| styles.unreadIndicatorContainer, | ||
| getOpacityStyle(props.animatedOpacity), | ||
| ]} | ||
| > | ||
| const UnreadActionIndicator = () => ( | ||
| <View style={styles.unreadIndicatorContainer}> | ||
| <View style={styles.unreadIndicatorLine} /> | ||
| <Text style={styles.unreadIndicatorText}> | ||
| NEW | ||
| </Text> | ||
| </Animated.View> | ||
| </View> | ||
| ); | ||
|
|
||
| UnreadActionIndicator.propTypes = propTypes; | ||
| UnreadActionIndicator.displayName = 'UnreadActionIndicator'; | ||
|
|
||
| export default UnreadActionIndicator; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| import React from 'react'; | ||
| import { | ||
| Animated, | ||
| View, | ||
| Keyboard, | ||
| AppState, | ||
|
|
@@ -11,7 +10,6 @@ import _ from 'underscore'; | |
| import lodashGet from 'lodash/get'; | ||
| import {withOnyx} from 'react-native-onyx'; | ||
| import Text from '../../../components/Text'; | ||
| import UnreadActionIndicator from '../../../components/UnreadActionIndicator'; | ||
| import { | ||
| fetchActions, | ||
| updateLastReadActionID, | ||
|
|
@@ -69,16 +67,10 @@ class ReportActionsView extends React.Component { | |
| this.recordMaxAction = this.recordMaxAction.bind(this); | ||
| this.onVisibilityChange = this.onVisibilityChange.bind(this); | ||
| this.loadMoreChats = this.loadMoreChats.bind(this); | ||
| this.scheduledRecordMaxAction = this.scheduledRecordMaxAction.bind(this); | ||
| this.sortedReportActions = []; | ||
| this.timers = []; | ||
| this.unreadIndicatorOpacity = new Animated.Value(1); | ||
|
|
||
| // Helper variable that keeps track of the unread action count before it updates to zero | ||
| this.unreadActionCount = 0; | ||
|
|
||
| // Helper variable that prevents the unread indicator to show up for new messages | ||
| // received while the report is still active | ||
| this.shouldShowUnreadActionIndicator = true; | ||
| this.unreadTimer = null; | ||
| this.newMessageMarkerPosition = -1; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we setting this to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just initializing it to a non-valid position so we know is has yet to be set. I could initialize it to null, probably, if you like that better.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm... I'm not entirely sold we need this variable yet. But if we are making
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm ok with that. If we keep the variable, we can do that :) |
||
|
|
||
| this.state = { | ||
| isLoadingMoreChats: false, | ||
|
|
@@ -127,10 +119,9 @@ class ReportActionsView extends React.Component { | |
| this.scrollToListBottom(); | ||
| } | ||
|
|
||
| // When the last action changes, wait three seconds, then record the max action | ||
| // This will make the unread indicator go away if you receive comments in the same chat you're looking at | ||
|
marcaaron marked this conversation as resolved.
|
||
| if (Visibility.isVisible()) { | ||
| this.timers.push(setTimeout(this.recordMaxAction, 3000)); | ||
| // If we are adding a new action while the chat is open, record the max action immediately | ||
| if (!this.unreadTimer && Visibility.isVisible()) { | ||
| this.scheduledRecordMaxAction(); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -142,7 +133,10 @@ class ReportActionsView extends React.Component { | |
|
|
||
| AppState.removeEventListener('change', this.onVisibilityChange); | ||
|
|
||
| _.each(this.timers, timer => clearTimeout(timer)); | ||
| if (this.unreadTimer) { | ||
| clearTimeout(this.unreadTimer); | ||
| this.unreadTimer = null; | ||
| } | ||
| unsubscribeFromReportChannel(this.props.reportID); | ||
| } | ||
|
|
||
|
|
@@ -151,33 +145,21 @@ class ReportActionsView extends React.Component { | |
| */ | ||
| onVisibilityChange() { | ||
| if (Visibility.isVisible()) { | ||
| this.timers.push(setTimeout(this.recordMaxAction, 3000)); | ||
| this.unreadTimer = setTimeout(this.scheduledRecordMaxAction, 3000); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Checks if the unreadActionIndicator should be shown. | ||
| * If it does, starts a timeout for the fading out animation and creates | ||
| * a flag to not show it again if the report is still open | ||
| * Sets the max action after a set delay | ||
| */ | ||
| setUpUnreadActionIndicator() { | ||
| if (!this.shouldShowUnreadActionIndicator) { | ||
| return; | ||
| } | ||
|
|
||
| this.unreadActionCount = this.props.report.unreadActionCount; | ||
|
|
||
| if (this.unreadActionCount > 0) { | ||
| this.unreadIndicatorOpacity = new Animated.Value(1); | ||
| this.timers.push(setTimeout(() => { | ||
| Animated.timing(this.unreadIndicatorOpacity, { | ||
| toValue: 0, | ||
| useNativeDriver: false, | ||
| }).start(); | ||
| }, 3000)); | ||
| scheduledRecordMaxAction() { | ||
| // Always cancel the existing timer | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if we do not cancel this timer ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to the answer above: I get rid of it so I could check for existence accurately (There is no "is there a timer running?" function) |
||
| if (this.unreadTimer) { | ||
| clearTimeout(this.unreadTimer); | ||
| this.unreadTimer = null; | ||
| } | ||
|
|
||
| this.shouldShowUnreadActionIndicator = false; | ||
| this.recordMaxAction(); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -192,6 +174,12 @@ class ReportActionsView extends React.Component { | |
|
|
||
| // Fetch the new set of actions | ||
| fetchActions(this.props.reportID); | ||
| this.newMessageMarkerPosition = -1; | ||
|
|
||
| // Wait three seconds, then record the max action | ||
| if (Visibility.isVisible()) { | ||
| this.unreadTimer = setTimeout(this.scheduledRecordMaxAction, 3000); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -335,15 +323,14 @@ class ReportActionsView extends React.Component { | |
| // <InvertedFlatList /> are implemented on native and web/desktop which leads to | ||
| // the unread indicator on native to render below the message instead of above it. | ||
| <View> | ||
| {this.unreadActionCount > 0 && index === this.unreadActionCount - 1 && ( | ||
| <UnreadActionIndicator animatedOpacity={this.unreadIndicatorOpacity} /> | ||
| )} | ||
| <ReportActionItem | ||
| reportID={this.props.reportID} | ||
| action={item.action} | ||
| displayAsGroup={this.isConsecutiveActionMadeByPreviousActor(index)} | ||
| onLayout={onLayout} | ||
| needsLayoutCalculation={needsLayoutCalculation} | ||
| displayNewIndicator={this.newMessageMarkerPosition > 0 | ||
| && item.action.sequenceNumber === this.newMessageMarkerPosition} | ||
| /> | ||
| </View> | ||
| ); | ||
|
|
@@ -364,7 +351,12 @@ class ReportActionsView extends React.Component { | |
| ); | ||
| } | ||
|
|
||
| this.setUpUnreadActionIndicator(); | ||
| if (this.newMessageMarkerPosition < 0) { | ||
| this.newMessageMarkerPosition = this.props.report.unreadActionCount === 0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we really need this variable, but correct me if this sounds wrong... Since the I think that will eliminate the need to "reset" this variable back to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems there are really only two things we need to know, yet we are expressing it in a single variable (and also updating it in a render method). This makes everything a little harder to understand IMO. Hopefully this helps think about the problem in a different way. We need to know...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for all the back and forth here. I'm having a hard time understanding things, but I think turning a corner on a real suggestion. 😅
Ok I think actually such a variable is not necessary, but it's an interesting exercise to think about when it might be I think it'd be This is where things get unclear for me...
Right now we are setting this to So we should be able to end up with something like:
I think that would clean things up a bit. Does that sound like it might work?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha, no worries! I also thought this would be simpler than it ended up being. This didn't work for a couple of reasons:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, thanks for explaining. It seems clear what is happening here is that there is one update for the Seems like we have two options...
What would you prefer to do? My expectation is that if a key depends on a prop and the prop it depends on changes we should check to see if we can also batch additional updates together instead of causing an extra re-render. I'm going to start looking into a solution on the Onyx side regardless and if we want to hold off for that, cool. Otherwise, we can go ahead with the workaround, but here's what I'd suggest to make everything a little clearer...
This will "force" an update. But I can't say whether that is a problem or not. I'd think maybe not. |
||
| ? this.props.report.unreadActionCount | ||
| : _.size(this.props.reportActions) - this.props.report.unreadActionCount; | ||
| } | ||
|
|
||
| this.updateSortedReportActions(); | ||
| return ( | ||
| <InvertedFlatList | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.