mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-14 19:20:28 +03:00
(chore) remove outdated code (#1765)
* optimize room typing members hook * remove unused code - WIP * remove old code from initMatrix * remove twemojify function * remove old sanitize util * delete old markdown util * delete Math atom component * uninstall unused dependencies * remove old notification system * decrypt message in inbox notification center and fix refresh in background * improve notification --------- Co-authored-by: Krishan <33421343+kfiven@users.noreply.github.com>
This commit is contained in:
parent
60e022035f
commit
4f09e6bbb5
147 changed files with 1164 additions and 15330 deletions
231
src/app/pages/client/ClientNonUIFeatures.tsx
Normal file
231
src/app/pages/client/ClientNonUIFeatures.tsx
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
import { useAtomValue } from 'jotai';
|
||||
import React, { ReactNode, useCallback, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
|
||||
import { roomToUnreadAtom, unreadEqual, unreadInfoToUnread } from '../../state/room/roomToUnread';
|
||||
import LogoSVG from '../../../../public/res/svg/cinny.svg';
|
||||
import LogoUnreadSVG from '../../../../public/res/svg/cinny-unread.svg';
|
||||
import LogoHighlightSVG from '../../../../public/res/svg/cinny-highlight.svg';
|
||||
import { setFavicon } from '../../utils/dom';
|
||||
import { useSetting } from '../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
import { allInvitesAtom } from '../../state/room-list/inviteList';
|
||||
import { usePreviousValue } from '../../hooks/usePreviousValue';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { getInboxInvitesPath, getInboxNotificationsPath } from '../pathUtils';
|
||||
import {
|
||||
getMemberDisplayName,
|
||||
getNotificationType,
|
||||
getUnreadInfo,
|
||||
isNotificationEvent,
|
||||
} from '../../utils/room';
|
||||
import { NotificationType, UnreadInfo } from '../../../types/matrix/room';
|
||||
import { getMxIdLocalPart } from '../../utils/matrix';
|
||||
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
|
||||
import { useInboxNotificationsSelected } from '../../hooks/router/useInbox';
|
||||
|
||||
function FaviconUpdater() {
|
||||
const roomToUnread = useAtomValue(roomToUnreadAtom);
|
||||
|
||||
useEffect(() => {
|
||||
if (roomToUnread.size === 0) {
|
||||
setFavicon(LogoSVG);
|
||||
} else {
|
||||
const highlight = Array.from(roomToUnread.entries()).find(
|
||||
([, unread]) => unread.highlight > 0
|
||||
);
|
||||
|
||||
setFavicon(highlight ? LogoHighlightSVG : LogoUnreadSVG);
|
||||
}
|
||||
}, [roomToUnread]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function InviteNotifications() {
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
const invites = useAtomValue(allInvitesAtom);
|
||||
const perviousInviteLen = usePreviousValue(invites.length, 0);
|
||||
const mx = useMatrixClient();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
|
||||
|
||||
const notify = useCallback(
|
||||
(count: number) => {
|
||||
const noti = new window.Notification('Invitation', {
|
||||
icon: LogoSVG,
|
||||
badge: LogoSVG,
|
||||
body: `You have ${count} new invitation request.`,
|
||||
silent: true,
|
||||
});
|
||||
|
||||
noti.onclick = () => {
|
||||
if (!window.closed) navigate(getInboxInvitesPath());
|
||||
noti.close();
|
||||
};
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const playSound = useCallback(() => {
|
||||
const audioElement = audioRef.current;
|
||||
audioElement?.play();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (invites.length > perviousInviteLen && mx.getSyncState() === 'SYNCING') {
|
||||
if (Notification.permission === 'granted') {
|
||||
notify(invites.length - perviousInviteLen);
|
||||
}
|
||||
|
||||
if (notificationSound) {
|
||||
playSound();
|
||||
}
|
||||
}
|
||||
}, [mx, invites, perviousInviteLen, notificationSound, notify, playSound]);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<audio ref={audioRef} style={{ display: 'none' }}>
|
||||
<source src="../../../../public/sound/invite.ogg" type="audio/ogg" />
|
||||
</audio>
|
||||
);
|
||||
}
|
||||
|
||||
function MessageNotifications() {
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
const notifRef = useRef<Notification>();
|
||||
const unreadCacheRef = useRef<Map<string, UnreadInfo>>(new Map());
|
||||
const mx = useMatrixClient();
|
||||
const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
|
||||
const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
|
||||
|
||||
const navigate = useNavigate();
|
||||
const notificationSelected = useInboxNotificationsSelected();
|
||||
const selectedRoomId = useSelectedRoom();
|
||||
|
||||
const notify = useCallback(
|
||||
({
|
||||
roomName,
|
||||
roomAvatar,
|
||||
username,
|
||||
}: {
|
||||
roomName: string;
|
||||
roomAvatar?: string;
|
||||
username: string;
|
||||
roomId: string;
|
||||
eventId: string;
|
||||
}) => {
|
||||
const noti = new window.Notification(roomName, {
|
||||
icon: roomAvatar,
|
||||
badge: roomAvatar,
|
||||
body: `New inbox notification from ${username}`,
|
||||
silent: true,
|
||||
});
|
||||
|
||||
noti.onclick = () => {
|
||||
if (!window.closed) navigate(getInboxNotificationsPath());
|
||||
noti.close();
|
||||
notifRef.current = undefined;
|
||||
};
|
||||
|
||||
notifRef.current?.close();
|
||||
notifRef.current = noti;
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const playSound = useCallback(() => {
|
||||
const audioElement = audioRef.current;
|
||||
audioElement?.play();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleTimelineEvent: RoomEventHandlerMap[RoomEvent.Timeline] = (
|
||||
mEvent,
|
||||
room,
|
||||
toStartOfTimeline,
|
||||
removed,
|
||||
data
|
||||
) => {
|
||||
if (
|
||||
mx.getSyncState() !== 'SYNCING' ||
|
||||
selectedRoomId === room?.roomId ||
|
||||
notificationSelected ||
|
||||
!room ||
|
||||
!data.liveEvent ||
|
||||
room.isSpaceRoom() ||
|
||||
!isNotificationEvent(mEvent) ||
|
||||
getNotificationType(mx, room.roomId) === NotificationType.Mute
|
||||
)
|
||||
return;
|
||||
|
||||
const sender = mEvent.getSender();
|
||||
const eventId = mEvent.getId();
|
||||
if (!sender || !eventId || mEvent.getSender() === mx.getUserId()) return;
|
||||
const unreadInfo = getUnreadInfo(room);
|
||||
const cachedUnreadInfo = unreadCacheRef.current.get(room.roomId);
|
||||
unreadCacheRef.current.set(room.roomId, unreadInfo);
|
||||
|
||||
if (
|
||||
cachedUnreadInfo &&
|
||||
unreadEqual(unreadInfoToUnread(cachedUnreadInfo), unreadInfoToUnread(unreadInfo))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showNotifications && Notification.permission === 'granted') {
|
||||
const avatarMxc =
|
||||
room.getAvatarFallbackMember()?.getMxcAvatarUrl() ?? room.getMxcAvatarUrl();
|
||||
notify({
|
||||
roomName: room.name ?? 'Unknown',
|
||||
roomAvatar: avatarMxc
|
||||
? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined
|
||||
: undefined,
|
||||
username: getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender) ?? sender,
|
||||
roomId: room.roomId,
|
||||
eventId,
|
||||
});
|
||||
}
|
||||
|
||||
if (notificationSound) {
|
||||
playSound();
|
||||
}
|
||||
};
|
||||
mx.on(RoomEvent.Timeline, handleTimelineEvent);
|
||||
return () => {
|
||||
mx.removeListener(RoomEvent.Timeline, handleTimelineEvent);
|
||||
};
|
||||
}, [
|
||||
mx,
|
||||
notificationSound,
|
||||
notificationSelected,
|
||||
showNotifications,
|
||||
playSound,
|
||||
notify,
|
||||
selectedRoomId,
|
||||
]);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<audio ref={audioRef} style={{ display: 'none' }}>
|
||||
<source src="../../../../public/sound/notification.ogg" type="audio/ogg" />
|
||||
</audio>
|
||||
);
|
||||
}
|
||||
|
||||
type ClientNonUIFeaturesProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export function ClientNonUIFeatures({ children }: ClientNonUIFeaturesProps) {
|
||||
return (
|
||||
<>
|
||||
<FaviconUpdater />
|
||||
<InviteNotifications />
|
||||
<MessageNotifications />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ import { Box, Spinner, Text } from 'folds';
|
|||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
import initMatrix from '../../../client/initMatrix';
|
||||
import { initHotkeys } from '../../../client/event/hotkeys';
|
||||
import { initRoomListListener } from '../../../client/event/roomList';
|
||||
import { getSecret } from '../../../client/state/auth';
|
||||
import { SplashScreen } from '../../components/splash-screen';
|
||||
import { CapabilitiesAndMediaConfigLoader } from '../../components/CapabilitiesAndMediaConfigLoader';
|
||||
|
|
@ -49,7 +48,6 @@ export function ClientRoot({ children }: ClientRootProps) {
|
|||
useEffect(() => {
|
||||
const handleStart = () => {
|
||||
initHotkeys();
|
||||
initRoomListListener(initMatrix.roomList);
|
||||
setLoading(false);
|
||||
};
|
||||
initMatrix.once('init_loading_finished', handleStart);
|
||||
|
|
|
|||
|
|
@ -31,13 +31,20 @@ import { InboxNotificationsPathSearchParams } from '../../paths';
|
|||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { RoomAvatar, RoomIcon } from '../../../components/room-avatar';
|
||||
import { getMemberAvatarMxc, getMemberDisplayName, getRoomAvatarUrl } from '../../../utils/room';
|
||||
import {
|
||||
getEditedEvent,
|
||||
getMemberAvatarMxc,
|
||||
getMemberDisplayName,
|
||||
getRoomAvatarUrl,
|
||||
} from '../../../utils/room';
|
||||
import { ScrollTopContainer } from '../../../components/scroll-top-container';
|
||||
import { useInterval } from '../../../hooks/useInterval';
|
||||
import {
|
||||
AvatarBase,
|
||||
ImageContent,
|
||||
MSticker,
|
||||
MessageNotDecryptedContent,
|
||||
MessageUnsupportedContent,
|
||||
ModernLayout,
|
||||
RedactedContent,
|
||||
Reply,
|
||||
|
|
@ -62,6 +69,7 @@ import { markAsRead } from '../../../../client/action/notifications';
|
|||
import { ContainerColor } from '../../../styles/ContainerColor.css';
|
||||
import { VirtualTile } from '../../../components/virtualizer';
|
||||
import { UserAvatar } from '../../../components/user-avatar';
|
||||
import { EncryptedContent } from '../../../features/room/message';
|
||||
|
||||
type RoomNotificationsGroup = {
|
||||
roomId: string;
|
||||
|
|
@ -225,6 +233,78 @@ function RoomNotificationsGroupComp({
|
|||
/>
|
||||
);
|
||||
},
|
||||
[MessageEvent.RoomMessageEncrypted]: (evt, displayName) => {
|
||||
const evtTimeline = room.getTimelineForEvent(evt.event_id);
|
||||
|
||||
const mEvent = evtTimeline?.getEvents().find((e) => e.getId() === evt.event_id);
|
||||
|
||||
if (!mEvent || !evtTimeline) {
|
||||
return (
|
||||
<Box grow="Yes" direction="Column">
|
||||
<Text size="T400" priority="300">
|
||||
<code className={customHtmlCss.Code}>{evt.type}</code>
|
||||
{' event'}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EncryptedContent mEvent={mEvent}>
|
||||
{() => {
|
||||
if (mEvent.isRedacted()) return <RedactedContent />;
|
||||
if (mEvent.getType() === MessageEvent.Sticker)
|
||||
return (
|
||||
<MSticker
|
||||
content={mEvent.getContent()}
|
||||
renderImageContent={(props) => (
|
||||
<ImageContent
|
||||
{...props}
|
||||
autoPlay={mediaAutoLoad}
|
||||
renderImage={(p) => <Image {...p} loading="lazy" />}
|
||||
renderViewer={(p) => <ImageViewer {...p} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
if (mEvent.getType() === MessageEvent.RoomMessage) {
|
||||
const editedEvent = getEditedEvent(
|
||||
evt.event_id,
|
||||
mEvent,
|
||||
evtTimeline.getTimelineSet()
|
||||
);
|
||||
const getContent = (() =>
|
||||
editedEvent?.getContent()['m.new_content'] ??
|
||||
mEvent.getContent()) as GetContentCallback;
|
||||
|
||||
return (
|
||||
<RenderMessageContent
|
||||
displayName={displayName}
|
||||
msgType={mEvent.getContent().msgtype ?? ''}
|
||||
ts={mEvent.getTs()}
|
||||
edited={!!editedEvent}
|
||||
getContent={getContent}
|
||||
mediaAutoLoad={mediaAutoLoad}
|
||||
urlPreview={urlPreview}
|
||||
htmlReactParserOptions={htmlReactParserOptions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (mEvent.getType() === MessageEvent.RoomMessageEncrypted)
|
||||
return (
|
||||
<Text>
|
||||
<MessageNotDecryptedContent />
|
||||
</Text>
|
||||
);
|
||||
return (
|
||||
<Text>
|
||||
<MessageUnsupportedContent />
|
||||
</Text>
|
||||
);
|
||||
}}
|
||||
</EncryptedContent>
|
||||
);
|
||||
},
|
||||
[MessageEvent.Sticker]: (event, displayName, getContent) => {
|
||||
if (event.unsigned?.redacted_because) {
|
||||
return <RedactedContent reason={event.unsigned?.redacted_because.content.reason} />;
|
||||
|
|
@ -398,7 +478,7 @@ const useNotificationsSearchParams = (
|
|||
[searchParams]
|
||||
);
|
||||
|
||||
const DEFAULT_REFRESH_MS = 10000;
|
||||
const DEFAULT_REFRESH_MS = 7000;
|
||||
|
||||
export function Notifications() {
|
||||
const mx = useMatrixClient();
|
||||
|
|
@ -441,9 +521,7 @@ export function Notifications() {
|
|||
|
||||
useInterval(
|
||||
useCallback(() => {
|
||||
if (document.hasFocus()) {
|
||||
silentReloadTimeline();
|
||||
}
|
||||
silentReloadTimeline();
|
||||
}, [silentReloadTimeline]),
|
||||
refreshIntervalTime
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue