mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	Add authenticated media support (#1930)
* chore: Bump matrix-js-sdk to 34.4.0 * feat: Authenticated media support * chore: Use Vite PWA for service worker support * fix: Fix Vite PWA SW entry point Forget this. :P * fix: Also add Nginx rewrite for sw.js * fix: Correct Nginx rewrite * fix: Add Netlify redirect for sw.js Otherwise the generic SPA rewrite to index.html would take effect, breaking Service Worker. * fix: Account for subpath when regisering service worker * chore: Correct types
This commit is contained in:
		
							parent
							
								
									043012e809
								
							
						
					
					
						commit
						c6a8fb1117
					
				
					 46 changed files with 3562 additions and 487 deletions
				
			
		
							
								
								
									
										3
									
								
								.npmrc
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								.npmrc
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,2 @@
 | 
				
			||||||
legacy-peer-deps=true
 | 
					legacy-peer-deps=true
 | 
				
			||||||
save-exact=true
 | 
					save-exact=true
 | 
				
			||||||
@matrix-org:registry=https://gitlab.matrix.org/api/v4/projects/27/packages/npm/
 | 
					 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ server {
 | 
				
			||||||
    rewrite ^/manifest.json$ /manifest.json break;
 | 
					    rewrite ^/manifest.json$ /manifest.json break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rewrite ^.*/olm.wasm$ /olm.wasm break;
 | 
					    rewrite ^.*/olm.wasm$ /olm.wasm break;
 | 
				
			||||||
 | 
					    rewrite ^/sw.js$ /sw.js break;
 | 
				
			||||||
    rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;
 | 
					    rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rewrite ^/public/(.*)$ /public/$1 break;
 | 
					    rewrite ^/public/(.*)$ /public/$1 break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ server {
 | 
				
			||||||
    rewrite ^/manifest.json$ /manifest.json break;
 | 
					    rewrite ^/manifest.json$ /manifest.json break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rewrite ^.*/olm.wasm$ /olm.wasm break;
 | 
					    rewrite ^.*/olm.wasm$ /olm.wasm break;
 | 
				
			||||||
 | 
					    rewrite ^/sw.js$ /sw.js break;
 | 
				
			||||||
    rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;
 | 
					    rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rewrite ^/public/(.*)$ /public/$1 break;
 | 
					    rewrite ^/public/(.*)$ /public/$1 break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,12 @@
 | 
				
			||||||
  from = "/manifest.json"
 | 
					  from = "/manifest.json"
 | 
				
			||||||
  to = "/manifest.json"
 | 
					  to = "/manifest.json"
 | 
				
			||||||
  status = 200
 | 
					  status = 200
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
 | 
					[[redirects]]
 | 
				
			||||||
 | 
					  from = "/sw.js"
 | 
				
			||||||
 | 
					  to = "/sw.js"
 | 
				
			||||||
 | 
					  status = 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[redirects]]
 | 
					[[redirects]]
 | 
				
			||||||
  from = "*/olm.wasm"
 | 
					  from = "*/olm.wasm"
 | 
				
			||||||
  to = "/olm.wasm"
 | 
					  to = "/olm.wasm"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3365
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										3365
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -24,7 +24,7 @@
 | 
				
			||||||
    "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0",
 | 
					    "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0",
 | 
				
			||||||
    "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3",
 | 
					    "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3",
 | 
				
			||||||
    "@fontsource/inter": "4.5.14",
 | 
					    "@fontsource/inter": "4.5.14",
 | 
				
			||||||
    "@matrix-org/olm": "3.2.14",
 | 
					    "@matrix-org/olm": "3.2.15",
 | 
				
			||||||
    "@tanstack/react-query": "5.24.1",
 | 
					    "@tanstack/react-query": "5.24.1",
 | 
				
			||||||
    "@tanstack/react-query-devtools": "5.24.1",
 | 
					    "@tanstack/react-query-devtools": "5.24.1",
 | 
				
			||||||
    "@tanstack/react-virtual": "3.2.0",
 | 
					    "@tanstack/react-virtual": "3.2.0",
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,7 @@
 | 
				
			||||||
    "jotai": "2.6.0",
 | 
					    "jotai": "2.6.0",
 | 
				
			||||||
    "linkify-react": "4.1.3",
 | 
					    "linkify-react": "4.1.3",
 | 
				
			||||||
    "linkifyjs": "4.1.3",
 | 
					    "linkifyjs": "4.1.3",
 | 
				
			||||||
    "matrix-js-sdk": "29.1.0",
 | 
					    "matrix-js-sdk": "34.4.0",
 | 
				
			||||||
    "millify": "6.1.0",
 | 
					    "millify": "6.1.0",
 | 
				
			||||||
    "pdfjs-dist": "4.2.67",
 | 
					    "pdfjs-dist": "4.2.67",
 | 
				
			||||||
    "prismjs": "1.29.0",
 | 
					    "prismjs": "1.29.0",
 | 
				
			||||||
| 
						 | 
					@ -90,6 +90,7 @@
 | 
				
			||||||
    "@types/react-dom": "18.2.17",
 | 
					    "@types/react-dom": "18.2.17",
 | 
				
			||||||
    "@types/react-google-recaptcha": "2.1.8",
 | 
					    "@types/react-google-recaptcha": "2.1.8",
 | 
				
			||||||
    "@types/sanitize-html": "2.9.0",
 | 
					    "@types/sanitize-html": "2.9.0",
 | 
				
			||||||
 | 
					    "@types/serviceworker": "0.0.95",
 | 
				
			||||||
    "@types/ua-parser-js": "0.7.36",
 | 
					    "@types/ua-parser-js": "0.7.36",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "5.46.1",
 | 
					    "@typescript-eslint/eslint-plugin": "5.46.1",
 | 
				
			||||||
    "@typescript-eslint/parser": "5.46.1",
 | 
					    "@typescript-eslint/parser": "5.46.1",
 | 
				
			||||||
| 
						 | 
					@ -106,6 +107,7 @@
 | 
				
			||||||
    "sass": "1.56.2",
 | 
					    "sass": "1.56.2",
 | 
				
			||||||
    "typescript": "4.9.4",
 | 
					    "typescript": "4.9.4",
 | 
				
			||||||
    "vite": "5.0.13",
 | 
					    "vite": "5.0.13",
 | 
				
			||||||
 | 
					    "vite-plugin-pwa": "0.20.5",
 | 
				
			||||||
    "vite-plugin-static-copy": "1.0.4",
 | 
					    "vite-plugin-static-copy": "1.0.4",
 | 
				
			||||||
    "vite-plugin-top-level-await": "1.4.1"
 | 
					    "vite-plugin-top-level-await": "1.4.1"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,8 @@ import { CommandElement, EmoticonElement, LinkElement, MentionElement } from './
 | 
				
			||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
				
			||||||
import { getBeginCommand } from './utils';
 | 
					import { getBeginCommand } from './utils';
 | 
				
			||||||
import { BlockType } from './types';
 | 
					import { BlockType } from './types';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Put this at the start and end of an inline component to work around this Chromium bug:
 | 
					// Put this at the start and end of an inline component to work around this Chromium bug:
 | 
				
			||||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1249405
 | 
					// https://bugs.chromium.org/p/chromium/issues/detail?id=1249405
 | 
				
			||||||
| 
						 | 
					@ -76,6 +78,8 @@ function RenderEmoticonElement({
 | 
				
			||||||
  children,
 | 
					  children,
 | 
				
			||||||
}: { element: EmoticonElement } & RenderElementProps) {
 | 
					}: { element: EmoticonElement } & RenderElementProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const selected = useSelected();
 | 
					  const selected = useSelected();
 | 
				
			||||||
  const focused = useFocused();
 | 
					  const focused = useFocused();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +94,7 @@ function RenderEmoticonElement({
 | 
				
			||||||
        {element.key.startsWith('mxc://') ? (
 | 
					        {element.key.startsWith('mxc://') ? (
 | 
				
			||||||
          <img
 | 
					          <img
 | 
				
			||||||
            className={css.EmoticonImg}
 | 
					            className={css.EmoticonImg}
 | 
				
			||||||
            src={mx.mxcUrlToHttp(element.key) ?? element.key}
 | 
					            src={mxcUrlToHttp(mx, element.key, useAuthentication) ?? element.key}
 | 
				
			||||||
            alt={element.shortcode}
 | 
					            alt={element.shortcode}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        ) : (
 | 
					        ) : (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,8 @@ import { useRelevantImagePacks } from '../../../hooks/useImagePacks';
 | 
				
			||||||
import { IEmoji, emojis } from '../../../plugins/emoji';
 | 
					import { IEmoji, emojis } from '../../../plugins/emoji';
 | 
				
			||||||
import { ExtendedPackImage, PackUsage } from '../../../plugins/custom-emoji';
 | 
					import { ExtendedPackImage, PackUsage } from '../../../plugins/custom-emoji';
 | 
				
			||||||
import { useKeyDown } from '../../../hooks/useKeyDown';
 | 
					import { useKeyDown } from '../../../hooks/useKeyDown';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type EmoticonCompleteHandler = (key: string, shortcode: string) => void;
 | 
					type EmoticonCompleteHandler = (key: string, shortcode: string) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +50,8 @@ export function EmoticonAutocomplete({
 | 
				
			||||||
  requestClose,
 | 
					  requestClose,
 | 
				
			||||||
}: EmoticonAutocompleteProps) {
 | 
					}: EmoticonAutocompleteProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const imagePacks = useRelevantImagePacks(mx, PackUsage.Emoticon, imagePackRooms);
 | 
					  const imagePacks = useRelevantImagePacks(mx, PackUsage.Emoticon, imagePackRooms);
 | 
				
			||||||
  const recentEmoji = useRecentEmoji(mx, 20);
 | 
					  const recentEmoji = useRecentEmoji(mx, 20);
 | 
				
			||||||
| 
						 | 
					@ -103,7 +107,7 @@ export function EmoticonAutocomplete({
 | 
				
			||||||
                <Box
 | 
					                <Box
 | 
				
			||||||
                  shrink="No"
 | 
					                  shrink="No"
 | 
				
			||||||
                  as="img"
 | 
					                  as="img"
 | 
				
			||||||
                  src={mx.mxcUrlToHttp(key) || key}
 | 
					                  src={mxcUrlToHttp(mx, key, useAuthentication) || key}
 | 
				
			||||||
                  alt={emoticon.shortcode}
 | 
					                  alt={emoticon.shortcode}
 | 
				
			||||||
                  style={{ width: toRem(24), height: toRem(24), objectFit: 'contain' }}
 | 
					                  style={{ width: toRem(24), height: toRem(24), objectFit: 'contain' }}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ import { useKeyDown } from '../../../hooks/useKeyDown';
 | 
				
			||||||
import { getMxIdLocalPart, getMxIdServer, validMxId } from '../../../utils/matrix';
 | 
					import { getMxIdLocalPart, getMxIdServer, validMxId } from '../../../utils/matrix';
 | 
				
			||||||
import { getMemberDisplayName, getMemberSearchStr } from '../../../utils/room';
 | 
					import { getMemberDisplayName, getMemberSearchStr } from '../../../utils/room';
 | 
				
			||||||
import { UserAvatar } from '../../user-avatar';
 | 
					import { UserAvatar } from '../../user-avatar';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MentionAutoCompleteHandler = (userId: string, name: string) => void;
 | 
					type MentionAutoCompleteHandler = (userId: string, name: string) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +85,8 @@ export function UserMentionAutocomplete({
 | 
				
			||||||
  requestClose,
 | 
					  requestClose,
 | 
				
			||||||
}: UserMentionAutocompleteProps) {
 | 
					}: UserMentionAutocompleteProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const roomId: string = room.roomId!;
 | 
					  const roomId: string = room.roomId!;
 | 
				
			||||||
  const roomAliasOrId = room.getCanonicalAlias() || roomId;
 | 
					  const roomAliasOrId = room.getCanonicalAlias() || roomId;
 | 
				
			||||||
  const members = useRoomMembers(mx, roomId);
 | 
					  const members = useRoomMembers(mx, roomId);
 | 
				
			||||||
| 
						 | 
					@ -143,7 +146,8 @@ export function UserMentionAutocomplete({
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
        autoCompleteMembers.map((roomMember) => {
 | 
					        autoCompleteMembers.map((roomMember) => {
 | 
				
			||||||
          const avatarUrl = roomMember.getAvatarUrl(mx.baseUrl, 32, 32, 'crop', undefined, false);
 | 
					          const avatarMxcUrl = roomMember.getMxcAvatarUrl();
 | 
				
			||||||
 | 
					          const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(avatarMxcUrl, 32, 32, 'crop', undefined, false, useAuthentication) : undefined;
 | 
				
			||||||
          return (
 | 
					          return (
 | 
				
			||||||
            <MenuItem
 | 
					            <MenuItem
 | 
				
			||||||
              key={roomMember.userId}
 | 
					              key={roomMember.userId}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,13 +42,14 @@ import { useRelevantImagePacks } from '../../hooks/useImagePacks';
 | 
				
			||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
				
			||||||
import { useRecentEmoji } from '../../hooks/useRecentEmoji';
 | 
					import { useRecentEmoji } from '../../hooks/useRecentEmoji';
 | 
				
			||||||
import { ExtendedPackImage, ImagePack, PackUsage } from '../../plugins/custom-emoji';
 | 
					import { ExtendedPackImage, ImagePack, PackUsage } from '../../plugins/custom-emoji';
 | 
				
			||||||
import { isUserId } from '../../utils/matrix';
 | 
					import { isUserId, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { editableActiveElement, isIntersectingScrollView, targetFromEvent } from '../../utils/dom';
 | 
					import { editableActiveElement, isIntersectingScrollView, targetFromEvent } from '../../utils/dom';
 | 
				
			||||||
import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
 | 
					import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
 | 
				
			||||||
import { useDebounce } from '../../hooks/useDebounce';
 | 
					import { useDebounce } from '../../hooks/useDebounce';
 | 
				
			||||||
import { useThrottle } from '../../hooks/useThrottle';
 | 
					import { useThrottle } from '../../hooks/useThrottle';
 | 
				
			||||||
import { addRecentEmoji } from '../../plugins/recent-emoji';
 | 
					import { addRecentEmoji } from '../../plugins/recent-emoji';
 | 
				
			||||||
import { mobileOrTablet } from '../../utils/user-agent';
 | 
					import { mobileOrTablet } from '../../utils/user-agent';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const RECENT_GROUP_ID = 'recent_group';
 | 
					const RECENT_GROUP_ID = 'recent_group';
 | 
				
			||||||
const SEARCH_GROUP_ID = 'search_group';
 | 
					const SEARCH_GROUP_ID = 'search_group';
 | 
				
			||||||
| 
						 | 
					@ -354,11 +355,13 @@ function ImagePackSidebarStack({
 | 
				
			||||||
  packs,
 | 
					  packs,
 | 
				
			||||||
  usage,
 | 
					  usage,
 | 
				
			||||||
  onItemClick,
 | 
					  onItemClick,
 | 
				
			||||||
 | 
					  useAuthentication,
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  mx: MatrixClient;
 | 
					  mx: MatrixClient;
 | 
				
			||||||
  packs: ImagePack[];
 | 
					  packs: ImagePack[];
 | 
				
			||||||
  usage: PackUsage;
 | 
					  usage: PackUsage;
 | 
				
			||||||
  onItemClick: (id: string) => void;
 | 
					  onItemClick: (id: string) => void;
 | 
				
			||||||
 | 
					  useAuthentication?: boolean;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const activeGroupId = useAtomValue(activeGroupIdAtom);
 | 
					  const activeGroupId = useAtomValue(activeGroupIdAtom);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
| 
						 | 
					@ -381,7 +384,7 @@ function ImagePackSidebarStack({
 | 
				
			||||||
                height: toRem(24),
 | 
					                height: toRem(24),
 | 
				
			||||||
                objectFit: 'contain',
 | 
					                objectFit: 'contain',
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl}
 | 
					              src={mxcUrlToHttp(mx, pack.getPackAvatarUrl(usage) ?? '', useAuthentication) || pack.avatarUrl}
 | 
				
			||||||
              alt={label || 'Unknown Pack'}
 | 
					              alt={label || 'Unknown Pack'}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </SidebarBtn>
 | 
					          </SidebarBtn>
 | 
				
			||||||
| 
						 | 
					@ -453,68 +456,70 @@ export function SearchEmojiGroup({
 | 
				
			||||||
  label,
 | 
					  label,
 | 
				
			||||||
  id,
 | 
					  id,
 | 
				
			||||||
  emojis: searchResult,
 | 
					  emojis: searchResult,
 | 
				
			||||||
 | 
					  useAuthentication,
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  mx: MatrixClient;
 | 
					  mx: MatrixClient;
 | 
				
			||||||
  tab: EmojiBoardTab;
 | 
					  tab: EmojiBoardTab;
 | 
				
			||||||
  label: string;
 | 
					  label: string;
 | 
				
			||||||
  id: string;
 | 
					  id: string;
 | 
				
			||||||
  emojis: Array<ExtendedPackImage | IEmoji>;
 | 
					  emojis: Array<ExtendedPackImage | IEmoji>;
 | 
				
			||||||
 | 
					  useAuthentication?: boolean;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <EmojiGroup key={id} id={id} label={label}>
 | 
					    <EmojiGroup key={id} id={id} label={label}>
 | 
				
			||||||
      {tab === EmojiBoardTab.Emoji
 | 
					      {tab === EmojiBoardTab.Emoji
 | 
				
			||||||
        ? searchResult.map((emoji) =>
 | 
					        ? searchResult.map((emoji) =>
 | 
				
			||||||
            'unicode' in emoji ? (
 | 
					          'unicode' in emoji ? (
 | 
				
			||||||
              <EmojiItem
 | 
					            <EmojiItem
 | 
				
			||||||
                key={emoji.unicode}
 | 
					              key={emoji.unicode}
 | 
				
			||||||
                label={emoji.label}
 | 
					              label={emoji.label}
 | 
				
			||||||
                type={EmojiType.Emoji}
 | 
					              type={EmojiType.Emoji}
 | 
				
			||||||
                data={emoji.unicode}
 | 
					              data={emoji.unicode}
 | 
				
			||||||
                shortcode={emoji.shortcode}
 | 
					              shortcode={emoji.shortcode}
 | 
				
			||||||
              >
 | 
					            >
 | 
				
			||||||
                {emoji.unicode}
 | 
					              {emoji.unicode}
 | 
				
			||||||
              </EmojiItem>
 | 
					            </EmojiItem>
 | 
				
			||||||
            ) : (
 | 
					          ) : (
 | 
				
			||||||
              <EmojiItem
 | 
					            <EmojiItem
 | 
				
			||||||
                key={emoji.shortcode}
 | 
					              key={emoji.shortcode}
 | 
				
			||||||
                label={emoji.body || emoji.shortcode}
 | 
					              label={emoji.body || emoji.shortcode}
 | 
				
			||||||
                type={EmojiType.CustomEmoji}
 | 
					              type={EmojiType.CustomEmoji}
 | 
				
			||||||
                data={emoji.url}
 | 
					              data={emoji.url}
 | 
				
			||||||
                shortcode={emoji.shortcode}
 | 
					              shortcode={emoji.shortcode}
 | 
				
			||||||
              >
 | 
					            >
 | 
				
			||||||
                <img
 | 
					              <img
 | 
				
			||||||
                  loading="lazy"
 | 
					                loading="lazy"
 | 
				
			||||||
                  className={css.CustomEmojiImg}
 | 
					                className={css.CustomEmojiImg}
 | 
				
			||||||
                  alt={emoji.body || emoji.shortcode}
 | 
					                alt={emoji.body || emoji.shortcode}
 | 
				
			||||||
                  src={mx.mxcUrlToHttp(emoji.url) ?? emoji.url}
 | 
					                src={mxcUrlToHttp(mx, emoji.url, useAuthentication) ?? emoji.url}
 | 
				
			||||||
                />
 | 
					              />
 | 
				
			||||||
              </EmojiItem>
 | 
					            </EmojiItem>
 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        : searchResult.map((emoji) =>
 | 
					        : searchResult.map((emoji) =>
 | 
				
			||||||
            'unicode' in emoji ? null : (
 | 
					          'unicode' in emoji ? null : (
 | 
				
			||||||
              <StickerItem
 | 
					            <StickerItem
 | 
				
			||||||
                key={emoji.shortcode}
 | 
					              key={emoji.shortcode}
 | 
				
			||||||
                label={emoji.body || emoji.shortcode}
 | 
					              label={emoji.body || emoji.shortcode}
 | 
				
			||||||
                type={EmojiType.Sticker}
 | 
					              type={EmojiType.Sticker}
 | 
				
			||||||
                data={emoji.url}
 | 
					              data={emoji.url}
 | 
				
			||||||
                shortcode={emoji.shortcode}
 | 
					              shortcode={emoji.shortcode}
 | 
				
			||||||
              >
 | 
					            >
 | 
				
			||||||
                <img
 | 
					              <img
 | 
				
			||||||
                  loading="lazy"
 | 
					                loading="lazy"
 | 
				
			||||||
                  className={css.StickerImg}
 | 
					                className={css.StickerImg}
 | 
				
			||||||
                  alt={emoji.body || emoji.shortcode}
 | 
					                alt={emoji.body || emoji.shortcode}
 | 
				
			||||||
                  src={mx.mxcUrlToHttp(emoji.url) ?? emoji.url}
 | 
					                src={mxcUrlToHttp(mx, emoji.url, useAuthentication) ?? emoji.url}
 | 
				
			||||||
                />
 | 
					              />
 | 
				
			||||||
              </StickerItem>
 | 
					            </StickerItem>
 | 
				
			||||||
            )
 | 
					          )
 | 
				
			||||||
          )}
 | 
					        )}
 | 
				
			||||||
    </EmojiGroup>
 | 
					    </EmojiGroup>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const CustomEmojiGroups = memo(
 | 
					export const CustomEmojiGroups = memo(
 | 
				
			||||||
  ({ mx, groups }: { mx: MatrixClient; groups: ImagePack[] }) => (
 | 
					  ({ mx, groups, useAuthentication }: { mx: MatrixClient; groups: ImagePack[]; useAuthentication?: boolean }) => (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {groups.map((pack) => (
 | 
					      {groups.map((pack) => (
 | 
				
			||||||
        <EmojiGroup key={pack.id} id={pack.id} label={pack.displayName || 'Unknown'}>
 | 
					        <EmojiGroup key={pack.id} id={pack.id} label={pack.displayName || 'Unknown'}>
 | 
				
			||||||
| 
						 | 
					@ -530,7 +535,7 @@ export const CustomEmojiGroups = memo(
 | 
				
			||||||
                loading="lazy"
 | 
					                loading="lazy"
 | 
				
			||||||
                className={css.CustomEmojiImg}
 | 
					                className={css.CustomEmojiImg}
 | 
				
			||||||
                alt={image.body || image.shortcode}
 | 
					                alt={image.body || image.shortcode}
 | 
				
			||||||
                src={mx.mxcUrlToHttp(image.url) ?? image.url}
 | 
					                src={mxcUrlToHttp(mx, image.url, useAuthentication) ?? image.url}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            </EmojiItem>
 | 
					            </EmojiItem>
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
| 
						 | 
					@ -540,7 +545,7 @@ export const CustomEmojiGroups = memo(
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const StickerGroups = memo(({ mx, groups }: { mx: MatrixClient; groups: ImagePack[] }) => (
 | 
					export const StickerGroups = memo(({ mx, groups, useAuthentication }: { mx: MatrixClient; groups: ImagePack[]; useAuthentication?: boolean }) => (
 | 
				
			||||||
  <>
 | 
					  <>
 | 
				
			||||||
    {groups.length === 0 && (
 | 
					    {groups.length === 0 && (
 | 
				
			||||||
      <Box
 | 
					      <Box
 | 
				
			||||||
| 
						 | 
					@ -573,7 +578,7 @@ export const StickerGroups = memo(({ mx, groups }: { mx: MatrixClient; groups: I
 | 
				
			||||||
              loading="lazy"
 | 
					              loading="lazy"
 | 
				
			||||||
              className={css.StickerImg}
 | 
					              className={css.StickerImg}
 | 
				
			||||||
              alt={image.body || image.shortcode}
 | 
					              alt={image.body || image.shortcode}
 | 
				
			||||||
              src={mx.mxcUrlToHttp(image.url) ?? image.url}
 | 
					              src={mxcUrlToHttp(mx, image.url, useAuthentication) ?? image.url}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </StickerItem>
 | 
					          </StickerItem>
 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
| 
						 | 
					@ -645,6 +650,8 @@ export function EmojiBoard({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const setActiveGroupId = useSetAtom(activeGroupIdAtom);
 | 
					  const setActiveGroupId = useSetAtom(activeGroupIdAtom);
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const emojiGroupLabels = useEmojiGroupLabels();
 | 
					  const emojiGroupLabels = useEmojiGroupLabels();
 | 
				
			||||||
  const emojiGroupIcons = useEmojiGroupIcons();
 | 
					  const emojiGroupIcons = useEmojiGroupIcons();
 | 
				
			||||||
  const imagePacks = useRelevantImagePacks(mx, usage, imagePackRooms);
 | 
					  const imagePacks = useRelevantImagePacks(mx, usage, imagePackRooms);
 | 
				
			||||||
| 
						 | 
					@ -729,14 +736,14 @@ export function EmojiBoard({
 | 
				
			||||||
      } else if (emojiInfo.type === EmojiType.CustomEmoji && emojiPreviewRef.current) {
 | 
					      } else if (emojiInfo.type === EmojiType.CustomEmoji && emojiPreviewRef.current) {
 | 
				
			||||||
        const img = document.createElement('img');
 | 
					        const img = document.createElement('img');
 | 
				
			||||||
        img.className = css.CustomEmojiImg;
 | 
					        img.className = css.CustomEmojiImg;
 | 
				
			||||||
        img.setAttribute('src', mx.mxcUrlToHttp(emojiInfo.data) || emojiInfo.data);
 | 
					        img.setAttribute('src', mxcUrlToHttp(mx, emojiInfo.data, useAuthentication) || emojiInfo.data);
 | 
				
			||||||
        img.setAttribute('alt', emojiInfo.shortcode);
 | 
					        img.setAttribute('alt', emojiInfo.shortcode);
 | 
				
			||||||
        emojiPreviewRef.current.textContent = '';
 | 
					        emojiPreviewRef.current.textContent = '';
 | 
				
			||||||
        emojiPreviewRef.current.appendChild(img);
 | 
					        emojiPreviewRef.current.appendChild(img);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      emojiPreviewTextRef.current.textContent = `:${emojiInfo.shortcode}:`;
 | 
					      emojiPreviewTextRef.current.textContent = `:${emojiInfo.shortcode}:`;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    [mx]
 | 
					    [mx, useAuthentication]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const throttleEmojiHover = useThrottle(handleEmojiPreview, {
 | 
					  const throttleEmojiHover = useThrottle(handleEmojiPreview, {
 | 
				
			||||||
| 
						 | 
					@ -829,6 +836,7 @@ export function EmojiBoard({
 | 
				
			||||||
                usage={usage}
 | 
					                usage={usage}
 | 
				
			||||||
                packs={imagePacks}
 | 
					                packs={imagePacks}
 | 
				
			||||||
                onItemClick={handleScrollToGroup}
 | 
					                onItemClick={handleScrollToGroup}
 | 
				
			||||||
 | 
					                useAuthentication={useAuthentication}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            {emojiTab && (
 | 
					            {emojiTab && (
 | 
				
			||||||
| 
						 | 
					@ -890,13 +898,14 @@ export function EmojiBoard({
 | 
				
			||||||
                  id={SEARCH_GROUP_ID}
 | 
					                  id={SEARCH_GROUP_ID}
 | 
				
			||||||
                  label={result.items.length ? 'Search Results' : 'No Results found'}
 | 
					                  label={result.items.length ? 'Search Results' : 'No Results found'}
 | 
				
			||||||
                  emojis={result.items}
 | 
					                  emojis={result.items}
 | 
				
			||||||
 | 
					                  useAuthentication={useAuthentication}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
              {emojiTab && recentEmojis.length > 0 && (
 | 
					              {emojiTab && recentEmojis.length > 0 && (
 | 
				
			||||||
                <RecentEmojiGroup id={RECENT_GROUP_ID} label="Recent" emojis={recentEmojis} />
 | 
					                <RecentEmojiGroup id={RECENT_GROUP_ID} label="Recent" emojis={recentEmojis} />
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
              {emojiTab && <CustomEmojiGroups mx={mx} groups={imagePacks} />}
 | 
					              {emojiTab && <CustomEmojiGroups mx={mx} groups={imagePacks} useAuthentication={useAuthentication} />}
 | 
				
			||||||
              {stickerTab && <StickerGroups mx={mx} groups={imagePacks} />}
 | 
					              {stickerTab && <StickerGroups mx={mx} groups={imagePacks} useAuthentication={useAuthentication} />}
 | 
				
			||||||
              {emojiTab && <NativeEmojiGroups groups={emojiGroups} labels={emojiGroupLabels} />}
 | 
					              {emojiTab && <NativeEmojiGroups groups={emojiGroups} labels={emojiGroupLabels} />}
 | 
				
			||||||
            </Box>
 | 
					            </Box>
 | 
				
			||||||
          </Scroll>
 | 
					          </Scroll>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ import * as css from './EventReaders.css';
 | 
				
			||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
				
			||||||
import { openProfileViewer } from '../../../client/action/navigation';
 | 
					import { openProfileViewer } from '../../../client/action/navigation';
 | 
				
			||||||
import { UserAvatar } from '../user-avatar';
 | 
					import { UserAvatar } from '../user-avatar';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type EventReadersProps = {
 | 
					export type EventReadersProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -30,6 +31,8 @@ export type EventReadersProps = {
 | 
				
			||||||
export const EventReaders = as<'div', EventReadersProps>(
 | 
					export const EventReaders = as<'div', EventReadersProps>(
 | 
				
			||||||
  ({ className, room, eventId, requestClose, ...props }, ref) => {
 | 
					  ({ className, room, eventId, requestClose, ...props }, ref) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const latestEventReaders = useRoomEventReaders(room, eventId);
 | 
					    const latestEventReaders = useRoomEventReaders(room, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getName = (userId: string) =>
 | 
					    const getName = (userId: string) =>
 | 
				
			||||||
| 
						 | 
					@ -55,9 +58,10 @@ export const EventReaders = as<'div', EventReadersProps>(
 | 
				
			||||||
            <Box className={css.Content} direction="Column">
 | 
					            <Box className={css.Content} direction="Column">
 | 
				
			||||||
              {latestEventReaders.map((readerId) => {
 | 
					              {latestEventReaders.map((readerId) => {
 | 
				
			||||||
                const name = getName(readerId);
 | 
					                const name = getName(readerId);
 | 
				
			||||||
                const avatarUrl = room
 | 
					                const avatarMxcUrl = room
 | 
				
			||||||
                  .getMember(readerId)
 | 
					                  .getMember(readerId)
 | 
				
			||||||
                  ?.getAvatarUrl(mx.baseUrl, 100, 100, 'crop', undefined, false);
 | 
					                  ?.getMxcAvatarUrl();
 | 
				
			||||||
 | 
					                const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(avatarMxcUrl, 100, 100, 'crop', undefined, false, useAuthentication) : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return (
 | 
					                return (
 | 
				
			||||||
                  <MenuItem
 | 
					                  <MenuItem
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk';
 | 
				
			||||||
import * as css from './Reaction.css';
 | 
					import * as css from './Reaction.css';
 | 
				
			||||||
import { getHexcodeForEmoji, getShortcodeFor } from '../../plugins/emoji';
 | 
					import { getHexcodeForEmoji, getShortcodeFor } from '../../plugins/emoji';
 | 
				
			||||||
import { getMemberDisplayName } from '../../utils/room';
 | 
					import { getMemberDisplayName } from '../../utils/room';
 | 
				
			||||||
import { eventWithShortcode, getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { eventWithShortcode, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Reaction = as<
 | 
					export const Reaction = as<
 | 
				
			||||||
  'button',
 | 
					  'button',
 | 
				
			||||||
| 
						 | 
					@ -13,8 +13,9 @@ export const Reaction = as<
 | 
				
			||||||
    mx: MatrixClient;
 | 
					    mx: MatrixClient;
 | 
				
			||||||
    count: number;
 | 
					    count: number;
 | 
				
			||||||
    reaction: string;
 | 
					    reaction: string;
 | 
				
			||||||
 | 
					    useAuthentication?: boolean;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
>(({ className, mx, count, reaction, ...props }, ref) => (
 | 
					>(({ className, mx, count, reaction, useAuthentication, ...props }, ref) => (
 | 
				
			||||||
  <Box
 | 
					  <Box
 | 
				
			||||||
    as="button"
 | 
					    as="button"
 | 
				
			||||||
    className={classNames(css.Reaction, className)}
 | 
					    className={classNames(css.Reaction, className)}
 | 
				
			||||||
| 
						 | 
					@ -28,7 +29,8 @@ export const Reaction = as<
 | 
				
			||||||
      {reaction.startsWith('mxc://') ? (
 | 
					      {reaction.startsWith('mxc://') ? (
 | 
				
			||||||
        <img
 | 
					        <img
 | 
				
			||||||
          className={css.ReactionImg}
 | 
					          className={css.ReactionImg}
 | 
				
			||||||
          src={mx.mxcUrlToHttp(reaction) ?? reaction}
 | 
					          src={mxcUrlToHttp(mx, reaction, useAuthentication) ?? reaction
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          alt={reaction}
 | 
					          alt={reaction}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,8 @@ import {
 | 
				
			||||||
} from '../../../hooks/media';
 | 
					} from '../../../hooks/media';
 | 
				
			||||||
import { useThrottle } from '../../../hooks/useThrottle';
 | 
					import { useThrottle } from '../../../hooks/useThrottle';
 | 
				
			||||||
import { secondsToMinutesAndSeconds } from '../../../utils/common';
 | 
					import { secondsToMinutesAndSeconds } from '../../../utils/common';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PLAY_TIME_THROTTLE_OPS = {
 | 
					const PLAY_TIME_THROTTLE_OPS = {
 | 
				
			||||||
  wait: 500,
 | 
					  wait: 500,
 | 
				
			||||||
| 
						 | 
					@ -44,11 +46,13 @@ export function AudioContent({
 | 
				
			||||||
  renderMediaControl,
 | 
					  renderMediaControl,
 | 
				
			||||||
}: AudioContentProps) {
 | 
					}: AudioContentProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [srcState, loadSrc] = useAsyncCallback(
 | 
					  const [srcState, loadSrc] = useAsyncCallback(
 | 
				
			||||||
    useCallback(
 | 
					    useCallback(
 | 
				
			||||||
      () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo),
 | 
					      () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo),
 | 
				
			||||||
      [mx, url, mimeType, encInfo]
 | 
					      [mx, url, useAuthentication, mimeType, encInfo]
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,8 @@ import {
 | 
				
			||||||
} from '../../../utils/mimeTypes';
 | 
					} from '../../../utils/mimeTypes';
 | 
				
			||||||
import * as css from './style.css';
 | 
					import * as css from './style.css';
 | 
				
			||||||
import { stopPropagation } from '../../../utils/keyboard';
 | 
					import { stopPropagation } from '../../../utils/keyboard';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const renderErrorButton = (retry: () => void, text: string) => (
 | 
					const renderErrorButton = (retry: () => void, text: string) => (
 | 
				
			||||||
  <TooltipProvider
 | 
					  <TooltipProvider
 | 
				
			||||||
| 
						 | 
					@ -75,11 +77,13 @@ type ReadTextFileProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: ReadTextFileProps) {
 | 
					export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: ReadTextFileProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const [textViewer, setTextViewer] = useState(false);
 | 
					  const [textViewer, setTextViewer] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const loadSrc = useCallback(
 | 
					  const loadSrc = useCallback(
 | 
				
			||||||
    () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo),
 | 
					    () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo),
 | 
				
			||||||
    [mx, url, mimeType, encInfo]
 | 
					    [mx, url, useAuthentication, mimeType, encInfo]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [textState, loadText] = useAsyncCallback(
 | 
					  const [textState, loadText] = useAsyncCallback(
 | 
				
			||||||
| 
						 | 
					@ -166,14 +170,16 @@ export type ReadPdfFileProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: ReadPdfFileProps) {
 | 
					export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: ReadPdfFileProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const [pdfViewer, setPdfViewer] = useState(false);
 | 
					  const [pdfViewer, setPdfViewer] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [pdfState, loadPdf] = useAsyncCallback(
 | 
					  const [pdfState, loadPdf] = useAsyncCallback(
 | 
				
			||||||
    useCallback(async () => {
 | 
					    useCallback(async () => {
 | 
				
			||||||
      const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo);
 | 
					      const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo);
 | 
				
			||||||
      setPdfViewer(true);
 | 
					      setPdfViewer(true);
 | 
				
			||||||
      return httpUrl;
 | 
					      return httpUrl;
 | 
				
			||||||
    }, [mx, url, mimeType, encInfo])
 | 
					    }, [mx, url, useAuthentication, mimeType, encInfo])
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
| 
						 | 
					@ -240,13 +246,15 @@ export type DownloadFileProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFileProps) {
 | 
					export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFileProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [downloadState, download] = useAsyncCallback(
 | 
					  const [downloadState, download] = useAsyncCallback(
 | 
				
			||||||
    useCallback(async () => {
 | 
					    useCallback(async () => {
 | 
				
			||||||
      const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo);
 | 
					      const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo);
 | 
				
			||||||
      FileSaver.saveAs(httpUrl, body);
 | 
					      FileSaver.saveAs(httpUrl, body);
 | 
				
			||||||
      return httpUrl;
 | 
					      return httpUrl;
 | 
				
			||||||
    }, [mx, url, mimeType, encInfo, body])
 | 
					    }, [mx, url, useAuthentication, mimeType, encInfo, body])
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return downloadState.status === AsyncStatus.Error ? (
 | 
					  return downloadState.status === AsyncStatus.Error ? (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,8 @@ import * as css from './style.css';
 | 
				
			||||||
import { bytesToSize } from '../../../utils/common';
 | 
					import { bytesToSize } from '../../../utils/common';
 | 
				
			||||||
import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes';
 | 
					import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes';
 | 
				
			||||||
import { stopPropagation } from '../../../utils/keyboard';
 | 
					import { stopPropagation } from '../../../utils/keyboard';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RenderViewerProps = {
 | 
					type RenderViewerProps = {
 | 
				
			||||||
  src: string;
 | 
					  src: string;
 | 
				
			||||||
| 
						 | 
					@ -69,6 +71,8 @@ export const ImageContent = as<'div', ImageContentProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const blurHash = info?.[MATRIX_BLUR_HASH_PROPERTY_NAME];
 | 
					    const blurHash = info?.[MATRIX_BLUR_HASH_PROPERTY_NAME];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [load, setLoad] = useState(false);
 | 
					    const [load, setLoad] = useState(false);
 | 
				
			||||||
| 
						 | 
					@ -77,8 +81,8 @@ export const ImageContent = as<'div', ImageContentProps>(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [srcState, loadSrc] = useAsyncCallback(
 | 
					    const [srcState, loadSrc] = useAsyncCallback(
 | 
				
			||||||
      useCallback(
 | 
					      useCallback(
 | 
				
			||||||
        () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo),
 | 
					        () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo),
 | 
				
			||||||
        [mx, url, mimeType, encInfo]
 | 
					        [mx, url, useAuthentication, mimeType, encInfo]
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@ import { IThumbnailContent } from '../../../../types/matrix/common';
 | 
				
			||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
				
			||||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 | 
					import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 | 
				
			||||||
import { getFileSrcUrl } from './util';
 | 
					import { getFileSrcUrl } from './util';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ThumbnailContentProps = {
 | 
					export type ThumbnailContentProps = {
 | 
				
			||||||
  info: IThumbnailContent;
 | 
					  info: IThumbnailContent;
 | 
				
			||||||
| 
						 | 
					@ -10,6 +12,8 @@ export type ThumbnailContentProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
 | 
					export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [thumbSrcState, loadThumbSrc] = useAsyncCallback(
 | 
					  const [thumbSrcState, loadThumbSrc] = useAsyncCallback(
 | 
				
			||||||
    useCallback(() => {
 | 
					    useCallback(() => {
 | 
				
			||||||
| 
						 | 
					@ -19,11 +23,11 @@ export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
 | 
				
			||||||
        throw new Error('Failed to load thumbnail');
 | 
					        throw new Error('Failed to load thumbnail');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return getFileSrcUrl(
 | 
					      return getFileSrcUrl(
 | 
				
			||||||
        mx.mxcUrlToHttp(thumbMxcUrl) ?? '',
 | 
					        mxcUrlToHttp(mx, thumbMxcUrl, useAuthentication) ?? '',
 | 
				
			||||||
        thumbInfo.mimetype,
 | 
					        thumbInfo.mimetype,
 | 
				
			||||||
        info.thumbnail_file
 | 
					        info.thumbnail_file
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }, [mx, info])
 | 
					    }, [mx, info, useAuthentication])
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,8 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 | 
				
			||||||
import { getFileSrcUrl } from './util';
 | 
					import { getFileSrcUrl } from './util';
 | 
				
			||||||
import { bytesToSize } from '../../../../util/common';
 | 
					import { bytesToSize } from '../../../../util/common';
 | 
				
			||||||
import { millisecondsToMinutesAndSeconds } from '../../../utils/common';
 | 
					import { millisecondsToMinutesAndSeconds } from '../../../utils/common';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RenderVideoProps = {
 | 
					type RenderVideoProps = {
 | 
				
			||||||
  title: string;
 | 
					  title: string;
 | 
				
			||||||
| 
						 | 
					@ -61,6 +63,8 @@ export const VideoContent = as<'div', VideoContentProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const blurHash = info.thumbnail_info?.[MATRIX_BLUR_HASH_PROPERTY_NAME];
 | 
					    const blurHash = info.thumbnail_info?.[MATRIX_BLUR_HASH_PROPERTY_NAME];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [load, setLoad] = useState(false);
 | 
					    const [load, setLoad] = useState(false);
 | 
				
			||||||
| 
						 | 
					@ -68,8 +72,8 @@ export const VideoContent = as<'div', VideoContentProps>(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [srcState, loadSrc] = useAsyncCallback(
 | 
					    const [srcState, loadSrc] = useAsyncCallback(
 | 
				
			||||||
      useCallback(
 | 
					      useCallback(
 | 
				
			||||||
        () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo),
 | 
					        () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo),
 | 
				
			||||||
        [mx, url, mimeType, encInfo]
 | 
					        [mx, url, useAuthentication, mimeType, encInfo]
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ import classNames from 'classnames';
 | 
				
			||||||
import FocusTrap from 'focus-trap-react';
 | 
					import FocusTrap from 'focus-trap-react';
 | 
				
			||||||
import * as css from './style.css';
 | 
					import * as css from './style.css';
 | 
				
			||||||
import { RoomAvatar } from '../room-avatar';
 | 
					import { RoomAvatar } from '../room-avatar';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { nameInitials } from '../../utils/common';
 | 
					import { nameInitials } from '../../utils/common';
 | 
				
			||||||
import { millify } from '../../plugins/millify';
 | 
					import { millify } from '../../plugins/millify';
 | 
				
			||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,7 @@ import { useJoinedRoomId } from '../../hooks/useJoinedRoomId';
 | 
				
			||||||
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
 | 
					import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
 | 
				
			||||||
import { getRoomAvatarUrl, getStateEvent } from '../../utils/room';
 | 
					import { getRoomAvatarUrl, getStateEvent } from '../../utils/room';
 | 
				
			||||||
import { useStateEventCallback } from '../../hooks/useStateEventCallback';
 | 
					import { useStateEventCallback } from '../../hooks/useStateEventCallback';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type GridColumnCount = '1' | '2' | '3';
 | 
					type GridColumnCount = '1' | '2' | '3';
 | 
				
			||||||
const getGridColumnCount = (gridWidth: number): GridColumnCount => {
 | 
					const getGridColumnCount = (gridWidth: number): GridColumnCount => {
 | 
				
			||||||
| 
						 | 
					@ -161,6 +162,8 @@ export const RoomCard = as<'div', RoomCardProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const joinedRoomId = useJoinedRoomId(allRooms, roomIdOrAlias);
 | 
					    const joinedRoomId = useJoinedRoomId(allRooms, roomIdOrAlias);
 | 
				
			||||||
    const joinedRoom = mx.getRoom(joinedRoomId);
 | 
					    const joinedRoom = mx.getRoom(joinedRoomId);
 | 
				
			||||||
    const [topicEvent, setTopicEvent] = useState(() =>
 | 
					    const [topicEvent, setTopicEvent] = useState(() =>
 | 
				
			||||||
| 
						 | 
					@ -171,8 +174,8 @@ export const RoomCard = as<'div', RoomCardProps>(
 | 
				
			||||||
    const fallbackTopic = roomIdOrAlias;
 | 
					    const fallbackTopic = roomIdOrAlias;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const avatar = joinedRoom
 | 
					    const avatar = joinedRoom
 | 
				
			||||||
      ? getRoomAvatarUrl(mx, joinedRoom, 96)
 | 
					      ? getRoomAvatarUrl(mx, joinedRoom, 96, useAuthentication)
 | 
				
			||||||
      : avatarUrl && mx.mxcUrlToHttp(avatarUrl, 96, 96, 'crop');
 | 
					      : avatarUrl && mxcUrlToHttp(mx, avatarUrl, useAuthentication, 96, 96, 'crop');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const roomName = joinedRoom?.name || name || fallbackName;
 | 
					    const roomName = joinedRoom?.name || name || fallbackName;
 | 
				
			||||||
    const roomTopic =
 | 
					    const roomTopic =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ import { openInviteUser } from '../../../client/action/navigation';
 | 
				
			||||||
import { IRoomCreateContent, Membership, StateEvent } from '../../../types/matrix/room';
 | 
					import { IRoomCreateContent, Membership, StateEvent } from '../../../types/matrix/room';
 | 
				
			||||||
import { getMemberDisplayName, getStateEvent } from '../../utils/room';
 | 
					import { getMemberDisplayName, getStateEvent } from '../../utils/room';
 | 
				
			||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
					import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
				
			||||||
import { timeDayMonthYear, timeHourMinute } from '../../utils/time';
 | 
					import { timeDayMonthYear, timeHourMinute } from '../../utils/time';
 | 
				
			||||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
					import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ import { RoomAvatar } from '../room-avatar';
 | 
				
			||||||
import { nameInitials } from '../../utils/common';
 | 
					import { nameInitials } from '../../utils/common';
 | 
				
			||||||
import { useRoomAvatar, useRoomName, useRoomTopic } from '../../hooks/useRoomMeta';
 | 
					import { useRoomAvatar, useRoomName, useRoomTopic } from '../../hooks/useRoomMeta';
 | 
				
			||||||
import { mDirectAtom } from '../../state/mDirectList';
 | 
					import { mDirectAtom } from '../../state/mDirectList';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type RoomIntroProps = {
 | 
					export type RoomIntroProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -21,6 +22,8 @@ export type RoomIntroProps = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => {
 | 
					export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const { navigateRoom } = useRoomNavigate();
 | 
					  const { navigateRoom } = useRoomNavigate();
 | 
				
			||||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
					  const mDirects = useAtomValue(mDirectAtom);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +31,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
 | 
				
			||||||
  const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
 | 
					  const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
 | 
				
			||||||
  const name = useRoomName(room);
 | 
					  const name = useRoomName(room);
 | 
				
			||||||
  const topic = useRoomTopic(room);
 | 
					  const topic = useRoomTopic(room);
 | 
				
			||||||
  const avatarHttpUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc) : undefined;
 | 
					  const avatarHttpUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication) : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const createContent = createEvent?.getContent<IRoomCreateContent>();
 | 
					  const createContent = createEvent?.getContent<IRoomCreateContent>();
 | 
				
			||||||
  const ts = createEvent?.getTs();
 | 
					  const ts = createEvent?.getTs();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,12 +10,16 @@ import {
 | 
				
			||||||
} from '../../hooks/useIntersectionObserver';
 | 
					} from '../../hooks/useIntersectionObserver';
 | 
				
			||||||
import * as css from './UrlPreviewCard.css';
 | 
					import * as css from './UrlPreviewCard.css';
 | 
				
			||||||
import { tryDecodeURIComponent } from '../../utils/dom';
 | 
					import { tryDecodeURIComponent } from '../../utils/dom';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const linkStyles = { color: color.Success.Main };
 | 
					const linkStyles = { color: color.Success.Main };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
 | 
					export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
 | 
				
			||||||
  ({ url, ts, ...props }, ref) => {
 | 
					  ({ url, ts, ...props }, ref) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const [previewStatus, loadPreview] = useAsyncCallback(
 | 
					    const [previewStatus, loadPreview] = useAsyncCallback(
 | 
				
			||||||
      useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx])
 | 
					      useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx])
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -27,7 +31,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
 | 
				
			||||||
    if (previewStatus.status === AsyncStatus.Error) return null;
 | 
					    if (previewStatus.status === AsyncStatus.Error) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const renderContent = (prev: IPreviewUrlResponse) => {
 | 
					    const renderContent = (prev: IPreviewUrlResponse) => {
 | 
				
			||||||
      const imgUrl = mx.mxcUrlToHttp(prev['og:image'] || '', 256, 256, 'scale', false);
 | 
					      const imgUrl = mxcUrlToHttp(mx, prev['og:image'] || '', useAuthentication, 256, 256, 'scale', false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return (
 | 
					      return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
 | 
				
			||||||
import { stopPropagation } from '../../utils/keyboard';
 | 
					import { stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
 | 
					import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
 | 
				
			||||||
import { BackRouteHandler } from '../../components/BackRouteHandler';
 | 
					import { BackRouteHandler } from '../../components/BackRouteHandler';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LobbyMenuProps = {
 | 
					type LobbyMenuProps = {
 | 
				
			||||||
  roomId: string;
 | 
					  roomId: string;
 | 
				
			||||||
| 
						 | 
					@ -122,6 +124,8 @@ type LobbyHeaderProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
 | 
					export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const space = useSpace();
 | 
					  const space = useSpace();
 | 
				
			||||||
  const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
 | 
					  const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
 | 
				
			||||||
  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
 | 
					  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
 | 
				
			||||||
| 
						 | 
					@ -129,7 +133,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const name = useRoomName(space);
 | 
					  const name = useRoomName(space);
 | 
				
			||||||
  const avatarMxc = useRoomAvatar(space);
 | 
					  const avatarMxc = useRoomAvatar(space);
 | 
				
			||||||
  const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
 | 
					  const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
					  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
				
			||||||
    setMenuAnchor(evt.currentTarget.getBoundingClientRect());
 | 
					    setMenuAnchor(evt.currentTarget.getBoundingClientRect());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,15 +11,19 @@ import { RoomTopicViewer } from '../../components/room-topic-viewer';
 | 
				
			||||||
import * as css from './LobbyHero.css';
 | 
					import * as css from './LobbyHero.css';
 | 
				
			||||||
import { PageHero } from '../../components/page';
 | 
					import { PageHero } from '../../components/page';
 | 
				
			||||||
import { onEnterOrSpace, stopPropagation } from '../../utils/keyboard';
 | 
					import { onEnterOrSpace, stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function LobbyHero() {
 | 
					export function LobbyHero() {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const space = useSpace();
 | 
					  const space = useSpace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const name = useRoomName(space);
 | 
					  const name = useRoomName(space);
 | 
				
			||||||
  const topic = useRoomTopic(space);
 | 
					  const topic = useRoomTopic(space);
 | 
				
			||||||
  const avatarMxc = useRoomAvatar(space);
 | 
					  const avatarMxc = useRoomAvatar(space);
 | 
				
			||||||
  const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
 | 
					  const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <PageHero
 | 
					    <PageHero
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,8 @@ import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
				
			||||||
import { ErrorCode } from '../../cs-errorcode';
 | 
					import { ErrorCode } from '../../cs-errorcode';
 | 
				
			||||||
import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room';
 | 
					import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room';
 | 
				
			||||||
import { ItemDraggableTarget, useDraggableItem } from './DnD';
 | 
					import { ItemDraggableTarget, useDraggableItem } from './DnD';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoomJoinButtonProps = {
 | 
					type RoomJoinButtonProps = {
 | 
				
			||||||
  roomId: string;
 | 
					  roomId: string;
 | 
				
			||||||
| 
						 | 
					@ -334,6 +336,8 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const { roomId, content } = item;
 | 
					    const { roomId, content } = item;
 | 
				
			||||||
    const room = getRoom(roomId);
 | 
					    const room = getRoom(roomId);
 | 
				
			||||||
    const targetRef = useRef<HTMLDivElement>(null);
 | 
					    const targetRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
| 
						 | 
					@ -364,7 +368,7 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
 | 
				
			||||||
                  name={localSummary.name}
 | 
					                  name={localSummary.name}
 | 
				
			||||||
                  topic={localSummary.topic}
 | 
					                  topic={localSummary.topic}
 | 
				
			||||||
                  avatarUrl={
 | 
					                  avatarUrl={
 | 
				
			||||||
                    dm ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96)
 | 
					                    dm ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication)
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                  memberCount={localSummary.memberCount}
 | 
					                  memberCount={localSummary.memberCount}
 | 
				
			||||||
                  suggested={content.suggested}
 | 
					                  suggested={content.suggested}
 | 
				
			||||||
| 
						 | 
					@ -418,8 +422,8 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
 | 
				
			||||||
                        topic={summaryState.data.topic}
 | 
					                        topic={summaryState.data.topic}
 | 
				
			||||||
                        avatarUrl={
 | 
					                        avatarUrl={
 | 
				
			||||||
                          summaryState.data?.avatar_url
 | 
					                          summaryState.data?.avatar_url
 | 
				
			||||||
                            ? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ??
 | 
					                            ? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ??
 | 
				
			||||||
                              undefined
 | 
					                            undefined
 | 
				
			||||||
                            : undefined
 | 
					                            : undefined
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        memberCount={summaryState.data.num_joined_members}
 | 
					                        memberCount={summaryState.data.num_joined_members}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,8 @@ import { ErrorCode } from '../../cs-errorcode';
 | 
				
			||||||
import { useDraggableItem } from './DnD';
 | 
					import { useDraggableItem } from './DnD';
 | 
				
			||||||
import { openCreateRoom, openSpaceAddExisting } from '../../../client/action/navigation';
 | 
					import { openCreateRoom, openSpaceAddExisting } from '../../../client/action/navigation';
 | 
				
			||||||
import { stopPropagation } from '../../utils/keyboard';
 | 
					import { stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
 | 
					import { mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function SpaceProfileLoading() {
 | 
					function SpaceProfileLoading() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
| 
						 | 
					@ -408,6 +410,8 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const { roomId, content } = item;
 | 
					    const { roomId, content } = item;
 | 
				
			||||||
    const space = getRoom(roomId);
 | 
					    const space = getRoom(roomId);
 | 
				
			||||||
    const targetRef = useRef<HTMLDivElement>(null);
 | 
					    const targetRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
| 
						 | 
					@ -432,7 +436,7 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
 | 
				
			||||||
                    <SpaceProfile
 | 
					                    <SpaceProfile
 | 
				
			||||||
                      roomId={roomId}
 | 
					                      roomId={roomId}
 | 
				
			||||||
                      name={localSummary.name}
 | 
					                      name={localSummary.name}
 | 
				
			||||||
                      avatarUrl={getRoomAvatarUrl(mx, space, 96)}
 | 
					                      avatarUrl={getRoomAvatarUrl(mx, space, 96, useAuthentication)}
 | 
				
			||||||
                      suggested={content.suggested}
 | 
					                      suggested={content.suggested}
 | 
				
			||||||
                      closed={closed}
 | 
					                      closed={closed}
 | 
				
			||||||
                      categoryId={categoryId}
 | 
					                      categoryId={categoryId}
 | 
				
			||||||
| 
						 | 
					@ -469,8 +473,8 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
 | 
				
			||||||
                        name={summaryState.data.name || summaryState.data.canonical_alias || roomId}
 | 
					                        name={summaryState.data.name || summaryState.data.canonical_alias || roomId}
 | 
				
			||||||
                        avatarUrl={
 | 
					                        avatarUrl={
 | 
				
			||||||
                          summaryState.data?.avatar_url
 | 
					                          summaryState.data?.avatar_url
 | 
				
			||||||
                            ? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ??
 | 
					                            ? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ??
 | 
				
			||||||
                              undefined
 | 
					                            undefined
 | 
				
			||||||
                            : undefined
 | 
					                            : undefined
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        suggested={content.suggested}
 | 
					                        suggested={content.suggested}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ import {
 | 
				
			||||||
  makeMentionCustomProps,
 | 
					  makeMentionCustomProps,
 | 
				
			||||||
  renderMatrixMention,
 | 
					  renderMatrixMention,
 | 
				
			||||||
} from '../../plugins/react-custom-html-parser';
 | 
					} from '../../plugins/react-custom-html-parser';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer';
 | 
					import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer';
 | 
				
			||||||
import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room';
 | 
					import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@ import { SequenceCard } from '../../components/sequence-card';
 | 
				
			||||||
import { UserAvatar } from '../../components/user-avatar';
 | 
					import { UserAvatar } from '../../components/user-avatar';
 | 
				
			||||||
import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
 | 
					import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
 | 
				
			||||||
import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
 | 
					import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SearchResultGroupProps = {
 | 
					type SearchResultGroupProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -56,6 +57,8 @@ export function SearchResultGroup({
 | 
				
			||||||
  onOpen,
 | 
					  onOpen,
 | 
				
			||||||
}: SearchResultGroupProps) {
 | 
					}: SearchResultGroupProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]);
 | 
					  const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const mentionClickHandler = useMentionClickHandler(room.roomId);
 | 
					  const mentionClickHandler = useMentionClickHandler(room.roomId);
 | 
				
			||||||
| 
						 | 
					@ -75,10 +78,11 @@ export function SearchResultGroup({
 | 
				
			||||||
      getReactCustomHtmlParser(mx, room.roomId, {
 | 
					      getReactCustomHtmlParser(mx, room.roomId, {
 | 
				
			||||||
        linkifyOpts,
 | 
					        linkifyOpts,
 | 
				
			||||||
        highlightRegex,
 | 
					        highlightRegex,
 | 
				
			||||||
 | 
					        useAuthentication,
 | 
				
			||||||
        handleSpoilerClick: spoilerClickHandler,
 | 
					        handleSpoilerClick: spoilerClickHandler,
 | 
				
			||||||
        handleMentionClick: mentionClickHandler,
 | 
					        handleMentionClick: mentionClickHandler,
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
    [mx, room, linkifyOpts, highlightRegex, mentionClickHandler, spoilerClickHandler]
 | 
					    [mx, room, linkifyOpts, highlightRegex, mentionClickHandler, spoilerClickHandler, useAuthentication]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderMatrixEvent = useMatrixEventRenderer<[IEventWithRoomId, string, GetContentCallback]>(
 | 
					  const renderMatrixEvent = useMatrixEventRenderer<[IEventWithRoomId, string, GetContentCallback]>(
 | 
				
			||||||
| 
						 | 
					@ -161,7 +165,7 @@ export function SearchResultGroup({
 | 
				
			||||||
          <Avatar size="200" radii="300">
 | 
					          <Avatar size="200" radii="300">
 | 
				
			||||||
            <RoomAvatar
 | 
					            <RoomAvatar
 | 
				
			||||||
              roomId={room.roomId}
 | 
					              roomId={room.roomId}
 | 
				
			||||||
              src={getRoomAvatarUrl(mx, room, 96)}
 | 
					              src={getRoomAvatarUrl(mx, room, 96, useAuthentication)}
 | 
				
			||||||
              alt={room.name}
 | 
					              alt={room.name}
 | 
				
			||||||
              renderFallback={() => (
 | 
					              renderFallback={() => (
 | 
				
			||||||
                <RoomIcon size="50" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
 | 
					                <RoomIcon size="50" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
 | 
				
			||||||
| 
						 | 
					@ -209,7 +213,7 @@ export function SearchResultGroup({
 | 
				
			||||||
                        userId={event.sender}
 | 
					                        userId={event.sender}
 | 
				
			||||||
                        src={
 | 
					                        src={
 | 
				
			||||||
                          senderAvatarMxc
 | 
					                          senderAvatarMxc
 | 
				
			||||||
                            ? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
 | 
					                            ? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined
 | 
				
			||||||
                            : undefined
 | 
					                            : undefined
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        alt={displayName}
 | 
					                        alt={displayName}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@ import { stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
import { getMatrixToRoom } from '../../plugins/matrix-to';
 | 
					import { getMatrixToRoom } from '../../plugins/matrix-to';
 | 
				
			||||||
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
 | 
					import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
 | 
				
			||||||
import { getViaServers } from '../../plugins/via-servers';
 | 
					import { getViaServers } from '../../plugins/via-servers';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoomNavItemMenuProps = {
 | 
					type RoomNavItemMenuProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -175,6 +176,8 @@ export function RoomNavItem({
 | 
				
			||||||
  linkPath,
 | 
					  linkPath,
 | 
				
			||||||
}: RoomNavItemProps) {
 | 
					}: RoomNavItemProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const [hover, setHover] = useState(false);
 | 
					  const [hover, setHover] = useState(false);
 | 
				
			||||||
  const { hoverProps } = useHover({ onHoverChange: setHover });
 | 
					  const { hoverProps } = useHover({ onHoverChange: setHover });
 | 
				
			||||||
  const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
 | 
					  const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
 | 
				
			||||||
| 
						 | 
					@ -217,7 +220,7 @@ export function RoomNavItem({
 | 
				
			||||||
                <RoomAvatar
 | 
					                <RoomAvatar
 | 
				
			||||||
                  roomId={room.roomId}
 | 
					                  roomId={room.roomId}
 | 
				
			||||||
                  src={
 | 
					                  src={
 | 
				
			||||||
                    direct ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96)
 | 
					                    direct ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication)
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                  alt={room.name}
 | 
					                  alt={room.name}
 | 
				
			||||||
                  renderFallback={() => (
 | 
					                  renderFallback={() => (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,7 @@ import { ScrollTopContainer } from '../../components/scroll-top-container';
 | 
				
			||||||
import { UserAvatar } from '../../components/user-avatar';
 | 
					import { UserAvatar } from '../../components/user-avatar';
 | 
				
			||||||
import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers';
 | 
					import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers';
 | 
				
			||||||
import { stopPropagation } from '../../utils/keyboard';
 | 
					import { stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const MembershipFilters = {
 | 
					export const MembershipFilters = {
 | 
				
			||||||
  filterJoined: (m: RoomMember) => m.membership === Membership.Join,
 | 
					  filterJoined: (m: RoomMember) => m.membership === Membership.Join,
 | 
				
			||||||
| 
						 | 
					@ -171,6 +172,8 @@ type MembersDrawerProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function MembersDrawer({ room, members }: MembersDrawerProps) {
 | 
					export function MembersDrawer({ room, members }: MembersDrawerProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const scrollRef = useRef<HTMLDivElement>(null);
 | 
					  const scrollRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
  const searchInputRef = useRef<HTMLInputElement>(null);
 | 
					  const searchInputRef = useRef<HTMLInputElement>(null);
 | 
				
			||||||
  const scrollTopAnchorRef = useRef<HTMLDivElement>(null);
 | 
					  const scrollTopAnchorRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
| 
						 | 
					@ -426,9 +429,8 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
 | 
				
			||||||
                        }}
 | 
					                        }}
 | 
				
			||||||
                        after={<Icon size="50" src={Icons.Cross} />}
 | 
					                        after={<Icon size="50" src={Icons.Cross} />}
 | 
				
			||||||
                      >
 | 
					                      >
 | 
				
			||||||
                        <Text size="B300">{`${result.items.length || 'No'} ${
 | 
					                        <Text size="B300">{`${result.items.length || 'No'} ${result.items.length === 1 ? 'Result' : 'Results'
 | 
				
			||||||
                          result.items.length === 1 ? 'Result' : 'Results'
 | 
					                          }`}</Text>
 | 
				
			||||||
                        }`}</Text>
 | 
					 | 
				
			||||||
                      </Chip>
 | 
					                      </Chip>
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
| 
						 | 
					@ -483,14 +485,16 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  const member = tagOrMember;
 | 
					                  const member = tagOrMember;
 | 
				
			||||||
                  const name = getName(member);
 | 
					                  const name = getName(member);
 | 
				
			||||||
                  const avatarUrl = member.getAvatarUrl(
 | 
					                  const avatarMxcUrl = member.getMxcAvatarUrl();
 | 
				
			||||||
                    mx.baseUrl,
 | 
					                  const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(
 | 
				
			||||||
 | 
					                    avatarMxcUrl,
 | 
				
			||||||
                    100,
 | 
					                    100,
 | 
				
			||||||
                    100,
 | 
					                    100,
 | 
				
			||||||
                    'crop',
 | 
					                    'crop',
 | 
				
			||||||
                    undefined,
 | 
					                    undefined,
 | 
				
			||||||
                    false
 | 
					                    false,
 | 
				
			||||||
                  );
 | 
					                    useAuthentication
 | 
				
			||||||
 | 
					                  ) : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  return (
 | 
					                  return (
 | 
				
			||||||
                    <MenuItem
 | 
					                    <MenuItem
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,7 @@ import {
 | 
				
			||||||
} from '../../components/editor';
 | 
					} from '../../components/editor';
 | 
				
			||||||
import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board';
 | 
					import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board';
 | 
				
			||||||
import { UseStateProvider } from '../../components/UseStateProvider';
 | 
					import { UseStateProvider } from '../../components/UseStateProvider';
 | 
				
			||||||
import { TUploadContent, encryptFile, getImageInfo, getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { TUploadContent, encryptFile, getImageInfo, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { useTypingStatusUpdater } from '../../hooks/useTypingStatusUpdater';
 | 
					import { useTypingStatusUpdater } from '../../hooks/useTypingStatusUpdater';
 | 
				
			||||||
import { useFilePicker } from '../../hooks/useFilePicker';
 | 
					import { useFilePicker } from '../../hooks/useFilePicker';
 | 
				
			||||||
import { useFilePasteHandler } from '../../hooks/useFilePasteHandler';
 | 
					import { useFilePasteHandler } from '../../hooks/useFilePasteHandler';
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,7 @@ import { mobileOrTablet } from '../../utils/user-agent';
 | 
				
			||||||
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
 | 
					import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
 | 
				
			||||||
import { ReplyLayout, ThreadIndicator } from '../../components/message';
 | 
					import { ReplyLayout, ThreadIndicator } from '../../components/message';
 | 
				
			||||||
import { roomToParentsAtom } from '../../state/room/roomToParents';
 | 
					import { roomToParentsAtom } from '../../state/room/roomToParents';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface RoomInputProps {
 | 
					interface RoomInputProps {
 | 
				
			||||||
  editor: Editor;
 | 
					  editor: Editor;
 | 
				
			||||||
| 
						 | 
					@ -118,6 +119,8 @@ interface RoomInputProps {
 | 
				
			||||||
export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
					export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
				
			||||||
  ({ editor, fileDropContainerRef, roomId, room }, ref) => {
 | 
					  ({ editor, fileDropContainerRef, roomId, room }, ref) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline');
 | 
					    const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline');
 | 
				
			||||||
    const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown');
 | 
					    const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown');
 | 
				
			||||||
    const commands = useCommands(mx, room);
 | 
					    const commands = useCommands(mx, room);
 | 
				
			||||||
| 
						 | 
					@ -366,7 +369,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => {
 | 
					    const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => {
 | 
				
			||||||
      const stickerUrl = mx.mxcUrlToHttp(mxc);
 | 
					      const stickerUrl = mxcUrlToHttp(mx, mxc, useAuthentication);
 | 
				
			||||||
      if (!stickerUrl) return;
 | 
					      if (!stickerUrl) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const info = await getImageInfo(
 | 
					      const info = await getImageInfo(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,6 +122,7 @@ import { roomToUnreadAtom } from '../../state/room/roomToUnread';
 | 
				
			||||||
import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
 | 
					import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
 | 
				
			||||||
import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
 | 
					import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
 | 
				
			||||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
					import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TimelineFloat = as<'div', css.TimelineFloatVariants>(
 | 
					const TimelineFloat = as<'div', css.TimelineFloatVariants>(
 | 
				
			||||||
  ({ position, className, ...props }, ref) => (
 | 
					  ({ position, className, ...props }, ref) => (
 | 
				
			||||||
| 
						 | 
					@ -310,9 +311,9 @@ const useTimelinePagination = (
 | 
				
			||||||
        range:
 | 
					        range:
 | 
				
			||||||
          offsetRange > 0
 | 
					          offsetRange > 0
 | 
				
			||||||
            ? {
 | 
					            ? {
 | 
				
			||||||
                start: currentTimeline.range.start + offsetRange,
 | 
					              start: currentTimeline.range.start + offsetRange,
 | 
				
			||||||
                end: currentTimeline.range.end + offsetRange,
 | 
					              end: currentTimeline.range.end + offsetRange,
 | 
				
			||||||
              }
 | 
					            }
 | 
				
			||||||
            : { ...currentTimeline.range },
 | 
					            : { ...currentTimeline.range },
 | 
				
			||||||
      }));
 | 
					      }));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -331,7 +332,7 @@ const useTimelinePagination = (
 | 
				
			||||||
      if (
 | 
					      if (
 | 
				
			||||||
        !paginationToken &&
 | 
					        !paginationToken &&
 | 
				
			||||||
        getTimelinesEventsCount(lTimelines) !==
 | 
					        getTimelinesEventsCount(lTimelines) !==
 | 
				
			||||||
          getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate))
 | 
					        getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate))
 | 
				
			||||||
      ) {
 | 
					      ) {
 | 
				
			||||||
        recalibratePagination(lTimelines, timelinesEventsCount, backwards);
 | 
					        recalibratePagination(lTimelines, timelinesEventsCount, backwards);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					@ -437,6 +438,8 @@ const getRoomUnreadInfo = (room: Room, scrollTo = false) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimelineProps) {
 | 
					export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimelineProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const encryptedRoom = mx.isRoomEncrypted(room.roomId);
 | 
					  const encryptedRoom = mx.isRoomEncrypted(room.roomId);
 | 
				
			||||||
  const [messageLayout] = useSetting(settingsAtom, 'messageLayout');
 | 
					  const [messageLayout] = useSetting(settingsAtom, 'messageLayout');
 | 
				
			||||||
  const [messageSpacing] = useSetting(settingsAtom, 'messageSpacing');
 | 
					  const [messageSpacing] = useSetting(settingsAtom, 'messageSpacing');
 | 
				
			||||||
| 
						 | 
					@ -490,10 +493,10 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [focusItem, setFocusItem] = useState<
 | 
					  const [focusItem, setFocusItem] = useState<
 | 
				
			||||||
    | {
 | 
					    | {
 | 
				
			||||||
        index: number;
 | 
					      index: number;
 | 
				
			||||||
        scrollTo: boolean;
 | 
					      scrollTo: boolean;
 | 
				
			||||||
        highlight: boolean;
 | 
					      highlight: boolean;
 | 
				
			||||||
      }
 | 
					    }
 | 
				
			||||||
    | undefined
 | 
					    | undefined
 | 
				
			||||||
  >();
 | 
					  >();
 | 
				
			||||||
  const alive = useAlive();
 | 
					  const alive = useAlive();
 | 
				
			||||||
| 
						 | 
					@ -511,10 +514,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
				
			||||||
    () =>
 | 
					    () =>
 | 
				
			||||||
      getReactCustomHtmlParser(mx, room.roomId, {
 | 
					      getReactCustomHtmlParser(mx, room.roomId, {
 | 
				
			||||||
        linkifyOpts,
 | 
					        linkifyOpts,
 | 
				
			||||||
 | 
					        useAuthentication,
 | 
				
			||||||
        handleSpoilerClick: spoilerClickHandler,
 | 
					        handleSpoilerClick: spoilerClickHandler,
 | 
				
			||||||
        handleMentionClick: mentionClickHandler,
 | 
					        handleMentionClick: mentionClickHandler,
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
    [mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler]
 | 
					    [mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  const parseMemberEvent = useMemberEventParser();
 | 
					  const parseMemberEvent = useMemberEventParser();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1466,14 +1470,14 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
				
			||||||
    const eventJSX = reactionOrEditEvent(mEvent)
 | 
					    const eventJSX = reactionOrEditEvent(mEvent)
 | 
				
			||||||
      ? null
 | 
					      ? null
 | 
				
			||||||
      : renderMatrixEvent(
 | 
					      : renderMatrixEvent(
 | 
				
			||||||
          mEvent.getType(),
 | 
					        mEvent.getType(),
 | 
				
			||||||
          typeof mEvent.getStateKey() === 'string',
 | 
					        typeof mEvent.getStateKey() === 'string',
 | 
				
			||||||
          mEventId,
 | 
					        mEventId,
 | 
				
			||||||
          mEvent,
 | 
					        mEvent,
 | 
				
			||||||
          item,
 | 
					        item,
 | 
				
			||||||
          timelineSet,
 | 
					        timelineSet,
 | 
				
			||||||
          collapsed
 | 
					        collapsed
 | 
				
			||||||
        );
 | 
					      );
 | 
				
			||||||
    prevEvent = mEvent;
 | 
					    prevEvent = mEvent;
 | 
				
			||||||
    isPrevRendered = !!eventJSX;
 | 
					    isPrevRendered = !!eventJSX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1555,9 +1559,8 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
				
			||||||
          {!canPaginateBack && rangeAtStart && getItems().length > 0 && (
 | 
					          {!canPaginateBack && rangeAtStart && getItems().length > 0 && (
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              style={{
 | 
					              style={{
 | 
				
			||||||
                padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${
 | 
					                padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${messageLayout === 1 ? config.space.S400 : toRem(64)
 | 
				
			||||||
                  messageLayout === 1 ? config.space.S400 : toRem(64)
 | 
					                  }`,
 | 
				
			||||||
                }`,
 | 
					 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <RoomIntro room={room} />
 | 
					              <RoomIntro room={room} />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ import { useSetSetting } from '../../state/hooks/settings';
 | 
				
			||||||
import { settingsAtom } from '../../state/settings';
 | 
					import { settingsAtom } from '../../state/settings';
 | 
				
			||||||
import { useSpaceOptionally } from '../../hooks/useSpace';
 | 
					import { useSpaceOptionally } from '../../hooks/useSpace';
 | 
				
			||||||
import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils';
 | 
					import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils';
 | 
				
			||||||
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
 | 
					import { getCanonicalAliasOrRoomId, isRoomAlias, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { _SearchPathSearchParams } from '../../pages/paths';
 | 
					import { _SearchPathSearchParams } from '../../pages/paths';
 | 
				
			||||||
import * as css from './RoomViewHeader.css';
 | 
					import * as css from './RoomViewHeader.css';
 | 
				
			||||||
import { useRoomUnread } from '../../state/hooks/unread';
 | 
					import { useRoomUnread } from '../../state/hooks/unread';
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,7 @@ import { stopPropagation } from '../../utils/keyboard';
 | 
				
			||||||
import { getMatrixToRoom } from '../../plugins/matrix-to';
 | 
					import { getMatrixToRoom } from '../../plugins/matrix-to';
 | 
				
			||||||
import { getViaServers } from '../../plugins/via-servers';
 | 
					import { getViaServers } from '../../plugins/via-servers';
 | 
				
			||||||
import { BackRouteHandler } from '../../components/BackRouteHandler';
 | 
					import { BackRouteHandler } from '../../components/BackRouteHandler';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoomMenuProps = {
 | 
					type RoomMenuProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -174,6 +175,8 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
 | 
				
			||||||
export function RoomViewHeader() {
 | 
					export function RoomViewHeader() {
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const screenSize = useScreenSizeContext();
 | 
					  const screenSize = useScreenSizeContext();
 | 
				
			||||||
  const room = useRoom();
 | 
					  const room = useRoom();
 | 
				
			||||||
  const space = useSpaceOptionally();
 | 
					  const space = useSpaceOptionally();
 | 
				
			||||||
| 
						 | 
					@ -185,7 +188,7 @@ export function RoomViewHeader() {
 | 
				
			||||||
  const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
 | 
					  const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
 | 
				
			||||||
  const name = useRoomName(room);
 | 
					  const name = useRoomName(room);
 | 
				
			||||||
  const topic = useRoomTopic(room);
 | 
					  const topic = useRoomTopic(room);
 | 
				
			||||||
  const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
 | 
					  const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
 | 
					  const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ import {
 | 
				
			||||||
  getMemberAvatarMxc,
 | 
					  getMemberAvatarMxc,
 | 
				
			||||||
  getMemberDisplayName,
 | 
					  getMemberDisplayName,
 | 
				
			||||||
} from '../../../utils/room';
 | 
					} from '../../../utils/room';
 | 
				
			||||||
import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomAlias } from '../../../utils/matrix';
 | 
					import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomAlias, mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
import { MessageLayout, MessageSpacing } from '../../../state/settings';
 | 
					import { MessageLayout, MessageSpacing } from '../../../state/settings';
 | 
				
			||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
				
			||||||
import { useRecentEmoji } from '../../../hooks/useRecentEmoji';
 | 
					import { useRecentEmoji } from '../../../hooks/useRecentEmoji';
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ import { copyToClipboard } from '../../../utils/dom';
 | 
				
			||||||
import { stopPropagation } from '../../../utils/keyboard';
 | 
					import { stopPropagation } from '../../../utils/keyboard';
 | 
				
			||||||
import { getMatrixToRoomEvent } from '../../../plugins/matrix-to';
 | 
					import { getMatrixToRoomEvent } from '../../../plugins/matrix-to';
 | 
				
			||||||
import { getViaServers } from '../../../plugins/via-servers';
 | 
					import { getViaServers } from '../../../plugins/via-servers';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
 | 
					export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,9 +235,9 @@ export const MessageSourceCodeItem = as<
 | 
				
			||||||
  const getContent = (evt: MatrixEvent) =>
 | 
					  const getContent = (evt: MatrixEvent) =>
 | 
				
			||||||
    evt.isEncrypted()
 | 
					    evt.isEncrypted()
 | 
				
			||||||
      ? {
 | 
					      ? {
 | 
				
			||||||
          [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
 | 
					        [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
 | 
				
			||||||
          [`<== ORIGINAL_EVENT ==>`]: evt.event,
 | 
					        [`<== ORIGINAL_EVENT ==>`]: evt.event,
 | 
				
			||||||
        }
 | 
					      }
 | 
				
			||||||
      : evt.event;
 | 
					      : evt.event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getText = (): string => {
 | 
					  const getText = (): string => {
 | 
				
			||||||
| 
						 | 
					@ -650,6 +651,8 @@ export const Message = as<'div', MessageProps>(
 | 
				
			||||||
    ref
 | 
					    ref
 | 
				
			||||||
  ) => {
 | 
					  ) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const senderId = mEvent.getSender() ?? '';
 | 
					    const senderId = mEvent.getSender() ?? '';
 | 
				
			||||||
    const [hover, setHover] = useState(false);
 | 
					    const [hover, setHover] = useState(false);
 | 
				
			||||||
    const { hoverProps } = useHover({ onHoverChange: setHover });
 | 
					    const { hoverProps } = useHover({ onHoverChange: setHover });
 | 
				
			||||||
| 
						 | 
					@ -709,7 +712,7 @@ export const Message = as<'div', MessageProps>(
 | 
				
			||||||
            userId={senderId}
 | 
					            userId={senderId}
 | 
				
			||||||
            src={
 | 
					            src={
 | 
				
			||||||
              senderAvatarMxc
 | 
					              senderAvatarMxc
 | 
				
			||||||
                ? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
 | 
					                ? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined
 | 
				
			||||||
                : undefined
 | 
					                : undefined
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            alt={senderDisplayName}
 | 
					            alt={senderDisplayName}
 | 
				
			||||||
| 
						 | 
					@ -950,26 +953,26 @@ export const Message = as<'div', MessageProps>(
 | 
				
			||||||
                        </Box>
 | 
					                        </Box>
 | 
				
			||||||
                        {((!mEvent.isRedacted() && canDelete) ||
 | 
					                        {((!mEvent.isRedacted() && canDelete) ||
 | 
				
			||||||
                          mEvent.getSender() !== mx.getUserId()) && (
 | 
					                          mEvent.getSender() !== mx.getUserId()) && (
 | 
				
			||||||
                          <>
 | 
					                            <>
 | 
				
			||||||
                            <Line size="300" />
 | 
					                              <Line size="300" />
 | 
				
			||||||
                            <Box direction="Column" gap="100" className={css.MessageMenuGroup}>
 | 
					                              <Box direction="Column" gap="100" className={css.MessageMenuGroup}>
 | 
				
			||||||
                              {!mEvent.isRedacted() && canDelete && (
 | 
					                                {!mEvent.isRedacted() && canDelete && (
 | 
				
			||||||
                                <MessageDeleteItem
 | 
					                                  <MessageDeleteItem
 | 
				
			||||||
                                  room={room}
 | 
					                                    room={room}
 | 
				
			||||||
                                  mEvent={mEvent}
 | 
					                                    mEvent={mEvent}
 | 
				
			||||||
                                  onClose={closeMenu}
 | 
					                                    onClose={closeMenu}
 | 
				
			||||||
                                />
 | 
					                                  />
 | 
				
			||||||
                              )}
 | 
					                                )}
 | 
				
			||||||
                              {mEvent.getSender() !== mx.getUserId() && (
 | 
					                                {mEvent.getSender() !== mx.getUserId() && (
 | 
				
			||||||
                                <MessageReportItem
 | 
					                                  <MessageReportItem
 | 
				
			||||||
                                  room={room}
 | 
					                                    room={room}
 | 
				
			||||||
                                  mEvent={mEvent}
 | 
					                                    mEvent={mEvent}
 | 
				
			||||||
                                  onClose={closeMenu}
 | 
					                                    onClose={closeMenu}
 | 
				
			||||||
                                />
 | 
					                                  />
 | 
				
			||||||
                              )}
 | 
					                                )}
 | 
				
			||||||
                            </Box>
 | 
					                              </Box>
 | 
				
			||||||
                          </>
 | 
					                            </>
 | 
				
			||||||
                        )}
 | 
					                          )}
 | 
				
			||||||
                      </Menu>
 | 
					                      </Menu>
 | 
				
			||||||
                    </FocusTrap>
 | 
					                    </FocusTrap>
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
| 
						 | 
					@ -1093,26 +1096,26 @@ export const Event = as<'div', EventProps>(
 | 
				
			||||||
                        </Box>
 | 
					                        </Box>
 | 
				
			||||||
                        {((!mEvent.isRedacted() && canDelete && !stateEvent) ||
 | 
					                        {((!mEvent.isRedacted() && canDelete && !stateEvent) ||
 | 
				
			||||||
                          (mEvent.getSender() !== mx.getUserId() && !stateEvent)) && (
 | 
					                          (mEvent.getSender() !== mx.getUserId() && !stateEvent)) && (
 | 
				
			||||||
                          <>
 | 
					                            <>
 | 
				
			||||||
                            <Line size="300" />
 | 
					                              <Line size="300" />
 | 
				
			||||||
                            <Box direction="Column" gap="100" className={css.MessageMenuGroup}>
 | 
					                              <Box direction="Column" gap="100" className={css.MessageMenuGroup}>
 | 
				
			||||||
                              {!mEvent.isRedacted() && canDelete && (
 | 
					                                {!mEvent.isRedacted() && canDelete && (
 | 
				
			||||||
                                <MessageDeleteItem
 | 
					                                  <MessageDeleteItem
 | 
				
			||||||
                                  room={room}
 | 
					                                    room={room}
 | 
				
			||||||
                                  mEvent={mEvent}
 | 
					                                    mEvent={mEvent}
 | 
				
			||||||
                                  onClose={closeMenu}
 | 
					                                    onClose={closeMenu}
 | 
				
			||||||
                                />
 | 
					                                  />
 | 
				
			||||||
                              )}
 | 
					                                )}
 | 
				
			||||||
                              {mEvent.getSender() !== mx.getUserId() && (
 | 
					                                {mEvent.getSender() !== mx.getUserId() && (
 | 
				
			||||||
                                <MessageReportItem
 | 
					                                  <MessageReportItem
 | 
				
			||||||
                                  room={room}
 | 
					                                    room={room}
 | 
				
			||||||
                                  mEvent={mEvent}
 | 
					                                    mEvent={mEvent}
 | 
				
			||||||
                                  onClose={closeMenu}
 | 
					                                    onClose={closeMenu}
 | 
				
			||||||
                                />
 | 
					                                  />
 | 
				
			||||||
                              )}
 | 
					                                )}
 | 
				
			||||||
                            </Box>
 | 
					                              </Box>
 | 
				
			||||||
                          </>
 | 
					                            </>
 | 
				
			||||||
                        )}
 | 
					                          )}
 | 
				
			||||||
                      </Menu>
 | 
					                      </Menu>
 | 
				
			||||||
                    </FocusTrap>
 | 
					                    </FocusTrap>
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@ import { useRelations } from '../../../hooks/useRelations';
 | 
				
			||||||
import * as css from './styles.css';
 | 
					import * as css from './styles.css';
 | 
				
			||||||
import { ReactionViewer } from '../reaction-viewer';
 | 
					import { ReactionViewer } from '../reaction-viewer';
 | 
				
			||||||
import { stopPropagation } from '../../../utils/keyboard';
 | 
					import { stopPropagation } from '../../../utils/keyboard';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ReactionsProps = {
 | 
					export type ReactionsProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -33,6 +34,8 @@ export type ReactionsProps = {
 | 
				
			||||||
export const Reactions = as<'div', ReactionsProps>(
 | 
					export const Reactions = as<'div', ReactionsProps>(
 | 
				
			||||||
  ({ className, room, relations, mEventId, canSendReaction, onReactionToggle, ...props }, ref) => {
 | 
					  ({ className, room, relations, mEventId, canSendReaction, onReactionToggle, ...props }, ref) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const [viewer, setViewer] = useState<boolean | string>(false);
 | 
					    const [viewer, setViewer] = useState<boolean | string>(false);
 | 
				
			||||||
    const myUserId = mx.getUserId();
 | 
					    const myUserId = mx.getUserId();
 | 
				
			||||||
    const reactions = useRelations(
 | 
					    const reactions = useRelations(
 | 
				
			||||||
| 
						 | 
					@ -86,6 +89,7 @@ export const Reactions = as<'div', ReactionsProps>(
 | 
				
			||||||
                  onClick={canSendReaction ? () => onReactionToggle(mEventId, key) : undefined}
 | 
					                  onClick={canSendReaction ? () => onReactionToggle(mEventId, key) : undefined}
 | 
				
			||||||
                  onContextMenu={handleViewReaction}
 | 
					                  onContextMenu={handleViewReaction}
 | 
				
			||||||
                  aria-disabled={!canSendReaction}
 | 
					                  aria-disabled={!canSendReaction}
 | 
				
			||||||
 | 
					                  useAuthentication={useAuthentication}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
            </TooltipProvider>
 | 
					            </TooltipProvider>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ import { useRelations } from '../../../hooks/useRelations';
 | 
				
			||||||
import { Reaction } from '../../../components/message';
 | 
					import { Reaction } from '../../../components/message';
 | 
				
			||||||
import { getHexcodeForEmoji, getShortcodeFor } from '../../../plugins/emoji';
 | 
					import { getHexcodeForEmoji, getShortcodeFor } from '../../../plugins/emoji';
 | 
				
			||||||
import { UserAvatar } from '../../../components/user-avatar';
 | 
					import { UserAvatar } from '../../../components/user-avatar';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ReactionViewerProps = {
 | 
					export type ReactionViewerProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -35,6 +36,8 @@ export type ReactionViewerProps = {
 | 
				
			||||||
export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
					export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
				
			||||||
  ({ className, room, initialKey, relations, requestClose, ...props }, ref) => {
 | 
					  ({ className, room, initialKey, relations, requestClose, ...props }, ref) => {
 | 
				
			||||||
    const mx = useMatrixClient();
 | 
					    const mx = useMatrixClient();
 | 
				
			||||||
 | 
					    const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					    const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
    const reactions = useRelations(
 | 
					    const reactions = useRelations(
 | 
				
			||||||
      relations,
 | 
					      relations,
 | 
				
			||||||
      useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], [])
 | 
					      useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], [])
 | 
				
			||||||
| 
						 | 
					@ -81,6 +84,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
				
			||||||
                    count={evts.size}
 | 
					                    count={evts.size}
 | 
				
			||||||
                    aria-selected={key === selectedKey}
 | 
					                    aria-selected={key === selectedKey}
 | 
				
			||||||
                    onClick={() => setSelectedKey(key)}
 | 
					                    onClick={() => setSelectedKey(key)}
 | 
				
			||||||
 | 
					                    useAuthentication={useAuthentication}
 | 
				
			||||||
                  />
 | 
					                  />
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
              })}
 | 
					              })}
 | 
				
			||||||
| 
						 | 
					@ -107,14 +111,16 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
				
			||||||
                  const member = room.getMember(senderId);
 | 
					                  const member = room.getMember(senderId);
 | 
				
			||||||
                  const name = (member ? getName(member) : getMxIdLocalPart(senderId)) ?? senderId;
 | 
					                  const name = (member ? getName(member) : getMxIdLocalPart(senderId)) ?? senderId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  const avatarUrl = member?.getAvatarUrl(
 | 
					                  const avatarMxcUrl = member?.getMxcAvatarUrl();
 | 
				
			||||||
                    mx.baseUrl,
 | 
					                  const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(
 | 
				
			||||||
 | 
					                    avatarMxcUrl,
 | 
				
			||||||
                    100,
 | 
					                    100,
 | 
				
			||||||
                    100,
 | 
					                    100,
 | 
				
			||||||
                    'crop',
 | 
					                    'crop',
 | 
				
			||||||
                    undefined,
 | 
					                    undefined,
 | 
				
			||||||
                    false
 | 
					                    false,
 | 
				
			||||||
                  );
 | 
					                    useAuthentication
 | 
				
			||||||
 | 
					                  ) : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  return (
 | 
					                  return (
 | 
				
			||||||
                    <MenuItem
 | 
					                    <MenuItem
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,9 +22,10 @@ import {
 | 
				
			||||||
  isNotificationEvent,
 | 
					  isNotificationEvent,
 | 
				
			||||||
} from '../../utils/room';
 | 
					} from '../../utils/room';
 | 
				
			||||||
import { NotificationType, UnreadInfo } from '../../../types/matrix/room';
 | 
					import { NotificationType, UnreadInfo } from '../../../types/matrix/room';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
 | 
				
			||||||
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
 | 
					import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
 | 
				
			||||||
import { useInboxNotificationsSelected } from '../../hooks/router/useInbox';
 | 
					import { useInboxNotificationsSelected } from '../../hooks/router/useInbox';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function SystemEmojiFeature() {
 | 
					function SystemEmojiFeature() {
 | 
				
			||||||
  const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
 | 
					  const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
 | 
				
			||||||
| 
						 | 
					@ -132,6 +133,8 @@ function MessageNotifications() {
 | 
				
			||||||
  const notifRef = useRef<Notification>();
 | 
					  const notifRef = useRef<Notification>();
 | 
				
			||||||
  const unreadCacheRef = useRef<Map<string, UnreadInfo>>(new Map());
 | 
					  const unreadCacheRef = useRef<Map<string, UnreadInfo>>(new Map());
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
 | 
					  const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
 | 
				
			||||||
  const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
 | 
					  const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,7 +219,7 @@ function MessageNotifications() {
 | 
				
			||||||
        notify({
 | 
					        notify({
 | 
				
			||||||
          roomName: room.name ?? 'Unknown',
 | 
					          roomName: room.name ?? 'Unknown',
 | 
				
			||||||
          roomAvatar: avatarMxc
 | 
					          roomAvatar: avatarMxc
 | 
				
			||||||
            ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined
 | 
					            ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined
 | 
				
			||||||
            : undefined,
 | 
					            : undefined,
 | 
				
			||||||
          username: getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender) ?? sender,
 | 
					          username: getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender) ?? sender,
 | 
				
			||||||
          roomId: room.roomId,
 | 
					          roomId: room.roomId,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@ import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
 | 
				
			||||||
import { useRoomTopic } from '../../../hooks/useRoomMeta';
 | 
					import { useRoomTopic } from '../../../hooks/useRoomMeta';
 | 
				
			||||||
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
 | 
					import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
 | 
				
			||||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
 | 
					import { BackRouteHandler } from '../../../components/BackRouteHandler';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const COMPACT_CARD_WIDTH = 548;
 | 
					const COMPACT_CARD_WIDTH = 548;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,6 +55,8 @@ type InviteCardProps = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
function InviteCard({ room, userId, direct, compact, onNavigate }: InviteCardProps) {
 | 
					function InviteCard({ room, userId, direct, compact, onNavigate }: InviteCardProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const roomName = room.name || room.getCanonicalAlias() || room.roomId;
 | 
					  const roomName = room.name || room.getCanonicalAlias() || room.roomId;
 | 
				
			||||||
  const member = room.getMember(userId);
 | 
					  const member = room.getMember(userId);
 | 
				
			||||||
  const memberEvent = member?.events.member;
 | 
					  const memberEvent = member?.events.member;
 | 
				
			||||||
| 
						 | 
					@ -110,7 +113,7 @@ function InviteCard({ room, userId, direct, compact, onNavigate }: InviteCardPro
 | 
				
			||||||
        <Avatar size="300">
 | 
					        <Avatar size="300">
 | 
				
			||||||
          <RoomAvatar
 | 
					          <RoomAvatar
 | 
				
			||||||
            roomId={room.roomId}
 | 
					            roomId={room.roomId}
 | 
				
			||||||
            src={direct ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96)}
 | 
					            src={direct ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication)}
 | 
				
			||||||
            alt={roomName}
 | 
					            alt={roomName}
 | 
				
			||||||
            renderFallback={() => (
 | 
					            renderFallback={() => (
 | 
				
			||||||
              <Text as="span" size="H6">
 | 
					              <Text as="span" size="H6">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ import { HTMLReactParserOptions } from 'html-react-parser';
 | 
				
			||||||
import { Opts as LinkifyOpts } from 'linkifyjs';
 | 
					import { Opts as LinkifyOpts } from 'linkifyjs';
 | 
				
			||||||
import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
 | 
					import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
 | 
				
			||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
import { InboxNotificationsPathSearchParams } from '../../paths';
 | 
					import { InboxNotificationsPathSearchParams } from '../../paths';
 | 
				
			||||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 | 
					import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 | 
				
			||||||
import { SequenceCard } from '../../../components/sequence-card';
 | 
					import { SequenceCard } from '../../../components/sequence-card';
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,7 @@ import { useMentionClickHandler } from '../../../hooks/useMentionClickHandler';
 | 
				
			||||||
import { useSpoilerClickHandler } from '../../../hooks/useSpoilerClickHandler';
 | 
					import { useSpoilerClickHandler } from '../../../hooks/useSpoilerClickHandler';
 | 
				
			||||||
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
 | 
					import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
 | 
				
			||||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
 | 
					import { BackRouteHandler } from '../../../components/BackRouteHandler';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoomNotificationsGroup = {
 | 
					type RoomNotificationsGroup = {
 | 
				
			||||||
  roomId: string;
 | 
					  roomId: string;
 | 
				
			||||||
| 
						 | 
					@ -191,6 +192,8 @@ function RoomNotificationsGroupComp({
 | 
				
			||||||
  onOpen,
 | 
					  onOpen,
 | 
				
			||||||
}: RoomNotificationsGroupProps) {
 | 
					}: RoomNotificationsGroupProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
 | 
					  const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
 | 
				
			||||||
  const mentionClickHandler = useMentionClickHandler(room.roomId);
 | 
					  const mentionClickHandler = useMentionClickHandler(room.roomId);
 | 
				
			||||||
  const spoilerClickHandler = useSpoilerClickHandler();
 | 
					  const spoilerClickHandler = useSpoilerClickHandler();
 | 
				
			||||||
| 
						 | 
					@ -208,10 +211,11 @@ function RoomNotificationsGroupComp({
 | 
				
			||||||
    () =>
 | 
					    () =>
 | 
				
			||||||
      getReactCustomHtmlParser(mx, room.roomId, {
 | 
					      getReactCustomHtmlParser(mx, room.roomId, {
 | 
				
			||||||
        linkifyOpts,
 | 
					        linkifyOpts,
 | 
				
			||||||
 | 
					        useAuthentication,
 | 
				
			||||||
        handleSpoilerClick: spoilerClickHandler,
 | 
					        handleSpoilerClick: spoilerClickHandler,
 | 
				
			||||||
        handleMentionClick: mentionClickHandler,
 | 
					        handleMentionClick: mentionClickHandler,
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
    [mx, room, linkifyOpts, mentionClickHandler, spoilerClickHandler]
 | 
					    [mx, room, linkifyOpts, mentionClickHandler, spoilerClickHandler, useAuthentication]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderMatrixEvent = useMatrixEventRenderer<[IRoomEvent, string, GetContentCallback]>(
 | 
					  const renderMatrixEvent = useMatrixEventRenderer<[IRoomEvent, string, GetContentCallback]>(
 | 
				
			||||||
| 
						 | 
					@ -369,7 +373,7 @@ function RoomNotificationsGroupComp({
 | 
				
			||||||
          <Avatar size="200" radii="300">
 | 
					          <Avatar size="200" radii="300">
 | 
				
			||||||
            <RoomAvatar
 | 
					            <RoomAvatar
 | 
				
			||||||
              roomId={room.roomId}
 | 
					              roomId={room.roomId}
 | 
				
			||||||
              src={getRoomAvatarUrl(mx, room, 96)}
 | 
					              src={getRoomAvatarUrl(mx, room, 96, useAuthentication)}
 | 
				
			||||||
              alt={room.name}
 | 
					              alt={room.name}
 | 
				
			||||||
              renderFallback={() => (
 | 
					              renderFallback={() => (
 | 
				
			||||||
                <RoomIcon size="50" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
 | 
					                <RoomIcon size="50" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
 | 
				
			||||||
| 
						 | 
					@ -424,7 +428,7 @@ function RoomNotificationsGroupComp({
 | 
				
			||||||
                        userId={event.sender}
 | 
					                        userId={event.sender}
 | 
				
			||||||
                        src={
 | 
					                        src={
 | 
				
			||||||
                          senderAvatarMxc
 | 
					                          senderAvatarMxc
 | 
				
			||||||
                            ? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
 | 
					                            ? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined
 | 
				
			||||||
                            : undefined
 | 
					                            : undefined
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        alt={displayName}
 | 
					                        alt={displayName}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ import { openInviteUser, openSpaceSettings } from '../../../../client/action/nav
 | 
				
			||||||
import { stopPropagation } from '../../../utils/keyboard';
 | 
					import { stopPropagation } from '../../../utils/keyboard';
 | 
				
			||||||
import { getMatrixToRoom } from '../../../plugins/matrix-to';
 | 
					import { getMatrixToRoom } from '../../../plugins/matrix-to';
 | 
				
			||||||
import { getViaServers } from '../../../plugins/via-servers';
 | 
					import { getViaServers } from '../../../plugins/via-servers';
 | 
				
			||||||
 | 
					import { getRoomAvatarUrl } from '../../../utils/room';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SpaceMenuProps = {
 | 
					type SpaceMenuProps = {
 | 
				
			||||||
  room: Room;
 | 
					  room: Room;
 | 
				
			||||||
| 
						 | 
					@ -225,18 +227,18 @@ const useDraggableItem = (
 | 
				
			||||||
    return !target
 | 
					    return !target
 | 
				
			||||||
      ? undefined
 | 
					      ? undefined
 | 
				
			||||||
      : draggable({
 | 
					      : draggable({
 | 
				
			||||||
          element: target,
 | 
					        element: target,
 | 
				
			||||||
          dragHandle,
 | 
					        dragHandle,
 | 
				
			||||||
          getInitialData: () => ({ item }),
 | 
					        getInitialData: () => ({ item }),
 | 
				
			||||||
          onDragStart: () => {
 | 
					        onDragStart: () => {
 | 
				
			||||||
            setDragging(true);
 | 
					          setDragging(true);
 | 
				
			||||||
            onDragging?.(item);
 | 
					          onDragging?.(item);
 | 
				
			||||||
          },
 | 
					        },
 | 
				
			||||||
          onDrop: () => {
 | 
					        onDrop: () => {
 | 
				
			||||||
            setDragging(false);
 | 
					          setDragging(false);
 | 
				
			||||||
            onDragging?.(undefined);
 | 
					          onDragging?.(undefined);
 | 
				
			||||||
          },
 | 
					        },
 | 
				
			||||||
        });
 | 
					      });
 | 
				
			||||||
  }, [targetRef, dragHandleRef, item, onDragging]);
 | 
					  }, [targetRef, dragHandleRef, item, onDragging]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return dragging;
 | 
					  return dragging;
 | 
				
			||||||
| 
						 | 
					@ -379,15 +381,17 @@ function SpaceTab({
 | 
				
			||||||
  onUnpin,
 | 
					  onUnpin,
 | 
				
			||||||
}: SpaceTabProps) {
 | 
					}: SpaceTabProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const targetRef = useRef<HTMLDivElement>(null);
 | 
					  const targetRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const spaceDraggable: SidebarDraggable = useMemo(
 | 
					  const spaceDraggable: SidebarDraggable = useMemo(
 | 
				
			||||||
    () =>
 | 
					    () =>
 | 
				
			||||||
      folder
 | 
					      folder
 | 
				
			||||||
        ? {
 | 
					        ? {
 | 
				
			||||||
            folder,
 | 
					          folder,
 | 
				
			||||||
            spaceId: space.roomId,
 | 
					          spaceId: space.roomId,
 | 
				
			||||||
          }
 | 
					        }
 | 
				
			||||||
        : space.roomId,
 | 
					        : space.roomId,
 | 
				
			||||||
    [folder, space]
 | 
					    [folder, space]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					@ -431,7 +435,7 @@ function SpaceTab({
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <RoomAvatar
 | 
					                <RoomAvatar
 | 
				
			||||||
                  roomId={space.roomId}
 | 
					                  roomId={space.roomId}
 | 
				
			||||||
                  src={space.getAvatarUrl(mx.baseUrl, 96, 96, 'crop') ?? undefined}
 | 
					                  src={getRoomAvatarUrl(mx, space, 96, useAuthentication) ?? undefined}
 | 
				
			||||||
                  alt={space.name}
 | 
					                  alt={space.name}
 | 
				
			||||||
                  renderFallback={() => (
 | 
					                  renderFallback={() => (
 | 
				
			||||||
                    <Text size={folder ? 'H6' : 'H4'}>{nameInitials(space.name, 2)}</Text>
 | 
					                    <Text size={folder ? 'H6' : 'H4'}>{nameInitials(space.name, 2)}</Text>
 | 
				
			||||||
| 
						 | 
					@ -524,6 +528,8 @@ function ClosedSpaceFolder({
 | 
				
			||||||
  disabled,
 | 
					  disabled,
 | 
				
			||||||
}: ClosedSpaceFolderProps) {
 | 
					}: ClosedSpaceFolderProps) {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const handlerRef = useRef<HTMLDivElement>(null);
 | 
					  const handlerRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const spaceDraggable: FolderDraggable = useMemo(() => ({ folder }), [folder]);
 | 
					  const spaceDraggable: FolderDraggable = useMemo(() => ({ folder }), [folder]);
 | 
				
			||||||
| 
						 | 
					@ -556,7 +562,7 @@ function ClosedSpaceFolder({
 | 
				
			||||||
                    <SidebarAvatar key={sId} size="200" radii="300">
 | 
					                    <SidebarAvatar key={sId} size="200" radii="300">
 | 
				
			||||||
                      <RoomAvatar
 | 
					                      <RoomAvatar
 | 
				
			||||||
                        roomId={space.roomId}
 | 
					                        roomId={space.roomId}
 | 
				
			||||||
                        src={space.getAvatarUrl(mx.baseUrl, 96, 96, 'crop') ?? undefined}
 | 
					                        src={getRoomAvatarUrl(mx, space, 96, useAuthentication) ?? undefined}
 | 
				
			||||||
                        alt={space.name}
 | 
					                        alt={space.name}
 | 
				
			||||||
                        renderFallback={() => (
 | 
					                        renderFallback={() => (
 | 
				
			||||||
                          <Text size="Inherit">
 | 
					                          <Text size="Inherit">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,9 @@ import { SidebarItem, SidebarItemTooltip, SidebarAvatar } from '../../../compone
 | 
				
			||||||
import { openSettings } from '../../../../client/action/navigation';
 | 
					import { openSettings } from '../../../../client/action/navigation';
 | 
				
			||||||
import { UserAvatar } from '../../../components/user-avatar';
 | 
					import { UserAvatar } from '../../../components/user-avatar';
 | 
				
			||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
					import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
				
			||||||
import { getMxIdLocalPart } from '../../../utils/matrix';
 | 
					import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix';
 | 
				
			||||||
import { nameInitials } from '../../../utils/common';
 | 
					import { nameInitials } from '../../../utils/common';
 | 
				
			||||||
 | 
					import { useSpecVersions } from '../../../hooks/useSpecVersions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UserProfile = {
 | 
					type UserProfile = {
 | 
				
			||||||
  avatar_url?: string;
 | 
					  avatar_url?: string;
 | 
				
			||||||
| 
						 | 
					@ -14,12 +15,14 @@ type UserProfile = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export function UserTab() {
 | 
					export function UserTab() {
 | 
				
			||||||
  const mx = useMatrixClient();
 | 
					  const mx = useMatrixClient();
 | 
				
			||||||
 | 
					  const { versions } = useSpecVersions();
 | 
				
			||||||
 | 
					  const useAuthentication = versions.includes('v1.11');
 | 
				
			||||||
  const userId = mx.getUserId()!;
 | 
					  const userId = mx.getUserId()!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [profile, setProfile] = useState<UserProfile>({});
 | 
					  const [profile, setProfile] = useState<UserProfile>({});
 | 
				
			||||||
  const displayName = profile.displayname ?? getMxIdLocalPart(userId) ?? userId;
 | 
					  const displayName = profile.displayname ?? getMxIdLocalPart(userId) ?? userId;
 | 
				
			||||||
  const avatarUrl = profile.avatar_url
 | 
					  const avatarUrl = profile.avatar_url
 | 
				
			||||||
    ? mx.mxcUrlToHttp(profile.avatar_url, 96, 96, 'crop') ?? undefined
 | 
					    ? mxcUrlToHttp(mx, profile.avatar_url, useAuthentication, 96, 96, 'crop') ?? undefined
 | 
				
			||||||
    : undefined;
 | 
					    : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ import { IntermediateRepresentation, Opts as LinkifyOpts, OptFn } from 'linkifyj
 | 
				
			||||||
import Linkify from 'linkify-react';
 | 
					import Linkify from 'linkify-react';
 | 
				
			||||||
import { ErrorBoundary } from 'react-error-boundary';
 | 
					import { ErrorBoundary } from 'react-error-boundary';
 | 
				
			||||||
import * as css from '../styles/CustomHtml.css';
 | 
					import * as css from '../styles/CustomHtml.css';
 | 
				
			||||||
import { getMxIdLocalPart, getCanonicalAliasRoomId, isRoomAlias } from '../utils/matrix';
 | 
					import { getMxIdLocalPart, getCanonicalAliasRoomId, isRoomAlias, mxcUrlToHttp } from '../utils/matrix';
 | 
				
			||||||
import { getMemberDisplayName } from '../utils/room';
 | 
					import { getMemberDisplayName } from '../utils/room';
 | 
				
			||||||
import { EMOJI_PATTERN, URL_NEG_LB } from '../utils/regex';
 | 
					import { EMOJI_PATTERN, URL_NEG_LB } from '../utils/regex';
 | 
				
			||||||
import { getHexcodeForEmoji, getShortcodeFor } from './emoji';
 | 
					import { getHexcodeForEmoji, getShortcodeFor } from './emoji';
 | 
				
			||||||
| 
						 | 
					@ -72,9 +72,8 @@ export const renderMatrixMention = (
 | 
				
			||||||
        className={css.Mention({ highlight: mx.getUserId() === userId })}
 | 
					        className={css.Mention({ highlight: mx.getUserId() === userId })}
 | 
				
			||||||
        data-mention-id={userId}
 | 
					        data-mention-id={userId}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {`@${
 | 
					        {`@${(currentRoom && getMemberDisplayName(currentRoom, userId)) ?? getMxIdLocalPart(userId)
 | 
				
			||||||
          (currentRoom && getMemberDisplayName(currentRoom, userId)) ?? getMxIdLocalPart(userId)
 | 
					          }`}
 | 
				
			||||||
        }`}
 | 
					 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -192,6 +191,7 @@ export const getReactCustomHtmlParser = (
 | 
				
			||||||
    highlightRegex?: RegExp;
 | 
					    highlightRegex?: RegExp;
 | 
				
			||||||
    handleSpoilerClick?: ReactEventHandler<HTMLElement>;
 | 
					    handleSpoilerClick?: ReactEventHandler<HTMLElement>;
 | 
				
			||||||
    handleMentionClick?: ReactEventHandler<HTMLElement>;
 | 
					    handleMentionClick?: ReactEventHandler<HTMLElement>;
 | 
				
			||||||
 | 
					    useAuthentication?: boolean;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
): HTMLReactParserOptions => {
 | 
					): HTMLReactParserOptions => {
 | 
				
			||||||
  const opts: HTMLReactParserOptions = {
 | 
					  const opts: HTMLReactParserOptions = {
 | 
				
			||||||
| 
						 | 
					@ -354,7 +354,7 @@ export const getReactCustomHtmlParser = (
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (name === 'img') {
 | 
					        if (name === 'img') {
 | 
				
			||||||
          const htmlSrc = mx.mxcUrlToHttp(props.src);
 | 
					          const htmlSrc = mxcUrlToHttp(mx, props.src, params.useAuthentication);
 | 
				
			||||||
          if (htmlSrc && props.src.startsWith('mxc://') === false) {
 | 
					          if (htmlSrc && props.src.startsWith('mxc://') === false) {
 | 
				
			||||||
            return (
 | 
					            return (
 | 
				
			||||||
              <a href={htmlSrc} target="_blank" rel="noreferrer noopener">
 | 
					              <a href={htmlSrc} target="_blank" rel="noreferrer noopener">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,3 +253,23 @@ export const removeRoomIdFromMDirect = async (mx: MatrixClient, roomId: string):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await mx.setAccountData(AccountDataEvent.Direct, userIdToRoomIds);
 | 
					  await mx.setAccountData(AccountDataEvent.Direct, userIdToRoomIds);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mxcUrlToHttp = (
 | 
				
			||||||
 | 
					  mx: MatrixClient,
 | 
				
			||||||
 | 
					  mxcUrl: string,
 | 
				
			||||||
 | 
					  useAuthentication?: boolean,
 | 
				
			||||||
 | 
					  width?: number,
 | 
				
			||||||
 | 
					  height?: number,
 | 
				
			||||||
 | 
					  resizeMethod?: string,
 | 
				
			||||||
 | 
					  allowDirectLinks?: boolean,
 | 
				
			||||||
 | 
					  allowRedirects?: boolean
 | 
				
			||||||
 | 
					): string | null =>
 | 
				
			||||||
 | 
					  mx.mxcUrlToHttp(
 | 
				
			||||||
 | 
					    mxcUrl,
 | 
				
			||||||
 | 
					    width,
 | 
				
			||||||
 | 
					    height,
 | 
				
			||||||
 | 
					    resizeMethod,
 | 
				
			||||||
 | 
					    allowDirectLinks,
 | 
				
			||||||
 | 
					    allowRedirects,
 | 
				
			||||||
 | 
					    useAuthentication
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,16 +273,26 @@ export const joinRuleToIconSrc = (
 | 
				
			||||||
export const getRoomAvatarUrl = (
 | 
					export const getRoomAvatarUrl = (
 | 
				
			||||||
  mx: MatrixClient,
 | 
					  mx: MatrixClient,
 | 
				
			||||||
  room: Room,
 | 
					  room: Room,
 | 
				
			||||||
  size: 32 | 96 = 32
 | 
					  size: 32 | 96 = 32,
 | 
				
			||||||
): string | undefined => room.getAvatarUrl(mx.baseUrl, size, size, 'crop') ?? undefined;
 | 
					  useAuthentication = false
 | 
				
			||||||
 | 
					): string | undefined => {
 | 
				
			||||||
 | 
					  const mxcUrl = room.getMxcAvatarUrl();
 | 
				
			||||||
 | 
					  return mxcUrl
 | 
				
			||||||
 | 
					    ? mx.mxcUrlToHttp(mxcUrl, size, size, 'crop', undefined, false, useAuthentication) ?? undefined
 | 
				
			||||||
 | 
					    : undefined;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getDirectRoomAvatarUrl = (
 | 
					export const getDirectRoomAvatarUrl = (
 | 
				
			||||||
  mx: MatrixClient,
 | 
					  mx: MatrixClient,
 | 
				
			||||||
  room: Room,
 | 
					  room: Room,
 | 
				
			||||||
  size: 32 | 96 = 32
 | 
					  size: 32 | 96 = 32,
 | 
				
			||||||
): string | undefined =>
 | 
					  useAuthentication = false
 | 
				
			||||||
  room.getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, size, size, 'crop', undefined, false) ??
 | 
					): string | undefined => {
 | 
				
			||||||
  undefined;
 | 
					  const mxcUrl = room.getAvatarFallbackMember()?.getMxcAvatarUrl();
 | 
				
			||||||
 | 
					  return mxcUrl
 | 
				
			||||||
 | 
					    ? mx.mxcUrlToHttp(mxcUrl, size, size, 'crop', undefined, false, useAuthentication) ?? undefined
 | 
				
			||||||
 | 
					    : undefined;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const trimReplyFromBody = (body: string): string => {
 | 
					export const trimReplyFromBody = (body: string): string => {
 | 
				
			||||||
  const match = body.match(/^> <.+?> .+\n(>.*\n)*?\n/m);
 | 
					  const match = body.match(/^> <.+?> .+\n(>.*\n)*?\n/m);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,6 @@ export const initClient = async (session: Session): Promise<MatrixClient> => {
 | 
				
			||||||
    localStorage: global.localStorage,
 | 
					    localStorage: global.localStorage,
 | 
				
			||||||
    dbName: 'web-sync-store',
 | 
					    dbName: 'web-sync-store',
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  await indexedDBStore.startup();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const mx = createClient({
 | 
					  const mx = createClient({
 | 
				
			||||||
    baseUrl: session.baseUrl,
 | 
					    baseUrl: session.baseUrl,
 | 
				
			||||||
| 
						 | 
					@ -38,6 +37,7 @@ export const initClient = async (session: Session): Promise<MatrixClient> => {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await mx.initCrypto();
 | 
					  await mx.initCrypto();
 | 
				
			||||||
 | 
					  await indexedDBStore.startup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mx.setGlobalErrorOnUnknownDevices(false);
 | 
					  mx.setGlobalErrorOnUnknownDevices(false);
 | 
				
			||||||
  mx.setMaxListeners(50);
 | 
					  mx.setMaxListeners(50);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@ import './index.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import settings from './client/state/settings';
 | 
					import settings from './client/state/settings';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { trimTrailingSlash } from './app/utils/common';
 | 
				
			||||||
import App from './app/pages/App';
 | 
					import App from './app/pages/App';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// import i18n (needs to be bundled ;))
 | 
					// import i18n (needs to be bundled ;))
 | 
				
			||||||
| 
						 | 
					@ -20,6 +21,23 @@ import './app/i18n';
 | 
				
			||||||
document.body.classList.add(configClass, varsClass);
 | 
					document.body.classList.add(configClass, varsClass);
 | 
				
			||||||
settings.applyTheme();
 | 
					settings.applyTheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Register Service Worker
 | 
				
			||||||
 | 
					if ('serviceWorker' in navigator) {
 | 
				
			||||||
 | 
					  navigator.serviceWorker.register(
 | 
				
			||||||
 | 
					    import.meta.env.MODE === 'production' ? `${trimTrailingSlash(import.meta.env.BASE_URL)}/sw.js` : '/dev-sw.js?dev-sw'
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					  navigator.serviceWorker.addEventListener('message', (event) => {
 | 
				
			||||||
 | 
					    if (event.data?.type === 'token' && event.data?.responseKey) {
 | 
				
			||||||
 | 
					      // Get the token for SW.
 | 
				
			||||||
 | 
					      const token = localStorage.getItem('cinny_access_token');
 | 
				
			||||||
 | 
					      event.source!.postMessage({
 | 
				
			||||||
 | 
					        responseKey: event.data.responseKey,
 | 
				
			||||||
 | 
					        token,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mountApp = () => {
 | 
					const mountApp = () => {
 | 
				
			||||||
  const rootContainer = document.getElementById('root');
 | 
					  const rootContainer = document.getElementById('root');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/sw.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/sw.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					async function askForAccessToken(client: Client): Promise<string | undefined> {
 | 
				
			||||||
 | 
					  return new Promise((resolve) => {
 | 
				
			||||||
 | 
					    const responseKey = Math.random().toString(36);
 | 
				
			||||||
 | 
					    const listener = (event: ExtendableMessageEvent) => {
 | 
				
			||||||
 | 
					      if (event.data.responseKey !== responseKey) return;
 | 
				
			||||||
 | 
					      resolve(event.data.token);
 | 
				
			||||||
 | 
					      self.removeEventListener('message', listener);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    self.addEventListener('message', listener);
 | 
				
			||||||
 | 
					    client.postMessage({ responseKey, type: 'token' });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fetchConfig(token?: string): RequestInit | undefined {
 | 
				
			||||||
 | 
					  if (!token) return undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    headers: {
 | 
				
			||||||
 | 
					      Authorization: `Bearer ${token}`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					self.addEventListener('fetch', (event: FetchEvent) => {
 | 
				
			||||||
 | 
					  const { url, method } = event.request;
 | 
				
			||||||
 | 
					  if (method !== 'GET') return;
 | 
				
			||||||
 | 
					  if (
 | 
				
			||||||
 | 
					    !url.includes('/_matrix/client/v1/media/download') &&
 | 
				
			||||||
 | 
					    !url.includes('/_matrix/client/v1/media/thumbnail')
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  event.respondWith(
 | 
				
			||||||
 | 
					    (async (): Promise<Response> => {
 | 
				
			||||||
 | 
					      const client = await clients.get(event.clientId);
 | 
				
			||||||
 | 
					      let token: string | undefined;
 | 
				
			||||||
 | 
					      if (client) token = await askForAccessToken(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // eslint-disable-next-line consistent-return
 | 
				
			||||||
 | 
					      return fetch(url, fetchConfig(token));
 | 
				
			||||||
 | 
					    })()
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,8 @@
 | 
				
			||||||
    "moduleResolution": "Node",
 | 
					    "moduleResolution": "Node",
 | 
				
			||||||
    "resolveJsonModule": true,
 | 
					    "resolveJsonModule": true,
 | 
				
			||||||
    "outDir": "dist",
 | 
					    "outDir": "dist",
 | 
				
			||||||
    "skipLibCheck": true
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					    "lib": ["ES2016", "DOM"]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "exclude": ["node_modules", "dist"],
 | 
					  "exclude": ["node_modules", "dist"],
 | 
				
			||||||
  "include": ["src"]
 | 
					  "include": ["src"]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
 | 
				
			||||||
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
 | 
					import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
 | 
				
			||||||
import inject from '@rollup/plugin-inject';
 | 
					import inject from '@rollup/plugin-inject';
 | 
				
			||||||
import topLevelAwait from 'vite-plugin-top-level-await';
 | 
					import topLevelAwait from 'vite-plugin-top-level-await';
 | 
				
			||||||
 | 
					import { VitePWA } from 'vite-plugin-pwa';
 | 
				
			||||||
import buildConfig from './build.config';
 | 
					import buildConfig from './build.config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const copyFiles = {
 | 
					const copyFiles = {
 | 
				
			||||||
| 
						 | 
					@ -50,11 +51,11 @@ export default defineConfig({
 | 
				
			||||||
    port: 8080,
 | 
					    port: 8080,
 | 
				
			||||||
    host: true,
 | 
					    host: true,
 | 
				
			||||||
    proxy: {
 | 
					    proxy: {
 | 
				
			||||||
      "^\\/.*?\\/olm\\.wasm$": {
 | 
					      '^\\/.*?\\/olm\\.wasm$': {
 | 
				
			||||||
        target: 'http://localhost:8080',
 | 
					        target: 'http://localhost:8080',
 | 
				
			||||||
        rewrite: () => '/olm.wasm'
 | 
					        rewrite: () => '/olm.wasm',
 | 
				
			||||||
      }
 | 
					      },
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  plugins: [
 | 
					  plugins: [
 | 
				
			||||||
    topLevelAwait({
 | 
					    topLevelAwait({
 | 
				
			||||||
| 
						 | 
					@ -67,6 +68,16 @@ export default defineConfig({
 | 
				
			||||||
    vanillaExtractPlugin(),
 | 
					    vanillaExtractPlugin(),
 | 
				
			||||||
    wasm(),
 | 
					    wasm(),
 | 
				
			||||||
    react(),
 | 
					    react(),
 | 
				
			||||||
 | 
					    VitePWA({
 | 
				
			||||||
 | 
					      srcDir: 'src',
 | 
				
			||||||
 | 
					      filename: 'sw.ts',
 | 
				
			||||||
 | 
					      strategies: 'injectManifest',
 | 
				
			||||||
 | 
					      injectRegister: false,
 | 
				
			||||||
 | 
					      manifest: false,
 | 
				
			||||||
 | 
					      injectManifest: {
 | 
				
			||||||
 | 
					        injectionPoint: undefined,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  optimizeDeps: {
 | 
					  optimizeDeps: {
 | 
				
			||||||
    esbuildOptions: {
 | 
					    esbuildOptions: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue