diff --git a/app/src/app/(drawer)/[account]/settings.tsx b/app/src/app/(drawer)/[account]/settings.tsx
index 936df58cd..b7ba15cb5 100644
--- a/app/src/app/(drawer)/[account]/settings.tsx
+++ b/app/src/app/(drawer)/[account]/settings.tsx
@@ -1,4 +1,4 @@
-import { useRouter } from 'expo-router';
+import { Link, useRouter } from 'expo-router';
import { gql } from '@api/generated';
import { FlashList } from '@shopify/flash-list';
import { EditIcon, NavigateNextIcon } from '@theme/icons';
@@ -117,17 +117,15 @@ function AccountSettingsScreen() {
)}
-
+
+
diff --git a/app/src/app/(drawer)/approvers/[address]/index.tsx b/app/src/app/(drawer)/approvers/[address]/index.tsx
index 87854e456..adc9987fe 100644
--- a/app/src/app/(drawer)/approvers/[address]/index.tsx
+++ b/app/src/app/(drawer)/approvers/[address]/index.tsx
@@ -1,4 +1,4 @@
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { View } from 'react-native';
import { Actions } from '~/components/layout/Actions';
import { StyleSheet } from 'react-native';
@@ -55,7 +55,6 @@ const ApproverScreenParams = z.object({ address: zAddress() });
function ApproverScreen() {
const params = useLocalParams(ApproverScreenParams);
- const router = useRouter();
const update = useMutation(Update)[1];
const query = useQuery(Query, { approver: params.address });
@@ -98,18 +97,17 @@ function ApproverScreen() {
-
+
+
>
diff --git a/app/src/app/onboard/auth.tsx b/app/src/app/onboard/auth.tsx
index 176765626..54fd26d63 100644
--- a/app/src/app/onboard/auth.tsx
+++ b/app/src/app/onboard/auth.tsx
@@ -1,17 +1,15 @@
-import { useRouter } from 'expo-router';
-import { Button } from 'react-native-paper';
+import { Link } from 'expo-router';
+import { Button } from '~/components/Button';
import { AuthSettings } from '~/components/shared/AuthSettings';
export default function NotificationsOnboardingScreen() {
- const router = useRouter();
-
return (
router.push(`/onboard/notifications`)}>
- Continue
-
+
+
+
}
/>
);
diff --git a/app/src/components/Button.tsx b/app/src/components/Button.tsx
index c0f0f6ca8..19214596b 100644
--- a/app/src/components/Button.tsx
+++ b/app/src/components/Button.tsx
@@ -1,14 +1,16 @@
import { useWithLoading } from '~/hooks/useWithLoading';
-import { Keyboard } from 'react-native';
+import { Keyboard, View } from 'react-native';
import { Button as PaperButton, ButtonProps as PaperButtonProps } from 'react-native-paper';
+import { forwardRef } from 'react';
export interface ButtonProps extends PaperButtonProps {}
-export const Button = (props: PaperButtonProps) => {
+export const Button = forwardRef((props, ref) => {
const [loading, onPress] = useWithLoading(props.onPress);
return (
{
})}
/>
);
-};
+});
diff --git a/app/src/components/home/GettingStarted/useCreatePolicySuggestion.tsx b/app/src/components/home/GettingStarted/useCreatePolicySuggestion.tsx
index 67b2e3373..09829e95e 100644
--- a/app/src/components/home/GettingStarted/useCreatePolicySuggestion.tsx
+++ b/app/src/components/home/GettingStarted/useCreatePolicySuggestion.tsx
@@ -1,6 +1,6 @@
import { FragmentType, gql, useFragment } from '@api';
import { PolicyIcon } from '@theme/icons';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { Suggestion } from '~/components/home/GettingStarted/suggestions';
import { ListItem } from '~/components/list/ListItem';
@@ -23,21 +23,18 @@ export interface UseCreatePolicySuggestionParams {
export function useCreatePolicySuggestion(props: UseCreatePolicySuggestionParams): Suggestion {
const account = useFragment(Account, props.account);
- const router = useRouter();
return {
Item: (props) => (
-
- router.push({
- pathname: `/(drawer)/[account]/policies/[key]/`,
- params: { account: account.address, key: 'add' },
- })
- }
- {...props}
- />
+
+
+
),
complete: account.policies.filter((p) => p.state).length > 1,
};
diff --git a/app/src/components/home/GettingStarted/useLinkDeviceSuggestion.tsx b/app/src/components/home/GettingStarted/useLinkDeviceSuggestion.tsx
index ad8111a71..5871436bd 100644
--- a/app/src/components/home/GettingStarted/useLinkDeviceSuggestion.tsx
+++ b/app/src/components/home/GettingStarted/useLinkDeviceSuggestion.tsx
@@ -1,7 +1,7 @@
import { FragmentType, gql, useFragment } from '@api';
import { useApproverAddress } from '~/lib/network/useApprover';
import { DevicesIcon } from '@theme/icons';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { Suggestion } from '~/components/home/GettingStarted/suggestions';
import { ListItem } from '~/components/list/ListItem';
@@ -27,16 +27,12 @@ export interface UseLinkDeviceSuggestionProps {
export function useLinkDeviceSuggestion(props: UseLinkDeviceSuggestionProps): Suggestion {
const user = useFragment(User, props.user);
const approver = useApproverAddress();
- const router = useRouter();
return {
Item: (props) => (
- router.push(`/link/`)}
- {...props}
- />
+
+
+
),
complete: !!user.approvers.find(
(a) => a.address !== approver && !a.bluetoothDevices?.length && !a.cloud,
diff --git a/app/src/components/item/UserApproverItem.tsx b/app/src/components/item/UserApproverItem.tsx
index 3c89f6e88..da82169e6 100644
--- a/app/src/components/item/UserApproverItem.tsx
+++ b/app/src/components/item/UserApproverItem.tsx
@@ -1,6 +1,6 @@
import { FragmentType, gql, useFragment } from '@api/generated';
import { useApproverAddress } from '~/lib/network/useApprover';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { ListItem, ListItemProps } from '~/components/list/ListItem';
import { truncateAddr } from '~/util/format';
@@ -23,19 +23,20 @@ export interface UserApproverItemProps extends Partial {
export function UserApproverItem(props: UserApproverItemProps) {
const a = useFragment(UserApprover, props.approver);
- const router = useRouter();
const selected = useApproverAddress() === a.address;
return (
-
- router.push({ pathname: `/(drawer)/approvers/[address]/`, params: { address: a.address } })
- }
- {...props}
- />
+
+
+
);
}
diff --git a/app/src/components/list/ListItem.tsx b/app/src/components/list/ListItem.tsx
index 95f6a0038..fafe30a64 100644
--- a/app/src/components/list/ListItem.tsx
+++ b/app/src/components/list/ListItem.tsx
@@ -1,4 +1,4 @@
-import { FC, ReactNode } from 'react';
+import { FC, ReactNode, forwardRef } from 'react';
import { IconProps } from '@theme/icons';
import { Text, TouchableRipple, TouchableRippleProps } from 'react-native-paper';
import { AddressOrLabelIcon } from '../Identicon/AddressOrLabelIcon';
@@ -34,119 +34,125 @@ export type ListItemProps = Pick &
textStyle?: StyleProp;
};
-export function ListItem({
- leading: Leading,
- leadingSize = typeof Leading === 'string' ? 'medium' : 'small',
- overline: Overline,
- headline: Headline,
- supporting: Supporting,
- trailing: Trailing,
- lines = (1 + Number(!!Overline) + Number(!!Supporting)) as Lines,
- selected,
- disabled,
- avatarLeadingSize,
- containerStyle,
- textStyle,
- ...touchableProps
-}: ListItemProps) {
- const { styles } = useStyles(
- useMemoApply(getStylesheet, { lines, leadingSize, selected, disabled, avatarLeadingSize }),
- );
-
- const OverlineText = ({ style, ...props }: TextProps) => (
-
- );
- const HeadlineText = ({ style, ...props }: TextProps) => (
-
- );
- const SupportingText = ({ style, ...props }: TextProps) => (
-
- );
- const TrailingText = ({ style, ...props }: TextProps) => (
-
- );
-
- return (
-
- <>
- {Leading && (
-
- {typeof Leading === 'string' ? (
-
- ) : (
-
- )}
-
- )}
-
-
- {Overline &&
- (typeof Overline === 'function' ? (
-
- ) : (
- {Overline}
- ))}
-
- {typeof Headline === 'function' ? (
-
- ) : (
- {Headline}
+export const ListItem = forwardRef(
+ (
+ {
+ leading: Leading,
+ leadingSize = typeof Leading === 'string' ? 'medium' : 'small',
+ overline: Overline,
+ headline: Headline,
+ supporting: Supporting,
+ trailing: Trailing,
+ lines = (1 + Number(!!Overline) + Number(!!Supporting)) as Lines,
+ selected,
+ disabled,
+ avatarLeadingSize,
+ containerStyle,
+ textStyle,
+ ...touchableProps
+ },
+ ref,
+ ) => {
+ const { styles } = useStyles(
+ useMemoApply(getStylesheet, { lines, leadingSize, selected, disabled, avatarLeadingSize }),
+ );
+
+ const OverlineText = ({ style, ...props }: TextProps) => (
+
+ );
+ const HeadlineText = ({ style, ...props }: TextProps) => (
+
+ );
+ const SupportingText = ({ style, ...props }: TextProps) => (
+
+ );
+ const TrailingText = ({ style, ...props }: TextProps) => (
+
+ );
+
+ return (
+
+ <>
+ {Leading && (
+
+ {typeof Leading === 'string' ? (
+
+ ) : (
+
+ )}
+
)}
- {Supporting &&
- (typeof Supporting === 'function' ? (
-
- ) : (
- {Supporting}
- ))}
-
-
- {Trailing && (
-
- {typeof Trailing === 'function' ? (
-
+
+ {Overline &&
+ (typeof Overline === 'function' ? (
+
+ ) : (
+ {Overline}
+ ))}
+
+ {typeof Headline === 'function' ? (
+
) : (
- {Trailing}
+ {Headline}
)}
+
+ {Supporting &&
+ (typeof Supporting === 'function' ? (
+
+ ) : (
+ {Supporting}
+ ))}
- )}
- >
-
- );
-}
+
+ {Trailing && (
+
+ {typeof Trailing === 'function' ? (
+
+ ) : (
+ {Trailing}
+ )}
+
+ )}
+ >
+
+ );
+ },
+);
interface StyleProps {
lines: Lines;
diff --git a/app/src/components/message/MessageItem.tsx b/app/src/components/message/MessageItem.tsx
index 45eed9cf3..828ab1d13 100644
--- a/app/src/components/message/MessageItem.tsx
+++ b/app/src/components/message/MessageItem.tsx
@@ -2,7 +2,7 @@ import { FragmentType, gql, useFragment } from '@api/generated';
import { ListItem, ListItemProps } from '../list/ListItem';
import { MessageIcon } from './MessageIcon';
import { P, match } from 'ts-pattern';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { createStyles, useStyles } from '@theme/styles';
const MessageProposal = gql(/* GraphQL */ `
@@ -34,7 +34,6 @@ export interface MessageItemProps {
export function MessageItem(props: MessageItemProps) {
const { styles } = useStyles(stylesheet);
- const router = useRouter();
const p = useFragment(MessageProposal, props.proposal);
const user = useFragment(User, props.user);
@@ -52,13 +51,14 @@ export function MessageItem(props: MessageItemProps) {
.exhaustive();
return (
- }
- leadingSize="medium"
- headline={p.label || 'Message'}
- supporting={supporting}
- onPress={() => router.push({ pathname: `/(drawer)/message/[id]`, params: { id: p.id } })}
- />
+
+ }
+ leadingSize="medium"
+ headline={p.label || 'Message'}
+ supporting={supporting}
+ />
+
);
}
diff --git a/app/src/components/policy/TokenLimitItem.tsx b/app/src/components/policy/TokenLimitItem.tsx
index 34bf07ec0..1fe41f396 100644
--- a/app/src/components/policy/TokenLimitItem.tsx
+++ b/app/src/components/policy/TokenLimitItem.tsx
@@ -1,6 +1,6 @@
import { FragmentType, gql, useFragment as getFragment } from '@api';
import { NavigateNextIcon } from '@theme/icons';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { Address, TransferLimit, asDecimal } from 'lib';
import _ from 'lodash';
import { Duration } from 'luxon';
@@ -29,7 +29,6 @@ export interface TokenSpendingProps {
export function TokenLimitItem({ address, ...props }: TokenSpendingProps) {
const token = getFragment(Token, props.token);
- const router = useRouter();
const [policy] = usePolicyDraftState();
const limit: TransferLimit | undefined = policy.transfers.limits[address];
@@ -41,30 +40,34 @@ export function TokenLimitItem({ address, ...props }: TokenSpendingProps) {
const duration = Duration.fromObject({ seconds: limit?.duration ?? 0 });
return (
-
- token ? (
-
- ) : (
-
- )
- }
- headline={token?.name ?? truncateAddr(address)}
- trailing={(props) => (
-
-
- {!limit?.amount ? 'Not allowed' : `${formattedAmount} per ${prettyDuration(duration)}`}
-
-
-
- )}
- onPress={() =>
- router.push({
- pathname: `/(drawer)/[account]/policies/[key]/spending/[token]`,
- params: { account: policy.account, key: policy.key ?? 'add', token: address },
- })
- }
- />
+
+
+ token ? (
+
+ ) : (
+
+ )
+ }
+ headline={token?.name ?? truncateAddr(address)}
+ trailing={(props) => (
+
+
+ {!limit?.amount
+ ? 'Not allowed'
+ : `${formattedAmount} per ${prettyDuration(duration)}`}
+
+
+
+ )}
+ />
+
);
}
diff --git a/app/src/components/shared/AuthSettings.tsx b/app/src/components/shared/AuthSettings.tsx
index 96333fdcd..a5cdc3b6b 100644
--- a/app/src/components/shared/AuthSettings.tsx
+++ b/app/src/components/shared/AuthSettings.tsx
@@ -12,7 +12,7 @@ import { ScrollableScreenSurface } from '~/components/layout/ScrollableScreenSur
import { AppbarOptions } from '~/components/Appbar/AppbarOptions';
import { AppbarMenu } from '~/components/Appbar/AppbarMenu';
import { Button } from '~/components/Button';
-import { Href, useRouter } from 'expo-router';
+import { Href, Link } from 'expo-router';
import { useBiometrics } from '~/hooks/useBiometrics';
import { usePasswordHash } from '~/app/(drawer)/settings/password';
import { persistedAtom } from '~/lib/persistedAtom';
@@ -35,7 +35,6 @@ export interface AuthSettingsProps {
}
function AuthSettings_({ actions, appbarMenu, passwordHref }: AuthSettingsProps) {
- const router = useRouter();
const biometrics = useBiometrics();
const passwordConfigured = !!usePasswordHash();
@@ -62,9 +61,9 @@ function AuthSettings_({ actions, appbarMenu, passwordHref }: AuthSettingsProps)
leading={PasswordIcon}
headline="Password"
trailing={() => (
-
+
+
+
)}
/>
diff --git a/app/src/components/transaction/TransactionItem.tsx b/app/src/components/transaction/TransactionItem.tsx
index fe73599ef..3b6a5559f 100644
--- a/app/src/components/transaction/TransactionItem.tsx
+++ b/app/src/components/transaction/TransactionItem.tsx
@@ -7,11 +7,9 @@ import { materialCommunityIcon } from '@theme/icons';
import { ICON_SIZE } from '@theme/paper';
import { FragmentType, gql, useFragment } from '@api/generated';
import { OperationLabel } from './OperationLabel';
-import { ETH_ICON_URI, TokenIcon } from '../token/TokenIcon';
import { ProposalValue } from './ProposalValue';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
import { createStyles, useStyles } from '@theme/styles';
-import { asUAddress } from 'lib';
import { OperationIcon } from '~/components/transaction/OperationIcon';
const Proposal = gql(/* GraphQL */ `
@@ -66,7 +64,6 @@ function TransactionItem_({
...itemProps
}: TransactionItemProps) {
const { styles } = useStyles(stylesheet);
- const router = useRouter();
const p = useFragment(Proposal, proposalFragment);
const user = useFragment(User, userFragment);
@@ -99,32 +96,33 @@ function TransactionItem_({
.exhaustive();
return (
-
- isMulti ? (
-
- ) : (
-
- )
- }
- leadingSize="medium"
- headline={
- p.label ??
- (isMulti ? (
- `${p.operations.length} operations`
- ) : (
-
- ))
- }
- supporting={supporting}
- trailing={({ Text }) => (
-
-
-
- )}
- onPress={() => router.push({ pathname: `/(drawer)/transaction/[id]`, params: { id: p.id } })}
- {...itemProps}
- />
+
+
+ isMulti ? (
+
+ ) : (
+
+ )
+ }
+ leadingSize="medium"
+ headline={
+ p.label ??
+ (isMulti ? (
+ `${p.operations.length} operations`
+ ) : (
+
+ ))
+ }
+ supporting={supporting}
+ trailing={({ Text }) => (
+
+
+
+ )}
+ {...itemProps}
+ />
+
);
}
diff --git a/app/src/components/walletconnect/PairingItem.tsx b/app/src/components/walletconnect/PairingItem.tsx
index 423b0c98b..4a9312008 100644
--- a/app/src/components/walletconnect/PairingItem.tsx
+++ b/app/src/components/walletconnect/PairingItem.tsx
@@ -7,7 +7,7 @@ import { useWalletConnect } from '~/util/walletconnect';
import { useTimestamp } from '~/components/format/Timestamp';
import { DateTime } from 'luxon';
import { MoreVerticalIcon } from '@theme/icons';
-import { useRouter } from 'expo-router';
+import { Link } from 'expo-router';
export interface PairingItemProps {
pairing: PairingTypes.Struct;
@@ -15,7 +15,6 @@ export interface PairingItemProps {
export const PairingItem = ({ pairing }: PairingItemProps) => {
const client = useWalletConnect();
- const router = useRouter();
const session: SessionTypes.Struct | undefined = client.session.getAll({
pairingTopic: pairing.topic,
})?.[0];
@@ -26,20 +25,22 @@ export const PairingItem = ({ pairing }: PairingItemProps) => {
const expires = status !== 'Expired' ? `Expires ${expiry}` : '';
return (
- 0
- ? (props) =>
- : peer.name || '?'
- }
- headline={peer.name || 'Unnamed DApp'}
- supporting={`${status}\n${expires}`}
- lines={3}
- trailing={MoreVerticalIcon}
- onPress={() =>
- router.push({ pathname: `/(sheet)/sessions/[topic]`, params: { topic: pairing.topic } })
- }
- />
+
+ 0
+ ? (props) =>
+ : peer.name || '?'
+ }
+ headline={peer.name || 'Unnamed DApp'}
+ supporting={`${status}\n${expires}`}
+ lines={3}
+ trailing={MoreVerticalIcon}
+ />
+
);
};