Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨feat(llm): add scan WS qr code #7512

Merged
merged 1 commit into from
Aug 8, 2024
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
5 changes: 5 additions & 0 deletions .changeset/empty-mayflies-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": patch
---

add WS scan qr code
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Props = {
buttonTitle: string;
onPress: () => void;
event: string;
hasNoBackground?: boolean;
};

const IconSettings = () => <Icon name="settings" size={16} color="neutral.c100" />;
Expand All @@ -22,11 +23,12 @@ const FallbackCameraBody: React.FC<Props> = ({
buttonTitle,
onPress,
event,
hasNoBackground,
}: Props) => {
const { colors } = useTheme();

return (
<Flex flex={1} bg="background.main" px={6}>
<Flex flex={1} bg={hasNoBackground ? "transparent" : "background.main"} px={6}>
<Flex flex={1} alignItems="center" justifyContent="center">
<FallbackCamera color={colors.constant.white} />
<Text variant="paragraph" mt={9} mb={3} fontSize={6}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props = {
* context, rather than directly showing an error screen.
* */
optimisticallyMountChildren?: boolean;
fallBackHasNoBackground?: boolean;
LucasWerey marked this conversation as resolved.
Show resolved Hide resolved
};

/**
Expand All @@ -38,6 +39,7 @@ type Props = {
const RequiresCameraPermissions: React.FC<Props> = ({
children,
optimisticallyMountChildren = false,
fallBackHasNoBackground = false,
}) => {
const { t } = useTranslation();
const {
Expand All @@ -59,6 +61,7 @@ const RequiresCameraPermissions: React.FC<Props> = ({
<Fallback
event="CameraPressAuthorize"
onPress={requestPermission}
hasNoBackground={fallBackHasNoBackground}
title={t("permissions.camera.title")}
description={t("permissions.camera.authorizeDescription")}
buttonTitle={t("permissions.camera.authorizeButtonTitle")}
Expand All @@ -68,6 +71,7 @@ const RequiresCameraPermissions: React.FC<Props> = ({
<Fallback
event="CameraOpenSettings"
onPress={openAppSettings}
hasNoBackground={fallBackHasNoBackground}
title={t("permissions.camera.title")}
description={t("permissions.camera.goToSettingsDescription")}
buttonTitle={t("permissions.camera.goToSettingsButtonTitle")}
Expand Down
11 changes: 10 additions & 1 deletion apps/ledger-live-mobile/src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -6806,7 +6806,16 @@
}
},
"scan": {
"title": "Scan"
"title": "Scan",
"description": "Scan QR code",
"explanation": {
"title": "Scan and synchronize your accounts using another Ledger Live app",
"steps": {
"step1": "Open the Ledger Live app you want to sync",
"step2": "Go to <0>Settings</0> <1>></1> <0>General</0> <1>></1> <0>Ledger Sync</0> <1>></1> <0>Synchronize</0> <1>></1> <0>Show QR</0>",
"step3": "Scan QR code until loader hits 100%."
}
}
},
"pinCode": {
"title": "Enter your code",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import React from "react";
import SelectAddAccountMethod from "./SelectAddAccountMethod";
import ChooseSyncMethod from "LLM/features/WalletSync/screens/Synchronize/ChooseMethod";
import QrCodeMethod from "LLM/features/WalletSync/screens/Synchronize/QrCodeMethod";
import PinCodeInput from "LLM/features/WalletSync/screens/Synchronize/PinCodeInput";
import { TrackScreen } from "~/analytics";
import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
import { AnalyticsPage } from "LLM/features/WalletSync/hooks/useLedgerSyncAnalytics";
import { Options, Steps } from "LLM/features/WalletSync/types/Activation";
import SyncError from "LLM/features/WalletSync/screens/Synchronize/SyncError";
import PinCodeDisplay from "LLM/features/WalletSync/screens/Synchronize/PinCodeDisplay";
import PinCodeInput from "LLM/features/WalletSync/screens/Synchronize/PinCodeInput";

type Props = {
currentStep: Steps;
Expand All @@ -19,6 +19,7 @@ type Props = {
currentOption: Options;
navigateToChooseSyncMethod: () => void;
navigateToQrCodeMethod: () => void;
onQrCodeScanned: (data: string) => void;
qrProcess: {
url: string | null;
error: Error | null;
Expand All @@ -35,6 +36,7 @@ const StepFlow = ({
currentOption,
navigateToChooseSyncMethod,
navigateToQrCodeMethod,
onQrCodeScanned,
qrProcess,
}: Props) => {
const getScene = () => {
Expand All @@ -58,7 +60,13 @@ const StepFlow = ({
</>
);
case Steps.QrCodeMethod:
return <QrCodeMethod currentOption={currentOption} setSelectedOption={setCurrentOption} />;
return (
<QrCodeMethod
onQrCodeScanned={onQrCodeScanned}
currentOption={currentOption}
setSelectedOption={setCurrentOption}
/>
);

case Steps.PinDisplay:
return qrProcess.pinCode ? <PinCodeDisplay pinCode={qrProcess.pinCode} /> : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function View({
navigateToChooseSyncMethod,
navigateToQrCodeMethod,
qrProcess,
onQrCodeScanned,
}: ViewProps) {
const CustomDrawerHeader = () => <DrawerHeader onClose={onCloseAddAccountDrawer} />;

Expand All @@ -51,6 +52,7 @@ function View({
navigateToChooseSyncMethod={navigateToChooseSyncMethod}
navigateToQrCodeMethod={navigateToQrCodeMethod}
qrProcess={qrProcess}
onQrCodeScanned={onQrCodeScanned}
/>
</Flex>
</QueuedDrawer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ const useAddAccountViewModel = ({ isOpened, onClose }: AddAccountDrawerProps) =>
currentOption,
});

const onQrCodeScanned = (data: string) => {
// eslint-disable-next-line no-console
console.log(data);
//setCurrentStep(Steps.PinCodeInput);
};

return {
isAddAccountDrawerVisible: isOpened,
onCloseAddAccountDrawer,
Expand All @@ -64,6 +70,7 @@ const useAddAccountViewModel = ({ isOpened, onClose }: AddAccountDrawerProps) =>
currentOption,
setCurrentStep,
onGoBack,
onQrCodeScanned,
qrProcess: {
url,
error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe("scanQRCode", () => {
await user.press(await screen.findByText(/ledger sync/i));
await user.press(await screen.findByText(/already created a key?/i));
await user.press(await screen.findByText(/scan a qr code/i));
await expect(await screen.findByText(/show qr/i)).toBeVisible();
await expect(screen.queryAllByText(/show qr/i)).toHaveLength(2);
await expect(screen.getByTestId("ws-scan-camera")).toBeVisible();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("SynchronizeWithQrCode", () => {
await user.press(await screen.findByText(/ledger sync/i));
await user.press(await screen.findByText(/already created a key?/i));
await user.press(await screen.findByText(/scan a qr code/i));
await user.press(await screen.findByText(/show qr/i));
await user.press(await screen.queryAllByText(/show qr/i)[0]);
expect(await screen.getByTestId("ws-qr-code-displayed")).toBeVisible();

//PinCode Page after scanning QRCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type Props = {
isLoading: boolean;
pinCode: string | null;
};

onQrCodeScanned: (data: string) => void;
currentOption: Options;
setOption: (option: Options) => void;
};
Expand All @@ -31,6 +31,7 @@ const ActivationFlow = ({
qrProcess,
currentOption,
setOption,
onQrCodeScanned,
}: Props) => {
const getScene = () => {
switch (currentStep) {
Expand All @@ -49,7 +50,13 @@ const ActivationFlow = ({
</>
);
case Steps.QrCodeMethod:
return <QrCodeMethod currentOption={currentOption} setSelectedOption={setOption} />;
return (
<QrCodeMethod
onQrCodeScanned={onQrCodeScanned}
currentOption={currentOption}
setSelectedOption={setOption}
/>
);

case Steps.PinDisplay:
return qrProcess.pinCode ? <PinCodeDisplay pinCode={qrProcess.pinCode} /> : null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import { ScrollContainer, Text, Flex } from "@ledgerhq/native-ui";
import { useTranslation } from "react-i18next";
import styled, { useTheme } from "styled-components/native";

type Props = {
steps: {
description: React.JSX.Element;
}[];
};

const BulletPoint = styled(Flex)`
width: 16px;
height: 16px;
justify-content: center;
align-items: center;
background-color: ${({ theme }) => theme.colors.primary.c80};
border-radius: 100px;
`;

const FlexContainer = styled(Flex)`
margin-bottom: 16px;
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 12px;
`;

const BottomContainer = ({ steps }: Props) => {
const { colors } = useTheme();
const { t } = useTranslation();

return (
<ScrollContainer
px={16}
py={24}
maxHeight={220}
background={colors.opacityDefault.c05}
borderRadius={24}
showsVerticalScrollIndicator={false}
>
<Text variant="h4" fontSize={18} color={colors.neutral.c100} mb={24}>
{t("walletSync.synchronize.qrCode.scan.explanation.title")}
</Text>
<Flex width={"100%"} mb={32}>
{steps.map((step, index) => (
<FlexContainer key={index}>
<BulletPoint>
<Text fontSize={11} color={colors.neutral.c00}>
{index + 1}
</Text>
</BulletPoint>
<Flex flex={1}>{step.description}</Flex>
</FlexContainer>
))}
</Flex>
</ScrollContainer>
);
};

export default BottomContainer;
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react";
import { Flex, Text, NumberedList, ScrollContainer } from "@ledgerhq/native-ui";
import { Flex, Text } from "@ledgerhq/native-ui";
import styled, { useTheme } from "styled-components/native";
import QRCode from "react-native-qrcode-svg";
import getWindowDimensions from "~/logic/getWindowDimensions";
import { Trans, useTranslation } from "react-i18next";
import BottomContainer from "./BottomContainer";

const Italic = styled(Text)`
font-style: italic;
Expand Down Expand Up @@ -31,14 +32,14 @@ const QrCode = ({ qrCodeValue }: Props) => {
const steps = [
{
description: (
<Text variant="body" flex={1} ml={12} fontSize={14} color={colors.opacityDefault.c70}>
<Text variant="body" flex={1} fontSize={14} color={colors.opacityDefault.c70}>
{t("walletSync.synchronize.qrCode.show.explanation.steps.step1")}
</Text>
),
},
{
description: (
<Text variant="body" flex={1} ml={12} fontSize={14} color={colors.opacityDefault.c70}>
<Text variant="body" flex={1} fontSize={14} color={colors.opacityDefault.c70}>
<Trans
i18nKey="walletSync.synchronize.qrCode.show.explanation.steps.step2"
components={[
Expand All @@ -51,7 +52,7 @@ const QrCode = ({ qrCodeValue }: Props) => {
},
{
description: (
<Text variant="body" flex={1} ml={12} fontSize={14} color={colors.opacityDefault.c70}>
<Text variant="body" flex={1} fontSize={14} color={colors.opacityDefault.c70}>
{t("walletSync.synchronize.qrCode.show.explanation.steps.step3")}
</Text>
),
Expand Down Expand Up @@ -85,20 +86,7 @@ const QrCode = ({ qrCodeValue }: Props) => {
size={QRCodeSize}
/>
</Flex>
<ScrollContainer
px={16}
mb={10}
width={"100%"}
maxHeight={280}
background={colors.opacityDefault.c05}
borderRadius={24}
showsVerticalScrollIndicator={false}
>
<Text variant="h4" fontSize={18} color={colors.neutral.c100} my={24}>
{t("walletSync.synchronize.qrCode.show.explanation.title")}
</Text>
<NumberedList items={steps} />
</ScrollContainer>
<BottomContainer steps={steps} />
</Flex>
);
};
Expand Down
Loading
Loading