Update LoginWithQR

This commit is contained in:
thororen1234 2024-10-06 13:42:21 -04:00
parent 94831de711
commit 77be17dcce
5 changed files with 87 additions and 51 deletions

View file

@ -8,11 +8,11 @@ export const images = {
cross: "https://i.imgur.com/XxRnu3b.png",
deviceImage: {
success:
"https://github.com/nexpid/Themelings/blob/3a063c5188f4cac096171f29163f9e2659f275a3/icons/images/native/img_remote_auth_succeeded.png",
"https://github.com/nexpid/Themelings/raw/data/icons/images/native/img_remote_auth_succeeded.png",
notFound:
"https://github.com/nexpid/Themelings/blob/3a063c5188f4cac096171f29163f9e2659f275a3/icons/images/native/img_remote_auth_not_found.png",
"https://github.com/nexpid/Themelings/raw/data/icons/images/native/img_remote_auth_not_found.png",
loading:
"https://github.com/nexpid/Themelings/blob/3a063c5188f4cac096171f29163f9e2659f275a3/icons/images/native/img_remote_auth_loaded.png",
"https://github.com/nexpid/Themelings/raw/data/icons/images/native/img_remote_auth_loaded.png",
},
} as const;

View file

@ -5,19 +5,25 @@
*/
import { definePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { Button, Forms, i18n, Menu, TabBar } from "@webpack/common";
import { Button, Forms, i18n, Menu } from "@webpack/common";
import { ReactElement } from "react";
import { preload, unload } from "./images";
import { cl, QrCodeIcon } from "./ui";
import { cl } from "./ui";
import openQrModal from "./ui/modals/QrModal";
export default definePlugin({
name: "LoginWithQR",
description: "Allows you to login to another device by scanning a login QR code, just like on mobile!",
authors: [EquicordDevs.nexpid],
description:
"Allows you to login to another device by scanning a login QR code, just like on mobile!",
// replace with EquicordDevs.nexpid when merged to Equicord
authors: [
{
name: "Nexpid",
id: 853550207039832084n,
},
],
settings: definePluginSettings({
scanQr: {
@ -62,25 +68,31 @@ export default definePlugin({
replace: ",$self.insertScanQrButton($1)",
},
},
// Insert a Scan QR Code MenuItem in the simplified user popout
// Insert a Scan QR Code MenuItem in the Swith Accounts popout
{
find: "Messages.MULTI_ACCOUNT_MENU_LABEL",
find: ".SWITCH_ACCOUNTS_MANAGE_ACCOUNTS,",
replacement: {
// Insert our own MenuItem before the Switch Accounts button
match: /children:\[(.{0,54}id:"switch-accounts")/,
replace: "children:[$self.ScanQrMenuItem,$1",
match: /(id:"manage-accounts",.*?)}\)\)(,\i)/,
replace: "$1}),$self.ScanQrMenuItem)$2"
}
},
},
// Add a Scan QR entry to the settings TabBar
// Insert a Scan QR Code button in the Settings sheet
{
find: ".BILLING_SETTINGS,",
find: "useGenerateUserSettingsSections",
replacement: {
match: /((\i\.settings)\.forEach.+?(\i).push\(.+}\)}\))/,
replace: (_, original, settings, elements) =>
`${original},${settings}?.[0]=="ACCOUNT"` +
`&&${elements}.push({section:"CUSTOM",element:$self.ScanQrTabBarComponent})`,
},
match: /(\.FRIEND_REQUESTS)/,
replace: "$1,\"SCAN_QR_CODE\""
}
},
// Insert a Scan QR Code button in the Settings sheet (part 2)
{
find: ".PRIVACY_ENCRYPTION_VERIFIED_DEVICES_V2]",
replacement: {
match: /(\.CLIPS]:{.*?},)/,
replace: "$1\"SCAN_QR_CODE\":$self.ScanQrSettingsSheet,"
}
}
],
qrModalOpen: false,
@ -93,26 +105,18 @@ export default definePlugin({
{button}
</div>
),
get ScanQrMenuItem() {
return (
<Menu.MenuGroup>
<Menu.MenuItem
id="scan-qr"
label={i18n.Messages.USER_SETTINGS_SCAN_QR_CODE}
icon={QrCodeIcon}
action={openQrModal}
showIconFirst
/>
</Menu.MenuGroup>
);
return <Menu.MenuItem id="scan-qr" label={i18n.Messages.USER_SETTINGS_SCAN_QR_CODE} action={openQrModal} />;
},
get ScanQrSettingsSheet() {
return {
section: i18n.Messages.USER_SETTINGS_SCAN_QR_CODE,
onClick: openQrModal,
searchableTitles: [i18n.Messages.USER_SETTINGS_SCAN_QR_CODE],
label: i18n.Messages.USER_SETTINGS_SCAN_QR_CODE,
ariaLabel: i18n.Messages.USER_SETTINGS_SCAN_QR_CODE
};
},
ScanQrTabBarComponent: () => (
<TabBar.Item id="Scan QR Code" onClick={openQrModal}>
{i18n.Messages.USER_SETTINGS_SCAN_QR_CODE}
</TabBar.Item>
),
start() {
// Preload images

View file

@ -43,4 +43,3 @@ export const QrCodeIcon = proxyLazy(() => icons.QrCodeCameraIcon ?? icons.QrCode
}>;
export const cl = classNameFactory("qrlogin-");

View file

@ -345,6 +345,7 @@ function QrModal(props: ModalProps) {
video.srcObject = str;
video.addEventListener("loadedmetadata", () => {
if (stopped) return stop(str);
video.play();
modalProps.current.setPreview(video);
snapshot();
@ -381,7 +382,8 @@ function QrModal(props: ModalProps) {
state === LoginStateType.Camera &&
!preview?.source &&
"modal-filepaste-disabled",
preview?.source && "modal-filepaste-preview"
preview?.source && "modal-filepaste-preview",
preview?.crosses && "modal-filepaste-crosses"
)}
onClick={() =>
state === LoginStateType.Idle && inputRef.current?.click()
@ -418,10 +420,28 @@ function QrModal(props: ModalProps) {
>
{preview?.source ? (
<div
style={{ width: "100%", height: "100%", position: "relative" }}
style={{
width: "100%",
height: "100%",
position: "relative",
["--scale" as any]: preview.crosses
? Math.max(preview.crosses[0].size * 0.9, 1)
: undefined,
["--offset-x" as any]: preview.crosses
? `${-(preview.crosses.reduce((i, { x }) => i + x, 0) /
preview.crosses.length -
50)}%`
: undefined,
["--offset-y" as any]: preview.crosses
? `${-(preview.crosses.reduce((i, { y }) => i + y, 0) /
preview.crosses.length -
50)}%`
: undefined,
}}
className={cl(preview?.crosses && "preview-crosses")}
>
{preview.source}
{preview.crosses?.map(({ x, y, rot, size }, i) => (
{preview.crosses?.map(({ x, y, rot, size }) => (
<span
className={cl("preview-cross")}
style={{

View file

@ -18,8 +18,8 @@
overflow: hidden;
transition: 200ms background-color ease-in-out, 200ms border-color ease-in-out,
200ms opacity ease-in-out, 200ms border-width ease-in-out,
250ms width cubic-bezier(0.68, -0.6, 0.32, 1.6),
250ms height cubic-bezier(0.68, -0.6, 0.32, 1.6);
250ms width cubic-bezier(0.76, 0, 0.24, 1),
250ms height cubic-bezier(0.76, 0, 0.24, 1);
}
.qrlogin-modal-filepaste * {
@ -41,6 +41,14 @@
background-color: #0005;
}
.qrlogin-modal-filepaste-preview video {
object-fit: fill;
}
.qrlogin-preview-crosses {
animation: 500ms preview-crosses cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
.qrlogin-preview-cross {
position: absolute;
width: var(--size);
@ -85,11 +93,10 @@
.qrlogin-device-confirm {
margin-top: 18px;
width: 20rem;
background: linear-gradient(
to right,
background: linear-gradient(to right,
var(--button-danger-background) calc(var(--progress) - 1%),
var(--button-danger-background-active) var(--progress)
) !important;
var(--button-danger-background-active) var(--progress)) !important;
border-radius: 420rem;
--progress: 0%;
}
@ -121,3 +128,9 @@
opacity: 1;
}
}
@keyframes preview-crosses {
to {
transform: translate(var(--offset-x), var(--offset-y)) scale(var(--scale));
}
}