Skip to content

Commit

Permalink
feat(web3hub): new bottom modal to select network and account with da…
Browse files Browse the repository at this point in the history
…pp browser v3

Small perf improvement for dapp browser v3 dapps initial load
Lots of small visual improvements, polish and bugfixes
Update app screen header url
  • Loading branch information
Justkant committed Aug 28, 2024
1 parent 531bc03 commit 248901b
Show file tree
Hide file tree
Showing 14 changed files with 457 additions and 38 deletions.
8 changes: 8 additions & 0 deletions .changeset/hip-plants-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"live-mobile": minor
---

feat(web3hub): new bottom modal to select network and account with dapp browser v3
Small perf improvement for dapp browser v3 dapps initial load
Lots of small visual improvements, polish and bugfixes
Update app screen header url
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export type AddAccountsNavigatorParamList = {
inline?: boolean;
returnToSwap?: boolean;
analyticsPropertyFlow?: string;
onSuccess?: () => void;
onSuccess?: (res: { scannedAccounts: Account[]; selected: Account[] }) => void;
};
[ScreenName.AddAccountsAccounts]: {
currency: CryptoOrTokenCurrency;
device: Device;
inline?: boolean;
returnToSwap?: boolean;
onSuccess?: (_?: unknown) => void;
onSuccess?: (res: { scannedAccounts: Account[]; selected: Account[] }) => void;
};
[ScreenName.AddAccountsSuccess]?: {
currency: CryptoOrTokenCurrency;
Expand Down
13 changes: 13 additions & 0 deletions apps/ledger-live-mobile/src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -6880,6 +6880,19 @@
"title": "Clear signing",
"description": "Clear signing allows you to sign a message without revealing the content of the message to the app. This is useful for privacy and security reasons."
}
},
"app": {
"selectAccountModal": {
"networkHeader": {
"title": "Choose a network"
},
"accountHeader": {
"title": "Choose an account"
},
"addAccountItem": {
"name": "Add an account"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from "react";
import React, { useCallback, useState } from "react";
import { Trans } from "react-i18next";
import { Text } from "@ledgerhq/native-ui";
import { AppManifest } from "@ledgerhq/live-common/wallet-api/types";
import { CurrentAccountHistDB } from "@ledgerhq/live-common/wallet-api/react";
import { useDappCurrentAccount } from "@ledgerhq/live-common/wallet-api/useDappLogic";
import Button from "~/components/Button";
import CircleCurrencyIcon from "~/components/CircleCurrencyIcon";
import { useSelectAccount } from "~/components/Web3AppWebview/helpers";
import { useMaybeAccountName } from "~/reducers/wallet";
import SelectAccountModal from "./SelectAccountModal";

type SelectAccountButtonProps = {
manifest: AppManifest;
Expand All @@ -17,36 +18,55 @@ export default function SelectAccountButton({
manifest,
currentAccountHistDb,
}: SelectAccountButtonProps) {
const { onSelectAccount, currentAccount } = useSelectAccount({ manifest, currentAccountHistDb });
const { currentAccount } = useDappCurrentAccount(currentAccountHistDb);

const currentAccountName = useMaybeAccountName(currentAccount);

const [modalOpened, setModalOpened] = useState(false);

const onSelectAccount = useCallback(() => {
setModalOpened(true);
}, []);

const onClose = useCallback(() => {
setModalOpened(false);
}, []);

return (
<Button
Icon={
!currentAccount ? undefined : (
<CircleCurrencyIcon
size={24}
currency={
currentAccount.type === "TokenAccount"
? currentAccount.token
: currentAccount.currency
}
/>
)
}
iconPosition={"left"}
type="primary"
onPress={onSelectAccount}
isNewIcon
>
{!currentAccount ? (
<Text>
<Trans i18nKey="common.selectAccount" />
</Text>
) : (
<Text color={"neutral.c20"}>{currentAccountName}</Text>
)}
</Button>
<>
<SelectAccountModal
manifest={manifest}
currentAccountHistDb={currentAccountHistDb}
isOpened={modalOpened}
onSelectAccount={onSelectAccount}
onClose={onClose}
/>
<Button
Icon={
!currentAccount ? undefined : (
<CircleCurrencyIcon
size={24}
currency={
currentAccount.type === "TokenAccount"
? currentAccount.token
: currentAccount.currency
}
/>
)
}
iconPosition={"left"}
type="primary"
onPress={onSelectAccount}
isNewIcon
>
{!currentAccount ? (
<Text>
<Trans i18nKey="common.selectAccount" />
</Text>
) : (
<Text color={"neutral.c20"}>{currentAccountName}</Text>
)}
</Button>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import { BorderlessButton } from "react-native-gesture-handler";
import { Box, Icons } from "@ledgerhq/native-ui";

export default function BackButton({ onPress }: { onPress: () => void }) {
return (
<BorderlessButton onPress={onPress} activeOpacity={0.5} borderless={false}>
<Box
pr={3}
height={32}
justifyContent={"center"}
accessible
accessibilityRole="button"
aria-label="back"
>
<Icons.ArrowLeft />
</Box>
</BorderlessButton>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { PropsWithChildren } from "react";
import { useTranslation } from "react-i18next";
import { Box, Flex, Text } from "@ledgerhq/native-ui";
import BackButton from "./BackButton";

export default function AccountHeaderWrapper(onBackPress: () => void) {
return function AccountHeader({ children }: PropsWithChildren) {
const { t } = useTranslation();

return (
<>
<Flex mt={6} mx={6} flexDirection={"row"}>
<BackButton onPress={onBackPress} />
<Flex flex={1} height={32} justifyContent={"center"}>
<Text variant="h5">{t("web3hub.app.selectAccountModal.accountHeader.title")}</Text>
</Flex>
{children}
</Flex>
<Box height="1px" width="100%" backgroundColor={"translucentGrey"} />
</>
);
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { TouchableOpacity } from "react-native";
import { useTheme } from "@react-navigation/native";
import { useTranslation } from "react-i18next";
import { Flex, Text, Icons } from "@ledgerhq/native-ui";

export default function AddAccountItem({ onPress }: { onPress: () => void }) {
const { t } = useTranslation();
const { colors } = useTheme();

return (
<>
<TouchableOpacity onPress={onPress}>
<Flex pt={6} px={6} pb={3} flexDirection={"row"} alignItems={"center"}>
<Flex
backgroundColor={colors.grey}
height={50}
width={50}
borderRadius={50}
alignItems={"center"}
justifyContent={"center"}
>
<Icons.Plus />
</Flex>

<Text flex={1} pl={4} variant="large" fontWeight="semiBold" numberOfLines={1}>
{t("web3hub.app.selectAccountModal.addAccountItem.name")}
</Text>
</Flex>
</TouchableOpacity>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from "react";
import { StyleSheet } from "react-native";
import { useSelector } from "react-redux";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
import { AccountLike, SubAccount } from "@ledgerhq/types-live";
import { isAccount } from "@ledgerhq/live-common/account/index";
import { FlashList } from "@shopify/flash-list";
import { accountsByCryptoCurrencyScreenSelector } from "~/reducers/accounts";
import AccountCard from "~/components/AccountCard";
import AddAccountItem from "./AddAccountItem";

type AccountTuple = {
account: AccountLike;
subAccount: SubAccount | null;
name: string;
};

const accountKeyExtractor = (item: AccountTuple) => item.subAccount?.id || item.account.id;

const noop = () => {};

const renderAccountItem = ({
item,
extraData = noop,
}: {
item: AccountTuple;
extraData?: (account: AccountLike) => void;
}) => {
const account = item.subAccount || item.account;
const parentAccount = item.subAccount && isAccount(item.account) ? item.account : undefined;

return (
<AccountCard
account={account}
parentAccount={parentAccount}
style={styles.accountCard}
iconSize={50}
// Cannot use useCallback as we are not in a component
onPress={() => {
extraData(account);
}}
/>
);
};

export default function AccountsList({
currency,
onPressItem,
onAddAccount,
}: {
currency: CryptoCurrency;
onPressItem: (account: AccountLike) => void;
onAddAccount: () => void;
}) {
const accounts = useSelector(accountsByCryptoCurrencyScreenSelector(currency));

return (
<FlashList
contentContainerStyle={styles.list}
testID="web3hub-select-account"
ListHeaderComponent={<AddAccountItem onPress={onAddAccount} />}
keyExtractor={accountKeyExtractor}
renderItem={renderAccountItem}
estimatedItemSize={60}
data={accounts}
extraData={onPressItem}
/>
);
}

const styles = StyleSheet.create({
accountCard: {
paddingHorizontal: 16,
},
list: {
paddingBottom: 16,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { PropsWithChildren } from "react";
import { useTranslation } from "react-i18next";
import { Box, Flex, Text } from "@ledgerhq/native-ui";

export default function NetworkHeader({ children }: PropsWithChildren) {
const { t } = useTranslation();

return (
<>
<Flex mt={6} mx={6} flexDirection={"row"}>
<Flex flex={1} height={32} justifyContent={"center"}>
<Text variant="h5">{t("web3hub.app.selectAccountModal.networkHeader.title")}</Text>
</Flex>
{children}
</Flex>
<Box height="1px" width="100%" backgroundColor={"translucentGrey"} />
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { useCallback } from "react";
import { TouchableOpacity } from "react-native";
import { Flex, Text } from "@ledgerhq/native-ui";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
import CircleCurrencyIcon from "~/components/CircleCurrencyIcon";

type Props = {
currency: CryptoCurrency;
onPress: (currency: CryptoCurrency) => void;
};

export default function NetworkItem({ currency, onPress }: Props) {
const handlePress = useCallback(() => {
onPress(currency);
}, [currency, onPress]);

return (
<TouchableOpacity onPress={handlePress}>
<Flex pt={6} px={6} flexDirection={"row"} alignItems={"center"}>
<CircleCurrencyIcon currency={currency} size={50} />

<Text flex={1} pl={4} variant="large" fontWeight="semiBold" numberOfLines={1}>
{currency.name}
</Text>
</Flex>
</TouchableOpacity>
);
}
Loading

0 comments on commit 248901b

Please sign in to comment.