forked from zulip/zulip-mobile
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
presence: move all presence-reporting logic into new HeartbeatComponent
Centralize all presence-reporting logic into a new zero-display React component, currently (and somewhat arbitrarily) located under AppStateHandlers. This fixes at least two issues: * If the user logs in and out, or otherwise performs an additional "initial fetch" without killing the app, the presence timer will be started multiple times. (This was previously concealed by throttling logic in usersActions.reportPresence, which was itself removed in a previous patch in this set.) * If the user goes idle (e.g. by hitting the Home button), the presence timer will still run, and will still attempt to send `active` notifications. (These attempts are often suppressed while the app is in the background, but there's no guarantee of this.) Fixes zulip#3699 (properly), and is work towards zulip#3659. Unfortunately, there is no user-visible change yet: modifications will be needed on the Zulip server side as well.
- Loading branch information
1 parent
c196f9d
commit 23c8f0d
Showing
3 changed files
with
69 additions
and
13 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
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,61 @@ | ||
// @flow strict-local | ||
import { PureComponent } from 'react'; | ||
import { AppState } from 'react-native'; | ||
import type { Auth, Dispatch } from '../types'; | ||
|
||
import { connect } from '../react-redux'; | ||
import { tryGetAuth } from '../account/accountsSelectors'; | ||
import { reportPresence } from '../actions'; | ||
import Heartbeat from './heartbeat'; | ||
|
||
type Props = $ReadOnly<{| | ||
dispatch: Dispatch, | ||
auth: Auth | void, | ||
|}>; | ||
|
||
/** | ||
* Component providing a recurrent `presence` signal. | ||
*/ | ||
// Note that "PureComponent" is of questionable veracity: this component's | ||
// entire purpose is to emit network calls for their observable side effects. | ||
// However, it is at least true that there is never a need to call `render()` if | ||
// the props haven't changed. | ||
class PresenceHeartbeat extends PureComponent<Props> { | ||
/** Callback for Heartbeat object. */ | ||
onHeartbeat = (state: boolean) => { | ||
// N.B.: If `auth` changes, we do not send out a final `false` presence | ||
// status for the previous `auth`. It's the responsibility of our logout | ||
// handler to determine whether that's necessary. | ||
if (this.props.auth) { | ||
this.props.dispatch(reportPresence(state)); | ||
} | ||
}; | ||
|
||
heartbeat: Heartbeat = new Heartbeat(this.onHeartbeat, 1000 * 60); | ||
|
||
componentDidMount() { | ||
this.onStateChange(); | ||
AppState.addEventListener('change', this.onStateChange); | ||
} | ||
|
||
componentWillUnmount() { | ||
AppState.removeEventListener('change', this.onStateChange); | ||
this.heartbeat.stop(); | ||
} | ||
|
||
// React to AppState or Auth change. | ||
onStateChange: () => void = () => { | ||
// heartbeat.toState is idempotent | ||
this.heartbeat.toState(AppState.currentState === 'active' && !!this.props.auth); | ||
}; | ||
|
||
render() { | ||
// react to `auth` changes | ||
this.onStateChange(); | ||
return null; | ||
} | ||
} | ||
|
||
export default connect(state => ({ | ||
auth: tryGetAuth(state), | ||
}))(PresenceHeartbeat); |