From 44cc8594a5de9073e72febc4e7592f1b589c4788 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 30 Apr 2024 16:59:23 +1000 Subject: [PATCH] fix: saved qr codes will be black and white by default qr code logos can now be svgs for better rendering performance --- images/session/brand/classic-dark.png | Bin 1606 -> 0 bytes images/session/brand/classic-light.png | Bin 927 -> 0 bytes images/session/brand/ocean-dark.png | Bin 927 -> 0 bytes images/session/brand/ocean-light.png | Bin 2283 -> 0 bytes images/session/qr/brand.svg | 1 + images/session/qr/shield.svg | 1 + images/session/shield/classic-dark.png | Bin 1213 -> 0 bytes images/session/shield/classic-light.png | Bin 1010 -> 0 bytes images/session/shield/ocean-dark.png | Bin 1010 -> 0 bytes images/session/shield/ocean-light.png | Bin 1017 -> 0 bytes ts/components/SessionQRCode.tsx | 100 +++++++++++++++++---- ts/components/dialog/EditProfileDialog.tsx | 7 +- ts/components/dialog/SessionSeedModal.tsx | 7 +- ts/util/saveQRCode.ts | 14 --- ts/util/saveQRCode.tsx | 34 +++++++ 15 files changed, 127 insertions(+), 37 deletions(-) delete mode 100755 images/session/brand/classic-dark.png delete mode 100755 images/session/brand/classic-light.png delete mode 100755 images/session/brand/ocean-dark.png delete mode 100755 images/session/brand/ocean-light.png create mode 100644 images/session/qr/brand.svg create mode 100644 images/session/qr/shield.svg delete mode 100755 images/session/shield/classic-dark.png delete mode 100755 images/session/shield/classic-light.png delete mode 100755 images/session/shield/ocean-dark.png delete mode 100755 images/session/shield/ocean-light.png delete mode 100644 ts/util/saveQRCode.ts create mode 100644 ts/util/saveQRCode.tsx diff --git a/images/session/brand/classic-dark.png b/images/session/brand/classic-dark.png deleted file mode 100755 index a174da7c8e742dfd09aa8d81337dedc101cc7a81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1606 zcmV-M2D$l(P)esx#KA8Xj z1 z48=Z%=gb}qgFOr@3WX(?fT5^C01*L$BA|%DZRk*f{?qR^6m^XYrbG;S46*FxKt6-$ zFN8&^dUYDscr)l@ISqIvB*kmcjf7__|DT9qpoDx088U}Ky7KBVbg9E2#qbykc6rjp z01Q3lC(~dwF_NN()-b?V2iyR(By2D)taBQGub7Dj-NO$u(C>MLhHe3d zUmrgaNnWwxMwuzDzZXKrV)ywgG(0cB&@RAGmSa%IoYT-Oz`&0;v>o|>KBjJ#t zWE%Fdb-f}j1m}aXKWK(|n7t5Q$YW@;3@xzU?U*tDj;{OTbA#)@w*R5IcT%iFx6O$m z+?3^R!ij>0m1Wr8ZFuq;+It%U9tL|I=bUDsuz|A-L%>k(yh7lWz}FU&_D`C{zzrWU z!vGkB5HmFQ4MYaP-g~e@4Mes9Du!ba00TP>hUO2%kY{L(ql%#?4k3JdS%=Aw{Gcw>m(D%Cn`r~Jk-qfq zZJsuaV97OLum|F77%0$}?!E3e!w~38|DONBFp&GA9eDO(V;FQ_;s(`eQwII%mm~wd zQ-}!zt<@bpYS80*GYr(I;-LmTzQdG3_vI>Ju)kWrH4LgRaf5zT?(>8}kJ}kH$c`<^ zltCj-2?l-Ce#)RvrA>~3cDgUM!RSlKp!;$#44o=ohT)+4@=wEL@h%w#eaaaI`l70V z8uZE0E5l^*LI%4p4Fjo9;|6_;Vi=zBxgZ;{Qih4*^|m3@mxh79XfbZk*Gn;2h#_RK z`|>0PyLd?kegAG4o`L6i9epVV>!K1g*f$emFgs`f4922~7>vH`F@r{EgI&Bt12ry# zkcUJAO&BJtk!k2$1|hE!4YYO{iWCDf>{&$_?14ZGEQuHjZrC$u_$tK+8kkW7p$5hc zQjD0P$uJOP*l~)Xkz%+FE$0{tU|`6g57Yy5#a4RTFve{-a@shQs9^_hb=ikUtExjT%;z6WM3|(Q7zUUfBDL zIZ%ph!-mk{1_A;YfObF)_UB)*;S)Im8|;>>hB4JJ=6^Cgk;9~NMUzjL6c zqH754LIULpaDk=BncQKJ8%$igDCO^ z|Ke|i_@%07*qoM6N<$ Ef-}w9hyVZp diff --git a/images/session/brand/classic-light.png b/images/session/brand/classic-light.png deleted file mode 100755 index a43f95c1aae72c1c978b28fa4a630b6e5868ffdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 927 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 FV1gM1DiHtx diff --git a/images/session/qr/brand.svg b/images/session/qr/brand.svg new file mode 100644 index 000000000..cbe4ed2ca --- /dev/null +++ b/images/session/qr/brand.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/session/qr/shield.svg b/images/session/qr/shield.svg new file mode 100644 index 000000000..edf943949 --- /dev/null +++ b/images/session/qr/shield.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/session/shield/classic-dark.png b/images/session/shield/classic-dark.png deleted file mode 100755 index b5d036219a3d454987e82abe12fbe9e27f8b008e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1213 zcmV;u1Va0XP)o zG&D0aGaDNl|Ns9RqfEU3000AYQchEJdYSc&zRmyu1X@W%K~#9!?cGss+b|G>;Q;9k z(i`*wEoKjpcIWM|Hsy%K2T_7%a-`WMcR-J*^n;`!N2V05XVP1 zhP>i`c1wr@S(2wLM@Z@+IL&SYc}CkUAUIn+1Q)7?;9{i^$0u1G?j0T*)hm7@;U-RX1}h7Ah|0cj`XgAyh4!8LmZO6&q5rc zYz_ilHUoKvvT+Es{Tzk7K;0O`AA@&Y{-Ue$cCJ>A*XG~X&Z9dh71qV=2Z}5uNnvks(=_r(nE|xxg5g5q>$LW zKW8q5#7_GA&_X7Tzbhd&^Rp`@Wcc5B1!VX?U)Mm|;rnD6Wa7MNUjj0AWMV(Agy8NV zCWMgm4LR8qD?n^RHsmoO+>kRb-Vj7w1Y#t81<2cA3qb6Bu-l(~KR$=u{Qb!LST~2n z2le9jtUMdaAy$9ID2`1Zf<+)uL1Ldn5EMYX1BsVZUmvk{V*#W;B?0kb2+u=WiTVkCcqv_w55y0}^VSqUU0er_i#Kp=3WR67AQnJ+XS8{U9lPTwu-&8(3&#k=WstX5tOCJcCV|Apo&;eB!tR7D0`UzI zecftZh;PUg#Oolef$)wXKawCk3h@ev)k1Ix@+Svkhas%^kpk-=B>hn!K0Ek4+Ug)w zLzwdO5e`9^@Sc@g2&TR_fEeO~4)6T^0K|v((Ay7`5afJN=OBbfc7hl~2>}Q56o_kY ze6kD(67GBYHVmQm<~Zg+`VvPP#E;w{hfX#H5oU`#m<_8uA@0`{#39S>6GF)1okCW5 zuA&aYDM%cf+d~|Z?0zAHBrXE6DDL_Z~~EI(z55Z6seK-3aTg-|vj0TEA$EwYRqI1JHF$pf!2 zc-_Hy=*1sNi6bCF$-}QyIw`R)u!!tJ%j(hvj(`XxCWp|+9C`=`9eN0#(Tg<@3LF8+ zll){IgfE{szT`6hmnFt(2tCIUkW2|#35hz6GD!2hfO<&OVN^kaLf#zm-iB<*X&Z9d b<3j!d2;48}$LKjR00000NkvXXu0mjfSS0zC diff --git a/images/session/shield/classic-light.png b/images/session/shield/classic-light.png deleted file mode 100755 index 0bdde1846afff1c9e773e95a268196c5aff7350d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1010 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 diff --git a/ts/components/SessionQRCode.tsx b/ts/components/SessionQRCode.tsx index a06bc7df0..54354f525 100644 --- a/ts/components/SessionQRCode.tsx +++ b/ts/components/SessionQRCode.tsx @@ -1,18 +1,33 @@ -import { MouseEvent } from 'react'; +import { isEmpty } from 'lodash'; +import { CSSProperties, MouseEvent, useState } from 'react'; import { QRCode } from 'react-qrcode-logo'; -import styled, { CSSProperties } from 'styled-components'; -import { THEME_GLOBALS } from '../themes/globals'; +import { useMount } from 'react-use'; +import styled from 'styled-components'; +import { THEME_GLOBALS, getThemeValue } from '../themes/globals'; import { saveQRCode } from '../util/saveQRCode'; import { AnimatedFlex } from './basic/Flex'; -// We fade in the QR code to hide the logo flickering on first render -const StyledQRView = styled(AnimatedFlex)` +/** AnimatedFlex because we fade in the QR code to hide the logo flickering on first render + * The container controls the visible width and height of the QR code because we lose quality if the html canvas size is too small so we scale down with CSS. + */ +const StyledQRView = styled(AnimatedFlex)<{ + canvasId?: string; + size?: number; + backgroundColor?: string; +}>` cursor: pointer; - border-radius: var(--border-radius); + border-radius: 10px; overflow: hidden; + padding: 10px; + + ${props => props.backgroundColor && ` background-color: ${props.backgroundColor}`}; + ${props => + props.canvasId && + props.size && + `#${props.canvasId} { width: ${props.size}px !important; height: ${props.size}px !important; }`} `; -type Props = { +export type SessionQRCodeProps = { id: string; value: string; size: number; @@ -21,29 +36,79 @@ type Props = { logoImage?: string; logoWidth?: number; logoHeight?: number; + logoIsSVG?: boolean; style?: CSSProperties; + ignoreTheme?: boolean; }; -export function SessionQRCode(props: Props) { +export function SessionQRCode(props: SessionQRCodeProps) { const { id, value, size, - backgroundColor = '#FFF', - foregroundColor = '#000', + backgroundColor = 'white', + foregroundColor = 'black', logoImage, logoWidth, logoHeight, + logoIsSVG, style, + ignoreTheme, } = props; + + const [svgDataURL, setSvgDataURL] = useState(''); + // Saving the QR code uses a separate react instance without the redux store so we don't use a selector here + const theme = window.Events.getThemeSetting(); + + useMount(() => { + if (logoImage && logoIsSVG && isEmpty(svgDataURL)) { + // eslint-disable-next-line more/no-then + fetch(logoImage) + .then(response => response.text()) + .then(response => { + const svgString = ignoreTheme + ? response + : response.replaceAll( + 'black', + getThemeValue( + theme.includes('dark') ? '--background-primary-color' : '--text-primary-color' + ) + ); + setSvgDataURL(`data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`); + }) + .catch(error => + window.log.error('Error fetching the QR Code logo which is an svg:', error) + ); + } + }); + + if (logoImage && logoIsSVG && isEmpty(svgDataURL)) { + return null; + } + + const qrCanvasSize = 1000; + const canvasLogoWidth = + logoWidth && logoHeight ? (qrCanvasSize * 0.25 * logoWidth) / logoHeight : undefined; + const canvasLogoHeight = logoHeight ? (qrCanvasSize * 0.25 * logoHeight) / logoHeight : undefined; + return ( { + canvasId={id} + size={size} + backgroundColor={backgroundColor} + onClick={(event: MouseEvent) => { event.preventDefault(); - saveQRCode(id); + void saveQRCode(id, { + ...props, + id: `temp-${props.id}`, + backgroundColor: 'white', + foregroundColor: 'black', + ignoreTheme: true, + style: { display: 'none' }, + }); }} initial={{ opacity: 0 }} animate={{ opacity: 1 }} @@ -54,13 +119,14 @@ export function SessionQRCode(props: Props) { id={id} value={value} ecLevel={'Q'} - size={size} - quietZone={10} + size={qrCanvasSize} bgColor={backgroundColor} fgColor={foregroundColor} - logoImage={logoImage} - logoWidth={logoWidth} - logoHeight={logoHeight} + quietZone={0} + logoImage={logoIsSVG ? svgDataURL : logoImage} + logoWidth={canvasLogoWidth} + logoHeight={canvasLogoHeight} + removeQrCodeBehindLogo={true} /> ); diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index b28a265a4..0b397c62b 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -34,9 +34,10 @@ const QRView = ({ sessionID }: { sessionID: string }) => { foregroundColor={getThemeValue( theme.includes('dark') ? '--background-primary-color' : '--text-primary-color' )} - logoImage={`./images/session/brand/${theme}.png`} - logoWidth={42} - logoHeight={44} + logoImage={'./images/session/qr/brand.svg'} + logoWidth={40} + logoHeight={40} + logoIsSVG={true} /> ); }; diff --git a/ts/components/dialog/SessionSeedModal.tsx b/ts/components/dialog/SessionSeedModal.tsx index 59f25b304..3def16ac3 100644 --- a/ts/components/dialog/SessionSeedModal.tsx +++ b/ts/components/dialog/SessionSeedModal.tsx @@ -142,9 +142,10 @@ const Seed = (props: SeedProps) => { foregroundColor={getThemeValue( theme.includes('dark') ? '--background-primary-color' : '--text-primary-color' )} - logoImage={`./images/session/shield/${theme}.png`} - logoWidth={60} - logoHeight={60} + logoImage={'./images/session/qr/shield.svg'} + logoWidth={56} + logoHeight={56} + logoIsSVG={true} style={{ margin: '0 auto var(--margins-lg)' }} /> diff --git a/ts/util/saveQRCode.ts b/ts/util/saveQRCode.ts deleted file mode 100644 index 2d4117ca6..000000000 --- a/ts/util/saveQRCode.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { saveURLAsFile } from './saveURLAsFile'; - -export function saveQRCode(id: string): void { - const qrCanvas = document.querySelector(`#${id}`) as HTMLCanvasElement; - if (qrCanvas) { - saveURLAsFile({ - filename: `${id}-${new Date().toISOString()}.png`, - url: qrCanvas.toDataURL(), - document, - }); - } else { - window.log.error('[saveQRCode] QR code not found!'); - } -} diff --git a/ts/util/saveQRCode.tsx b/ts/util/saveQRCode.tsx new file mode 100644 index 000000000..b99e922f6 --- /dev/null +++ b/ts/util/saveQRCode.tsx @@ -0,0 +1,34 @@ +import { isEmpty } from 'lodash'; +import { createRoot } from 'react-dom/client'; +import { SessionQRCode, SessionQRCodeProps } from '../components/SessionQRCode'; +import { sleepFor } from '../session/utils/Promise'; +import { saveURLAsFile } from './saveURLAsFile'; + +export async function saveQRCode(id: string, customProps?: SessionQRCodeProps): Promise { + let qrCanvas: HTMLCanvasElement | undefined; + + if (!isEmpty(customProps)) { + const root = document.querySelector('#root'); + const divElement = document.createElement('div'); + root?.appendChild(divElement); + const reactRoot = createRoot(divElement!); + reactRoot.render(); + // wait for it to render + await sleepFor(100); + qrCanvas = root?.querySelector(`#${customProps.id}`) as HTMLCanvasElement; + reactRoot?.unmount(); + root?.removeChild(divElement); + } else { + qrCanvas = document.querySelector(`#${id}`) as HTMLCanvasElement; + } + + if (qrCanvas) { + saveURLAsFile({ + filename: `${id}-${new Date().toISOString()}.png`, + url: qrCanvas.toDataURL(), + document, + }); + } else { + window.log.error('[saveQRCode] QR code not found!'); + } +}