diff --git a/app/src/app/(sheet)/address/[address].tsx b/app/src/app/(sheet)/address/[address].tsx
new file mode 100644
index 000000000..236d793de
--- /dev/null
+++ b/app/src/app/(sheet)/address/[address].tsx
@@ -0,0 +1,105 @@
+import { useAddressLabel } from '#/address/AddressLabel';
+import { AddressIcon } from '#/Identicon/AddressIcon';
+import { PressableOpacity } from '#/PressableOpacity';
+import { Scrollable } from '#/Scrollable';
+import { Sheet } from '#/sheet/Sheet';
+import { ContactOutlineIcon, OutboundIcon, ShareIcon, WebIcon } from '@theme/icons';
+import { CORNER, ICON_SIZE } from '@theme/paper';
+import { createStyles, useStyles } from '@theme/styles';
+import { CHAINS } from 'chains';
+import { Link } from 'expo-router';
+import { asAddress, asChain } from 'lib';
+import { View } from 'react-native';
+import { Text } from 'react-native-paper';
+import { z } from 'zod';
+import { useLocalParams } from '~/hooks/useLocalParams';
+import { useSelectedAccount } from '~/hooks/useSelectedAccount';
+import { share } from '~/lib/share';
+import { zUAddress } from '~/lib/zod';
+
+const Params = z.object({ address: zUAddress() });
+
+export default function AddressSheet() {
+ const { styles } = useStyles(stylesheet);
+ const { address } = useLocalParams(Params);
+ const account = useSelectedAccount();
+
+ const explorer = CHAINS[asChain(address)].blockExplorers?.native.url;
+
+ return (
+
+
+
+
+ {useAddressLabel(address)}
+
+
+ {asAddress(address)}
+
+
+
+
+ share({ url: address })}>
+
+ Share
+
+
+ {explorer && (
+
+
+
+ Explorer
+
+
+ )}
+
+
+
+
+ Contact
+
+
+
+ {account && (
+
+
+
+ Send
+
+
+ )}
+
+
+ );
+}
+
+const stylesheet = createStyles(({ colors }) => ({
+ container: {
+ paddingBottom: 16,
+ },
+ headerContainer: {
+ alignItems: 'center',
+ gap: 8,
+ marginHorizontal: 16,
+ marginVertical: 8,
+ },
+ address: {
+ color: colors.onSurfaceVariant,
+ },
+ actions: {
+ justifyContent: 'center',
+ gap: 16,
+ paddingHorizontal: 16,
+ marginVertical: 8,
+ },
+ action: {
+ alignItems: 'center',
+ gap: 8,
+ width: 80,
+ paddingVertical: 8,
+ borderRadius: CORNER.m,
+ },
+}));
diff --git a/app/src/components/QrModal.tsx b/app/src/components/QrModal.tsx
index 84dfbcb90..1e07bbec1 100644
--- a/app/src/components/QrModal.tsx
+++ b/app/src/components/QrModal.tsx
@@ -35,9 +35,9 @@ export function QrModal({ address, actions }: QrModalProps) {
-
- {isUAddress(address) && }
-
+ {isUAddress(address) && (
+
+ )}
diff --git a/app/src/components/activity/IncomingTransferItem.tsx b/app/src/components/activity/IncomingTransferItem.tsx
index 7f3d19f97..a416df689 100644
--- a/app/src/components/activity/IncomingTransferItem.tsx
+++ b/app/src/components/activity/IncomingTransferItem.tsx
@@ -1,4 +1,4 @@
-import { useAddressLabel } from '#/address/AddressLabel';
+import { AddressLabel } from '#/address/AddressLabel';
import { Timestamp } from '#/format/Timestamp';
import { ListItem, ListItemProps } from '#/list/ListItem';
import { ListItemSkeleton } from '#/list/ListItemSkeleton';
@@ -40,7 +40,6 @@ export interface IncomingTransferItemProps extends Partial {
function IncomingTransferItem_(props: IncomingTransferItemProps) {
const transfer = useFragment(Transfer, props.transfer);
- const from = useAddressLabel(asUAddress(transfer.from, transfer.account.chain));
const amount = useTokenAmount({ token: transfer.token, amount: transfer.amount });
return (
@@ -58,7 +57,12 @@ function IncomingTransferItem_(props: IncomingTransferItemProps) {
}
- headline={`Received ${amount} from ${from}`}
+ headline={
+ <>
+ {`Received ${amount} from `}
+
+ >
+ }
supporting={}
trailing={({ Text }) =>
transfer.value !== null && transfer.value !== undefined ? (
diff --git a/app/src/components/address/AddressLabel.tsx b/app/src/components/address/AddressLabel.tsx
index f02b0c73b..d9defd8aa 100644
--- a/app/src/components/address/AddressLabel.tsx
+++ b/app/src/components/address/AddressLabel.tsx
@@ -3,26 +3,38 @@ import { useLazyQuery } from '~/api';
import { graphql } from 'relay-runtime';
import { AddressLabelQuery } from '~/api/__generated__/AddressLabelQuery.graphql';
import { truncateAddr } from '~/util/format';
+import { Text, TextProps } from 'react-native-paper';
+import { useRouter } from 'expo-router';
const Query = graphql`
- query AddressLabelQuery($address: UAddress!, $skip: Boolean!) {
- label(address: $address) @skip(if: $skip)
+ query AddressLabelQuery($address: UAddress!) {
+ label(address: $address)
}
`;
-export const useAddressLabel = (address: A) => {
- const { label } = useLazyQuery(Query, {
- address: address!,
- skip: !address,
- });
+export function useAddressLabel(address: UAddress) {
+ const { label } = useLazyQuery(
+ Query,
+ { address },
+ { fetchPolicy: 'store-or-network' },
+ );
- return (address ? label || truncateAddr(address) : undefined) as A extends undefined
- ? string | undefined
- : string;
-};
+ return label || truncateAddr(address);
+}
-export interface AddressLabelProps {
+export interface AddressLabelProps extends Omit, 'children'> {
address: UAddress;
}
-export const AddressLabel = ({ address }: AddressLabelProps) => useAddressLabel(address);
+export function AddressLabel({ address, ...textProps }: AddressLabelProps) {
+ const router = useRouter();
+
+ return (
+ router.push({ pathname: `/address/[address]`, params: { address } })}
+ >
+ {useAddressLabel(address)}
+
+ );
+}
diff --git a/app/src/components/policy/ApproverItem.tsx b/app/src/components/policy/ApproverItem.tsx
index 48edf2c98..70ec39bbb 100644
--- a/app/src/components/policy/ApproverItem.tsx
+++ b/app/src/components/policy/ApproverItem.tsx
@@ -1,7 +1,6 @@
import { UAddress } from 'lib';
-import { useAddressLabel } from '#/address/AddressLabel';
+import { AddressLabel } from '#/address/AddressLabel';
import { ListItem, ListItemProps } from '#/list/ListItem';
-import { truncateAddr } from '~/util/format';
import { I18nManager } from 'react-native';
import { RectButton, Swipeable } from 'react-native-gesture-handler';
import { CloseIcon, DeleteIcon } from '@theme/icons';
@@ -17,8 +16,6 @@ export interface ApproverItemProps extends Partial {
export function ApproverItem({ address, remove, ...props }: ApproverItemProps) {
const { styles } = useStyles(stylesheet);
- const label = useAddressLabel(address);
- const truncated = truncateAddr(address);
const ref = useRef(null);
@@ -46,8 +43,7 @@ export function ApproverItem({ address, remove, ...props }: ApproverItemProps) {
>
}
- headline={label}
- supporting={label !== truncated ? truncated : undefined}
+ headline={}
trailing={}
containerStyle={styles.itemContainer}
{...props}
diff --git a/app/src/components/transaction/OperationDetails.tsx b/app/src/components/transaction/OperationDetails.tsx
index 14cfd1d7f..77264037b 100644
--- a/app/src/components/transaction/OperationDetails.tsx
+++ b/app/src/components/transaction/OperationDetails.tsx
@@ -2,7 +2,7 @@ import { ClockOutlineIcon } from '@theme/icons';
import { UAddress, asChain, asUAddress } from 'lib';
import { DateTime } from 'luxon';
import { match } from 'ts-pattern';
-import { AddressLabel, useAddressLabel } from '#/address/AddressLabel';
+import { AddressLabel } from '#/address/AddressLabel';
import { useTimestamp } from '#/format/Timestamp';
import { ListItem } from '#/list/ListItem';
import { AddressIcon } from '#/Identicon/AddressIcon';
@@ -85,7 +85,7 @@ function TransferOp({ f, chain }: PropsFor<'TransferOp'>) {
}
overline="To"
- headline={useAddressLabel(asUAddress(f.to, chain))}
+ headline={}
/>
}
@@ -136,7 +136,7 @@ function TransferApprovalOp({ f, chain }: PropsFor<'TransferApprovalOp'>) {
}
overline="Spender"
- headline={useAddressLabel(asUAddress(f.to, chain))}
+ headline={}
/>
}
@@ -186,7 +186,7 @@ function Other({ op, chain }: OtherProps) {
}
overline={op.data ? 'Contract' : 'To'}
- headline={useAddressLabel(asUAddress(op.to, chain))}
+ headline={}
/>
);
}
diff --git a/app/src/components/transaction/PendingApprovalItem.tsx b/app/src/components/transaction/PendingApprovalItem.tsx
index c37b8654d..e45cda463 100644
--- a/app/src/components/transaction/PendingApprovalItem.tsx
+++ b/app/src/components/transaction/PendingApprovalItem.tsx
@@ -8,7 +8,8 @@ import { useFragment } from 'react-relay';
import { PendingApprovalItem_user$key } from '~/api/__generated__/PendingApprovalItem_user.graphql';
import { PendingApprovalItem_approver$key } from '~/api/__generated__/PendingApprovalItem_approver.graphql';
import { PendingApprovalItem_proposal$key } from '~/api/__generated__/PendingApprovalItem_proposal.graphql';
-import { truncateAddr } from '~/util/format';
+import { AddressLabel } from '#/address/AddressLabel';
+import { asUAddress } from 'lib';
const User = graphql`
fragment PendingApprovalItem_user on User {
@@ -50,7 +51,7 @@ export function PendingApprovalItem(props: PendingApprovalItemProps) {
return (
}
- headline={approver.label || truncateAddr(approver.address)}
+ headline={}
{...(approve && {
trailing: ({ size }) => (
diff --git a/app/src/util/theme/icons.tsx b/app/src/util/theme/icons.tsx
index 42a2b3f30..783be2fbd 100644
--- a/app/src/util/theme/icons.tsx
+++ b/app/src/util/theme/icons.tsx
@@ -39,7 +39,7 @@ export const materialCommunityIcon = icon('materialCommunity');
export const HomeIcon = materialIcon('home');
export const OutboundIcon = materialCommunityIcon('arrow-top-right');
-export const UserOutlineIcon = materialIcon('person-outline');
+export const ContactOutlineIcon = materialIcon('person-outline');
export const ContactsIcon = materialIcon('people');
export const ContactsOutlineIcon = materialIcon('people-outline');
export const AddIcon = materialCommunityIcon('plus');