mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 08:30:58 -05:00
Move typing indicator into revolt.js
This commit is contained in:
parent
29cc221a34
commit
6b6279ffee
10 changed files with 18 additions and 126 deletions
|
@ -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",
|
||||||
|
|
|
@ -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],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
|
@ -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",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue