-
-
Notifications
You must be signed in to change notification settings - Fork 672
More prep commits for new avatar_url handling (#4157)
#4216
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
78e00a9
ef3c7fd
f2b5b71
871742a
2c5d03c
bf504a9
6217f89
eb2fd33
99f959f
c72ec2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /* @flow strict-local */ | ||
| // import { Vibration } from 'react-native'; | ||
|
|
||
| import { AppState } from 'react-native'; | ||
| import type { GlobalState, GetState, Dispatch, Message } from '../types'; | ||
| import type { EventAction } from '../actionTypes'; | ||
| import { EVENT_NEW_MESSAGE } from '../actionConstants'; | ||
| import { isHomeNarrow, isMessageInNarrow } from '../utils/narrow'; | ||
| import { getActiveAccount, getChatScreenParams, getOwnEmail } from '../selectors'; | ||
| import { playMessageSound } from '../utils/sound'; | ||
| import { NULL_ARRAY } from '../nullObjects'; | ||
|
|
||
| /** | ||
| * React to incoming `MessageEvent`s. | ||
| */ | ||
| const messageEvent = (state: GlobalState, message: Message): void => { | ||
| const flags = message.flags ?? NULL_ARRAY; | ||
|
|
||
| if (AppState.currentState !== 'active') { | ||
| return; | ||
| } | ||
|
|
||
| const isPrivateMessage = Array.isArray(message.display_recipient); | ||
| const isMentioned = flags.includes('mentioned') || flags.includes('wildcard_mentioned'); | ||
| if (!(isPrivateMessage || isMentioned)) { | ||
| return; | ||
| } | ||
|
|
||
| const activeAccount = getActiveAccount(state); | ||
| const { narrow } = getChatScreenParams(state); | ||
| const isUserInSameNarrow = | ||
| activeAccount | ||
| && narrow !== undefined // chat screen is not at top | ||
| && !isHomeNarrow(narrow) | ||
| && isMessageInNarrow(message, narrow, activeAccount.email); | ||
| const isSenderSelf = getOwnEmail(state) === message.sender_email; | ||
| if (!isUserInSameNarrow && !isSenderSelf) { | ||
| playMessageSound(); | ||
| // Vibration.vibrate(); | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * React to actions dispatched for Zulip server events. | ||
| * | ||
| * To be dispatched after the event actions are dispatched. | ||
| */ | ||
| export default (action: EventAction) => async (dispatch: Dispatch, getState: GetState) => { | ||
| const state = getState(); | ||
| switch (action.type) { | ||
| case EVENT_NEW_MESSAGE: { | ||
| messageEvent(state, action.message); | ||
| break; | ||
| } | ||
| default: | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,32 @@ | ||
| /* @flow strict-local */ | ||
| import { batchActions } from 'redux-batched-actions'; | ||
|
|
||
| import type { EventAction } from '../actionTypes'; | ||
| import type { Action, Dispatch, GeneralEvent, GetState, GlobalState } from '../types'; | ||
| import * as api from '../api'; | ||
| import { logout } from '../account/accountActions'; | ||
| import { deadQueue } from '../session/sessionActions'; | ||
| import eventToAction from './eventToAction'; | ||
| import eventMiddleware from './eventMiddleware'; | ||
| import doEventActionSideEffects from './doEventActionSideEffects'; | ||
| import { tryGetAuth } from '../selectors'; | ||
| import actionCreator from '../actionCreator'; | ||
| import { BackoffMachine } from '../utils/async'; | ||
| import { ApiError } from '../api/apiErrors'; | ||
|
|
||
| /** Convert an `/events` response into a sequence of our Redux actions. */ | ||
| export const responseToActions = ( | ||
| export const eventsToActions = ( | ||
| state: GlobalState, | ||
| events: $ReadOnlyArray<GeneralEvent>, | ||
| ): Action[] => | ||
| ): EventAction[] => | ||
| events | ||
| .map(event => { | ||
| eventMiddleware(state, event); | ||
| return eventToAction(state, event); | ||
| }) | ||
| .map(event => eventToAction(state, event)) | ||
| .filter(action => { | ||
| if (action.type === 'ignore') { | ||
| return false; | ||
| } | ||
|
|
||
| if (!action || !action.type || action.type === 'unknown') { | ||
| console.log('Can not handle event', action.event); // eslint-disable-line | ||
| if (action.type === 'unknown') { | ||
| console.log('Cannot handle event', action.event); // eslint-disable-line | ||
| return false; | ||
| } | ||
|
|
||
|
|
@@ -73,11 +71,18 @@ export const startEventPolling = (queueId: number, eventId: number) => async ( | |
| break; | ||
| } | ||
|
|
||
| const actions = responseToActions(getState(), events); | ||
| const actions = eventsToActions(getState(), events); | ||
|
|
||
| actionCreator(dispatch, actions, getState()); | ||
| dispatchOrBatch(dispatch, actions); | ||
|
|
||
| actions.forEach(action => { | ||
|
Member
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. This has a subtle effect on behavior which it's not obvious to me whether it matters. Previously, we're dispatching the Maybe that's fine, but we should check explicitly that we think that's fine. I guess the same thing is true a few commits earlier, of the message sound vs. the EVENT_NEW_MESSAGE action. I'm pretty sure that one is fine -- the sound doesn't affect anything else, and the logic for whether we play the sound doesn't depend on anything that'd get updated by reducers on an EVENT_NEW_MESSAGE. (Definitely agreed that this is a much better place for it! If the order matters, probably just move the side effects to come before
Collaborator
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.
Or, I guess, move these side effects into a new custom Redux Middleware; in there, we can choose when to call
Collaborator
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.
Hmmm, right. I assumed it wouldn't matter, because I'll try and see if I can understand what's going on with that condition; it seems kind of wrong, like "If there are no typing notifications, clear the typing notifications".
Collaborator
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. OK, I resolved this confusion by reimplementing the client-side timer for the typing state; take a look, and see what you think. |
||
| // These side effects should not be moved to reducers, which | ||
| // are explicitly not the place for side effects (see | ||
| // https://redux.js.org/faq/actions). | ||
| dispatch(doEventActionSideEffects(action)); | ||
| }); | ||
|
|
||
| lastEventId = Math.max.apply(null, [lastEventId, ...events.map(x => x.id)]); | ||
| } catch (e) { | ||
| if (e.httpStatus === 401) { | ||
|
|
||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.