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: snaps dynamic UI #12429

Open
wants to merge 89 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
1a12630
added content from the original POC branch
Daniel-Cross Nov 22, 2024
280b4a7
working branch
Daniel-Cross Nov 26, 2024
fc9b773
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Nov 26, 2024
24f219e
fixed import issue
Daniel-Cross Nov 27, 2024
6c7f28d
add SnapInterfaceController to types
owencraston Nov 28, 2024
02f2054
add requestUserApproval snap method
owencraston Nov 28, 2024
f86e326
render snaps dialog
owencraston Nov 28, 2024
1426dc6
disable old state check
owencraston Nov 28, 2024
4bf801e
working dialogs except for custom
Daniel-Cross Dec 4, 2024
db88bb6
added updateInterface
Daniel-Cross Dec 5, 2024
2786acd
input on custom dialog now working
Daniel-Cross Dec 10, 2024
8d20924
removed some unused imports and comsole logs
Daniel-Cross Dec 13, 2024
f0d31c4
added missing components
Daniel-Cross Dec 13, 2024
351cebf
removed debounce
Daniel-Cross Dec 13, 2024
04876a5
resolved conflicts
Daniel-Cross Dec 16, 2024
34bed71
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 16, 2024
d8aea79
changed import location
Daniel-Cross Dec 17, 2024
2f34a7d
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 17, 2024
0b14396
updated snapshots
Daniel-Cross Dec 17, 2024
c141fb5
fix engine lint errors
owencraston Dec 18, 2024
93a3d17
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 18, 2024
7bc4a32
fix engine tests
owencraston Dec 18, 2024
a3d5413
add @nobles/hashes
owencraston Dec 18, 2024
b180225
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 18, 2024
683f4cd
updated snapshots
Daniel-Cross Dec 18, 2024
956aac3
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 19, 2024
c5664c1
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Dec 19, 2024
8666385
updated based on feedback and synced files with the extension
Daniel-Cross Dec 21, 2024
4fecdd1
resolved conflicts
Daniel-Cross Dec 21, 2024
41923b1
added input props
Daniel-Cross Dec 25, 2024
26476fb
made changes to types for input
Daniel-Cross Dec 28, 2024
dcd89af
addressed footer type issue
Daniel-Cross Dec 29, 2024
29ea7f6
fixed some liter issues
Daniel-Cross Dec 31, 2024
ef4832b
fixed colours
Daniel-Cross Dec 31, 2024
5da4e2e
fixed colour import
Daniel-Cross Dec 31, 2024
e8bd935
fixed global element declaration issue
Daniel-Cross Dec 31, 2024
c8f3a18
removed the need to use flex on mobile
Daniel-Cross Dec 31, 2024
d7d00ad
changed enum related values in footer
Daniel-Cross Dec 31, 2024
d8e191c
fixed linting issues from enums
Daniel-Cross Dec 31, 2024
5f42682
removed enum usage
Daniel-Cross Jan 1, 2025
125e2da
removed unused import
Daniel-Cross Jan 1, 2025
53a16d9
added a package for handling html entities
Daniel-Cross Jan 7, 2025
cde7cee
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 7, 2025
59f2c7d
yarn deduplicate
Daniel-Cross Jan 7, 2025
4a1d0fb
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 7, 2025
79d81bf
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 8, 2025
7d03e1b
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 9, 2025
f9665d3
Add SnapInterfaceController:stateChange to permissions
owencraston Jan 11, 2025
82bbfd5
working snaps dialogs again
Daniel-Cross Jan 11, 2025
4c43ab0
fixed conflicts from main
Daniel-Cross Jan 12, 2025
ece756d
added some tests
Daniel-Cross Jan 12, 2025
02e9381
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 13, 2025
d4bb190
added snapDialogApproval tests
Daniel-Cross Jan 13, 2025
8946c40
removed unused test
Daniel-Cross Jan 13, 2025
9313660
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 13, 2025
b4cee38
moved test files
Daniel-Cross Jan 13, 2025
cb608e7
fixed conflicts from main
Daniel-Cross Jan 14, 2025
ea17669
added more tests for snapsInterfaceContext
Daniel-Cross Jan 14, 2025
e7b545e
added tests for snaps ui input
Daniel-Cross Jan 14, 2025
e11a162
added tests for formTextField
Daniel-Cross Jan 14, 2025
d5691e6
fixed liting issues on tests
Daniel-Cross Jan 14, 2025
fb7769a
fixed linting for heading tests
Daniel-Cross Jan 14, 2025
e02d763
added tests for box
Daniel-Cross Jan 14, 2025
1f7d313
added Box tests
Daniel-Cross Jan 14, 2025
2830669
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 14, 2025
e548a60
updated tests for linter
Daniel-Cross Jan 14, 2025
96e2b62
more linter fixes
Daniel-Cross Jan 14, 2025
478cf3a
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 14, 2025
1b7d9a7
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 14, 2025
2302c37
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 15, 2025
2ea5db0
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 16, 2025
dbce24c
Update app/core/Permissions/specifications.js
Daniel-Cross Jan 17, 2025
2097ad7
Update app/core/Snaps/SnapsMethodMiddleware.ts
Daniel-Cross Jan 17, 2025
09d3ea4
Update app/components/Approvals/Snaps/SnapUIRenderer/SnapUIRenderer.tsx
Daniel-Cross Jan 17, 2025
590a82a
Update app/components/Approvals/Snaps/SnapUIRenderer/utils.ts
Daniel-Cross Jan 17, 2025
c522d51
Update app/components/Approvals/Snaps/SnapUIRenderer/utils.ts
Daniel-Cross Jan 17, 2025
a574fbd
working custom snaps buttons
Daniel-Cross Jan 28, 2025
ede58f0
working confirm button
Daniel-Cross Jan 28, 2025
9b3be41
added icons to custom buttons
Daniel-Cross Jan 29, 2025
f78b392
resolved conflicts
Daniel-Cross Jan 29, 2025
fc0fb8a
updated tests
Daniel-Cross Jan 29, 2025
2ff8865
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Jan 29, 2025
a79a624
get snap icon
owencraston Jan 30, 2025
221785e
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Feb 3, 2025
3fe8fd9
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Feb 3, 2025
67834d7
fixed some tests
Daniel-Cross Feb 3, 2025
1b55d6c
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Feb 4, 2025
9e9ea6c
Merge branch 'main' into epic/snaps-ui
Daniel-Cross Feb 4, 2025
8537e3c
working footer tests
Daniel-Cross Feb 4, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const ButtonPrimary = ({
onPressOut,
isDanger = false,
label,
startIconName,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @brianacnguyen pointed out, what is the goal of this change?

endIconName,
...props
}: ButtonPrimaryProps) => {
const [pressed, setPressed] = useState(false);
Expand Down Expand Up @@ -60,9 +62,9 @@ const ButtonPrimary = ({
label
);

const renderLoading = () => (
<ActivityIndicator size="small" color={DEFAULT_BUTTONPRIMARY_LABEL_COLOR} />
);
const renderLoading = () => (
<ActivityIndicator size="small" color={DEFAULT_BUTTONPRIMARY_LABEL_COLOR} />
);

return (
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,6 @@ exports[`ButtonPrimary render matches latest snapshot 1`] = `
}
}
>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

<SvgMock
color="#ffffff"
height={16}
name="Add"
style={
{
"height": 16,
"marginRight": 8,
"width": 16,
}
}
width={16}
/>
<Text
accessibilityRole="text"
style={
Expand All @@ -50,18 +37,5 @@ exports[`ButtonPrimary render matches latest snapshot 1`] = `
>
Sample label
</Text>
<SvgMock
color="#ffffff"
height={16}
name="AddSquare"
style={
{
"height": 16,
"marginLeft": 8,
"width": 16,
}
}
width={16}
/>
</TouchableOpacity>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { StyleSheet } from 'react-native';
import { Theme } from '../../../../util/theme/models';
import Device from '../../../../util/device';

/**
*
* @param params Style sheet params.
* @param params.theme App theme from ThemeContext.
* @param params.vars Inputs that the style sheet depends on.
* @returns StyleSheet object.
*/
const styleSheet = (params: { theme: Theme }) => {
const { theme } = params;
const { colors } = theme;
return StyleSheet.create({
root: {
backgroundColor: colors.background.default,
paddingTop: 24,
paddingLeft: 16,
paddingRight: 16,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
minHeight: 200,
paddingBottom: Device.isIphoneX() ? 20 : 0,
},
actionContainer: {
flex: 0,
paddingVertical: 16,
justifyContent: 'center',
},
});
};

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps)
import React, { useState } from 'react';
import { useStyles } from '../../../hooks/useStyles';
import { strings } from '../../../../../locales/i18n';
import stylesheet from './SnapDialogApproval.styles';
import useApprovalRequest from '../../../Views/confirmations/hooks/useApprovalRequest';
import { View } from 'react-native-animatable';
import ApprovalModal from '../../ApprovalModal';
import BottomSheetFooter, {
ButtonsAlignment,
} from '../../../../component-library/components/BottomSheets/BottomSheetFooter';
import {
ButtonVariants,
ButtonSize,
} from '../../../../component-library/components/Buttons/Button';
import Engine from '../../../../core/Engine';
import { SnapUIRenderer } from '../SnapUIRenderer/SnapUIRenderer';
import { SnapId } from '@metamask/snaps-sdk';
import { IconName } from '../../../../component-library/components/Icons/Icon';

enum SnapDialogTypes {
ALERT = 'snap_dialog:alert',
CONFIRM = 'snap_dialog:confirmation',
PROMPT = 'snap_dialog:prompt',
CUSTOM = 'snap_dialog',
}
Comment on lines +20 to +25

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


enum TemplateConfirmation {
Ok = 'template_confirmation.ok',
CANCEL = 'template_confirmation.cancel',
}

const SnapDialogApproval = () => {
const [isLoading, setIsLoading] = useState(false);
const { approvalRequest } = useApprovalRequest();
const { styles } = useStyles(stylesheet, {});

const onCancel = async () => {
if (!approvalRequest) return;

await Engine.acceptPendingApproval(approvalRequest.id, null as any);
};

const onConfirmInput = async () => {
setIsLoading(true);
if (!approvalRequest) return;

const inputState =
await Engine.context.SnapInterfaceController.getInterface(
approvalRequest?.origin as SnapId,
approvalRequest.requestData.id,
);
await Engine.acceptPendingApproval(
approvalRequest.id,
inputState.state['custom-input'] as any,
);
setIsLoading(false);
};

const onConfirm = async () => {
setIsLoading(true);
if (!approvalRequest) return;

await Engine.acceptPendingApproval(approvalRequest.id, true as any);

setIsLoading(false);
};

const onReject = async () => {
if (!approvalRequest) return;

await Engine.acceptPendingApproval(approvalRequest.id, false as any);
};

if (
approvalRequest?.type !== SnapDialogTypes.ALERT &&
approvalRequest?.type !== SnapDialogTypes.CONFIRM &&
approvalRequest?.type !== SnapDialogTypes.PROMPT &&
approvalRequest?.type !== SnapDialogTypes.CUSTOM
)
return null;

const getDialogButtons = (type: SnapDialogTypes | undefined) => {
switch (type) {
case SnapDialogTypes.ALERT:
return [
{
variant: ButtonVariants.Primary,
label: strings(TemplateConfirmation.Ok),
size: ButtonSize.Lg,
onPress: onCancel,
},
];

case SnapDialogTypes.CONFIRM:
case SnapDialogTypes.PROMPT:
return [
{
variant: ButtonVariants.Secondary,
label: strings(TemplateConfirmation.CANCEL),
size: ButtonSize.Lg,
onPress: onReject,
},
{
variant: ButtonVariants.Primary,
label: strings(TemplateConfirmation.Ok),
size: ButtonSize.Lg,
onPress: onConfirm,
},
];
case SnapDialogTypes.CUSTOM:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom dialogs can define their own buttons. We will need to support that instead of hardcoding their text and the logic to confirm/cancel

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a Type for the expected data on these custom buttons? I took a look at the extension code but it's much different to how we implement on Mobile so it's hard to make sense of what data should be expected for the custom buttons. Also, it doesn't seem to have any custom data coming from the snaps when I search for the button content.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has also not been addressed yet, unresolving.

return [
{
variant: ButtonVariants.Secondary,
label: strings(TemplateConfirmation.CANCEL),
size: ButtonSize.Lg,
onPress: onCancel,
startIconName: IconName.Close,
},
{
variant: ButtonVariants.Primary,
label: strings(TemplateConfirmation.Ok),
size: ButtonSize.Lg,
onPress: onConfirmInput,
endIconName: IconName.Check,
},
];

default:
return [];
}
};

const buttons = getDialogButtons(approvalRequest?.type);
const snapId = approvalRequest?.origin;
const interfaceId = approvalRequest?.requestData?.id;

return (
<ApprovalModal
isVisible={
approvalRequest?.type === SnapDialogTypes.ALERT ||
approvalRequest?.type === SnapDialogTypes.CONFIRM ||
approvalRequest?.type === SnapDialogTypes.PROMPT ||
approvalRequest?.type === SnapDialogTypes.CUSTOM
}
onCancel={onCancel}
>
<View style={styles.root}>
<SnapUIRenderer
snapId={snapId}
interfaceId={interfaceId}
isLoading={isLoading}
/>
<View style={styles.actionContainer}>
<BottomSheetFooter
buttonsAlignment={ButtonsAlignment.Horizontal}
buttonPropsArray={buttons}
/>
</View>
</View>
</ApprovalModal>
);
};

export default SnapDialogApproval;
///: END:ONLY_INCLUDE_IF
3 changes: 3 additions & 0 deletions app/components/Approvals/Snaps/SnapDialogApproval/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps)
export { default } from './SnapDialogApproval';

Check failure on line 2 in app/components/Approvals/Snaps/SnapDialogApproval/index.ts

View workflow job for this annotation

GitHub Actions / scripts (lint:tsc)

Cannot find module './SnapDialogApproval' or its corresponding type declarations.
///: END:ONLY_INCLUDE_IF
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ImageSourcePropType } from 'react-native';

