Merge branch 'develop' into dbkr/stateafter
This commit is contained in:
commit
cb0d72fc2f
32 changed files with 200 additions and 135 deletions
|
@ -8,10 +8,10 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import React, { ReactNode } from "react";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
import { RestartIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import AccessibleButton from "../../../views/elements/AccessibleButton";
|
||||
import { Icon as EMailPromptIcon } from "../../../../../res/img/element-icons/email-prompt.svg";
|
||||
import { Icon as RetryIcon } from "../../../../../res/img/compound/retry-16px.svg";
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import { useTimeoutToggle } from "../../../../hooks/useTimeoutToggle";
|
||||
import { ErrorMessage } from "../../ErrorMessage";
|
||||
|
@ -60,7 +60,7 @@ export const CheckEmail: React.FC<CheckEmailProps> = ({
|
|||
<span className="mx_VerifyEMailDialog_text-light">{_t("auth|check_email_resend_prompt")}</span>
|
||||
<Tooltip description={_t("auth|check_email_resend_tooltip")} placement="top" open={tooltipVisible}>
|
||||
<AccessibleButton className="mx_AuthBody_resend-button" kind="link" onClick={onResendClickFn}>
|
||||
<RetryIcon className="mx_Icon mx_Icon_16" />
|
||||
<RestartIcon className="mx_Icon mx_Icon_16" />
|
||||
{_t("action|resend")}
|
||||
</AccessibleButton>
|
||||
</Tooltip>
|
||||
|
|
|
@ -8,10 +8,10 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import React, { ReactNode } from "react";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
import { RestartIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import AccessibleButton from "../../../views/elements/AccessibleButton";
|
||||
import { Icon as RetryIcon } from "../../../../../res/img/compound/retry-16px.svg";
|
||||
import { Icon as EmailPromptIcon } from "../../../../../res/img/element-icons/email-prompt.svg";
|
||||
import { useTimeoutToggle } from "../../../../hooks/useTimeoutToggle";
|
||||
import { ErrorMessage } from "../../ErrorMessage";
|
||||
|
@ -59,7 +59,7 @@ export const VerifyEmailModal: React.FC<Props> = ({
|
|||
<span className="mx_VerifyEMailDialog_text-light">{_t("auth|check_email_resend_prompt")}</span>
|
||||
<Tooltip description={_t("auth|check_email_resend_tooltip")} placement="top" open={tooltipVisible}>
|
||||
<AccessibleButton className="mx_AuthBody_resend-button" kind="link" onClick={onResendClickFn}>
|
||||
<RetryIcon className="mx_Icon mx_Icon_16" />
|
||||
<RestartIcon className="mx_Icon mx_Icon_16" />
|
||||
{_t("action|resend")}
|
||||
</AccessibleButton>
|
||||
</Tooltip>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Room, EventType } from "matrix-js-sdk/src/matrix";
|
|||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t, _td, TranslationKey } from "../../../languageHandler";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
|
@ -34,7 +35,6 @@ import LazyRenderList from "../elements/LazyRenderList";
|
|||
import { useSettingValue } from "../../../hooks/useSettings";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
import WarningBadgeSvg from "../../../../res/img/element-icons/warning-badge.svg";
|
||||
|
||||
// These values match CSS
|
||||
const ROW_HEIGHT = 32 + 12;
|
||||
|
@ -229,7 +229,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
if (error) {
|
||||
footer = (
|
||||
<>
|
||||
<img src={WarningBadgeSvg} height="24" width="24" alt="" />
|
||||
<ErrorIcon height="24px" width="24px" />
|
||||
|
||||
<span className="mx_AddExistingToSpaceDialog_error">
|
||||
<div className="mx_AddExistingToSpaceDialog_errorHeading">
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
WidgetApiFromWidgetAction,
|
||||
WidgetKind,
|
||||
} from "matrix-widget-api";
|
||||
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { _t, getUserLanguage } from "../../../languageHandler";
|
||||
|
@ -33,7 +34,6 @@ import { arrayFastClone } from "../../../utils/arrays";
|
|||
import { ElementWidget } from "../../../stores/widgets/StopGapWidget";
|
||||
import { ELEMENT_CLIENT_ID } from "../../../identifiers";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import WarningBadgeSvg from "../../../../res/img/element-icons/warning-badge.svg";
|
||||
|
||||
interface IProps {
|
||||
widgetDefinition: IModalWidgetOpenRequestData;
|
||||
|
@ -186,7 +186,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
|||
onFinished={this.props.onFinished}
|
||||
>
|
||||
<div className="mx_ModalWidgetDialog_warning">
|
||||
<img src={WarningBadgeSvg} height="16" width="16" alt="" />
|
||||
<ErrorIcon width="16px" height="16px" />
|
||||
{_t("widget|modal_data_warning", {
|
||||
widgetDomain: parsed.hostname,
|
||||
})}
|
||||
|
|
|
@ -8,9 +8,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, CSSProperties } from "react";
|
||||
import React, { createRef, CSSProperties, useRef, useState } from "react";
|
||||
import FocusLock from "react-focus-lock";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixEvent, parseErrorResponse } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
|
@ -30,6 +30,9 @@ import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
|||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { presentableTextForFile } from "../../../utils/FileUtils";
|
||||
import AccessibleButton from "./AccessibleButton";
|
||||
import Modal from "../../../Modal";
|
||||
import ErrorDialog from "../dialogs/ErrorDialog";
|
||||
import { FileDownloader } from "../../../utils/FileDownloader";
|
||||
|
||||
// Max scale to keep gaps around the image
|
||||
const MAX_SCALE = 0.95;
|
||||
|
@ -309,15 +312,6 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
this.setZoomAndRotation(cur + 90);
|
||||
};
|
||||
|
||||
private onDownloadClick = (): void => {
|
||||
const a = document.createElement("a");
|
||||
a.href = this.props.src;
|
||||
if (this.props.name) a.download = this.props.name;
|
||||
a.target = "_blank";
|
||||
a.rel = "noreferrer noopener";
|
||||
a.click();
|
||||
};
|
||||
|
||||
private onOpenContextMenu = (): void => {
|
||||
this.setState({
|
||||
contextMenuDisplayed: true,
|
||||
|
@ -555,11 +549,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
title={_t("lightbox|rotate_right")}
|
||||
onClick={this.onRotateClockwiseClick}
|
||||
/>
|
||||
<AccessibleButton
|
||||
className="mx_ImageView_button mx_ImageView_button_download"
|
||||
title={_t("action|download")}
|
||||
onClick={this.onDownloadClick}
|
||||
/>
|
||||
<DownloadButton url={this.props.src} fileName={this.props.name} />
|
||||
{contextMenuButton}
|
||||
<AccessibleButton
|
||||
className="mx_ImageView_button mx_ImageView_button_close"
|
||||
|
@ -591,3 +581,61 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
function DownloadButton({ url, fileName }: { url: string; fileName?: string }): JSX.Element {
|
||||
const downloader = useRef(new FileDownloader()).current;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const blobRef = useRef<Blob>();
|
||||
|
||||
function showError(e: unknown): void {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("timeline|download_failed"),
|
||||
description: (
|
||||
<>
|
||||
<div>{_t("timeline|download_failed_description")}</div>
|
||||
<div>{e instanceof Error ? e.toString() : ""}</div>
|
||||
</>
|
||||
),
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const onDownloadClick = async (): Promise<void> => {
|
||||
try {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
if (blobRef.current) {
|
||||
// Cheat and trigger a download, again.
|
||||
return downloadBlob(blobRef.current);
|
||||
}
|
||||
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) {
|
||||
throw parseErrorResponse(res, await res.text());
|
||||
}
|
||||
const blob = await res.blob();
|
||||
blobRef.current = blob;
|
||||
await downloadBlob(blob);
|
||||
} catch (e) {
|
||||
showError(e);
|
||||
}
|
||||
};
|
||||
|
||||
async function downloadBlob(blob: Blob): Promise<void> {
|
||||
await downloader.download({
|
||||
blob,
|
||||
name: fileName ?? _t("common|image"),
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<AccessibleButton
|
||||
className="mx_ImageView_button mx_ImageView_button_download"
|
||||
title={loading ? _t("timeline|download_action_downloading") : _t("action|download")}
|
||||
onClick={onDownloadClick}
|
||||
disabled={loading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { Icon as WarningBadge } from "../../../../res/img/element-icons/warning-badge.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { getLocationShareErrorMessage, LocationShareError } from "../../../utils/location";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
@ -29,7 +29,7 @@ export const MapError: React.FC<MapErrorProps> = ({ error, isMinimised, classNam
|
|||
className={classNames("mx_MapError", className, { mx_MapError_isMinimised: isMinimised })}
|
||||
onClick={onClick}
|
||||
>
|
||||
<WarningBadge className="mx_MapError_icon" />
|
||||
<ErrorIcon className="mx_MapError_icon" />
|
||||
<Heading className="mx_MapError_heading" size="3">
|
||||
{_t("location_sharing|failed_load_map")}
|
||||
</Heading>
|
||||
|
|
|
@ -27,11 +27,11 @@ import {
|
|||
OverflowHorizontalIcon,
|
||||
ReplyIcon,
|
||||
DeleteIcon,
|
||||
RestartIcon,
|
||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { Icon as EditIcon } from "../../../../res/img/element-icons/room/message-bar/edit.svg";
|
||||
import { Icon as EmojiIcon } from "../../../../res/img/element-icons/room/message-bar/emoji.svg";
|
||||
import { Icon as ResendIcon } from "../../../../res/img/element-icons/retry.svg";
|
||||
import { Icon as ThreadIcon } from "../../../../res/img/element-icons/message/thread.svg";
|
||||
import { Icon as ExpandMessageIcon } from "../../../../res/img/element-icons/expand-message.svg";
|
||||
import { Icon as CollapseMessageIcon } from "../../../../res/img/element-icons/collapse-message.svg";
|
||||
|
@ -475,14 +475,14 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
|||
0,
|
||||
0,
|
||||
<RovingAccessibleButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
className="mx_MessageActionBar_iconButton mx_MessageActionBar_retryButton"
|
||||
title={_t("action|retry")}
|
||||
onClick={this.onResendClick}
|
||||
onContextMenu={this.onResendClick}
|
||||
key="resend"
|
||||
placement="left"
|
||||
>
|
||||
<ResendIcon />
|
||||
<RestartIcon />
|
||||
</RovingAccessibleButton>,
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue