Move typing indicator into revolt.js

This commit is contained in:
Paul 2021-07-31 13:48:26 +01:00
parent 29cc221a34
commit 6b6279ffee
10 changed files with 18 additions and 126 deletions

View file

@ -97,7 +97,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scroll": "^1.8.2", "react-scroll": "^1.8.2",
"redux": "^4.1.0", "redux": "^4.1.0",
"revolt.js": "5.0.0-alpha.14", "revolt.js": "5.0.0-alpha.16-patch.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"sass": "^1.35.1", "sass": "^1.35.1",
"shade-blend-color": "^1.0.0", "shade-blend-color": "^1.0.0",

View file

@ -1,15 +1,15 @@
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import styled from "styled-components"; import styled from "styled-components";
import { Text } from "preact-i18n"; import { Text } from "preact-i18n";
import { connectState } from "../../../../redux/connector"; import { connectState } from "../../../../redux/connector";
import { TypingUser } from "../../../../redux/reducers/typing";
import { useClient } from "../../../../context/revoltjs/RevoltClient"; import { useClient } from "../../../../context/revoltjs/RevoltClient";
interface Props { interface Props {
typing?: TypingUser[]; channel: Channel;
} }
const Base = styled.div` const Base = styled.div`
@ -55,22 +55,21 @@ const Base = styled.div`
} }
`; `;
export const TypingIndicator = observer(({ typing }: Props) => { export default observer(({ channel }: Props) => {
if (typing && typing.length > 0) { const users = channel.typing.filter(
const client = useClient(); (x) => typeof x !== "undefined" && x._id !== x.client.user!._id,
const users = typing );
.map((x) => client.users.get(x.id)!)
.filter((x) => typeof x !== "undefined");
if (users.length > 0) {
users.sort((a, b) => users.sort((a, b) =>
a._id.toUpperCase().localeCompare(b._id.toUpperCase()), a!._id.toUpperCase().localeCompare(b!._id.toUpperCase()),
); );
let text; let text;
if (users.length >= 5) { if (users.length >= 5) {
text = <Text id="app.main.channel.typing.several" />; text = <Text id="app.main.channel.typing.several" />;
} else if (users.length > 1) { } else if (users.length > 1) {
const userlist = [...users].map((x) => x.username); const userlist = [...users].map((x) => x!.username);
const user = userlist.pop(); const user = userlist.pop();
/*for (let i = 0; i < userlist.length - 1; i++) { /*for (let i = 0; i < userlist.length - 1; i++) {
@ -90,7 +89,7 @@ export const TypingIndicator = observer(({ typing }: Props) => {
text = ( text = (
<Text <Text
id="app.main.channel.typing.single" id="app.main.channel.typing.single"
fields={{ user: users[0].username }} fields={{ user: users[0]!.username }}
/> />
); );
} }
@ -102,7 +101,7 @@ export const TypingIndicator = observer(({ typing }: Props) => {
{users.map((user) => ( {users.map((user) => (
<img <img
loading="eager" loading="eager"
src={user.generateAvatarURL({ max_side: 256 })} src={user!.generateAvatarURL({ max_side: 256 })}
/> />
))} ))}
</div> </div>
@ -114,9 +113,3 @@ export const TypingIndicator = observer(({ typing }: Props) => {
return null; return null;
}); });
export default connectState<{ id: string }>(TypingIndicator, (state, props) => {
return {
typing: state.typing && state.typing[props.id],
};
});

View file

@ -39,10 +39,7 @@ export function useUnreads({ channel, unreads }: UnreadProps) {
message, message,
}); });
client.req( channel.ack(message);
"PUT",
`/channels/${channel._id}/ack/${message}` as "/channels/id/ack/id",
);
} }
} }
} }

View file

@ -8,13 +8,11 @@ import { useContext, useEffect } from "preact/hooks";
import { dispatch } from "../../redux"; import { dispatch } from "../../redux";
import { connectState } from "../../redux/connector"; import { connectState } from "../../redux/connector";
import { QueuedMessage } from "../../redux/reducers/queue"; import { QueuedMessage } from "../../redux/reducers/queue";
import { Typing } from "../../redux/reducers/typing";
import { AppContext } from "./RevoltClient"; import { AppContext } from "./RevoltClient";
type Props = { type Props = {
messages: QueuedMessage[]; messages: QueuedMessage[];
typing: Typing;
}; };
function StateMonitor(props: Props) { function StateMonitor(props: Props) {
@ -41,36 +39,11 @@ function StateMonitor(props: Props) {
return () => client.removeListener("message", add); return () => client.removeListener("message", add);
}, [props.messages]); }, [props.messages]);
useEffect(() => {
function removeOld() {
if (!props.typing) return;
for (const channel of Object.keys(props.typing)) {
const users = props.typing[channel];
for (const user of users) {
if (+new Date() > user.started + 5000) {
dispatch({
type: "TYPING_STOP",
channel,
user: user.id,
});
}
}
}
}
removeOld();
const interval = setInterval(removeOld, 1000);
return () => clearInterval(interval);
}, [props.typing]);
return null; return null;
} }
export default connectState(StateMonitor, (state) => { export default connectState(StateMonitor, (state) => {
return { return {
messages: [...state.queue], messages: [...state.queue],
typing: state.typing,
}; };
}); });

View file

@ -47,24 +47,6 @@ export function registerEvents(
packet: (packet: ClientboundNotification) => { packet: (packet: ClientboundNotification) => {
switch (packet.type) { switch (packet.type) {
case "ChannelStartTyping": {
if (packet.user === client.user?._id) return;
dispatch({
type: "TYPING_START",
channel: packet.id,
user: packet.user,
});
break;
}
case "ChannelStopTyping": {
if (packet.user === client.user?._id) return;
dispatch({
type: "TYPING_STOP",
channel: packet.id,
user: packet.user,
});
break;
}
case "ChannelAck": { case "ChannelAck": {
dispatch({ dispatch({
type: "UNREADS_MARK_READ", type: "UNREADS_MARK_READ",

View file

@ -89,7 +89,7 @@ const TextChannel = observer(({ channel }: { channel: ChannelI }) => {
<ChannelContent> <ChannelContent>
<VoiceHeader id={id} /> <VoiceHeader id={id} />
<MessageArea id={id} /> <MessageArea id={id} />
<TypingIndicator id={id} /> <TypingIndicator channel={channel} />
<JumpToBottom id={id} /> <JumpToBottom id={id} />
<MessageBox channel={channel} /> <MessageBox channel={channel} />
</ChannelContent> </ChannelContent>

View file

@ -14,7 +14,6 @@ import { QueuedMessage } from "./reducers/queue";
import { SectionToggle } from "./reducers/section_toggle"; import { SectionToggle } from "./reducers/section_toggle";
import { Settings } from "./reducers/settings"; import { Settings } from "./reducers/settings";
import { SyncOptions } from "./reducers/sync"; import { SyncOptions } from "./reducers/sync";
import { Typing } from "./reducers/typing";
import { Unreads } from "./reducers/unreads"; import { Unreads } from "./reducers/unreads";
export type State = { export type State = {
@ -24,7 +23,6 @@ export type State = {
settings: Settings; settings: Settings;
unreads: Unreads; unreads: Unreads;
queue: QueuedMessage[]; queue: QueuedMessage[];
typing: Typing;
drafts: Drafts; drafts: Drafts;
sync: SyncOptions; sync: SyncOptions;
experiments: ExperimentOptions; experiments: ExperimentOptions;

View file

@ -12,7 +12,6 @@ import { sectionToggle, SectionToggleAction } from "./section_toggle";
import { config, ConfigAction } from "./server_config"; import { config, ConfigAction } from "./server_config";
import { settings, SettingsAction } from "./settings"; import { settings, SettingsAction } from "./settings";
import { sync, SyncAction } from "./sync"; import { sync, SyncAction } from "./sync";
import { typing, TypingAction } from "./typing";
import { unreads, UnreadsAction } from "./unreads"; import { unreads, UnreadsAction } from "./unreads";
export default combineReducers({ export default combineReducers({
@ -22,7 +21,6 @@ export default combineReducers({
settings, settings,
unreads, unreads,
queue, queue,
typing,
drafts, drafts,
sync, sync,
experiments, experiments,
@ -38,7 +36,6 @@ export type Action =
| SettingsAction | SettingsAction
| UnreadsAction | UnreadsAction
| QueueAction | QueueAction
| TypingAction
| DraftAction | DraftAction
| SyncAction | SyncAction
| ExperimentsAction | ExperimentsAction

View file

@ -1,48 +0,0 @@
export type TypingUser = { id: string; started: number };
export type Typing = { [key: string]: TypingUser[] };
export type TypingAction =
| { type: undefined }
| {
type: "TYPING_START";
channel: string;
user: string;
}
| {
type: "TYPING_STOP";
channel: string;
user: string;
}
| {
type: "RESET";
};
export function typing(state: Typing = {}, action: TypingAction): Typing {
switch (action.type) {
case "TYPING_START":
return {
...state,
[action.channel]: [
...(state[action.channel] ?? []).filter(
(x) => x.id !== action.user,
),
{
id: action.user,
started: +new Date(),
},
],
};
case "TYPING_STOP":
return {
...state,
[action.channel]:
state[action.channel]?.filter(
(x) => x.id !== action.user,
) ?? [],
};
case "RESET":
return {};
default:
return state;
}
}

View file

@ -3570,10 +3570,10 @@ revolt-api@0.5.1-alpha.10-patch.0:
resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.1-alpha.10-patch.0.tgz#97d31bec7dfa4573567097443acb059c4feaac20" resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.1-alpha.10-patch.0.tgz#97d31bec7dfa4573567097443acb059c4feaac20"
integrity sha512-UyM890HkGlYNQOxpHuEpUsJHLt8Ujnjg9/zPEDGpbvS4iy0jmHX23Hh8tOCfb/ewxbNrtT3G1HpSWKOneW/vYg== integrity sha512-UyM890HkGlYNQOxpHuEpUsJHLt8Ujnjg9/zPEDGpbvS4iy0jmHX23Hh8tOCfb/ewxbNrtT3G1HpSWKOneW/vYg==
revolt.js@5.0.0-alpha.14: revolt.js@5.0.0-alpha.16-patch.0:
version "5.0.0-alpha.14" version "5.0.0-alpha.16-patch.0"
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.0.0-alpha.14.tgz#13b1d350a89467eb2ad6905a290ee1fada4150c1" resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.0.0-alpha.16-patch.0.tgz#a46aaf037cb43c8760f4c282574cbc6d54baa59c"
integrity sha512-kZBIx9PX8Y8Esu51Y6OgeFwlpajtaRv/ap3YKlWEELlAcDAEDoSZj+iL4ilkxIxvh4RDJMlVlAforwSvXvy9DQ== integrity sha512-DFDH5KjTUCvbsdHRluS7YbQHrtyRyAnlY5uE4ZC0uVBjEaGWAH7kdIVi8ztzVQE45obpXprmXz//r/1UgsBtUA==
dependencies: dependencies:
axios "^0.19.2" axios "^0.19.2"
eventemitter3 "^4.0.7" eventemitter3 "^4.0.7"