export interface SnapUICardProps {
image?: ImageSourcePropType;
title?: string;
description?: string;
value?: string;
extra?: string;
}
89 changes: 89 additions & 0 deletions app/components/Approvals/Snaps/SnapUICard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps)
import React from 'react';
import { Image } from 'react-native';
// External dependencies.
import {
AlignItems,
Display,
FlexDirection,
JustifyContent,
TextAlign,
} from '../SnapUIRenderer/utils';
import Text, {
TextColor,
TextVariant,
} from '../../../../component-library/components/Texts/Text';
import { SnapUICardProps } from './SnapUICard.props';
import styles, { Box } from '../../../UI/Box';

export const SnapUICard: React.FC<SnapUICardProps> = ({
image,
title,
description,
value,
extra,
}) => (
<Box
testID="snaps-ui-card"
display={Display.Flex}
justifyContent={JustifyContent.spaceBetween}
alignItems={AlignItems.center}
>
<Box display={Display.Flex} gap={4} alignItems={AlignItems.center}>
{image && (
<Image
Daniel-Cross marked this conversation as resolved.
Show resolved Hide resolved
width={32}
height={32}
source={image}
style={styles.overflowHidden}
/>
)}
<Box
display={Display.Flex}
flexDirection={FlexDirection.Column}
style={styles.overflowHidden}
>
<Text
variant={TextVariant.BodyMDMedium}
numberOfLines={1}
ellipsizeMode="tail"
>
{title}
</Text>
{description && (
<Text
color={TextColor.Alternative}
numberOfLines={1}
ellipsizeMode="tail"
>
{description}
</Text>
)}
</Box>
</Box>
<Box
display={Display.Flex}
flexDirection={FlexDirection.Column}
textAlign={TextAlign.right}
style={styles.overflowHidden}
>
<Text
variant={TextVariant.BodyMDMedium}
numberOfLines={1}
ellipsizeMode="tail"
>
{value}
</Text>
{extra && (
<Text
color={TextColor.Alternative}
numberOfLines={1}
ellipsizeMode="tail"
>
{extra}
</Text>
)}
</Box>
</Box>
);
///: END:ONLY_INCLUDE_IF
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type SetCurrentInputFocus = (name: string | null) => void;
Loading
Loading