fix: ctrl+p print dialog, gallery 400 error, poll multi-choice UX
- Suppress Ctrl+P browser print dialog via SuppressPrintShortcut in ClientNonUIFeatures (no UI opened, just preventDefault) - mxcUrlToHttp: build URL manually instead of delegating to SDK. The SDK forces allow_redirect=true when useAuthentication=true; Synapse's /_matrix/client/v1/media/thumbnail rejects that with 400. Manual construction omits allow_redirect entirely. - Gallery: redesign using folds color tokens (color.Surface.*) instead of non-existent CSS custom properties; add ThumbState so broken images show an icon placeholder; use useAuthentication for thumbnails now that the URL builder is fixed; "Load More" always visible. - PollCreator: replace raw <button> with folds Button components so the Single/Multiple choice toggle renders with actual visual difference. - PollContent: support multiple-choice polls end-to-end — myVote:string → myVotes:Set<string>; computeVotes collects all m.selections (not just [0]); toggle-select for multi, radio for single; checkbox/radio indicator icons next to each option; "◉ Poll · Multiple choice" / "Single choice" label in header; sends full selections array on every vote event. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+24
-12
@@ -284,18 +284,30 @@ export const mxcUrlToHttp = (
|
||||
height?: number,
|
||||
resizeMethod?: string,
|
||||
allowDirectLinks?: boolean,
|
||||
// Synapse's thumbnail endpoint returns 400 for allow_redirect=true; keep false everywhere.
|
||||
allowRedirects = false,
|
||||
): string | null =>
|
||||
mx.mxcUrlToHttp(
|
||||
mxcUrl,
|
||||
width,
|
||||
height,
|
||||
resizeMethod,
|
||||
allowDirectLinks,
|
||||
allowRedirects,
|
||||
useAuthentication,
|
||||
);
|
||||
): string | null => {
|
||||
// Build the URL manually so we never add allow_redirect.
|
||||
// The SDK forces allow_redirect=true when useAuthentication=true, but Synapse's
|
||||
// /_matrix/client/v1/media/thumbnail endpoint rejects that parameter with 400.
|
||||
if (!mxcUrl) return null;
|
||||
if (!mxcUrl.startsWith('mxc://')) {
|
||||
return allowDirectLinks ? mxcUrl : null;
|
||||
}
|
||||
const parts = mxcUrl.slice(6).split('/');
|
||||
if (parts.length !== 2 || !parts[0] || !parts[1]) return null;
|
||||
const [serverName, mediaId] = parts;
|
||||
|
||||
const isThumbnail = !!(width || height || resizeMethod);
|
||||
const verb = isThumbnail ? 'thumbnail' : 'download';
|
||||
const prefix = useAuthentication
|
||||
? `/_matrix/client/v1/media/${verb}`
|
||||
: `/_matrix/media/v3/${verb}`;
|
||||
|
||||
const url = new URL(`${prefix}/${serverName}/${mediaId}`, mx.getHomeserverUrl());
|
||||
if (width) url.searchParams.set('width', String(Math.round(width)));
|
||||
if (height) url.searchParams.set('height', String(Math.round(height)));
|
||||
if (resizeMethod) url.searchParams.set('method', resizeMethod);
|
||||
return url.href;
|
||||
};
|
||||
|
||||
export const downloadMedia = async (src: string): Promise<Blob> => {
|
||||
// this request is authenticated by service worker
|
||||
|
||||
Reference in New Issue
Block a user