diff --git a/packages/mobile/src/core/HideableAmount/ShowBalance.tsx b/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
index b6890c3c1..aa8417ab0 100644
--- a/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
+++ b/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
@@ -5,19 +5,41 @@ import { Steezy } from '$styles';
import { Pressable, View } from '$uikit';
import { Haptics, isAndroid } from '$utils';
import { DarkTheme } from '$styled';
-import { Text } from '@tonkeeper/uikit';
+import { Icon, Text } from '@tonkeeper/uikit';
+import { DangerLevel } from '@tonkeeper/shared/hooks';
+import { useNavigation } from '@tonkeeper/router';
+import { SettingsStackRouteNames } from '$navigation';
const TouchableComponent = isAndroid ? Pressable : TouchableHighlight;
-export const ShowBalance: React.FC<{ amount: string }> = ({ amount }) => {
+const getColorByDangerLevel = (
+ dangerLevel: DangerLevel,
+): undefined | 'accentOrange' | 'accentRed' => {
+ switch (dangerLevel) {
+ case DangerLevel.Normal:
+ return undefined;
+ case DangerLevel.Medium:
+ return 'accentOrange';
+ case DangerLevel.High:
+ return 'accentRed';
+ }
+};
+
+export const ShowBalance: React.FC<{ amount: string; dangerLevel: DangerLevel }> = ({
+ amount,
+ dangerLevel,
+}) => {
const hideAmounts = usePrivacyStore((state) => state.actions.toggleHiddenAmounts);
const isHidden = usePrivacyStore((state) => state.hiddenAmounts);
+ const nav = useNavigation();
const handleToggleHideAmounts = useCallback(() => {
hideAmounts();
Haptics.impactHeavy();
}, [hideAmounts]);
+ const handleNavigateToBackup = () => nav.navigate(SettingsStackRouteNames.Backup);
+
return (
{isHidden ? (
@@ -34,7 +56,22 @@ export const ShowBalance: React.FC<{ amount: string }> = ({ amount }) => {
) : (
- {amount}
+
+ {amount}
+
+
+ )}
+ {dangerLevel !== DangerLevel.Normal && (
+
+
)}
@@ -46,6 +83,7 @@ const styles = Steezy.create(({ colors }) => ({
flexDirection: 'row',
height: 54,
alignItems: 'center',
+ gap: 8,
},
starsContainer: {
height: 40,
@@ -59,4 +97,8 @@ const styles = Steezy.create(({ colors }) => ({
stars: {
paddingTop: 8,
},
+ dangerButton: {
+ paddingTop: 21,
+ paddingBottom: 11,
+ },
}));
diff --git a/packages/mobile/src/screens/BackupScreen/BackupScreen.tsx b/packages/mobile/src/screens/BackupScreen/BackupScreen.tsx
index d5632b91b..563c99280 100644
--- a/packages/mobile/src/screens/BackupScreen/BackupScreen.tsx
+++ b/packages/mobile/src/screens/BackupScreen/BackupScreen.tsx
@@ -4,16 +4,51 @@ import { memo } from 'react';
import { format } from 'date-fns';
import { getLocale } from '$utils/date';
import { i18n, t } from '@tonkeeper/shared/i18n';
-import { useWalletSetup } from '@tonkeeper/shared/hooks';
+import {
+ DangerLevel,
+ useDangerLevel,
+ useWalletCurrency,
+ useWalletSetup,
+} from '@tonkeeper/shared/hooks';
+import { tk } from '$wallet';
+import { formatter } from '@tonkeeper/shared/formatter';
export const BackupScreen = memo(() => {
const { lastBackupAt } = useWalletSetup();
const nav = useNavigation();
+ const currency = useWalletCurrency();
+ const dangerLevel = useDangerLevel(tk.wallet.totalTon);
+
return (
+ {dangerLevel !== DangerLevel.Normal && (
+ <>
+
+
+ {t('backup_screen.backup_warning', {
+ totalFiat: formatter.format(tk.wallet.totalFiat, { currency }),
+ })}
+
+
+
+ >
+ )}
{t('backup_screen.manual_title')}
@@ -27,7 +62,7 @@ export const BackupScreen = memo(() => {
) : (
@@ -92,4 +127,16 @@ const styles = Steezy.create(({ colors }) => ({
position: 'absolute',
right: 16,
},
+ dangerBanner: {
+ paddingHorizontal: 16,
+ paddingVertical: 12,
+ marginHorizontal: 16,
+ borderRadius: 16,
+ },
+ dangerBannerYellow: {
+ backgroundColor: colors.accentOrange,
+ },
+ dangerBannerRed: {
+ backgroundColor: colors.accentRed,
+ },
}));
diff --git a/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.tsx b/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.tsx
index 308467c6b..d84d8526d 100644
--- a/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.tsx
+++ b/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.tsx
@@ -1,10 +1,9 @@
import React, { FC, useCallback, useMemo, useRef, useState } from 'react';
import Animated, {
+ FadeIn,
FadeOut,
useAnimatedScrollHandler,
- useAnimatedStyle,
useSharedValue,
- withTiming,
} from 'react-native-reanimated';
import { TapGestureHandler } from 'react-native-gesture-handler';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -40,7 +39,7 @@ export const ImportWalletForm: FC = (props) => {
const [isConfigInputShown, setConfigInputShown] = useState(false);
const [config, setConfig] = useState('');
const [isRestoring, setRestoring] = useState(false);
- const [hasTouchedInputs, setHasTouchedInputs] = useState(false);
+ const [hasTextInAnyOfInputs, setHasTextInAnyOfInputs] = useState(false);
const deferredScrollToInput = useRef<((offset: number) => void) | null>(null);
const { keyboardHeight } = useReanimatedKeyboardHeight({
@@ -64,8 +63,8 @@ export const ImportWalletForm: FC = (props) => {
const handleMultipleWords = useCallback(
(index: number, text: string) => {
- if (!hasTouchedInputs) {
- setHasTouchedInputs(true);
+ if (!hasTextInAnyOfInputs) {
+ setHasTextInAnyOfInputs(true);
}
const words = text
.replace(/\r\n|\r|\n/g, ' ')
@@ -86,18 +85,18 @@ export const ImportWalletForm: FC = (props) => {
inputsRegistry.getRef(cursor - 1)?.focus();
}
},
- [hasTouchedInputs, inputsRegistry],
+ [hasTextInAnyOfInputs, inputsRegistry],
);
const handlePasteButton = useCallback(async () => {
- if (!hasTouchedInputs) {
- setHasTouchedInputs(true);
+ if (!hasTextInAnyOfInputs) {
+ setHasTextInAnyOfInputs(true);
}
const maybePhrase = await Clipboard.getString();
if (maybePhrase.replace(/\r\n|\r|\n/g, ' ').split(' ').length === 24) {
handleMultipleWords(0, maybePhrase);
}
- }, [hasTouchedInputs, handleMultipleWords]);
+ }, [hasTextInAnyOfInputs, handleMultipleWords]);
const handleSpace = useCallback((index: number) => {
if (index === 24) {
@@ -207,8 +206,14 @@ export const ImportWalletForm: FC = (props) => {
const handleChangeText = useCallback(
(index: number) => (text: string) => {
- if (!hasTouchedInputs) {
- setHasTouchedInputs(true);
+ if (
+ !text &&
+ hasTextInAnyOfInputs &&
+ Object.values(inputsRegistry.refs).filter((val) => val.getValue()).length === 1
+ ) {
+ setHasTextInAnyOfInputs(false);
+ } else if (!hasTextInAnyOfInputs) {
+ setHasTextInAnyOfInputs(true);
}
const overlap = 10;
const offsetTop = inputsRegistry.getPosition(index) + S.INPUT_HEIGHT - overlap;
@@ -226,7 +231,7 @@ export const ImportWalletForm: FC = (props) => {
},
});
},
- [hasTouchedInputs],
+ [hasTextInAnyOfInputs],
);
const scrollHandler = useAnimatedScrollHandler({
@@ -296,16 +301,21 @@ export const ImportWalletForm: FC = (props) => {
- {!hasTouchedInputs && (
-
-
-
- )}
+
+ {!hasTextInAnyOfInputs && (
+
+
+
+ )}
+
>
@@ -317,6 +327,6 @@ const styles = Steezy.create({
position: 'absolute',
left: 0,
right: 0,
- alignItems: 'center',
},
+ buttonContainer: { height: 48, width: '100%', alignItems: 'center' },
});
diff --git a/packages/mobile/src/tabs/Wallet/WalletScreen.tsx b/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
index 8a589ccbc..f6f911340 100644
--- a/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
+++ b/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
@@ -92,7 +92,10 @@ export const WalletScreen = memo(({ navigation }) => {
{shouldUpdate && }
-
+
{!isWatchOnly && }
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts
index a537a0a00..51b50a9f8 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts
@@ -1,18 +1,13 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import { TonInscriptionsState } from '$wallet/managers/TonInscriptions';
+import { Wallet } from '$wallet/Wallet';
export class InscriptionsDependency extends DependencyPrototype<
TonInscriptionsState,
TonInscriptionsState['items']
> {
- constructor() {
- super(tk.wallet.tonInscriptions.state, (state) => state.items);
- }
-
- setWallet(wallet) {
- this.dataProvider = wallet.tonInscriptions.state;
- super.setWallet(wallet);
+ constructor(wallet: Wallet) {
+ super(wallet.tonInscriptions.state, (state) => state.items);
}
}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts
index 07177ddbb..a592c90dd 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts
@@ -1,18 +1,18 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import { JettonsState } from '$wallet/managers/JettonsManager';
import { FiatRate } from '../utils/types';
import { Address } from '@tonkeeper/core';
import { formatter } from '$utils/formatter';
import BigNumber from 'bignumber.js';
+import { Wallet } from '$wallet/Wallet';
export class JettonBalancesDependency extends DependencyPrototype<
JettonsState,
Pick
> {
- constructor() {
- super(tk.wallet.jettons.state, (state) => ({
+ constructor(wallet: Wallet) {
+ super(wallet.jettons.state, (state) => ({
jettonBalances: state.jettonBalances,
jettonRates: state.jettonRates,
}));
@@ -40,6 +40,7 @@ export class JettonBalancesDependency extends DependencyPrototype<
trend:
rate.diff_24h.startsWith('+') || rate.diff_24h === '0' ? 'positive' : 'negative',
total: {
+ in_ton: new BigNumber(jettonBalance).multipliedBy(rate.ton).toString(),
formatted: formatter.format(
new BigNumber(jettonBalance).multipliedBy(rate.fiat),
{ currency },
@@ -48,9 +49,4 @@ export class JettonBalancesDependency extends DependencyPrototype<
},
};
}
-
- setWallet(wallet) {
- this.dataProvider = wallet.jettons.state;
- super.setWallet(wallet);
- }
}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/staking.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/staking.ts
index 1a89e3605..8e111d76b 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/staking.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/staking.ts
@@ -1,21 +1,16 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import { StakingState } from '$wallet/managers/StakingManager';
import { AccountStakingInfo, PoolInfo } from '@tonkeeper/core/src/TonAPI';
+import { Wallet } from '$wallet/Wallet';
export class StakingDependency extends DependencyPrototype<
StakingState,
{ info: AccountStakingInfo; pool: PoolInfo }[]
> {
- constructor() {
- super(tk.wallet.staking.state, (s) =>
+ constructor(wallet: Wallet) {
+ super(wallet.staking.state, (s) =>
s.pools.map((pool) => ({ info: s.stakingInfo[pool.address], pool })),
);
}
-
- setWallet(wallet) {
- this.dataProvider = wallet.staking.state;
- super.setWallet(wallet);
- }
}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/stakingJettons.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/stakingJettons.ts
index 66ada7c19..d5f736792 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/stakingJettons.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/stakingJettons.ts
@@ -1,21 +1,16 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import { Address } from '@tonkeeper/shared/Address';
import { StakingState } from '$wallet/managers/StakingManager';
import { JettonBalanceModel } from '$wallet/models/JettonBalanceModel';
+import { Wallet } from '$wallet/Wallet';
export class StakingJettonsDependency extends DependencyPrototype<
StakingState,
Pick
> {
- constructor() {
- super(tk.wallet.staking.state, (state) => ({ stakingJettons: state.stakingJettons }));
- }
-
- setWallet(wallet) {
- this.dataProvider = wallet.staking.state;
- super.setWallet(wallet);
+ constructor(wallet: Wallet) {
+ super(wallet.staking.state, (state) => ({ stakingJettons: state.stakingJettons }));
}
get filterTokensBalancesFn(): (balance: JettonBalanceModel) => boolean {
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts
index 059c9d47a..83388e478 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts
@@ -1,5 +1,4 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import {
TokenApprovalState,
@@ -11,18 +10,14 @@ import {
JettonVerification,
} from '$wallet/models/JettonBalanceModel';
import { InscriptionBalance } from '@tonkeeper/core/src/TonAPI';
+import { Wallet } from '$wallet/Wallet';
export class TokenApprovalDependency extends DependencyPrototype<
TokenApprovalState,
Pick
> {
- constructor() {
- super(tk.wallet.tokenApproval.state, (state) => ({ tokens: state.tokens }));
- }
-
- setWallet(wallet) {
- this.dataProvider = wallet.tokenApproval.state;
- super.setWallet(wallet);
+ constructor(wallet: Wallet) {
+ super(wallet.tokenApproval.state, (state) => ({ tokens: state.tokens }));
}
get filterInscriptionsFn(): (balance: InscriptionBalance) => boolean {
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts
index d78762f75..132f0a3cc 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts
@@ -1,6 +1,6 @@
import { DependencyPrototype } from './utils/prototype';
-import { tk } from '$wallet';
import { BalancesState } from '$wallet/managers/BalancesManager';
+import { Wallet } from '$wallet/Wallet';
export enum TonBalanceType {
Liquid = 'Liquid',
@@ -17,19 +17,14 @@ export class TonBalancesDependency extends DependencyPrototype<
BalancesState,
Pick
> {
- constructor() {
- super(tk.wallet.balances.state, (state) => ({
+ constructor(wallet: Wallet) {
+ super(wallet.balances.state, (state) => ({
ton: state.ton,
tonLocked: state.tonLocked,
tonRestricted: state.tonRestricted,
}));
}
- setWallet(wallet) {
- this.dataProvider = wallet.balances.state;
- super.setWallet(wallet);
- }
-
get balances() {
const balances: TonBalance[] = [
{ type: TonBalanceType.Liquid, balance: this.state.ton },
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts
index ecf6694d0..969554e19 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts
@@ -1,16 +1,16 @@
import { DependencyPrototype } from './utils/prototype';
import { PricesState } from '$wallet/managers/TonPriceManager';
-import { tk } from '$wallet';
import { FiatRate } from '../utils/types';
import { formatter } from '@tonkeeper/shared/formatter';
import BigNumber from 'bignumber.js';
+import { State } from '@tonkeeper/core';
export class TonPriceDependency extends DependencyPrototype<
PricesState,
Pick
> {
- constructor() {
- super(tk.tonPrice.state, (state) => ({ ton: state.ton, currency: state.currency }));
+ constructor(state: State) {
+ super(state, (state) => ({ ton: state.ton, currency: state.currency }));
}
protected shouldEmit(
@@ -20,11 +20,6 @@ export class TonPriceDependency extends DependencyPrototype<
return prev.ton !== cur.ton;
}
- setWallet(wallet) {
- this.dataProvider = wallet.tonPrice.state;
- super.setWallet(wallet);
- }
-
public getRawTotal(balance: string): string {
return new BigNumber(balance).multipliedBy(this.state.ton.fiat).toString();
}
@@ -45,6 +40,7 @@ export class TonPriceDependency extends DependencyPrototype<
? 'positive'
: 'negative',
total: {
+ in_ton: balance,
formatted: formatter.format(new BigNumber(balance).multipliedBy(rate.ton.fiat), {
currency: rate.currency,
}),
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/utils/prototype.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/utils/prototype.ts
index 08b8e6061..3e21054ea 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/utils/prototype.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/utils/prototype.ts
@@ -69,10 +69,7 @@ export class DependencyPrototype<
};
}
- public setWallet(wallet: Wallet) {
+ public destroy() {
this.unsubscribe?.();
- this.wallet = wallet;
- this.subscribeToDataProvider();
- this.onStateChanged();
}
}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/inscriptions.ts b/packages/mobile/src/tabs/Wallet/content-providers/inscriptions.ts
index 9f28412a9..1f644dd82 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/inscriptions.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/inscriptions.ts
@@ -54,6 +54,7 @@ export class InscriptionsContentProvider extends ContentProviderPrototype<{
},
trend: 'negative',
total: {
+ in_ton: '0',
formatted: formatter.format(0, {
currency: this.deps.tonPrice.state.currency,
}),
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts
index 4179d0282..d4827df6b 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts
@@ -8,13 +8,14 @@ import { TokensContentProvider } from '../tokens';
import { StakingJettonsDependency } from '../dependencies/stakingJettons';
import { TokenApprovalDependency } from '../dependencies/tokenApproval';
import { JettonBalancesDependency } from '../dependencies/jettons';
-import { Wallet } from '$wallet/Wallet';
import { StakingContentProvider } from '../staking';
import { StakingDependency } from '../dependencies/staking';
import { InscriptionsContentProvider } from '../inscriptions';
import { InscriptionsDependency } from '../dependencies/inscriptions';
import { NamespacedLogger, logger } from '$logger';
import BigNumber from 'bignumber.js';
+import { Wallet } from '$wallet/Wallet';
+import { tk } from '$wallet';
type Subscriber = (cells: CellItemToRender[]) => void;
@@ -23,14 +24,15 @@ export class WalletContentReceiver {
private subscribers = new Set();
private logger: NamespacedLogger;
+ private wallet: Wallet = tk.wallet;
- private tonPrice = new TonPriceDependency();
- private tonBalances = new TonBalancesDependency();
- private stakingJettons = new StakingJettonsDependency();
- private tokenApproval = new TokenApprovalDependency();
- private jettonBalances = new JettonBalancesDependency();
- private staking = new StakingDependency();
- private inscriptions = new InscriptionsDependency();
+ private tonPrice = new TonPriceDependency(tk.tonPrice.state);
+ private tonBalances = new TonBalancesDependency(this.wallet);
+ private stakingJettons = new StakingJettonsDependency(this.wallet);
+ private tokenApproval = new TokenApprovalDependency(this.wallet);
+ private jettonBalances = new JettonBalancesDependency(this.wallet);
+ private staking = new StakingDependency(this.wallet);
+ private inscriptions = new InscriptionsDependency(this.wallet);
private memoizedCells = new Map();
@@ -44,6 +46,11 @@ export class WalletContentReceiver {
this.inscriptions,
];
+ constructor() {
+ this.subscribeToProvidersChanges(this.providersList);
+ this.logger = logger.extend('WalletListContent');
+ }
+
private providersList: ContentProviderPrototype[] = [
new TONContentProvider(this.tonPrice, this.tonBalances),
new TokensContentProvider(
@@ -56,15 +63,10 @@ export class WalletContentReceiver {
new InscriptionsContentProvider(this.tonPrice, this.inscriptions, this.tokenApproval),
];
- constructor() {
- this.subscribeToProvidersChanges(this.providersList);
- this.logger = logger.extend('WalletListContent');
- }
-
- public setWallet(wallet: Wallet) {
- this.logger.debug('provide wallet to deps');
+ public destroy() {
+ this.logger.warn('Destroy');
this.depsList.forEach((provider) => {
- provider.setWallet(wallet);
+ provider.destroy();
});
}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts
index 165ba9e80..b72c9d5d5 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts
@@ -5,6 +5,7 @@ import { TonIconProps } from '@tonkeeper/uikit';
export type FiatRate = {
total: {
formatted: string;
+ in_ton: string;
raw: string;
};
percent?: string;
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/usePreparedWalletContent.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/usePreparedWalletContent.ts
index 8e1bed33d..e1819d182 100644
--- a/packages/mobile/src/tabs/Wallet/content-providers/utils/usePreparedWalletContent.ts
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/usePreparedWalletContent.ts
@@ -1,17 +1,15 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { CellItemToRender } from './types';
-import { useInstance } from '$hooks/useInstance';
import { WalletContentReceiver } from './receiver';
-import { tk } from '$wallet';
+import { useWallet } from '@tonkeeper/shared/hooks';
export const usePreparedWalletContent = () => {
- const providersReceiver = useInstance(() => new WalletContentReceiver());
+ const wallet = useWallet();
+ const providersReceiver = useMemo(() => new WalletContentReceiver(), [wallet]);
const [preparedContent, setPreparedContent] = useState([]);
useEffect(() => {
- return tk.onChangeWallet(() => {
- providersReceiver.setWallet(tk.wallet);
- });
+ return () => providersReceiver.destroy();
}, [providersReceiver]);
useEffect(() => {
diff --git a/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts b/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
index f9a30e3e1..e576e52d7 100644
--- a/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
+++ b/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import BigNumber from 'bignumber.js';
import { formatter } from '$utils/formatter';
-import { useWalletCurrency } from '@tonkeeper/shared/hooks';
+import { useDangerLevel, useWalletCurrency } from '@tonkeeper/shared/hooks';
import { CellItemToRender } from '../content-providers/utils/types';
export type Rate = {
@@ -12,17 +12,33 @@ export type Rate = {
export const useBalance = (cellItems: CellItemToRender[]) => {
const currency = useWalletCurrency();
+ const { inSelectedCurrency, inTonRaw } = useMemo(
+ () =>
+ cellItems.reduce(
+ (total, item) => {
+ const balance = item.fiatRate?.total.raw ?? '0';
+ const tonBalance = item.fiatRate?.total.in_ton ?? '0';
- return useMemo(() => {
- const totalNumber = cellItems.reduce((total, item) => {
- const balance = item.fiatRate?.total.raw ?? '0';
- return total.plus(balance);
- }, new BigNumber(0));
+ total.inSelectedCurrency = total.inSelectedCurrency.plus(balance);
+ total.inTonRaw = total.inTonRaw.plus(tonBalance);
+
+ return total;
+ },
+ { inSelectedCurrency: new BigNumber(0), inTonRaw: new BigNumber(0) },
+ ),
+ [cellItems],
+ );
- return formatter.format(totalNumber.toString(), {
- currency,
- forceRespectDecimalPlaces: true,
- decimals: totalNumber.gte(1000) ? 0 : 2,
- });
- }, [cellItems, currency]);
+ const dangerLevel = useDangerLevel(inTonRaw.toString());
+
+ return useMemo(() => {
+ return {
+ inSelectedCurrency: formatter.format(inSelectedCurrency.toString(), {
+ currency,
+ forceRespectDecimalPlaces: true,
+ decimals: inSelectedCurrency.gte(1000) ? 0 : 2,
+ }),
+ dangerLevel,
+ };
+ }, [currency, dangerLevel, inSelectedCurrency]);
};
diff --git a/packages/mobile/src/wallet/Wallet/WalletContent.ts b/packages/mobile/src/wallet/Wallet/WalletContent.ts
index 3918274a8..e8bdad4f3 100644
--- a/packages/mobile/src/wallet/Wallet/WalletContent.ts
+++ b/packages/mobile/src/wallet/Wallet/WalletContent.ts
@@ -26,6 +26,7 @@ import { TonProofManager } from '../managers/TonProofManager';
import { JettonVerification } from '../models/JettonBalanceModel';
import { CardsManager } from '$wallet/managers/CardsManager';
import { JettonQuantity } from '@tonkeeper/core/src/TonAPI';
+import { WalletContentReceiver } from '../../tabs/Wallet/content-providers/utils/receiver';
export interface WalletStatusState {
isReloading: boolean;
@@ -193,6 +194,33 @@ export class WalletContent extends WalletBase {
]);
}
+ public get totalTon() {
+ const ton = new BigNumber(this.balances.state.data.ton).multipliedBy(
+ this.tonPrice.state.data.ton.fiat,
+ );
+ const jettons = this.jettons.state.data.jettonBalances.reduce((total, jetton) => {
+ const isBlacklisted = jetton.verification === JettonVerification.BLACKLIST;
+ const approvalStatus =
+ this.tokenApproval.state.data.tokens[Address.parse(jetton.jettonAddress).toRaw()];
+ if (
+ (isBlacklisted && !approvalStatus) ||
+ approvalStatus?.current === TokenApprovalStatus.Declined
+ ) {
+ return total;
+ }
+ const rate =
+ this.jettons.state.data.jettonRates[Address.parse(jetton.jettonAddress).toRaw()];
+
+ return rate
+ ? total.plus(new BigNumber(jetton.balance).multipliedBy(rate.ton))
+ : total;
+ }, new BigNumber(0));
+ const staking = new BigNumber(this.staking.state.data.stakingBalance).multipliedBy(
+ this.tonPrice.state.data.ton.fiat,
+ );
+ return ton.plus(jettons).plus(staking).toString();
+ }
+
public get totalFiat() {
const ton = new BigNumber(this.balances.state.data.ton).multipliedBy(
this.tonPrice.state.data.ton.fiat,
diff --git a/packages/shared/hooks/index.ts b/packages/shared/hooks/index.ts
index faf7be6ea..6d386d70e 100644
--- a/packages/shared/hooks/index.ts
+++ b/packages/shared/hooks/index.ts
@@ -12,3 +12,4 @@ export * from './useBiometrySettings';
export * from './useLockSettings';
export * from './useWalletSetup';
export * from './useIsEnabledForBattery';
+export * from './useDangerLevel';
diff --git a/packages/shared/hooks/useDangerLevel.ts b/packages/shared/hooks/useDangerLevel.ts
new file mode 100644
index 000000000..2d5d2eeaf
--- /dev/null
+++ b/packages/shared/hooks/useDangerLevel.ts
@@ -0,0 +1,27 @@
+import BigNumber from 'bignumber.js';
+import { useWalletSetup } from './useWalletSetup';
+import { useWallet } from './useWallet';
+
+export enum DangerLevel {
+ Normal,
+ Medium,
+ High,
+}
+
+export const useDangerLevel = (inTonRaw: string): DangerLevel => {
+ const { lastBackupAt } = useWalletSetup();
+ const wallet = useWallet();
+
+ if (lastBackupAt !== null || wallet.isWatchOnly) {
+ return DangerLevel.Normal;
+ }
+
+ const inTonBn = new BigNumber(inTonRaw);
+
+ if (inTonBn.gte(20)) {
+ return DangerLevel.High;
+ } else if (inTonBn.gte(2)) {
+ return DangerLevel.Medium;
+ }
+ return DangerLevel.Normal;
+};
diff --git a/packages/shared/i18n/locales/tonkeeper/en.json b/packages/shared/i18n/locales/tonkeeper/en.json
index 96196eb9d..d3298e3c0 100644
--- a/packages/shared/i18n/locales/tonkeeper/en.json
+++ b/packages/shared/i18n/locales/tonkeeper/en.json
@@ -1168,6 +1168,7 @@
},
"backup_screen": {
"title": "Backup",
+ "backup_warning": "Your balance is %{totalFiat}, and it's only protected by a recovery phrase you haven't written down yet. Backup the phrase to avoid losing funds in case of device issues.",
"manual_title": "Manual",
"manual_caption": "Back up your wallet manually by writing down the recovery phrase.",
"manual_button": "Back Up Manually",
diff --git a/packages/shared/i18n/locales/tonkeeper/ru-RU.json b/packages/shared/i18n/locales/tonkeeper/ru-RU.json
index 7046f0ece..9207aa3d0 100644
--- a/packages/shared/i18n/locales/tonkeeper/ru-RU.json
+++ b/packages/shared/i18n/locales/tonkeeper/ru-RU.json
@@ -1232,6 +1232,7 @@
},
"backup_screen": {
"title": "Резервная копия",
+ "backup_warning": "На вашем балансе %{totalFiat} и он защищён только секретным ключом, который вы ещё не записали. Сделайте резервную копию ключа, чтобы не потерять средства в случае проблем с устройством.",
"manual_title": "Вручную",
"manual_caption": "Создайте резервную копию своего кошелька вручную, записав секретный ключ.",
"manual_button": "Сделать копию вручную",
diff --git a/packages/uikit/assets/icons/png/ic-information-circle-24@4x.png b/packages/uikit/assets/icons/png/ic-information-circle-24@4x.png
new file mode 100644
index 000000000..e70f91f21
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-information-circle-24@4x.png differ
diff --git a/packages/uikit/assets/icons/svg/24/ic-information-circle-24.svg b/packages/uikit/assets/icons/svg/24/ic-information-circle-24.svg
new file mode 100644
index 000000000..17792fa9a
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/24/ic-information-circle-24.svg
@@ -0,0 +1,4 @@
+
diff --git a/packages/uikit/src/components/Icon/Icon.tsx b/packages/uikit/src/components/Icon/Icon.tsx
index 1df0c98f7..795704885 100644
--- a/packages/uikit/src/components/Icon/Icon.tsx
+++ b/packages/uikit/src/components/Icon/Icon.tsx
@@ -13,6 +13,7 @@ export type IconColors =
| 'constantWhite'
| 'accentBlue'
| 'accentOrange'
+ | 'accentRed'
| 'accentGreen';
export interface IconProps {
diff --git a/packages/uikit/src/components/Icon/Icon.types.ts b/packages/uikit/src/components/Icon/Icon.types.ts
index 0d0e3bcb0..25d2be6aa 100644
--- a/packages/uikit/src/components/Icon/Icon.types.ts
+++ b/packages/uikit/src/components/Icon/Icon.types.ts
@@ -54,6 +54,7 @@ export type IconNames =
| 'ic-backspace-bold-24'
| 'ic-backup-24'
| 'ic-battery-almost-empty-24'
+ | 'ic-information-circle-24'
| 'ic-key-24'
| 'ic-reset-24'
| 'ic-ton-disabled-24'
@@ -242,6 +243,7 @@ export const AllIcons = [
'ic-backspace-bold-24',
'ic-backup-24',
'ic-battery-almost-empty-24',
+ 'ic-information-circle-24',
'ic-key-24',
'ic-reset-24',
'ic-ton-disabled-24',
@@ -431,6 +433,7 @@ export const IconSizes = {
'ic-backspace-bold-24': 24,
'ic-backup-24': 24,
'ic-battery-almost-empty-24': 24,
+ 'ic-information-circle-24': 24,
'ic-key-24': 24,
'ic-reset-24': 24,
'ic-ton-disabled-24': 24,
diff --git a/packages/uikit/src/components/Icon/IconList.native.ts b/packages/uikit/src/components/Icon/IconList.native.ts
index 84e50d81d..97b6dab47 100644
--- a/packages/uikit/src/components/Icon/IconList.native.ts
+++ b/packages/uikit/src/components/Icon/IconList.native.ts
@@ -54,6 +54,7 @@ export const IconList = {
'ic-backspace-bold-24': require('../../../assets/icons/png/ic-backspace-bold-24.png'),
'ic-backup-24': require('../../../assets/icons/png/ic-backup-24.png'),
'ic-battery-almost-empty-24': require('../../../assets/icons/png/ic-battery-almost-empty-24.png'),
+ 'ic-information-circle-24': require('../../../assets/icons/png/ic-information-circle-24.png'),
'ic-key-24': require('../../../assets/icons/png/ic-key-24.png'),
'ic-reset-24': require('../../../assets/icons/png/ic-reset-24.png'),
'ic-ton-disabled-24': require('../../../assets/icons/png/ic-ton-disabled-24.png'),
diff --git a/packages/uikit/src/components/Text/Text.tsx b/packages/uikit/src/components/Text/Text.tsx
index 6accefbe6..9ff87e25e 100644
--- a/packages/uikit/src/components/Text/Text.tsx
+++ b/packages/uikit/src/components/Text/Text.tsx
@@ -17,6 +17,7 @@ export type TextColors =
| 'textAccent'
| 'textPrimaryAlternate'
| 'accentOrange'
+ | 'accentRed'
| 'accentGreen'
| 'accentBlue'
| 'constantWhite'
diff --git a/packages/uikit/src/styles/themes/dark.ts b/packages/uikit/src/styles/themes/dark.ts
index 030c7ea75..9fb190483 100644
--- a/packages/uikit/src/styles/themes/dark.ts
+++ b/packages/uikit/src/styles/themes/dark.ts
@@ -3,7 +3,7 @@ export const DarkTheme = {
textSecondary: '#8994A3',
textTertiary: '#556170',
textAccent: '#45AEF5',
- textPrimaryAlternate: '#10161F',
+ textPrimaryAlternate: '#000000',
backgroundPage: '#10161F',
backgroundTransparent: 'rgba(16, 22, 31, 0.96)',