Remember room scroll position across switches, reserve image/video heights from Matrix dimensions, cache authenticated media blobs for avatars, restore jumbo emoji-only messages, and extend emoji font unicode-range for Unicode 15 glyphs.
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { useMatrixClient } from './useMatrixClient';
|
|
import {
|
|
getCachedAuthenticatedMediaUrl,
|
|
isAuthenticatedMediaUrl,
|
|
resolveAuthenticatedMediaUrl,
|
|
} from '../utils/authenticatedMediaCache';
|
|
|
|
/**
|
|
* Resolves media URLs for Matrix authenticated media.
|
|
* Uses a shared blob-URL cache so avatars/thumbs are not re-fetched on every remount.
|
|
*/
|
|
export const useAuthenticatedMediaUrl = (
|
|
src: string | undefined,
|
|
useAuthentication: boolean
|
|
): string | undefined => {
|
|
const mx = useMatrixClient();
|
|
const [blobUrl, setBlobUrl] = useState<string | undefined>(() => {
|
|
if (!src) return undefined;
|
|
if (!useAuthentication || !isAuthenticatedMediaUrl(src)) return src;
|
|
return getCachedAuthenticatedMediaUrl(src);
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!src) {
|
|
setBlobUrl(undefined);
|
|
return undefined;
|
|
}
|
|
|
|
if (!useAuthentication || !isAuthenticatedMediaUrl(src)) {
|
|
setBlobUrl(src);
|
|
return undefined;
|
|
}
|
|
|
|
const cached = getCachedAuthenticatedMediaUrl(src);
|
|
if (cached) {
|
|
setBlobUrl(cached);
|
|
return undefined;
|
|
}
|
|
|
|
let cancelled = false;
|
|
|
|
resolveAuthenticatedMediaUrl(src, useAuthentication)
|
|
.then((url) => {
|
|
if (!cancelled) setBlobUrl(url);
|
|
})
|
|
.catch((error) => {
|
|
console.warn('[useAuthenticatedMediaUrl] Error fetching authenticated media:', error);
|
|
if (!cancelled) setBlobUrl(src);
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
// Shared cache owns blob URLs — do not revoke on unmount.
|
|
};
|
|
}, [src, useAuthentication, mx]);
|
|
|
|
return blobUrl;
|
|
};
|
|
|
|
/**
|
|
* Creates an authenticated fetch function for media URLs.
|
|
* Useful for components that need to load multiple images.
|
|
*/
|
|
export const useAuthenticatedMediaFetch = () => {
|
|
const mx = useMatrixClient();
|
|
|
|
return useCallback(
|
|
async (src: string, useAuthentication = true): Promise<string> => {
|
|
try {
|
|
return await resolveAuthenticatedMediaUrl(src, useAuthentication);
|
|
} catch (error) {
|
|
console.warn('[useAuthenticatedMediaFetch] Error fetching authenticated media:', error);
|
|
return src;
|
|
}
|
|
},
|
|
[mx]
|
|
);
|
|
};
|