Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Replace getQRCodeBytes with generateQRCode #11241

Merged
merged 3 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/components/views/elements/QRCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { _t } from "../../../languageHandler";
import Spinner from "./Spinner";

interface IProps extends QRCodeRenderersOptions {
data: string | QRCodeSegment[];
/** The data for the QR code. If `null`, a spinner is shown. */
data: null | string | QRCodeSegment[];
className?: string;
}

Expand All @@ -33,6 +34,10 @@ const defaultOptions: QRCodeToDataURLOptions = {
const QRCode: React.FC<IProps> = ({ data, className, ...options }) => {
const [dataUri, setUri] = React.useState<string | null>(null);
React.useEffect(() => {
if (data === null) {
setUri(null);
return;
}
let cancelled = false;
toDataURL(data, { ...defaultOptions, ...options }).then((uri) => {
if (cancelled) return;
Expand Down
5 changes: 3 additions & 2 deletions src/components/views/elements/crypto/VerificationQRCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import React from "react";
import QRCode from "../QRCode";

interface IProps {
qrCodeBytes: Buffer;
/** The data for the QR code. If `undefined`, a spinner is shown. */
qrCodeBytes: undefined | Buffer;
}

export default class VerificationQRCode extends React.PureComponent<IProps> {
public render(): React.ReactNode {
return (
<QRCode
data={[{ data: this.props.qrCodeBytes, mode: "byte" }]}
data={this.props.qrCodeBytes === undefined ? null : [{ data: this.props.qrCodeBytes, mode: "byte" }]}
className="mx_VerificationQRCode"
width={196}
/>
Expand Down
36 changes: 30 additions & 6 deletions src/components/views/right_panel/VerificationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ interface IProps {
}

interface IState {
/**
* The data for the QR code to display.
*
* We attempt to calculate this once the verification request transitions into the "Ready" phase. If the other
* side cannot scan QR codes, it will remain `undefined`.
*/
qrCodeBytes: Buffer | undefined;

sasEvent: ShowSasCallbacks | null;
emojiButtonClicked?: boolean;
reciprocateButtonClicked?: boolean;
Expand All @@ -68,17 +76,19 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
/** have we yet tried to check the other device's info */
private haveCheckedDevice = false;

/** have we yet tried to get the QR code */
private haveFetchedQRCode = false;

public constructor(props: IProps) {
super(props);
this.state = { sasEvent: null, reciprocateQREvent: null };
this.state = { qrCodeBytes: undefined, sasEvent: null, reciprocateQREvent: null };
this.hasVerifier = false;
}

private renderQRPhase(): JSX.Element {
const { member, request } = this.props;
const showSAS: boolean = request.otherPartySupportsMethod(verificationMethods.SAS);
const showQR: boolean = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD);
const qrCodeBytes = showQR ? request.getQRCodeBytes() : null;
const brand = SdkConfig.get().brand;

const noCommonMethodError: JSX.Element | null =
Expand All @@ -97,11 +107,11 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
// HACK: This is a terrible idea.
let qrBlockDialog: JSX.Element | undefined;
let sasBlockDialog: JSX.Element | undefined;
if (!!qrCodeBytes) {
if (showQR) {
qrBlockDialog = (
<div className="mx_VerificationPanel_QRPhase_startOption">
<p>{_t("Scan this unique code")}</p>
<VerificationQRCode qrCodeBytes={qrCodeBytes} />
<VerificationQRCode qrCodeBytes={this.state.qrCodeBytes} />
</div>
);
}
Expand Down Expand Up @@ -145,7 +155,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
}

let qrBlock: JSX.Element | undefined;
if (!!qrCodeBytes) {
if (showQR) {
qrBlock = (
<div className="mx_UserInfo_container">
<h3>{_t("Verify by scanning")}</h3>
Expand All @@ -156,7 +166,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
</p>

<div className="mx_VerificationPanel_qrCode">
<VerificationQRCode qrCodeBytes={qrCodeBytes} />
<VerificationQRCode qrCodeBytes={this.state.qrCodeBytes} />
</div>
</div>
);
Expand Down Expand Up @@ -426,6 +436,20 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
// if we have a device ID and did not have one before, fetch the device's details
this.maybeGetOtherDevice();

// if we have had a reply from the other side (ie, the phase is "ready") and we have not
// yet done so, fetch the QR code
if (request.phase === Phase.Ready && !this.haveFetchedQRCode) {
this.haveFetchedQRCode = true;
request.generateQRCode().then(
(buf) => {
this.setState({ qrCodeBytes: buf });
},
(error) => {
console.error("Error generating QR code:", error);
},
);
}

const hadVerifier = this.hasVerifier;
this.hasVerifier = !!request.verifier;
if (!hadVerifier && this.hasVerifier) {
Expand Down
5 changes: 5 additions & 0 deletions test/components/views/elements/QRCode-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ describe("<QRCode />", () => {
cleanup();
});

it("shows a spinner when data is null", async () => {
const { container } = render(<QRCode data={null} />);
expect(container.querySelector(".mx_Spinner")).toBeDefined();
});

it("renders a QR with defaults", async () => {
const { container, getAllByAltText } = render(<QRCode data="asd" />);
await waitFor(() => getAllByAltText("QR Code").length === 1);
Expand Down
1 change: 1 addition & 0 deletions test/components/views/right_panel/UserInfo-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ describe("<UserInfo />", () => {
Object.assign(this, {
channel: { transactionId: 1 },
otherPartySupportsMethod: jest.fn(),
generateQRCode: jest.fn().mockReturnValue(new Promise(() => {})),
...opts,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("<VerificationPanel />", () => {
const request = makeMockVerificationRequest({
phase: Phase.Ready,
});
request.getQRCodeBytes.mockReturnValue(Buffer.from("test", "utf-8"));
request.generateQRCode.mockResolvedValue(Buffer.from("test", "utf-8"));
const container = renderComponent({
request: request,
layout: "dialog",
Expand All @@ -81,7 +81,7 @@ describe("<VerificationPanel />", () => {
const request = makeMockVerificationRequest({
phase: Phase.Ready,
});
request.getQRCodeBytes.mockReturnValue(Buffer.from("test", "utf-8"));
request.generateQRCode.mockResolvedValue(Buffer.from("test", "utf-8"));
const container = renderComponent({
request: request,
member: new User("@other:user"),
Expand Down Expand Up @@ -198,7 +198,7 @@ function makeMockVerificationRequest(props: Partial<VerificationRequest> = {}):
Object.assign(request, {
cancel: jest.fn(),
otherPartySupportsMethod: jest.fn().mockReturnValue(true),
getQRCodeBytes: jest.fn(),
generateQRCode: jest.fn().mockResolvedValue(undefined),
...props,
});
return request as unknown as Mocked<VerificationRequest>;
Expand Down